From aae5858b5174024dc74531d067118cdf5c042210 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 12 Apr 2021 08:45:48 +0200 Subject: [PATCH 01/17] small stuff coverage related --- rowers/views/workoutviews.py | 118 ++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index c26b1ac7..0048006e 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -2054,7 +2054,7 @@ def workouts_view(request,message='',successmessage='', activity_startdate = activity_startdate.replace(hour=0,minute=0,second=0) else: activity_enddate = enddate - except ValueError: + except ValueError: # pragma: no cover activity_enddate = enddate g_startdate = activity_startdate @@ -2064,7 +2064,7 @@ def workouts_view(request,message='',successmessage='', if teamid: try: theteam = Team.objects.get(id=teamid) - except Team.DoesNotExist: + except Team.DoesNotExist: # pragma: no cover raise Http404("Team doesn't exist") if theteam.viewing == 'allmembers' or theteam.manager == request.user: @@ -2138,7 +2138,7 @@ def workouts_view(request,message='',successmessage='', # polarization = dataprep.polarization_index(df,r) - if query: + if query: # pragma: no cover query_list = query.split() workouts = workouts.filter( reduce(operator.and_, @@ -2151,13 +2151,11 @@ def workouts_view(request,message='',successmessage='', searchform = SearchForm() paginator = Paginator(workouts,20) # show 25 workouts per page - page = request.GET.get('page') + page = request.GET.get('page',1) try: workouts = paginator.page(page) - except PageNotAnInteger: - workouts = paginator.page(1) - except EmptyPage: + except EmptyPage: # pragma: no cover workouts = paginator.page(paginator.num_pages) today = timezone.now() @@ -2174,7 +2172,7 @@ def workouts_view(request,message='',successmessage='', stack='type' yaxis = request.GET.get('yaxis','duration') - if yaxis not in ['duration','trimp','rscore']: + if yaxis not in ['duration','trimp','rscore']: # pragma: no cover yaxis = 'duration' script,div = interactive_activitychart(g_workouts, @@ -2254,7 +2252,7 @@ def workout_fusion_list(request,id=0, enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) #enddate = enddate+datetime.timedelta(days=1) - if enddate < startdate: + if enddate < startdate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -2269,7 +2267,7 @@ def workout_fusion_list(request,id=0, startdatetime__lte=enddate).order_by("-date", "-starttime").exclude(id=theid) query = request.GET.get('q') - if query: + if query: # pragma: no cover query_list = query.split() workouts = workouts.filter( reduce(operator.and_, @@ -2282,12 +2280,10 @@ def workout_fusion_list(request,id=0, searchform = SearchForm() paginator = Paginator(workouts,15) # show 25 workouts per page - page = request.GET.get('page') + page = request.GET.get('page',1) try: workouts = paginator.page(page) - except PageNotAnInteger: - workouts = paginator.page(1) except EmptyPage: workouts = paginator.page(paginator.num_pages) row = get_workoutuser(id, request) @@ -2499,7 +2495,7 @@ def workout_undo_smoothenpace_view( filename = row.csvfilename row = rdata(filename) - if row == 0: + if row == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") if 'originalvelo' in row.df: @@ -2534,7 +2530,7 @@ def workout_smoothenpace_view(request,id=0,message="",successmessage=""): filename = row.csvfilename row = rdata(filename) - if row == 0: + if row == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") try: @@ -2542,7 +2538,7 @@ def workout_smoothenpace_view(request,id=0,message="",successmessage=""): velo = 500./pace except KeyError: messages.error(request,'Unable to find the data') - if previousurl: + if previousurl: # pragma: no cover url = previousurl else: url = reverse(r.defaultlandingpage, @@ -2595,7 +2591,7 @@ def workout_downloadwind_view(request,id=0, # create bearing rowdata = rdata(f1) - if rowdata == 0: + if rowdata == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") try: @@ -2623,7 +2619,7 @@ def workout_downloadwind_view(request,id=0, if message is not None: try: row.notes += "\n"+message - except TypeError: + except TypeError: # pragma: no cover if message is not None and row.notes is not None: row.notes += message @@ -2664,7 +2660,7 @@ def workout_downloadmetar_view(request,id=0, # create bearing rowdata = rdata(f1) - if rowdata == 0: + if rowdata == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") try: @@ -2691,7 +2687,7 @@ def workout_downloadmetar_view(request,id=0, message = winddata[2] try: row.notes += "\n"+message - except TypeError: + except TypeError: # pragma: no cover if message is not None: try: row.notes += message @@ -2752,7 +2748,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""): # create bearing rowdata = rdata(f1) - if row == 0: + if row == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") @@ -2762,7 +2758,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""): except KeyError: hascoordinates = 0 - if hascoordinates and not latitude.std(): + if hascoordinates and not latitude.std(): # pragma: no cover hascoordinates = 0 try: @@ -2806,7 +2802,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""): rowdata.write_csv(f1,gzip=True) - else: + else: # pragma: no cover message = "Invalid Form" messages.error(request,message) kwargs = { @@ -2868,7 +2864,7 @@ def workout_stream_view(request,id=0,message="",successmessage=""): r = getrower(u) rowdata = rdata(f1) - if rowdata == 0: + if rowdata == 0: # pragma: no cover messages.info(request,"Error: CSV data file not found") url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(row.id)}) return HttpResponseRedirect(url) @@ -2891,7 +2887,7 @@ def workout_stream_view(request,id=0,message="",successmessage=""): rowdata.write_csv(f1,gzip=True) - else: + else: # pragma: no cover message = "Invalid Form" messages.error(request,message) kwargs = { @@ -2968,7 +2964,7 @@ def workout_otwsetpower_view(request,id=0,message="",successmessage=""): # load row data & create power/wind/bearing columns if not set f1 = w.csvfilename rowdata = rdata(f1) - if rowdata == 0: + if rowdata == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") try: vstream = rowdata.df['vstream'] @@ -3025,7 +3021,7 @@ def workout_otwsetpower_view(request,id=0,message="",successmessage=""): response = HttpResponseRedirect(url) return response - else: + else: # pragma: no cover message = "Invalid Form" messages.error(request,message) kwargs = { @@ -3098,7 +3094,7 @@ def instroke_view(request,id=0): try: instrokemetrics = rowdata.get_instroke_columns() instrokemetrics = [m for m in instrokemetrics if not m in nometrics] - except AttributeError: + except AttributeError: # pragma: no cover instrokemetrics = [] @@ -3484,7 +3480,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""): try: fielddict.pop('pace') - except KeyError: + except KeyError: # pragma: no cover pass for field,verbosename in fielddict.items(): @@ -3501,7 +3497,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""): 'verbosename':verbosename, } stats[field] = thedict - except KeyError: + except KeyError: # pragma: no cover pass # Create a dict with correlation values @@ -3513,7 +3509,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""): for field2,verbosename2 in fielddict.items(): try: thedict[verbosename2] = cor.loc[field1,field2] - except KeyError: + except KeyError: # pragma: no cover thedict[verbosename2] = 0 cordict[verbosename1] = thedict @@ -3578,7 +3574,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""): 'value': hrdrift, 'unit': '%', } - except (ZeroDivisionError,ValueError): + except (ZeroDivisionError,ValueError): # pragma: no cover pass # TRIMP @@ -3753,7 +3749,7 @@ def workout_workflow_view(request,id): try: template.loader.get_template(t) middleTemplates.append(t) - except template.TemplateDoesNotExist: + except template.TemplateDoesNotExist: # pragma: no cover pass leftTemplates = [] @@ -3761,7 +3757,7 @@ def workout_workflow_view(request,id): try: template.loader.get_template(t) leftTemplates.append(t) - except template.TemplateDoesNotExist: + except template.TemplateDoesNotExist: # pragma: no cover pass @@ -3804,7 +3800,7 @@ def workout_flexchart3_view(request,*args,**kwargs): try: id = kwargs['id'] - except KeyError: + except KeyError: # pragma: no cover raise Http404("Invalid workout number") if 'promember' in kwargs: @@ -3841,7 +3837,7 @@ def workout_flexchart3_view(request,*args,**kwargs): if favorites: try: t = favorites[favoritenr].xparam - except IndexError: + except IndexError: # pragma: no cover favoritenr=0 except AssertionError: favoritenr=0 @@ -3864,7 +3860,7 @@ def workout_flexchart3_view(request,*args,**kwargs): if 'yparam2' in kwargs: yparam2 = kwargs['yparam2'] - if yparam2 == '': + if yparam2 == '': # pragma: no cover yparam2 = 'None' else: if favorites: @@ -3879,7 +3875,7 @@ def workout_flexchart3_view(request,*args,**kwargs): if favoritenr>=0 and r.showfavoritechartnotes: try: favoritechartnotes = favorites[favoritenr].notes - except IndexError: + except IndexError: # pragma: no cover favoritechartnotes = '' else: favoritechartnotes = '' @@ -3992,12 +3988,12 @@ def workout_flexchart3_view(request,*args,**kwargs): rowdata = rdata(row.csvfilename) try: rowdata.set_instroke_metrics() - except (AttributeError,TypeError): + except (AttributeError,TypeError): # pragma: no cover pass try: additionalmetrics = rowdata.get_additional_metrics() additionalmetrics = [m for m in additionalmetrics if not m in nometrics] - except AttributeError: + except AttributeError: # pragma: no cover additionalmetrics = [] @@ -4387,6 +4383,19 @@ def workout_edit_view(request,id=0,message="",successmessage=""): except: pass + if request.user.rower.rowerplan == 'basic' and 'nklinklogbook' in row.workoutsource: + data = getsmallrowdata_db(['wash'],ids=[encoder.decode_hex(id)]) + try: + if data['wash'].std() != 0: + url = reverse('paidplans_view') + messages.info( + request, + 'Some Empower Oarlock data are only available to users with a paid plan'.format(u=url) + ) + except: + pass + + form = WorkoutForm(instance=row) if request.method == 'POST': @@ -4410,13 +4419,10 @@ def workout_edit_view(request,id=0,message="",successmessage=""): rpe = form.cleaned_data['rpe'] if not rpe: rpe = -1 - except KeyError: + except KeyError: # pragma: no cover rpe = -1 - try: - ps = form.cleaned_data['plannedsession'] - except KeyError: - ps = None + ps = form.cleaned_data.get('plannedsession',None) try: boattype = request.POST['boattype'] @@ -4557,7 +4563,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): except (KeyError,AttributeError): hascoordinates = 0 - else: + else: # pragma: no cover hascoordinates = 0 @@ -4570,7 +4576,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): rowdata.df[' latitude'], rowdata.df[' longitude'], row.name) - except KeyError: + except KeyError: # pragma: no cover pass breadcrumbs = [ @@ -5877,12 +5883,10 @@ def list_videos(request,userid=0): paginator = Paginator(g,8) - page = request.GET.get('page') + page = request.GET.get('page',1) try: g = paginator.page(page) - except PageNotAnInteger: - g = paginator.page(1) except EmptyPage: g = paginator.page(paginator.num_pages) @@ -6005,7 +6009,7 @@ def workout_summary_restore_view(request,id,message="",successmessage=""): powerperc=powerperc,powerzones=r.powerzones, hrzones=r.hrzones) rowdata = rdata(f1,rower=rr) - if rowdata == 0: + if rowdata == 0: # pragma: no cover raise Http404("Error: CSV Data File Not Found") rowdata.restoreintervaldata() rowdata.write_csv(f1,gzip=True) @@ -6019,7 +6023,7 @@ def workout_summary_restore_view(request,id,message="",successmessage=""): res = interactive_chart(encoder.decode_hex(id),promember=1) script = res[0] div = res[1] - except ValueError: + except ValueError: # pragma: no cover pass @@ -6072,7 +6076,7 @@ def workout_split_view(request,id=0): ) for message in mesgs: messages.info(request,message) - except IndexError: + except IndexError: # pragma: no cover messages.error(request,"Something went wrong in Split") @@ -6114,7 +6118,7 @@ def workout_split_view(request,id=0): res = interactive_chart(encoder.decode_hex(id),promember=1) script = res[0] div = res[1] - except ValueError: + except ValueError: # pragma: no cover pass return render(request, 'splitworkout.html', @@ -6263,12 +6267,12 @@ def workout_summary_edit_view(request,id,message="",successmessage="" powerperc=powerperc,powerzones=r.powerzones, hrzones=r.hrzones) rowdata = rdata(f1,rower=rr) - if rowdata == 0: + if rowdata == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") intervalstats = rowdata.allstats() try: itime,idist,itype = rowdata.intervalstats_values() - except TypeError: + except TypeError: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") nrintervals = len(idist) @@ -6307,7 +6311,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" try: normspm = int(normspm) - except ValueError: + except ValueError: # pragma: no cover normspm = 18 try: From 53b5660c8f5d5a27a4610263dc45cd6e5752313d Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 12 Apr 2021 12:10:11 +0200 Subject: [PATCH 02/17] coverage improvements --- rowers/tests/test_aworkouts.py | 70 ++- rowers/tests/test_uploads.py | 52 +++ rowers/tests/testdata/Impeller.csv | 684 +++++++++++++++++++++++++++++ rowers/views/workoutviews.py | 49 +-- 4 files changed, 821 insertions(+), 34 deletions(-) create mode 100644 rowers/tests/testdata/Impeller.csv diff --git a/rowers/tests/test_aworkouts.py b/rowers/tests/test_aworkouts.py index 9adfa075..9228e781 100644 --- a/rowers/tests/test_aworkouts.py +++ b/rowers/tests/test_aworkouts.py @@ -42,6 +42,7 @@ class WorkoutViewTest(TestCase): rowerplan='coach') self.c = Client() + self.c2 = Client() # for anonymous self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) self.factory = RequestFactory() self.password = faker.word() @@ -121,7 +122,9 @@ class WorkoutViewTest(TestCase): ) def tearDown(self): - pass + vs = VideoAnalysis.objects.all() + for v in vs: + v.delete() @patch('rowers.dataprep.create_engine') @patch('rowers.dataprep.getsmallrowdata_db') @@ -137,7 +140,8 @@ class WorkoutViewTest(TestCase): self.assertEqual(response.status_code,200) form_data = { - 'workstrokesonly': True + 'workstrokesonly': True, + 'plottype': 'scatter' } response = self.c.post(url,form_data) @@ -657,6 +661,68 @@ class WorkoutViewTest(TestCase): response = self.c.post(url,form_data) self.assertEqual(response.status_code,200) + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db') + @patch('rowers.dataprep.get_video_data',side_effect=mocked_videodata) + def test_workout_video_view_erg(self, mocked_sqlalchemy, mocked_getsmallrowdata_db, + mocked_videodata): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + + url = reverse('workout_video_create_view',kwargs={'id':encoder.encode_hex(self.werg1.id)}) + url2 = reverse('workout_video_view',kwargs={'id':encoder.encode_hex(1)}) + + + yturl = 'https://youtu.be/6UzaWm1Ybrw' + + response = self.c.get(url) + + self.assertEqual(response.status_code,200) + + form_data = { + 'url': yturl, + 'delay': -119, + 'groups': ['basic'], + 'name': 'Video A', + 'save_button':'Save', + } + + response = self.c.post(url,form_data) + self.assertRedirects(response, + expected_url=url2, + status_code=302, + target_status_code=200) + + response = self.c.get(url2) + self.assertEqual(response.status_code,200) + + form_data = { + 'url': yturl, + 'delay': -119, + 'groups': ['basic'], + 'name': 'Video A', + 'save_button': 'Save', + } + + response = self.c.post(url2,form_data) + self.assertEqual(response.status_code,200) + + url = reverse('workout_video_view_mini',kwargs={'id':encoder.encode_hex(1)}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + response = self.c.post(url,form_data) + self.assertEqual(response.status_code,200) + + url = reverse('workout_video_view_mini',kwargs={'id':encoder.encode_hex(1)}) + response = self.c2.get(url) + self.assertEqual(response.status_code,200) + + url = reverse('workout_video_view',kwargs={'id':encoder.encode_hex(1)}) + response = self.c2.get(url) + self.assertEqual(response.status_code,200) + + @patch('rowers.dataprep.create_engine') @patch('rowers.dataprep.getrowdata_db',side_effect=mocked_getrowdata_db) @patch('rowers.dataprep.get_video_data',side_effect=mocked_videodata) diff --git a/rowers/tests/test_uploads.py b/rowers/tests/test_uploads.py index d9fbbac5..2f57451a 100644 --- a/rowers/tests/test_uploads.py +++ b/rowers/tests/test_uploads.py @@ -378,6 +378,58 @@ class ViewTest(TestCase): except (FileNotFoundError,OSError): pass + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.TCXParser') + def test_upload_view_SpeedCoachImpeller(self, mocked_sqlalchemy, + mocked_tcx_parser): + self.c.login(username='john',password='koeinsloot') + + filename = 'rowers/tests/testdata/Impeller.csv' + f = open(filename,'rb') + file_data = {'file': f} + + form_data = { + 'title':'test', + 'workouttype':'water', + 'boattype':'1x', + 'notes':'aap noot mies', + 'make_plot':False, + 'upload_to_c2':False, + 'plottype':'timeplot', + 'file': f, + 'rpe':6, + } + + form = DocumentsForm(form_data,file_data) + + response = self.c.post('/rowers/workout/upload/', form_data, follow=True) + f.close() + self.assertRedirects(response, expected_url='/rowers/workout/'+encoded1+'/edit/', + status_code=302,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + url = reverse('otw_use_gps',kwargs={'id':encoded1}) + + response = self.c.get(url,follow=True) + self.assertRedirects(response, expected_url='/rowers/workout/'+encoded1+'/edit/', + status_code=302,target_status_code=200) + + url = reverse('otw_use_impeller',kwargs={'id':encoded1}) + + response = self.c.get(url,follow=True) + self.assertRedirects(response, expected_url='/rowers/workout/'+encoded1+'/edit/', + status_code=302,target_status_code=200) + + + w = Workout.objects.get(id=1) + f_to_be_deleted = w.csvfilename + try: + os.remove(f_to_be_deleted+'.gz') + except (FileNotFoundError,OSError): + pass + + @patch('rowers.dataprep.create_engine') diff --git a/rowers/tests/testdata/Impeller.csv b/rowers/tests/testdata/Impeller.csv new file mode 100644 index 00000000..d0caa00a --- /dev/null +++ b/rowers/tests/testdata/Impeller.csv @@ -0,0 +1,684 @@ +Session Information:,,,,Device Information:,,,,Oarlock Information:,,,,Oarlock Settings:,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,, +Name:,3(10x150M/1:00),,,Name:,SpdCoach 2384229,,,Firmware:,1.01,,,Boat ID:,18EMP,,,,,,,,,, +Start Time:,6/29/20 6:57,,,Model:,SpeedCoach GPS Pro,,,,,,,Seat Number:,1,,,,,,,,,, +Type:,Interval,,,Serial:,2384229,,,,,,,Port Starboard:,Port,,,,,,,,,, +System of Units:,Meters/Split500,,,Firmware Version:,2.22,,,,,,,Oar Length:,283,,,,,,,,,, +Speed Input:,Impeller,,,Profile Version:,0.03,,,,,,,Inboard Length:,87,,,,,,,,,, +,,,,Hardware Version:,Rev 11,,,,,,,,,,,,,,,,,, +,,,,LiNK Version:,2.1.68,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,, +Session Summary:,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,, +Total Intervals,Total Distance (GPS),Total Distance (IMP),Total Elapsed Time,Avg Split (GPS),Avg Speed (GPS),Avg Split (IMP),Avg Speed (IMP),Avg Stroke Rate,Total Strokes,Distance/Stroke (GPS),Distance/Stroke (IMP),Avg Heart Rate,Avg Power,Avg Catch,Avg Slip,Avg Finish,Avg Wash,Avg Force Avg,Avg Work,Avg Force Max,Avg Max Force Angle,Start GPS Lat.,Start GPS Lon. +(Interval),(Meters),(Meters),(HH:MM:SS.tenths),(/500),(M/S),(/500),(M/S),(SPM),(Strokes),(Meters),(Meters),(BPM),(Watts),(Degrees),(Degrees),(Degrees),(Degrees),(Newtons),(Joules),(Newtons),(Degrees),(Degrees),(Degrees) +30,4501.1,4500.8,18:35.6,02:03.9,4.04,02:04.1,4.03,35.5,597,7.5,7.6,142,270,-66,5,37,12,270,475,468,-6,41.5995564,-71.0665364 +,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,, +Interval Summaries:,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,, +Interval,Total Distance (GPS),Total Distance (IMP),Total Elapsed Time,Avg Split (GPS),Avg Speed (GPS),Avg Split (IMP),Avg Speed (IMP),Avg Stroke Rate,Total Strokes,Distance/Stroke (GPS),Distance/Stroke (IMP),Avg Heart Rate,Avg Power,Avg Catch,Avg Slip,Avg Finish,Avg Wash,Avg Force Avg,Avg Work,Avg Force Max,Avg Max Force Angle,Start GPS Lat.,Start GPS Lon. +(Interval),(Meters),(Meters),(HH:MM:SS.tenths),(/500),(M/S),(/500),(M/S),(SPM),(Strokes),(Meters),(Meters),(BPM),(Watts),(Degrees),(Degrees),(Degrees),(Degrees),(Newtons),(Joules),(Newtons),(Degrees),(Degrees),(Degrees) +1,156.2,150.1,00:35.0,01:52.1,4.46,01:56.8,4.28,40.5,22,7.1,6.8,132,289,-64,4,36,12,278,477,491,-6,41.5995564,-71.0665364 +2,154.1,150,00:34.1,01:50.4,4.53,01:53.9,4.39,39,20,7.7,7.5,146,281,-64,5,37,13,282,478,494,-10,41.5973351,-71.0664761 +3,152.4,150,00:33.8,01:48.2,4.62,01:52.9,4.43,40,20,7.6,7.5,139,278,-63,4,37,13,277,468,491,-10,41.5952349,-71.066896 +4,155.1,150,00:34.8,01:49.6,4.56,01:56.0,4.31,34,19,8.2,7.9,141,270,-66,5,37,13,273,474,476,-11,41.5930859,-71.067406 +5,158.3,150,00:38.8,02:00.2,4.16,02:09.5,3.86,34,20,7.9,7.5,142,266,-65,5,37,13,265,462,471,-9,41.5909617,-71.0679011 +6,152.1,150.1,00:34.7,01:51.9,4.47,01:55.7,4.32,38,20,7.6,7.5,143,265,-66,5,37,12,271,470,465,-7,41.5892061,-71.0696163 +7,158.2,150.1,00:40.1,02:06.3,3.96,02:13.7,3.74,33.5,20,7.9,7.5,144,279,-66,5,37,12,279,480,468,-5,41.5871894,-71.0704806 +8,157.1,150,00:39.6,02:04.1,4.03,02:12.3,3.78,33.5,20,7.9,7.5,143,278,-66,5,37,11,279,481,466,-4,41.5850482,-71.0701023 +9,157,150,00:40.3,02:07.6,3.92,02:14.4,3.72,38.5,21,7.5,7.1,141,282,-65,4,33,11,262,467,432,-8,41.5828997,-71.0705657 +10,157.6,150,00:36.2,01:54.2,4.38,02:00.8,4.14,36,21,7.5,7.1,140,254,-66,5,37,12,263,467,454,-5,41.580819,-71.0714181 +11,134.9,150,00:35.4,02:09.9,3.85,01:58.2,4.23,36,20,6.7,7.5,143,249,-65,5,38,13,263,445,447,-2,41.5791371,-71.0717237 +12,138.6,150.1,00:34.7,02:02.5,4.08,01:55.7,4.32,33.5,19,7.3,7.9,146,255,-67,5,37,13,261,453,440,-9,41.5809033,-71.0711711 +13,137.8,150,00:38.3,02:18.1,3.62,02:07.9,3.91,36,20,6.9,7.5,144,242,-65,7,38,13,253,440,438,-2,41.5825778,-71.0702609 +14,140.6,150.1,00:36.8,02:07.9,3.91,02:02.9,4.07,32,18,7.8,8.3,144,238,-67,5,38,13,248,440,421,-4,41.5844843,-71.0696758 +15,139.3,150,00:42.2,02:30.6,3.32,02:20.8,3.55,35.5,21,6.6,7.1,141,258,-65,4,34,12,267,457,453,-6,41.5862039,-71.0695255 +16,142.4,150,00:40.7,02:20.4,3.56,02:15.9,3.68,32.5,20,7.1,7.5,144,272,-65,4,38,12,273,489,482,-3,41.5878803,-71.0695177 +17,139.5,150,00:41.9,02:27.1,3.4,02:19.7,3.58,37.5,22,6.3,6.8,145,268,-66,5,38,12,271,476,472,-3,41.5894643,-71.0691011 +18,136.5,150.1,00:40.2,02:26.6,3.41,02:14.0,3.73,34,20,6.8,7.5,144,248,-63,5,32,12,254,429,441,-6,41.5907955,-71.0676746 +19,137.2,150,00:35.1,02:07.6,3.92,01:57.1,4.27,37,21,6.5,7.1,143,275,-65,5,37,12,273,470,478,-4,41.5922912,-71.0668988 +20,137.5,150,00:40.4,02:25.3,3.44,02:14.8,3.71,32.5,19,7.2,7.9,144,261,-65,5,34,12,252,481,475,-8,41.5939639,-71.0665077 +21,155.9,150.1,00:35.0,01:52.4,4.45,01:56.8,4.28,33.5,19,8.2,7.9,148,279,-67,5,37,12,270,477,466,-6,41.5950311,-71.0665461 +22,159.5,150,00:35.4,01:49.6,4.56,01:58.2,4.23,38.5,21,7.6,7.1,143,269,-66,5,37,12,265,477,478,-4,41.5929694,-71.0673018 +23,156.5,150,00:33.7,01:45.5,4.74,01:52.4,4.45,34.5,19,8.2,7.9,148,268,-65,5,34,12,259,474,460,-7,41.5907816,-71.0681228 +24,151.4,150,00:35.6,01:55.7,4.32,01:58.8,4.21,33.5,17,8.9,8.8,146,263,-68,5,38,13,260,486,478,-5,41.5890631,-71.0697857 +25,153.9,150,00:35.1,01:53.6,4.4,01:57.1,4.27,33,19,8.1,7.9,145,291,-68,4,37,12,283,501,491,-6,41.5870056,-71.0696265 +26,156.2,150,00:33.6,01:45.7,4.73,01:52.1,4.46,34,19,8.2,7.9,144,287,-68,4,37,11,280,499,478,-3,41.5848979,-71.069679 +27,162.1,150,00:41.5,02:06.6,3.95,02:18.5,3.61,36,21,7.7,7.1,146,280,-66,4,38,11,281,501,488,-2,41.5828133,-71.069893 +28,157.2,150,00:33.4,01:45.0,4.76,01:51.4,4.49,34.5,19,8.3,7.9,147,299,-68,4,37,11,290,512,485,-3,41.5806848,-71.0707818 +29,152.7,150,00:39.8,02:07.9,3.91,02:13.0,3.76,37.5,20,7.6,7.5,145,287,-67,5,38,10,294,518,505,-5,41.5788242,-71.0721609 +30,153.6,150,00:39.4,02:06.9,3.94,02:11.6,3.8,37,20,7.7,7.5,144,274,-67,4,34,10,270,494,465,-2,41.576721,-71.0719792 +,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,, +Per-Stroke Data:,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,, +Interval,Distance (GPS),Distance (IMP),Elapsed Time,Split (GPS),Speed (GPS),Split (IMP),Speed (IMP),Stroke Rate,Total Strokes,Distance/Stroke (GPS),Distance/Stroke (IMP),Heart Rate,Power,Catch,Slip,Finish,Wash,Force Avg,Work,Force Max,Max Force Angle,GPS Lat.,GPS Lon. +(Interval),(Meters),(Meters),(HH:MM:SS.tenths),(/500),(M/S),(/500),(M/S),(SPM),(Strokes),(Meters),(Meters),(BPM),(Watts),(Degrees),(Degrees),(Degrees),(Degrees),(Newtons),(Joules),(Newtons),(Degrees),(Degrees),(Degrees) +1,1.6,0,00:01.5,09:15.6,0.9,00:00.0,0,38.5,1,1.6,0,119,206,-45,0,41,8,232,563,690,10,41.5995564,-71.0665364 +1,2.7,0.8,00:01.9,04:01.5,2.07,03:01.8,2.75,109.5,2,1.1,0.8,119,321,-43,3,36,6,382,491,619,12,41.5995462,-71.0665366 +1,8.4,6.6,00:03.5,02:36.7,3.19,02:21.6,3.53,41.5,3,5.7,5.8,119,348,-53,4,38,8,338,518,561,1,41.5994952,-71.0665351 +1,14.3,12.5,00:04.9,02:15.9,3.68,02:04.7,4.01,39.5,4,5.9,5.9,119,317,-61,4,37,11,299,491,502,7,41.5994419,-71.0665328 +1,21.5,19.5,00:06.5,01:58.5,4.22,01:55.5,4.33,37.5,5,7.1,7,118,301,-63,5,36,9,284,475,472,8,41.5993778,-71.0665304 +1,29,26.8,00:08.2,01:51.1,4.5,01:51.1,4.5,37.5,6,7.5,7.3,118,296,-64,5,36,11,272,476,480,5,41.5993107,-71.0665281 +1,36.5,34,00:09.7,01:47.8,4.64,01:50.1,4.54,37.5,7,7.6,7.3,119,294,-66,4,36,12,271,473,462,5,41.5992427,-71.0665247 +1,44.2,41.3,00:11.3,01:46.6,4.69,01:49.2,4.58,37.5,8,7.7,7.3,120,295,-66,5,37,12,267,479,491,-9,41.5991737,-71.0665205 +1,51.8,48.7,00:12.9,01:46.6,4.69,01:48.5,4.61,36.5,9,7.6,7.4,121,304,-67,5,36,11,271,499,493,-7,41.5991058,-71.0665155 +1,60.1,58.2,00:15.0,01:46.6,4.69,01:48.2,4.62,37,10,8.3,9.5,123,317,-68,5,37,12,290,527,508,-3,41.5990312,-71.0665079 +1,67.9,64.5,00:16.3,01:45.5,4.74,01:47.1,4.67,35.5,11,7.7,6.3,126,312,-67,4,37,12,290,509,494,-12,41.5989619,-71.0665004 +1,74.9,72.2,00:18.0,01:45.3,4.75,01:47.1,4.67,35.5,12,7,7.7,129,278,-67,5,36,13,272,462,460,-14,41.598899,-71.0664938 +1,84,80.3,00:19.7,01:42.9,4.86,01:48.7,4.6,36,13,9.2,8,133,276,-68,5,36,13,266,461,452,-14,41.5988169,-71.0664861 +1,91.6,87.6,00:21.3,01:43.9,4.81,01:47.8,4.64,36,14,7.6,7.4,136,288,-68,4,35,13,280,480,469,-17,41.598749,-71.0664801 +1,99.2,95.1,00:22.9,01:46.6,4.69,01:49.6,4.56,37,15,7.6,7.5,138,278,-67,4,35,12,269,461,463,-14,41.5986808,-71.0664738 +1,106.8,102.3,00:24.5,01:46.6,4.69,01:49.4,4.57,35.5,16,7.5,7.3,140,284,-67,4,35,14,265,469,462,-12,41.5986132,-71.0664674 +1,115.2,110.5,00:26.3,01:46.8,4.68,01:49.9,4.55,37.5,17,8.4,8.2,142,288,-67,5,35,14,267,458,444,-6,41.5985377,-71.0664617 +1,122.1,117.1,00:27.8,01:47.3,4.66,01:49.9,4.55,37.5,18,6.9,6.6,145,246,-66,5,35,17,234,389,412,-13,41.598476,-71.0664579 +1,129.5,124.1,00:29.3,01:47.1,4.67,01:50.9,4.51,37.5,19,7.4,7,147,292,-67,3,34,14,278,472,479,-15,41.5984093,-71.0664532 +1,137.8,132.1,00:31.1,01:47.5,4.65,01:51.9,4.47,37.5,20,8.3,7.9,149,286,-67,5,35,14,274,457,447,-17,41.5983352,-71.0664489 +1,145.1,140.4,00:33.0,01:47.8,4.64,01:51.1,4.5,36,21,7.4,8.3,151,270,-67,4,36,16,258,440,466,-15,41.5982689,-71.0664483 +1,152.5,146.4,00:34.3,01:46.6,4.69,01:52.9,4.43,37,22,7.4,6,152,268,-67,5,36,16,254,442,469,-16,41.5982026,-71.0664484 +2,1.7,3.7,00:00.5,04:05.1,2.04,03:05.2,2.7,109.5,1,1.7,3.7,143,341,-45,2,37,7,404,532,652,4,41.5973351,-71.0664761 +2,---,---,---,---,---,---,---,---,1,---,---,---,296,-48,2,40,7,426,592,673,11,---,--- +2,7.4,9.5,00:02.2,02:35.8,3.21,02:22.9,3.5,39.5,2,5.7,5.8,141,366,-54,3,37,8,362,534,595,2,41.5972841,-71.0664759 +2,14.1,16,00:03.7,02:14.4,3.72,02:03.8,4.04,40.5,3,6.7,6.5,140,346,-62,4,38,10,325,543,548,-11,41.5972237,-71.0664759 +2,21.4,23.1,00:05.3,01:56.6,4.29,01:54.7,4.36,38.5,4,7.3,7.1,137,328,-63,4,38,12,301,511,500,-9,41.5971578,-71.0664769 +2,28.2,29.7,00:06.7,01:49.4,4.57,01:48.7,4.6,37.5,5,6.8,6.6,138,327,-65,4,37,10,298,517,509,-16,41.5970972,-71.0664784 +2,36,37.2,00:08.4,01:45.7,4.73,01:47.1,4.67,37,6,7.8,7.5,138,297,-65,5,38,14,272,473,482,-3,41.597027,-71.0664808 +2,43.8,44.5,00:09.9,01:44.2,4.8,01:48.7,4.6,38,7,7.8,7.3,138,317,-68,6,37,13,295,504,503,-12,41.5969567,-71.0664838 +2,51.6,51.9,00:11.5,01:44.4,4.79,01:49.2,4.58,37,8,7.8,7.4,138,285,-66,4,38,15,265,473,459,-10,41.5968866,-71.0664874 +2,60.1,61.2,00:13.6,01:44.8,4.77,01:48.5,4.61,35.5,9,8.5,9.3,139,269,-67,6,37,14,258,457,446,-14,41.5968104,-71.066492 +2,67.8,67.4,00:15.0,01:43.9,4.81,01:51.1,4.5,34,10,7.7,6.3,141,252,-67,5,37,15,242,444,452,-11,41.5967416,-71.0664974 +2,76.1,75.4,00:16.8,01:45.7,4.73,01:53.4,4.41,34,11,8.3,8,142,262,-68,6,36,14,258,458,468,-17,41.5966674,-71.0665039 +2,84.4,83.1,00:18.5,01:46.8,4.68,01:54.7,4.36,34,12,8.3,7.7,145,265,-68,5,36,14,269,467,496,-15,41.596593,-71.0665118 +2,92.6,91,00:20.3,01:48.5,4.61,01:53.6,4.4,34,13,8.2,7.9,147,243,-67,5,38,16,238,442,451,-14,41.5965194,-71.0665215 +2,100.8,98.7,00:22.1,01:50.1,4.54,01:55.2,4.34,32.5,14,8.1,7.7,149,254,-67,5,37,14,249,455,463,-15,41.5964468,-71.0665318 +2,108.8,106.4,00:23.9,01:51.4,4.49,01:57.1,4.27,34,15,8.1,7.7,151,249,-68,5,38,16,241,452,458,-17,41.5963747,-71.0665437 +2,116.3,113.9,00:25.7,01:52.1,4.46,01:57.1,4.27,32.5,16,7.5,7.5,152,243,-68,5,37,15,246,438,430,-17,41.5963082,-71.0665559 +2,125,121.9,00:27.5,01:50.1,4.54,01:57.6,4.25,32.5,17,8.7,7.9,154,246,-68,5,37,15,250,445,457,-12,41.5962314,-71.0665719 +2,133,129.4,00:29.3,01:51.1,4.5,01:57.9,4.24,32.5,18,8,7.5,156,245,-68,5,37,17,250,449,454,-17,41.5961602,-71.0665871 +2,141.7,138.7,00:31.6,01:53.1,4.42,01:58.2,4.23,32.5,19,8.7,9.3,157,229,-68,6,37,16,237,426,431,-10,41.5960832,-71.0666054 +2,149.6,145.2,00:33.1,01:53.9,4.39,02:00.2,4.16,32.5,20,7.9,6.5,158,237,-68,5,38,18,246,432,440,-14,41.5960134,-71.0666236 +3,1.7,3.7,00:00.5,04:16.4,1.95,03:01.2,2.76,111,1,1.7,3.7,131,336,-42,3,36,6,402,497,632,12,41.5952349,-71.066896 +3,---,---,---,---,---,---,---,---,1,---,---,---,226,-48,1,43,8,248,616,708,10,---,--- +3,7.5,9.5,00:02.1,02:36.7,3.19,02:21.6,3.53,41.5,2,5.8,5.8,129,344,-51,3,37,8,351,489,572,8,41.5951834,-71.0669076 +3,13.7,15.6,00:03.5,02:16.6,3.66,02:01.4,4.12,41.5,3,6.2,6,128,356,-61,4,36,8,341,534,535,-11,41.5951287,-71.0669195 +3,21,22.7,00:05.1,01:57.1,4.27,01:52.6,4.44,39.5,4,7.3,7.1,126,356,-62,3,37,8,330,531,528,-13,41.5950636,-71.0669331 +3,27.9,29.3,00:06.5,01:48.5,4.61,01:48.2,4.62,39.5,5,6.8,6.6,126,309,-64,4,37,12,285,482,471,-8,41.595003,-71.0669464 +3,35.7,36.9,00:08.1,01:44.6,4.78,01:45.7,4.73,39,6,7.8,7.6,126,312,-65,3,36,12,280,490,473,-10,41.5949336,-71.0669617 +3,43.6,44.6,00:09.7,01:42.7,4.87,01:45.0,4.76,37.5,7,7.9,7.7,127,295,-66,4,38,14,270,482,473,-12,41.5948639,-71.0669772 +3,52.1,52.9,00:11.5,01:42.5,4.88,01:45.9,4.72,34.5,8,8.5,8.3,128,276,-67,5,36,13,280,457,449,-16,41.5947884,-71.0669944 +3,59.7,61.4,00:13.4,01:45.0,4.76,01:49.9,4.55,35.5,9,7.6,8.5,131,265,-67,5,36,14,266,458,468,-15,41.5947213,-71.0670102 +3,67.2,67.4,00:14.7,01:45.9,4.72,01:50.4,4.53,35.5,10,7.5,6.1,134,258,-67,6,37,15,245,449,457,-16,41.5946549,-71.0670261 +3,74.7,75.2,00:16.5,01:47.1,4.67,01:51.4,4.49,34,11,7.6,7.8,136,259,-66,4,37,14,248,447,468,-13,41.5945881,-71.0670424 +3,83.6,83.3,00:18.3,01:47.3,4.66,01:54.2,4.38,35.5,12,8.9,8.1,140,250,-67,7,37,15,248,423,436,-14,41.5945097,-71.0670612 +3,91,90.4,00:19.9,01:48.9,4.59,01:54.4,4.37,34.5,13,7.4,7.1,144,286,-67,4,36,14,293,481,486,-15,41.5944442,-71.0670761 +3,99.1,98.2,00:21.7,01:50.6,4.52,01:54.2,4.38,35.5,14,8.1,7.8,147,242,-66,5,36,14,261,411,415,-14,41.594373,-71.0670933 +3,106.4,105.3,00:23.4,01:51.9,4.47,01:55.2,4.34,34,15,7.4,7.1,148,235,-67,4,36,16,240,432,458,-13,41.5943077,-71.0671095 +3,114.5,113.9,00:25.4,01:52.1,4.46,01:55.7,4.32,34,16,8,8.6,150,258,-67,5,37,16,255,442,471,-16,41.5942368,-71.0671264 +3,122.5,120.6,00:26.9,01:50.6,4.52,01:56.8,4.28,34,17,8,6.7,152,249,-67,5,35,14,245,448,469,-15,41.5941662,-71.0671436 +3,129.7,127.7,00:28.6,01:52.1,4.46,01:57.6,4.25,34,18,7.3,7.1,153,238,-67,6,36,16,232,414,438,-13,41.5941021,-71.0671598 +3,138.1,135.8,00:30.5,01:52.6,4.44,01:58.2,4.23,34,19,8.4,8.1,155,241,-67,5,35,15,249,422,453,-14,41.5940283,-71.0671791 +3,145.2,142.6,00:32.1,01:54.4,4.37,01:59.3,4.19,34,20,7.1,6.8,157,239,-67,4,36,17,244,425,441,-22,41.5939659,-71.0671961 +4,4.9,5.6,00:01.5,04:21.8,1.91,02:21.2,3.54,39,1,4.9,5.6,134,330,-57,3,38,10,325,524,552,5,41.5930859,-71.067406 +4,---,---,---,---,---,---,---,---,1,---,---,---,353,-51,3,37,7,409,572,650,7,---,--- +4,11.6,12.3,00:03.1,02:17.4,3.64,02:02.0,4.1,39.5,2,6.8,6.7,131,374,-62,4,37,8,344,542,541,0,41.5930252,-71.0674061 +4,19.1,19.5,00:04.7,01:57.4,4.26,01:52.6,4.44,37.5,3,7.5,7.2,130,315,-63,6,36,11,303,491,502,-2,41.5929582,-71.0674055 +4,26.7,27.9,00:06.6,01:48.0,4.63,01:49.6,4.56,37,4,7.7,8.4,128,291,-64,5,38,11,277,477,463,-12,41.5928895,-71.0674047 +4,34.4,34.1,00:07.9,01:44.4,4.79,01:49.4,4.57,37.5,5,7.6,6.2,130,298,-68,7,36,12,284,494,487,-12,41.5928208,-71.0674037 +4,41.4,41.6,00:09.6,01:44.4,4.79,01:48.2,4.62,34.5,6,7,7.5,130,295,-68,6,38,13,283,504,491,-17,41.5927577,-71.0674024 +4,50.6,49.8,00:11.3,01:42.5,4.88,01:49.6,4.56,33.5,7,9.2,8.2,132,282,-69,5,39,14,281,517,491,-12,41.5926751,-71.0674016 +4,59.1,57.9,00:13.1,01:44.2,4.8,01:50.1,4.54,34,8,8.5,8,134,266,-68,5,38,14,255,479,455,-16,41.5925985,-71.0674029 +4,67.6,66,00:14.9,01:47.1,4.67,01:50.1,4.54,34,9,8.4,8.1,136,274,-69,6,38,15,267,477,476,-15,41.5925227,-71.0674039 +4,76,73.9,00:16.7,01:47.8,4.64,01:52.4,4.45,32.5,10,8.4,8,137,253,-69,5,37,14,261,456,447,-16,41.5924472,-71.0674048 +4,83.6,82,00:18.6,01:48.9,4.59,01:53.9,4.39,32.5,11,7.6,8,141,243,-68,6,37,14,254,451,446,-7,41.5923791,-71.0674063 +4,92.9,90.3,00:20.5,01:48.0,4.63,01:57.4,4.26,32.5,12,9.3,8.3,143,221,-68,7,37,16,232,424,426,-15,41.5922951,-71.0674094 +4,100.9,97.9,00:22.3,01:50.6,4.52,01:57.9,4.24,31.5,13,8,7.6,146,236,-68,6,36,14,243,437,442,-16,41.5922233,-71.0674145 +4,109,105.5,00:24.1,01:53.6,4.4,02:00.2,4.16,31.5,14,8.1,7.6,148,225,-69,5,37,16,237,432,433,-15,41.5921505,-71.0674208 +4,117.7,113.7,00:26.1,01:53.9,4.39,02:01.1,4.13,31,15,8.6,8.1,152,222,-68,5,37,15,234,437,452,-19,41.5920731,-71.0674294 +4,126.3,121.8,00:28.1,01:55.7,4.32,02:02.0,4.1,31.5,16,8.6,8.1,154,231,-69,6,38,16,242,433,422,-13,41.5919965,-71.0674396 +4,134.3,129.4,00:29.9,01:55.5,4.33,02:01.1,4.13,31.5,17,8.1,7.6,154,240,-69,5,38,16,249,464,471,-18,41.5919246,-71.0674506 +4,142.9,137.5,00:31.9,01:54.9,4.35,02:01.4,4.12,31.5,18,8.6,8.2,155,241,-69,5,36,15,253,456,455,-18,41.5918477,-71.0674641 +4,150.9,145.3,00:33.8,01:54.7,4.36,02:00.2,4.16,31.5,19,7.9,7.8,155,219,-69,7,36,16,234,420,428,-14,41.5917773,-71.0674789 +5,5.9,4,00:06.0,09:15.6,0.9,03:12.3,2.6,10,1,5.9,4,137,319,-51,2,36,7,376,520,606,7,41.5909617,-71.0679011 +5,---,---,---,---,---,---,---,---,1,---,---,---,147,-51,3,41,7,169,587,658,13,---,--- +5,11.9,11.2,00:07.8,03:46.2,2.21,02:24.1,3.47,39.5,2,6,7.3,134,362,-53,2,37,8,356,507,567,0,41.5909172,-71.0679412 +5,18.2,16,00:09.0,02:12.3,3.78,01:59.9,4.17,40,3,6.3,4.8,133,317,-63,4,38,9,298,517,508,5,41.5908702,-71.0679833 +5,25.7,24.2,00:10.8,01:54.2,4.38,01:52.9,4.43,37,4,7.5,8.2,134,319,-65,5,37,9,294,510,509,4,41.5908139,-71.0680335 +5,34.3,31.4,00:12.4,01:45.0,4.76,01:49.2,4.58,36,5,8.5,7.2,133,297,-66,4,37,11,287,493,479,-13,41.5907499,-71.0680897 +5,41.2,38.6,00:13.9,01:42.9,4.86,01:48.9,4.59,37,6,7,7.2,133,300,-67,4,37,12,278,505,500,-14,41.5906982,-71.0681373 +5,49.8,46.3,00:15.6,01:41.4,4.93,01:47.5,4.65,35.5,7,8.6,7.6,133,298,-67,5,38,12,282,498,473,-14,41.5906351,-71.0681968 +5,58.5,54.6,00:17.4,01:41.4,4.93,01:48.0,4.63,35.5,8,8.7,8.4,134,283,-68,5,37,13,268,475,457,-4,41.5905721,-71.0682581 +5,66.4,62.1,00:19.0,01:43.3,4.84,01:47.1,4.67,34.5,9,7.9,7.4,134,276,-67,6,36,12,269,461,452,-15,41.5905147,-71.0683138 +5,74.2,69.4,00:20.6,01:43.9,4.81,01:48.2,4.62,35.5,10,7.8,7.4,136,273,-68,5,37,13,263,462,449,-6,41.5904579,-71.0683694 +5,82.8,77.7,00:22.4,01:44.6,4.78,01:49.6,4.56,35.5,11,8.6,8.2,138,272,-67,4,37,14,259,458,466,-11,41.5903957,-71.0684303 +5,90.6,85,00:24.0,01:45.3,4.75,01:49.6,4.56,35,12,7.7,7.3,140,276,-68,4,37,13,271,473,480,-11,41.5903396,-71.0684853 +5,98.4,93.2,00:25.8,01:45.9,4.72,01:50.9,4.51,35.5,13,7.8,8.2,144,259,-67,5,38,16,247,440,431,-15,41.5902831,-71.0685411 +5,106.8,100.3,00:27.4,01:43.5,4.83,01:51.4,4.49,34,14,8.4,7.1,147,255,-68,7,37,13,256,444,431,-12,41.5902233,-71.0686025 +5,115.1,108.2,00:29.2,01:45.5,4.74,01:52.6,4.44,34,15,8.3,7.9,150,235,-67,6,36,13,239,420,427,-10,41.5901641,-71.0686639 +5,123.3,116.1,00:31.0,01:49.2,4.58,01:54.7,4.36,34,16,8.2,7.9,152,231,-67,5,36,14,237,409,416,-10,41.5901065,-71.0687246 +5,131.4,123.7,00:32.8,01:50.6,4.52,01:56.6,4.29,34,17,8.1,7.6,154,243,-67,5,35,15,257,418,422,-15,41.5900495,-71.0687857 +5,139.5,132.5,00:34.8,01:51.4,4.49,01:56.0,4.31,34,18,8.1,8.8,156,241,-68,6,35,16,262,421,414,-10,41.5899928,-71.0688471 +5,147,138.5,00:36.2,01:50.6,4.52,01:55.5,4.33,34,19,7.4,6,157,223,-67,5,36,17,234,401,417,-16,41.5899403,-71.0689024 +5,154.9,146.3,00:38.0,01:51.4,4.49,01:57.1,4.27,34,20,8,7.8,158,158,-66,6,34,22,172,285,340,-42,41.5898854,-71.0689636 +6,1.3,3.7,00:01.5,09:03.5,0.92,16:40.0,0.5,40.5,1,1.3,3.7,136,162,-48,1,40,7,240,578,659,9,41.5892061,-71.0696163 +6,2.6,4.7,00:01.9,04:08.8,2.01,02:57.9,2.81,95.5,2,1.3,0.9,136,314,-51,3,37,8,370,518,602,8,41.5891955,-71.069622 +6,9,11,00:03.7,02:33.4,3.26,02:23.3,3.49,37.5,3,6.4,6.3,135,344,-62,5,37,8,348,550,541,7,41.5891424,-71.0696498 +6,15.9,17.7,00:05.3,02:15.1,3.7,02:03.2,4.06,37.5,4,6.9,6.8,135,319,-63,3,37,11,307,511,495,-14,41.5890852,-71.0696816 +6,23.3,26,00:07.1,01:56.8,4.28,01:52.1,4.46,37.5,5,7.4,8.3,135,302,-66,4,36,10,285,499,475,3,41.5890238,-71.0697157 +6,31.7,33.3,00:08.7,01:46.8,4.68,01:48.7,4.6,35.5,6,8.5,7.3,135,282,-66,5,37,12,266,471,461,0,41.588954,-71.0697558 +6,38.7,40.6,00:10.2,01:44.4,4.79,01:48.0,4.63,35.5,7,7,7.3,136,291,-67,6,36,13,271,486,474,0,41.5888957,-71.0697878 +6,47.2,48.2,00:11.9,01:42.2,4.89,01:47.5,4.65,35.5,8,8.5,7.6,136,274,-67,6,37,13,255,452,432,-9,41.5888257,-71.0698282 +6,55.8,56.5,00:13.7,01:42.5,4.88,01:47.1,4.67,34,9,8.5,8.4,137,247,-68,6,37,13,241,446,423,-2,41.588755,-71.0698681 +6,64.3,64.7,00:15.5,01:45.5,4.74,01:50.1,4.54,34,10,8.5,8.2,138,261,-68,5,37,12,256,464,434,-16,41.5886843,-71.0699071 +6,72.7,72.8,00:17.3,01:47.8,4.64,01:50.6,4.52,34,11,8.4,8.1,139,279,-69,4,38,12,278,489,445,-7,41.5886143,-71.0699455 +6,80.3,81.2,00:19.1,01:48.0,4.63,01:49.6,4.56,32.5,12,7.7,8.4,141,269,-69,6,36,13,279,469,449,-15,41.588551,-71.069981 +6,88.7,88.3,00:20.7,01:45.0,4.76,01:50.9,4.51,34,13,8.3,7.1,143,269,-69,5,37,13,278,476,464,-14,41.5884822,-71.0700205 +6,97,96.5,00:22.5,01:45.9,4.72,01:51.4,4.49,34,14,8.3,8.2,146,262,-69,7,36,12,271,461,463,-12,41.5884132,-71.0700596 +6,105.3,104.5,00:24.3,01:48.2,4.62,01:50.6,4.52,34,15,8.2,8,147,237,-68,5,36,13,245,429,415,-11,41.588345,-71.0700981 +6,113.4,112.5,00:26.1,01:49.6,4.56,01:53.4,4.41,34,16,8.2,8,150,255,-68,6,36,14,264,434,426,-12,41.5882774,-71.0701362 +6,121.5,121.4,00:28.1,01:50.6,4.52,01:53.1,4.42,34,17,8.1,9,152,231,-68,6,36,15,239,418,415,-13,41.5882102,-71.0701731 +6,128.9,127.5,00:29.5,01:51.1,4.5,01:54.9,4.35,34,18,7.4,6,154,248,-68,5,35,14,259,422,412,-6,41.5881492,-71.0702069 +6,136.2,135,00:31.2,01:51.6,4.48,01:55.2,4.34,34,19,7.3,7.5,155,246,-68,5,34,13,251,445,438,-13,41.5880881,-71.0702401 +6,144.8,142.9,00:33.1,01:49.9,4.55,01:55.7,4.32,34,20,8.6,7.9,157,216,-68,6,35,16,225,377,374,-14,41.5880168,-71.0702811 +7,6.2,3.9,00:07.0,09:15.6,0.9,03:00.5,2.77,8.5,1,6.2,3.9,135,337,-55,2,37,6,383,560,608,9,41.5871894,-71.0704806 +7,---,---,---,---,---,---,---,---,1,---,---,---,285,-50,2,40,6,400,578,654,10,---,--- +7,12.1,9.9,00:08.6,03:49.4,2.18,02:23.3,3.49,38,2,6,6,134,366,-60,3,37,7,361,552,549,8,41.5871368,-71.0704665 +7,19.2,16.8,00:10.2,02:11.2,3.81,01:58.2,4.23,39,3,7,6.9,134,325,-64,3,37,8,305,523,493,7,41.5870751,-71.0704501 +7,26.7,24.1,00:11.8,01:53.9,4.39,01:52.1,4.46,36,4,7.6,7.3,133,312,-67,5,37,10,291,511,492,-1,41.5870083,-71.0704326 +7,34.4,31.5,00:13.4,01:47.5,4.65,01:48.5,4.61,37,5,7.7,7.4,133,298,-67,4,38,12,278,489,475,2,41.5869407,-71.0704147 +7,43.1,39.8,00:15.2,01:45.5,4.74,01:47.3,4.66,35.5,6,8.7,8.3,133,301,-68,4,38,12,289,500,469,-6,41.5868638,-71.0703949 +7,51,47.3,00:16.8,01:44.4,4.79,01:48.2,4.62,35.5,7,7.9,7.5,133,271,-68,6,37,12,258,466,447,7,41.5867945,-71.0703773 +7,58.8,55.6,00:18.7,01:44.2,4.8,01:48.7,4.6,34,8,7.8,8.4,135,277,-68,5,38,12,268,488,451,1,41.5867257,-71.0703598 +7,68,63.7,00:20.4,01:41.6,4.92,01:48.5,4.61,34,9,9.3,8.1,138,275,-69,6,38,14,263,479,443,-18,41.5866441,-71.0703389 +7,75.8,71,00:22.0,01:43.1,4.85,01:50.1,4.54,34,10,7.8,7.3,141,275,-68,5,37,11,275,464,438,-14,41.5865754,-71.0703222 +7,84.3,79.1,00:23.8,01:45.7,4.73,01:51.9,4.47,34,11,8.5,8.1,142,244,-68,6,38,15,241,449,433,-14,41.5865004,-71.0703037 +7,92.7,87.1,00:25.6,01:46.4,4.7,01:51.6,4.48,34,12,8.5,8,145,260,-67,4,38,14,245,449,424,-12,41.5864255,-71.0702866 +7,101.1,96.1,00:27.7,01:47.3,4.66,01:52.9,4.43,35.5,13,8.3,9,147,256,-67,5,38,14,245,446,429,-11,41.5863516,-71.07027 +7,108.6,102.1,00:29.0,01:47.8,4.64,01:54.2,4.38,34,14,7.5,6,149,252,-68,6,37,12,246,448,425,-9,41.5862851,-71.070254 +7,116.2,109.7,00:30.8,01:48.5,4.61,01:55.7,4.32,32.5,15,7.7,7.6,150,252,-68,6,37,14,253,438,425,-16,41.5862176,-71.0702378 +7,125.1,117.6,00:32.6,01:47.8,4.64,01:55.5,4.33,34,16,8.8,7.9,153,259,-69,5,36,13,257,464,428,-18,41.5861392,-71.0702199 +7,133.3,125.4,00:34.4,01:48.7,4.6,01:55.5,4.33,34,17,8.2,7.8,155,245,-68,5,36,14,242,436,431,-9,41.5860663,-71.0702039 +7,141.4,133.2,00:36.2,01:49.6,4.56,01:55.7,4.32,34,18,8.1,7.8,157,249,-69,6,36,14,241,443,440,-8,41.5859941,-71.0701893 +7,149.5,140.9,00:38.0,01:50.1,4.54,01:56.0,4.31,32.5,19,8.1,7.7,159,236,-68,6,37,15,233,415,412,-13,41.5859221,-71.0701753 +7,156.1,148,00:39.7,01:50.9,4.51,01:56.8,4.28,34,20,6.6,7.1,159,---,---,---,---,---,---,---,---,---,41.5858636,-71.0701646 +8,5.7,3.9,00:06.6,10:32.9,0.79,03:14.6,2.57,9,1,5.7,3.9,134,305,-53,3,37,7,364,521,592,12,41.5850482,-71.0701023 +8,---,---,---,---,---,---,---,---,1,---,---,---,213,-50,3,40,7,242,541,629,10,---,--- +8,11.9,10.1,00:08.4,04:00.4,2.08,02:27.1,3.4,37.5,2,6.2,6.2,133,353,-61,4,38,8,352,551,531,9,41.5849925,-71.0701083 +8,18.8,16.7,00:10.0,02:16.6,3.66,02:02.8,4.07,37.5,3,6.9,6.6,133,329,-64,4,37,9,318,520,511,5,41.5849306,-71.0701148 +8,26.2,23.9,00:11.6,01:56.8,4.28,01:53.9,4.39,36.5,4,7.4,7.2,133,308,-66,4,37,10,293,518,506,-4,41.5848645,-71.0701219 +8,34.6,32,00:13.4,01:49.4,4.57,01:50.9,4.51,37,5,8.4,8,133,307,-68,5,36,11,286,504,480,-5,41.5847897,-71.0701305 +8,42.2,39.3,00:15.0,01:47.3,4.66,01:49.2,4.58,35.5,6,7.6,7.3,133,286,-67,6,37,13,289,470,460,-12,41.5847213,-71.0701391 +8,49.9,46.7,00:16.6,01:46.6,4.69,01:50.1,4.54,35.5,7,7.7,7.4,133,268,-67,6,36,11,260,462,434,-11,41.5846527,-71.0701485 +8,57.7,55,00:18.4,01:46.4,4.7,01:49.2,4.58,34.5,8,7.8,8.4,134,291,-69,5,37,10,280,494,455,6,41.5845834,-71.0701581 +8,66.1,62.4,00:20.0,01:42.9,4.86,01:48.2,4.62,35,9,8.5,7.3,136,274,-68,7,38,12,254,473,432,8,41.5845076,-71.0701697 +8,74.7,70.6,00:21.8,01:43.5,4.83,01:47.3,4.66,34,10,8.6,8.3,137,269,-69,5,38,14,254,473,433,-18,41.5844312,-71.0701818 +8,83.2,78.8,00:23.6,01:45.7,4.73,01:49.6,4.56,34.5,11,8.5,8.2,140,269,-69,5,37,11,254,469,441,-5,41.5843556,-71.0701943 +8,90.9,86.2,00:25.2,01:46.6,4.69,01:50.6,4.52,35,12,7.7,7.4,143,274,-69,6,37,11,260,482,440,-8,41.5842869,-71.0702055 +8,99.3,94.2,00:27.0,01:47.5,4.65,01:50.9,4.51,34,13,8.4,8,145,279,-69,5,36,12,273,460,418,-5,41.5842124,-71.070219 +8,107.6,102.3,00:28.8,01:48.2,4.62,01:51.1,4.5,34,14,8.3,8,148,266,-69,5,37,13,281,460,421,0,41.584138,-71.0702344 +8,114.4,109.7,00:30.4,01:48.5,4.61,01:52.4,4.45,34,15,6.8,7.4,149,238,-69,5,36,14,241,433,403,-15,41.5840782,-71.0702484 +8,123.4,117.5,00:32.2,01:46.2,4.71,01:51.4,4.49,35.5,16,9,7.8,152,267,-69,5,36,13,267,446,413,-4,41.583999,-71.070267 +8,131.5,125.3,00:34.0,01:47.3,4.66,01:53.9,4.39,34,17,8.2,7.8,155,257,-69,7,35,13,276,439,434,-13,41.5839267,-71.0702854 +8,139.1,132.4,00:35.6,01:49.4,4.57,01:54.4,4.37,34,18,7.5,7.1,156,251,-69,4,36,13,256,459,434,-10,41.5838601,-71.0703018 +8,147.3,140.3,00:37.4,01:49.9,4.55,01:54.7,4.36,34,19,8.2,7.8,157,268,-69,5,35,13,272,452,448,-15,41.583788,-71.0703208 +8,155.5,149.1,00:39.4,01:50.1,4.54,01:54.4,4.37,34,20,8.3,8.8,159,---,---,---,---,---,---,---,---,---,41.5837155,-71.0703411 +9,4.9,3.6,00:07.7,10:02.4,0.83,17:21.7,0.48,7.5,1,4.9,3.6,136,235,-49,0,39,6,273,536,597,13,41.5828997,-71.0705657 +9,6.4,5.3,00:08.3,04:16.4,1.95,02:59.2,2.79,109.5,2,1.5,1.7,135,327,-52,2,37,7,371,527,581,8,41.5828868,-71.0705697 +9,12.8,11.2,00:09.9,02:25.8,3.43,02:21.2,3.54,39.5,3,6.5,5.9,133,353,-58,3,37,8,345,512,520,9,41.58283,-71.0705852 +9,18.5,17.5,00:11.3,02:06.3,3.96,01:59.3,4.19,39.5,4,5.6,6.2,132,339,-63,4,38,8,321,518,480,13,41.5827804,-71.0705981 +9,26.7,24.6,00:12.9,01:49.2,4.58,01:49.6,4.56,39.5,5,8.2,7.2,131,314,-64,4,36,9,301,478,467,9,41.582708,-71.0706173 +9,34.6,32.4,00:14.5,01:43.3,4.84,01:47.1,4.67,37.5,6,7.9,7.7,130,288,-65,5,36,10,280,456,436,6,41.5826379,-71.0706346 +9,42.4,39.7,00:16.1,01:41.4,4.93,01:45.5,4.74,38,7,7.7,7.4,131,284,-66,5,37,12,267,461,427,-11,41.5825697,-71.070653 +9,50.2,47.1,00:17.7,01:41.4,4.93,01:47.1,4.67,37,8,7.9,7.4,133,304,-69,5,38,13,283,493,449,-16,41.5825004,-71.0706726 +9,58.1,54.7,00:19.3,01:42.2,4.89,01:46.8,4.68,37,9,7.9,7.6,134,299,-68,4,37,10,277,500,455,-13,41.5824314,-71.070693 +9,66.8,63,00:21.1,01:42.2,4.89,01:46.8,4.68,35.5,10,8.6,8.3,136,292,-67,5,38,12,268,476,429,8,41.5823558,-71.0707168 +9,74.6,70.5,00:22.7,01:42.7,4.87,01:47.3,4.66,36,11,7.8,7.6,138,285,-67,4,36,12,266,474,438,-14,41.5822877,-71.0707396 +9,82.4,77.8,00:24.3,01:44.2,4.8,01:48.5,4.61,37.5,12,7.8,7.3,139,277,-67,4,38,14,259,460,435,-12,41.5822198,-71.0707634 +9,90.1,85.3,00:25.9,01:44.4,4.79,01:48.9,4.59,35.5,13,7.7,7.5,139,281,-68,4,36,13,264,461,442,-11,41.582153,-71.0707877 +9,98.5,93.5,00:27.7,01:44.2,4.8,01:47.5,4.65,35.5,14,8.4,8.2,141,281,-69,6,37,12,274,458,423,-2,41.5820804,-71.070816 +9,105.4,101,00:29.3,01:45.3,4.75,01:50.4,4.53,35.5,15,6.9,7.4,143,279,-68,4,35,11,276,477,459,-16,41.5820211,-71.0708396 +9,113.9,108.2,00:30.9,01:42.2,4.89,01:49.6,4.56,35.5,16,8.5,7.2,146,248,-67,5,37,15,239,416,403,-13,41.5819482,-71.0708699 +9,121.6,115.6,00:32.5,01:43.3,4.84,01:51.9,4.47,35.5,17,7.7,7.4,148,259,-68,5,37,16,251,434,434,-12,41.5818827,-71.0708979 +9,129.8,123.1,00:34.3,01:46.4,4.7,01:53.9,4.39,35.5,18,8.3,7.6,150,251,-68,6,36,13,257,420,409,-14,41.5818122,-71.0709289 +9,137.8,130.9,00:36.1,01:48.2,4.62,01:55.2,4.34,34.5,19,8,7.8,155,228,-67,4,35,13,229,411,388,-15,41.5817443,-71.0709603 +9,145.9,138.7,00:37.9,01:49.9,4.55,01:55.5,4.33,35,20,8.1,7.7,158,251,-68,4,36,14,242,437,414,-14,41.5816753,-71.0709917 +9,153.4,145.7,00:39.5,01:51.1,4.5,01:55.2,4.34,34,21,7.5,7,159,---,-58,---,-47,---,-19,---,31,-58,41.5816122,-71.0710225 +9,---,---,---,---,---,---,---,---,21,---,---,---,246,-68,6,35,13,245,413,388,-19,---,--- +10,0.8,0.6,00:01.3,10:25.0,0.8,26:02.5,0.32,8,1,0.8,0.6,140,178,-50,1,39,8,310,595,659,8,41.5808118,-71.071421 +10,3,3.2,00:02.1,07:56.2,1.05,26:02.5,0.32,53.5,2,2.1,2.6,140,---,---,---,---,---,---,---,---,---,41.5807927,-71.0714241 +10,5,4.9,00:02.7,03:28.3,2.4,02:56.7,2.83,95.5,3,2,1.7,137,302,-59,3,38,9,355,544,556,11,41.5807745,-71.0714273 +10,12.2,11.8,00:04.7,02:28.8,3.36,02:27.9,3.38,34.5,4,7.1,6.9,134,321,-63,3,37,8,319,539,531,1,41.5807108,-71.0714374 +10,19.2,18.6,00:06.3,02:11.9,3.79,02:02.8,4.07,37,5,7,6.8,132,336,-65,4,37,9,328,534,527,-4,41.5806481,-71.0714472 +10,27.4,26.4,00:08.1,01:55.7,4.32,01:54.9,4.35,35.5,6,8.2,7.9,131,307,-67,4,38,12,316,516,491,0,41.5805747,-71.0714592 +10,35.1,34.9,00:09.9,01:48.7,4.6,01:50.9,4.51,34.5,7,7.7,8.5,130,274,-67,4,37,10,265,485,465,2,41.5805063,-71.0714703 +10,43.8,42,00:11.5,01:44.2,4.8,01:49.6,4.56,35.5,8,8.7,7.1,131,253,-68,6,37,14,245,436,416,-9,41.580429,-71.0714827 +10,51.5,49.5,00:13.1,01:43.9,4.81,01:49.9,4.55,34,9,7.8,7.5,131,259,-68,4,38,13,249,462,440,-4,41.5803598,-71.0714936 +10,60.8,58.2,00:15.1,01:44.2,4.8,01:50.9,4.51,32.5,10,9.3,8.7,131,249,-69,5,38,12,247,455,436,-6,41.580277,-71.0715071 +10,69.2,66.1,00:16.9,01:45.3,4.75,01:52.6,4.44,32.5,11,8.4,8,132,245,-69,6,38,12,246,457,422,3,41.5802017,-71.071518 +10,77.7,75.2,00:18.9,01:47.3,4.66,01:53.1,4.42,32.5,12,8.4,9.1,133,243,-69,5,37,13,248,440,424,-2,41.5801265,-71.0715297 +10,85.9,82,00:20.5,01:47.3,4.66,01:53.9,4.39,32.5,13,8.2,6.8,135,245,-69,5,36,11,245,457,422,-15,41.580053,-71.0715413 +10,94.2,89.9,00:22.3,01:48.2,4.62,01:54.7,4.36,32.5,14,8.3,7.9,137,235,-68,5,36,13,237,423,406,-4,41.5799785,-71.0715534 +10,102.5,97.7,00:24.1,01:48.7,4.6,01:56.0,4.31,32.5,15,8.3,7.8,138,236,-68,6,37,12,238,438,419,-5,41.5799048,-71.0715671 +10,110.7,105.5,00:25.9,01:49.6,4.56,01:55.7,4.32,32.5,16,8.2,7.8,141,249,-68,5,38,14,254,456,430,-14,41.579832,-71.0715806 +10,119,114,00:27.9,01:50.6,4.52,01:57.9,4.24,32.5,17,8.3,8.5,148,232,-67,6,37,14,230,424,421,-10,41.5797585,-71.0715943 +10,127.8,121.5,00:29.7,01:48.5,4.61,01:57.1,4.27,32.5,18,8.9,7.5,152,232,-68,6,38,16,230,421,411,-11,41.5796795,-71.0716087 +10,136,129.2,00:31.5,01:49.6,4.56,01:59.3,4.19,32.5,19,8.1,7.6,155,233,-68,6,36,14,236,421,418,-16,41.5796071,-71.0716216 +10,144,136.8,00:33.3,01:52.6,4.44,01:56.8,4.28,34,20,8,7.7,157,227,-68,5,35,14,235,406,385,-14,41.5795356,-71.0716351 +10,152.1,144.3,00:35.1,01:53.4,4.41,01:59.9,4.17,32.5,21,8.1,7.5,157,231,-69,6,37,14,233,427,405,-14,41.5794639,-71.0716493 +11,1.6,3.9,00:00.6,05:40.1,1.47,03:09.4,2.64,95.5,1,1.6,3.9,139,269,-49,3,38,10,321,473,562,10,41.5791371,-71.0717237 +11,---,---,---,---,---,---,---,---,1,---,---,---,337,-45,0,43,10,407,542,616,5,---,--- +11,7,10.2,00:02.4,03:10.8,2.62,02:26.6,3.41,35.5,2,5.3,6.3,137,297,-61,4,38,10,303,499,521,8,41.5791845,-71.071715 +11,13.3,18.6,00:04.5,02:43.9,3.05,02:06.3,3.96,35.5,3,6.3,8.4,134,312,-64,4,37,10,302,515,520,0,41.5792408,-71.0717031 +11,19.7,24.4,00:05.8,02:17.0,3.65,01:57.1,4.27,34,4,6.4,5.8,132,285,-65,5,36,12,291,487,499,-9,41.5792971,-71.0716907 +11,26.2,32.1,00:07.6,02:07.9,3.91,01:54.4,4.37,35.5,5,6.6,7.7,131,276,-66,5,37,12,277,477,465,0,41.5793553,-71.0716766 +11,34.1,40.2,00:09.4,02:02.2,4.09,01:53.4,4.41,33,6,7.8,8.1,132,255,-67,5,37,13,258,452,440,5,41.5794244,-71.0716588 +11,41.3,48.1,00:11.2,02:02.0,4.1,01:54.7,4.36,35,7,7.2,8,132,250,-67,5,37,13,258,440,416,-3,41.5794881,-71.0716415 +11,48.7,56.1,00:13.0,02:04.1,4.03,01:53.9,4.39,32.5,8,7.4,7.9,132,230,-67,5,38,16,237,426,400,-13,41.5795531,-71.0716232 +11,55.9,63.7,00:14.8,02:04.7,4.01,01:55.2,4.34,32.5,9,7.2,7.7,133,243,-68,5,37,15,246,441,419,-14,41.5796166,-71.0716049 +11,62.5,71.3,00:16.6,02:06.6,3.95,01:57.4,4.26,32.5,10,6.5,7.6,134,249,-68,5,38,14,269,445,408,7,41.5796737,-71.0715879 +11,70.1,79.1,00:18.4,02:04.4,4.02,01:57.6,4.25,31.5,11,7.6,7.8,137,215,-67,6,38,15,237,420,414,0,41.5797406,-71.0715676 +11,77.8,87.5,00:20.4,02:06.3,3.96,01:58.2,4.23,32.5,12,7.7,8.3,139,210,-67,7,38,14,225,392,398,3,41.5798074,-71.0715449 +11,84.7,96.2,00:22.5,02:09.9,3.85,01:58.8,4.21,32.5,13,7,8.7,145,212,-67,6,37,16,224,403,390,2,41.5798685,-71.0715256 +11,91.7,102.7,00:24.0,02:09.5,3.86,01:58.8,4.21,31.5,14,7,6.5,150,221,-68,6,37,14,226,415,418,-2,41.5799296,-71.0715072 +11,99.2,111,00:26.0,02:11.2,3.81,02:00.5,4.15,32.5,15,7.5,8.3,153,224,-66,6,36,14,238,405,409,-6,41.5799955,-71.0714872 +11,106.2,118.5,00:27.8,02:11.9,3.79,01:59.0,4.2,31.5,16,6.9,7.5,155,231,-68,6,38,15,248,436,417,-17,41.580056,-71.0714686 +11,113.1,126,00:29.6,02:13.0,3.76,02:00.5,4.15,32.5,17,6.9,7.5,155,227,-66,6,38,16,234,426,430,-9,41.5801162,-71.0714481 +11,119.4,133.7,00:31.5,02:14.0,3.73,02:01.4,4.12,32.5,18,6.3,7.7,156,219,-67,5,36,14,235,401,402,1,41.5801712,-71.0714284 +11,127.4,141.6,00:33.4,02:08.9,3.88,02:01.1,4.13,31.5,19,8,7.9,157,219,-68,5,36,14,233,414,399,-9,41.5802404,-71.0714027 +11,134.3,149.1,00:35.2,02:09.5,3.86,02:02.0,4.1,32.5,20,6.9,7.5,159,---,---,---,---,---,---,---,---,---,41.5803,-71.0713797 +12,6.4,6.8,00:01.7,03:45.2,2.22,02:06.9,3.94,35,1,6.4,6.8,138,298,-64,3,39,11,307,524,515,0,41.5809033,-71.0711711 +12,---,---,---,---,---,---,---,---,1,---,---,---,324,-63,4,38,11,347,547,539,-16,---,--- +12,13.4,14.4,00:03.5,02:11.9,3.79,01:57.4,4.26,34,2,7,7.6,136,294,-66,4,37,12,294,509,515,-3,41.5809614,-71.0711402 +12,20.5,22.2,00:05.3,02:08.2,3.9,01:56.6,4.29,34,3,7.1,7.8,136,277,-67,6,37,12,289,476,479,-11,41.5810197,-71.0711054 +12,27.7,30,00:07.1,02:05.6,3.98,01:55.2,4.34,34,4,7.2,7.8,135,261,-68,6,37,12,278,473,466,-7,41.5810783,-71.0710701 +12,34.9,38.9,00:09.1,02:04.7,4.01,01:55.2,4.34,33,5,7.3,8.9,135,266,-68,6,38,12,271,485,457,2,41.5811379,-71.0710344 +12,42.2,45.7,00:10.7,02:04.1,4.03,01:53.4,4.41,33.5,6,7.3,6.9,135,264,-68,6,38,12,263,478,443,-17,41.5811981,-71.0709992 +12,49,53.1,00:12.4,02:04.1,4.03,01:53.4,4.41,33,7,6.7,7.4,136,256,-68,5,38,13,254,456,434,4,41.5812531,-71.0709655 +12,56.5,60.8,00:14.1,02:01.1,4.13,01:53.9,4.39,33.5,8,7.5,7.6,137,255,-68,5,37,12,256,448,440,-9,41.5813142,-71.0709281 +12,63.9,68.8,00:15.9,02:01.4,4.12,01:52.9,4.43,34,9,7.4,8,140,260,-68,4,39,15,260,463,444,-8,41.5813749,-71.0708921 +12,71.2,76.8,00:17.7,02:03.2,4.06,01:54.2,4.38,34,10,7.4,8,142,247,-68,5,38,13,244,444,424,-2,41.5814349,-71.0708553 +12,78.5,84.6,00:19.5,02:03.8,4.04,01:54.2,4.38,32.5,11,7.3,7.8,147,255,-68,5,37,12,258,457,427,-20,41.581494,-71.0708177 +12,85.2,92.3,00:21.3,02:04.4,4.02,01:54.9,4.35,34,12,6.7,7.7,149,238,-67,4,37,14,240,427,409,-12,41.5815481,-71.0707826 +12,93,100.2,00:23.1,02:01.1,4.13,01:54.2,4.38,32.5,13,7.8,7.9,152,241,-68,5,37,15,247,431,429,-14,41.5816109,-71.0707407 +12,100.3,108.1,00:24.9,02:02.2,4.09,01:56.0,4.31,34,14,7.3,7.9,154,226,-67,5,37,16,233,405,400,-5,41.5816694,-71.0707018 +12,107.5,115.7,00:26.7,02:05.3,3.99,01:56.6,4.29,32.5,15,7.2,7.6,157,242,-67,5,37,15,253,431,421,-13,41.5817275,-71.070664 +12,114.7,123.3,00:28.5,02:07.6,3.92,01:58.2,4.23,34,16,7.2,7.6,158,219,-67,5,36,15,229,398,380,-18,41.5817856,-71.070626 +12,121.2,130.7,00:30.2,02:08.9,3.88,01:58.2,4.23,32.5,17,6.5,7.4,159,230,-67,5,37,15,240,414,390,-16,41.5818382,-71.070592 +12,128.8,138.5,00:32.1,02:06.3,3.96,01:57.9,4.24,34,18,7.6,7.8,161,227,-67,5,37,16,237,409,398,-9,41.5818998,-71.0705527 +12,135.6,146,00:33.9,02:07.2,3.93,01:59.9,4.17,32.5,19,6.9,7.5,161,217,-65,6,35,13,227,387,387,-9,41.5819556,-71.0705181 +13,2.3,4.6,00:04.5,11:44.2,0.71,11:24.9,0.73,13.5,1,2.3,4.6,142,162,-46,5,39,5,214,488,581,17,41.5825778,-71.0702609 +13,3.3,5.4,00:04.9,05:08.6,1.62,03:10.1,2.63,96,2,1,0.8,141,302,-54,3,38,7,349,508,538,14,41.5825868,-71.0702586 +13,8.4,11.9,00:06.7,02:57.3,2.82,02:24.5,3.46,36,3,5.1,6.4,141,295,-61,4,38,9,297,491,488,8,41.5826321,-71.0702475 +13,15.6,19.3,00:08.5,02:29.7,3.34,02:01.4,4.12,35.5,4,7.2,7.5,139,311,-66,4,38,11,300,520,509,-1,41.5826952,-71.0702319 +13,22.2,26.5,00:10.1,02:10.2,3.84,01:56.0,4.31,35.5,5,6.6,7.2,138,292,-66,4,38,10,282,494,483,8,41.5827533,-71.070216 +13,29.6,34.4,00:11.9,02:04.1,4.03,01:52.9,4.43,34.5,6,7.4,7.9,136,300,-68,4,38,10,300,504,484,0,41.5828184,-71.0701975 +13,36.5,41.7,00:13.5,02:01.7,4.11,01:51.9,4.47,35,7,6.9,7.3,136,265,-67,4,38,12,258,460,445,-5,41.582879,-71.0701787 +13,44,50.9,00:15.5,02:00.8,4.14,01:50.4,4.53,35.5,8,7.5,9.2,135,266,-67,6,38,12,260,457,427,-3,41.5829448,-71.0701582 +13,51.6,57.8,00:17.1,01:58.8,4.21,01:51.1,4.5,34,9,7.5,6.9,135,253,-67,5,39,14,251,445,431,1,41.5830102,-71.0701364 +13,58.4,65.2,00:18.8,01:59.3,4.19,01:51.9,4.47,34,10,6.8,7.4,135,251,-68,5,38,12,250,453,432,-1,41.5830695,-71.0701163 +13,65.8,73,00:20.5,01:58.2,4.23,01:53.1,4.42,32.5,11,7.5,7.8,137,262,-69,7,37,11,266,448,424,-14,41.5831345,-71.0700938 +13,73.2,80.9,00:22.3,01:59.0,4.2,01:53.6,4.4,34,12,7.4,7.9,139,218,-66,4,36,14,226,401,380,8,41.5831986,-71.0700698 +13,80.6,88.7,00:24.1,02:01.7,4.11,01:53.6,4.4,34,13,7.4,7.8,142,236,-67,5,37,16,238,408,414,-7,41.5832621,-71.0700455 +13,87.9,96.5,00:25.9,02:03.5,4.05,01:55.2,4.34,34,14,7.3,7.8,144,233,-67,5,38,15,235,417,406,-13,41.5833255,-71.0700225 +13,94.6,104.1,00:27.7,02:04.1,4.03,01:55.7,4.32,32.5,15,6.7,7.6,147,232,-67,6,37,13,245,406,395,4,41.5833834,-71.0700012 +13,102.4,112,00:29.5,02:01.7,4.11,01:57.1,4.27,32.5,16,7.8,7.9,152,226,-68,5,37,14,240,423,399,-15,41.5834511,-71.0699762 +13,109.7,119.7,00:31.3,02:03.5,4.05,01:58.2,4.23,32.5,17,7.2,7.6,155,225,-68,6,37,13,229,420,405,-15,41.5835135,-71.0699507 +13,116.9,127.5,00:33.1,02:05.9,3.97,01:55.7,4.32,32.5,18,7.3,7.8,158,222,-68,6,38,15,225,413,402,-12,41.5835757,-71.0699247 +13,124.2,135.1,00:34.9,02:06.3,3.96,01:57.6,4.25,32.5,19,7.3,7.7,159,231,-68,5,37,14,241,415,396,-7,41.583638,-71.0698973 +13,131.4,142.9,00:36.8,02:07.6,3.92,01:59.0,4.2,32.5,20,7.1,7.7,160,282,-58,2,38,9,312,504,514,8,41.5836992,-71.0698712 +13,---,---,---,---,---,---,---,---,20,---,---,---,255,-57,8,39,7,300,508,581,12,---,--- +13,---,---,---,---,---,---,---,---,20,---,---,---,32,-66,42,38,53,78,129,141,-22,---,--- +13,---,---,---,---,---,---,---,---,20,---,---,---,213,-67,5,36,13,217,397,392,-6,---,--- +14,11.8,13.6,00:04.9,03:42.2,2.25,02:17.4,3.64,34,1,11.8,13.6,137,292,-63,4,39,11,284,485,489,0,41.5845904,-71.06968 +14,18.7,21.2,00:06.7,02:25.3,3.44,02:02.0,4.1,35.5,2,6.9,7.5,135,268,-66,5,39,13,266,466,445,5,41.5846526,-71.0696795 +14,26,28.9,00:08.5,02:09.9,3.85,01:56.6,4.29,32.5,3,7.2,7.7,135,252,-67,5,38,10,254,462,447,9,41.5847175,-71.0696793 +14,32.7,36.6,00:10.3,02:04.4,4.02,01:54.7,4.36,33,4,6.7,7.7,136,268,-67,5,37,11,275,460,437,0,41.5847778,-71.0696789 +14,40.7,44.7,00:12.1,01:59.3,4.19,01:54.2,4.38,33.5,5,8,8,135,241,-67,4,38,11,247,455,420,6,41.5848499,-71.0696778 +14,48.3,52.5,00:13.9,01:59.3,4.19,01:54.2,4.38,32.5,6,7.6,7.9,135,262,-69,6,38,11,272,471,431,-2,41.5849179,-71.0696761 +14,56.5,62.4,00:16.2,02:01.1,4.13,01:54.2,4.38,31.5,7,8.2,9.9,137,238,-69,5,38,12,249,463,443,-4,41.5849918,-71.0696722 +14,64,69.2,00:17.7,02:01.4,4.12,01:55.2,4.34,31.5,8,7.5,6.8,139,194,-67,5,37,16,214,375,371,5,41.5850592,-71.0696659 +14,71.4,77,00:19.5,02:03.8,4.04,01:55.5,4.33,31.5,9,7.4,7.8,141,231,-68,7,37,13,242,430,407,-17,41.5851255,-71.0696599 +14,79.4,85.5,00:21.5,02:04.1,4.03,01:56.8,4.28,32.5,10,8,8.5,144,236,-68,5,38,14,244,451,425,-7,41.5851973,-71.0696542 +14,86.9,93.4,00:23.4,02:05.0,4,01:56.0,4.31,31.5,11,7.4,7.8,146,232,-68,5,38,13,237,437,429,-8,41.5852639,-71.0696477 +14,94.3,101.7,00:25.3,02:04.7,4.01,01:57.1,4.27,30,12,7.5,8.3,149,236,-67,5,40,14,260,456,429,-4,41.5853307,-71.0696401 +14,102.9,110.3,00:27.3,02:02.0,4.1,01:57.4,4.26,31.5,13,8.6,8.6,150,222,-68,6,36,12,233,431,423,-8,41.5854075,-71.0696296 +14,110.3,117.9,00:29.1,02:04.1,4.03,01:58.8,4.21,31.5,14,7.4,7.6,151,239,-68,5,36,11,263,439,407,-3,41.5854733,-71.0696199 +14,117.6,126.4,00:31.2,02:06.3,3.96,02:00.2,4.16,32.5,15,7.3,8.5,152,213,-67,4,37,14,230,419,394,-17,41.5855381,-71.0696075 +14,125.5,133.9,00:32.9,02:02.5,4.08,01:59.0,4.2,31.5,16,7.9,7.5,153,203,-67,5,36,16,217,384,372,-19,41.585608,-71.0695926 +14,133.3,142.2,00:34.9,02:03.5,4.05,01:58.2,4.23,32.5,17,7.9,8.4,154,215,-68,5,37,16,223,400,389,-2,41.5856776,-71.0695768 +14,140.6,149.7,00:36.7,02:06.6,3.95,01:59.3,4.19,31.5,18,7.3,7.5,155,---,---,---,---,---,---,---,---,---,41.5857419,-71.0695618 +15,0.4,0,00:07.3,19:22.8,0.43,00:00.0,0,8,1,0.4,0,137,185,-49,2,41,8,342,527,646,11,41.5862039,-71.0695255 +15,---,---,---,---,---,---,---,---,1,---,---,---,1,-54,---,-47,---,12,3,22,-48,---,--- +15,2.4,3.1,00:08.6,23:08.9,0.36,00:00.0,0,36.5,2,2.1,3.1,136,---,---,---,---,---,---,---,---,---,41.5862222,-71.069528 +15,4.1,4.7,00:09.3,04:52.4,1.71,03:13.1,2.59,89.5,3,1.7,1.7,135,333,-54,3,38,6,379,552,611,8,41.5862375,-71.0695301 +15,9.8,11.2,00:11.1,02:54.8,2.86,02:23.7,3.48,37.5,4,5.6,6.4,133,329,-60,3,38,8,332,523,504,6,41.5862878,-71.0695369 +15,15.4,18.2,00:12.7,02:29.7,3.34,02:01.1,4.13,37.5,5,5.7,7,132,316,-63,3,39,10,302,509,507,9,41.5863383,-71.0695432 +15,22.7,25.2,00:14.2,02:03.8,4.04,01:52.9,4.43,35.5,6,7.3,7,130,328,-66,3,37,9,313,521,495,2,41.5864036,-71.0695509 +15,29.7,32.9,00:15.9,01:56.6,4.29,01:47.5,4.65,37.5,7,7,7.8,130,293,-66,4,37,10,284,492,494,-1,41.5864662,-71.0695563 +15,37.4,41,00:17.7,01:55.7,4.32,01:48.0,4.63,35.5,8,7.7,8,129,309,-68,5,39,12,296,516,482,-13,41.5865353,-71.0695618 +15,44.5,48.5,00:19.3,01:54.4,4.37,01:47.3,4.66,35.5,9,7.1,7.5,130,310,-67,4,38,11,291,531,526,-8,41.586599,-71.0695661 +15,52.2,56.8,00:21.1,01:55.2,4.34,01:47.3,4.66,34,10,7.8,8.4,132,285,-68,5,39,12,281,493,479,-13,41.5866686,-71.0695694 +15,59.9,65.1,00:22.9,01:57.4,4.26,01:48.2,4.62,34,11,7.7,8.2,133,264,-68,4,38,12,263,473,439,-14,41.5867375,-71.0695715 +15,66.9,73.2,00:24.7,01:59.3,4.19,01:51.6,4.48,32.5,12,7,8.2,136,251,-69,6,38,13,258,457,428,4,41.5868006,-71.0695725 +15,75.1,81.3,00:26.5,01:56.6,4.29,01:51.6,4.48,32.5,13,8.2,8,139,256,-68,5,40,14,261,469,459,-5,41.586874,-71.0695715 +15,82.5,89.3,00:28.3,01:58.2,4.23,01:50.9,4.51,32.5,14,7.4,8,141,247,-68,5,38,14,256,447,436,-3,41.5869408,-71.0695702 +15,89.9,97.2,00:30.1,02:02.2,4.09,01:54.4,4.37,34.5,15,7.3,7.9,144,248,-68,6,38,14,246,447,413,-8,41.5870066,-71.0695677 +15,97.3,105,00:31.8,02:04.1,4.03,01:52.9,4.43,34,16,7.5,7.8,145,246,-68,5,38,11,241,441,409,1,41.5870733,-71.0695648 +15,104.1,113,00:33.7,02:03.8,4.04,01:54.9,4.35,32.5,17,6.8,8,150,264,-68,5,38,14,259,470,467,-14,41.587134,-71.0695609 +15,111.9,120.6,00:35.5,01:59.9,4.17,01:56.3,4.3,34,18,7.8,7.6,154,251,-68,4,36,12,253,451,445,-11,41.587204,-71.0695537 +15,119.1,128.4,00:37.2,02:01.4,4.12,01:56.3,4.3,32.5,19,7.2,7.8,157,242,-68,5,38,15,247,445,426,-13,41.5872685,-71.069544 +15,126.3,136.1,00:39.1,02:04.7,4.01,01:56.8,4.28,32.5,20,7.2,7.7,159,229,-67,5,37,14,231,419,411,-5,41.5873326,-71.0695322 +15,133.5,143.7,00:40.9,02:06.9,3.94,01:57.4,4.26,32.5,21,7.2,7.6,160,239,-67,4,36,15,256,416,414,-15,41.5873963,-71.0695191 +16,3.2,3,00:06.5,22:31.4,0.37,02:25.3,3.44,9,1,3.2,3,140,310,-52,2,38,8,357,514,569,11,41.5878803,-71.0695177 +16,---,---,---,---,---,---,---,---,1,---,---,---,131,-49,4,39,6,162,526,604,7,---,--- +16,8.4,8.8,00:08.1,05:03.0,1.65,02:22.4,3.51,38,2,5.2,5.9,138,368,-61,3,39,10,369,571,570,7,41.5879272,-71.0695227 +16,14.7,15.7,00:09.7,02:32.4,3.28,02:00.8,4.14,37,3,6.3,6.8,136,314,-63,4,37,10,308,503,511,7,41.5879835,-71.0695285 +16,22,23.5,00:11.5,02:10.5,3.83,01:54.9,4.35,37,4,7.3,7.8,134,325,-66,4,37,11,301,546,543,-2,41.5880492,-71.0695362 +16,28.8,32,00:13.3,02:03.2,4.06,01:52.4,4.45,36,5,6.8,8.5,135,350,-66,4,37,9,328,550,536,-5,41.5881097,-71.0695442 +16,35.6,37.9,00:14.7,01:59.3,4.19,01:49.6,4.56,37,6,6.8,6,135,324,-67,4,36,10,322,531,517,-14,41.5881706,-71.0695515 +16,41.9,45.2,00:16.3,01:58.8,4.21,01:52.1,4.46,35.5,7,6.3,7.3,136,322,-68,3,38,10,308,567,546,-2,41.5882271,-71.069555 +16,50.1,53,00:18.0,01:54.7,4.36,01:51.9,4.47,34.5,8,8.2,7.8,136,302,-68,5,37,11,292,520,514,-1,41.5883009,-71.0695565 +16,57.8,61,00:19.9,01:55.7,4.32,01:53.1,4.42,34,9,7.6,8,138,274,-68,4,39,12,272,496,463,-1,41.5883695,-71.069553 +16,65.4,68.9,00:21.7,01:59.0,4.2,01:53.9,4.39,32.5,10,7.6,7.9,139,261,-68,5,39,13,259,476,458,-2,41.5884375,-71.0695454 +16,72.9,76.8,00:23.5,02:01.1,4.13,01:54.9,4.35,34,11,7.5,7.9,139,265,-68,4,38,13,259,471,448,8,41.5885046,-71.0695344 +16,79.7,84.7,00:25.3,02:02.0,4.1,01:55.5,4.33,32.5,12,6.8,7.9,142,254,-68,5,38,13,252,467,458,-5,41.5885651,-71.0695215 +16,87.7,92.2,00:27.1,01:58.8,4.21,01:57.1,4.27,32.5,13,8,7.5,144,250,-68,4,38,13,252,460,422,-7,41.5886358,-71.069503 +16,95.1,99.9,00:28.9,02:00.8,4.14,01:58.5,4.22,32.5,14,7.4,7.7,146,262,-68,5,38,12,266,474,439,-1,41.5887004,-71.0694829 +16,102.4,107.5,00:30.7,02:04.4,4.02,01:58.2,4.23,32.5,15,7.3,7.6,149,241,-68,6,37,14,246,447,415,-12,41.5887638,-71.0694591 +16,109.7,115.1,00:32.5,02:05.9,3.97,01:58.2,4.23,32.5,16,7.3,7.6,152,235,-68,6,37,14,240,436,426,-8,41.5888262,-71.0694319 +16,117,123.3,00:34.4,02:05.6,3.98,01:58.2,4.23,32.5,17,7.3,8.2,155,229,-68,5,37,14,231,424,422,0,41.5888877,-71.0694023 +16,124.9,131.1,00:36.3,02:01.7,4.11,01:59.3,4.19,31.5,18,7.9,7.8,157,236,-68,5,38,14,243,446,427,-17,41.5889545,-71.0693696 +16,132.8,139.4,00:38.3,02:02.2,4.09,01:59.3,4.19,31.5,19,7.9,8.3,158,227,-67,5,37,13,240,422,401,-4,41.5890205,-71.0693343 +16,140.1,148,00:40.3,02:05.6,3.98,01:59.3,4.19,32.5,20,7.3,8.6,159,227,-68,6,37,15,235,433,428,-12,41.5890809,-71.0693007 +17,0.9,0,00:07.3,09:26.7,0.12,00:00.0,0,8,1,0.9,0,140,225,-53,4,39,6,265,553,611,15,41.5894643,-71.0691011 +17,2.5,2.1,00:07.8,10:57.9,0.76,00:00.0,0,75,2,1.6,2.1,139,---,---,---,---,---,---,---,---,---,41.5894758,-71.06909 +17,3.7,3.6,00:08.4,04:03.9,2.05,03:01.8,2.75,98.5,3,1.3,1.5,139,302,-55,3,38,8,335,522,567,8,41.589485,-71.0690812 +17,9.9,10.2,00:10.2,02:53.6,2.88,02:21.6,3.53,37,4,6.1,6.6,137,316,-61,4,38,10,311,506,516,4,41.5895296,-71.0690378 +17,16.1,16.9,00:11.8,02:28.8,3.36,02:02.2,4.09,35.5,5,6.3,6.8,137,339,-64,3,37,10,333,542,505,-11,41.589575,-71.068993 +17,23.5,24.9,00:13.7,02:09.2,3.87,01:54.7,4.36,35.5,6,7.4,8,137,288,-68,6,38,10,285,513,494,6,41.5896281,-71.0689399 +17,30.4,32.1,00:15.2,02:02.0,4.1,01:51.6,4.48,34,7,6.9,7.2,137,289,-68,6,37,11,285,483,481,8,41.5896777,-71.0688901 +17,37.9,41.4,00:17.3,01:59.3,4.19,01:50.4,4.53,35.5,8,7.5,9.3,138,285,-67,5,37,12,272,490,487,-5,41.589731,-71.0688358 +17,44.7,47.7,00:18.7,01:57.9,4.24,01:48.5,4.61,35.5,9,6.9,6.2,138,291,-68,5,37,12,281,486,457,7,41.5897795,-71.0687849 +17,51.1,55.3,00:20.3,01:57.4,4.26,01:49.4,4.57,34,10,6.3,7.6,138,279,-67,5,38,12,274,482,448,5,41.5898235,-71.068737 +17,59.4,63.2,00:22.0,01:54.2,4.38,01:49.6,4.56,34.5,11,8.3,7.9,138,258,-68,7,38,12,251,460,443,3,41.5898803,-71.0686722 +17,67,71.4,00:23.8,01:55.7,4.32,01:50.1,4.54,33.5,12,7.6,8.2,140,249,-67,4,38,14,244,448,446,-8,41.589932,-71.0686121 +17,74.5,79.4,00:25.7,02:00.2,4.16,01:52.9,4.43,34,13,7.5,8,142,259,-68,4,40,16,260,459,439,-10,41.5899829,-71.0685531 +17,81.8,87.2,00:27.4,02:02.5,4.08,01:53.9,4.39,32.5,14,7.3,7.8,144,249,-67,5,38,14,247,451,457,-11,41.5900323,-71.0684951 +17,88.5,95.3,00:29.3,02:04.4,4.02,01:54.7,4.36,34,15,6.7,8.1,147,266,-68,5,37,14,280,457,450,-5,41.5900771,-71.0684423 +17,96.2,102.8,00:31.0,02:01.1,4.13,01:55.7,4.32,32.5,16,7.7,7.6,150,234,-67,5,36,13,248,447,451,-13,41.590129,-71.0683802 +17,103.4,110.8,00:32.9,02:01.7,4.11,01:54.9,4.35,33,17,7.2,8,154,251,-67,5,38,15,261,424,411,-6,41.590177,-71.0683221 +17,110.5,118.5,00:34.7,02:05.6,3.98,01:55.7,4.32,33.5,18,7.1,7.7,156,237,-67,4,37,13,246,457,452,-14,41.5902245,-71.0682648 +17,117.7,126.2,00:36.4,02:07.6,3.92,01:55.7,4.32,32.5,19,7.2,7.7,157,250,-68,6,36,12,250,445,433,-8,41.5902715,-71.0682062 +17,124.3,134.2,00:38.3,02:07.2,3.93,01:56.0,4.31,34,20,6.6,8,158,251,-68,5,36,13,247,454,448,-12,41.5903141,-71.0681505 +17,132.2,141.9,00:40.0,02:02.0,4.1,01:54.9,4.35,32.5,21,7.9,7.7,160,245,-67,5,37,15,246,438,439,-16,41.5903638,-71.0680832 +17,139.5,149.6,00:41.9,02:02.5,4.08,01:56.0,4.31,32.5,22,7.3,7.7,160,---,---,---,---,---,---,---,---,---,41.5904085,-71.0680197 +18,2.9,3.8,00:07.1,29:45.7,0.28,03:00.5,2.77,8.5,1,2.9,3.8,139,326,-42,2,37,8,380,476,589,-4,41.5907955,-71.0676746 +18,---,---,---,---,---,---,---,---,1,---,---,---,169,-53,4,40,7,248,583,653,10,---,--- +18,7.9,9.5,00:08.6,04:52.4,1.71,02:18.9,3.6,41.5,2,5,5.7,137,355,-57,2,38,9,360,533,556,7,41.5908371,-71.0676535 +18,14,16.3,00:10.2,02:32.4,3.28,02:00.8,4.14,38,3,6.1,6.8,136,320,-61,4,37,9,318,499,500,2,41.5908883,-71.0676277 +18,20.5,23.5,00:11.8,02:12.3,3.78,01:52.1,4.46,38.5,4,6.5,7.2,135,300,-62,3,36,9,298,480,493,-7,41.5909429,-71.0676001 +18,27.2,30.8,00:13.4,02:03.2,4.06,01:50.4,4.53,36,5,6.7,7.4,133,290,-65,5,35,11,297,466,492,-15,41.5909994,-71.0675721 +18,33.8,38,00:15.0,02:01.4,4.12,01:51.1,4.5,37,6,6.7,7.2,133,228,-63,6,35,14,234,375,427,-11,41.5910553,-71.0675432 +18,40.5,45.3,00:16.6,02:02.8,4.07,01:49.6,4.56,37.5,7,6.6,7.3,134,283,-67,5,37,11,275,470,466,1,41.5911115,-71.0675163 +18,47.9,53.5,00:18.4,02:02.0,4.1,01:49.4,4.57,35.5,8,7.4,8.2,135,289,-66,4,36,10,283,474,455,5,41.5911744,-71.0674873 +18,54.8,61,00:20.0,02:01.1,4.13,01:48.2,4.62,35.5,9,6.9,7.4,136,239,-66,5,37,12,234,427,423,5,41.5912331,-71.067459 +18,61.6,69.2,00:21.9,02:00.8,4.14,01:49.9,4.55,34,10,6.8,8.2,137,250,-67,5,37,14,244,431,425,4,41.5912907,-71.0674312 +18,69.7,77.1,00:23.6,01:57.1,4.27,01:51.4,4.49,34,11,8,7.9,140,257,-67,5,36,13,258,445,457,-6,41.5913586,-71.0673984 +18,76.4,84.3,00:25.2,01:59.3,4.19,01:52.1,4.46,34,12,6.7,7.2,143,241,-67,4,36,14,242,429,422,-5,41.5914148,-71.0673704 +18,83.6,92.3,00:27.0,02:03.2,4.06,01:53.4,4.41,34,13,7.3,8,144,249,-67,5,35,12,248,436,433,-13,41.5914758,-71.0673392 +18,90.9,100.1,00:28.8,02:04.1,4.03,01:53.6,4.4,34,14,7.3,7.8,147,222,-65,5,35,13,233,382,397,-7,41.5915371,-71.067309 +18,98.1,109.2,00:30.9,02:04.7,4.01,01:52.4,4.45,34,15,7.1,9,152,241,-67,4,36,13,239,433,414,-11,41.5915977,-71.0672794 +18,104.7,115.1,00:32.2,02:04.7,4.01,01:53.9,4.39,34,16,6.6,6,155,253,-67,4,36,13,247,441,430,-7,41.5916529,-71.0672514 +18,111.3,122.9,00:34.0,02:05.0,4,01:54.2,4.38,34,17,6.6,7.8,156,238,-67,5,36,13,240,417,412,-9,41.5917082,-71.0672213 +18,119.1,130.9,00:35.8,02:02.8,4.07,01:54.2,4.38,34,18,7.8,8,159,230,-67,6,36,16,234,402,398,-5,41.5917725,-71.0671849 +18,126.3,138.7,00:37.6,02:03.8,4.04,01:54.9,4.35,34,19,7.2,7.8,160,221,-67,7,36,15,223,397,409,-4,41.5918318,-71.0671502 +18,133.3,146.4,00:39.4,02:06.6,3.95,01:57.6,4.25,34,20,7,7.7,162,0,-57,---,-52,---,5,1,21,-55,41.5918896,-71.067117 +18,---,---,---,---,---,---,---,---,20,---,---,---,247,-67,6,37,14,243,435,429,-13,---,--- +19,0.1,0,00:01.0,55:33.3,0.15,00:00.0,0,8,1,0.1,0,137,251,-51,1,42,8,299,558,619,11,41.5922903,-71.0668989 +19,1.8,3.1,00:02.2,22:31.4,0.37,32:03.1,0.26,38.5,2,1.7,3.1,137,---,---,---,---,---,---,---,---,---,41.5923072,-71.0668937 +19,3.1,4.8,00:02.7,05:06.7,1.63,02:58.6,2.8,101.5,3,1.3,1.7,137,320,-49,2,37,6,353,497,598,10,41.5923185,-71.06689 +19,8.6,11,00:04.4,02:56.7,2.83,02:14.4,3.72,39.5,4,5.5,6.2,137,349,-58,3,37,8,343,516,542,10,41.5923664,-71.0668761 +19,14.8,17.9,00:06.0,02:29.3,3.35,01:57.6,4.25,39,5,6.2,6.9,135,318,-63,5,37,11,300,505,503,-3,41.5924206,-71.066859 +19,21.4,25.3,00:07.6,02:08.5,3.89,01:51.1,4.5,37.5,6,6.7,7.4,134,319,-64,4,36,10,302,492,490,0,41.5924788,-71.0668408 +19,28.3,32.7,00:09.2,01:59.9,4.17,01:46.8,4.68,37,7,6.8,7.4,132,287,-66,6,35,11,280,476,481,-17,41.5925387,-71.0668227 +19,35.2,40.2,00:10.8,01:57.9,4.24,01:48.5,4.61,37.5,8,6.9,7.5,131,280,-64,5,35,10,265,448,458,-12,41.5925989,-71.0668042 +19,42.1,47.6,00:12.4,01:57.9,4.24,01:46.2,4.71,36.5,9,6.9,7.4,133,295,-67,5,38,10,272,498,480,-1,41.5926595,-71.0667852 +19,49.8,55.9,00:14.2,01:57.6,4.25,01:47.8,4.64,35,10,7.7,8.3,135,289,-69,6,38,12,283,503,484,-5,41.5927274,-71.0667648 +19,57.6,64.3,00:16.0,01:57.4,4.26,01:48.0,4.63,33,11,7.8,8.4,137,259,-68,5,37,11,261,460,442,2,41.5927958,-71.0667437 +19,64,71.9,00:17.6,01:57.6,4.25,01:48.5,4.61,34,12,6.4,7.6,139,259,-67,4,37,14,275,440,434,0,41.5928518,-71.0667265 +19,72.2,80,00:19.4,01:54.9,4.35,01:49.6,4.56,34,13,8.2,8,142,251,-69,7,37,12,257,457,429,-17,41.5929237,-71.0667052 +19,79.8,88.1,00:21.2,01:57.1,4.27,01:50.1,4.54,34,14,7.6,8.1,145,237,-67,5,37,15,237,426,413,-14,41.5929902,-71.0666859 +19,87.3,96.2,00:23.0,02:00.8,4.14,01:50.9,4.51,34,15,7.5,8.1,147,215,-66,5,35,16,221,374,399,-8,41.5930563,-71.0666673 +19,94.8,104.2,00:24.8,02:02.8,4.07,01:52.6,4.44,34,16,7.4,8.1,149,249,-67,5,36,14,241,440,470,-10,41.5931218,-71.0666501 +19,101.5,112.3,00:26.6,02:03.5,4.05,01:52.6,4.44,34,17,6.7,8.1,151,282,-68,5,37,12,265,485,470,-4,41.5931814,-71.0666373 +19,108.8,119.4,00:28.2,01:59.9,4.17,01:52.9,4.43,34,18,7.3,7.1,156,266,-68,4,39,14,260,472,472,-6,41.5932461,-71.0666247 +19,116.1,127.2,00:30.0,02:01.1,4.13,01:52.1,4.46,34,19,7.3,7.9,158,252,-68,5,37,13,246,456,427,3,41.5933115,-71.0666123 +19,123.4,135.3,00:31.8,02:03.8,4.04,01:54.7,4.36,34,20,7.3,8,159,247,-67,5,36,13,239,432,444,-9,41.5933761,-71.0665981 +19,130.6,142.9,00:33.6,02:04.7,4.01,01:53.6,4.4,34,21,7.2,7.6,161,269,-68,5,37,14,258,473,500,-12,41.59344,-71.0665839 +20,3.4,4.2,00:07.7,27:46.7,0.3,02:54.2,2.87,7.5,1,3.4,4.2,137,298,-56,4,37,8,343,513,589,8,41.5939639,-71.0665077 +20,---,---,---,---,---,---,---,---,1,---,---,---,188,-51,1,40,6,236,562,634,9,---,--- +20,9,10.9,00:09.5,04:57.6,1.68,02:17.0,3.65,35.5,2,5.6,6.7,136,344,-63,3,37,8,344,551,563,4,41.5940142,-71.0665016 +20,15.3,18.9,00:11.4,02:29.7,3.34,01:57.9,4.24,37.5,3,6.3,8,134,350,-66,6,39,9,339,561,549,-13,41.5940706,-71.0664929 +20,22.9,26.2,00:12.9,02:03.8,4.04,01:48.7,4.6,35.5,4,7.6,7.3,132,275,-66,6,37,12,267,485,514,-3,41.5941384,-71.0664832 +20,30,33.9,00:14.6,01:56.0,4.31,01:47.8,4.64,35.5,5,7.1,7.7,131,277,-67,8,37,12,262,451,475,-8,41.5942013,-71.0664727 +20,37,41.2,00:16.1,01:54.4,4.37,01:46.8,4.68,35.5,6,7,7.3,132,309,-67,5,37,12,296,504,521,-11,41.5942641,-71.0664638 +20,44.7,49.6,00:17.9,01:54.7,4.36,01:46.4,4.7,35.5,7,7.6,8.4,134,297,-68,8,40,13,283,508,520,-11,41.5943324,-71.0664554 +20,52.4,57.9,00:19.7,01:56.3,4.3,01:48.2,4.62,34,8,7.7,8.3,135,307,-68,4,38,10,296,550,540,-6,41.5944016,-71.0664458 +20,60.2,66.1,00:21.5,01:57.6,4.25,01:50.1,4.54,34,9,7.8,8.2,137,273,-68,6,39,13,267,486,479,-15,41.5944708,-71.066435 +20,67.2,74.5,00:23.4,01:58.2,4.23,01:48.7,4.6,32.5,10,7.1,8.4,139,268,-68,6,38,13,266,475,465,-1,41.5945338,-71.0664257 +20,74.9,81.8,00:24.9,01:55.2,4.34,01:49.6,4.56,34,11,7.7,7.3,143,257,-67,5,37,12,265,458,453,3,41.5946024,-71.0664164 +20,82.5,89.8,00:26.7,01:57.9,4.24,01:50.9,4.51,34,12,7.6,8,146,240,-67,5,37,14,246,433,435,-9,41.5946707,-71.0664084 +20,90.1,97.8,00:28.5,02:00.5,4.15,01:51.1,4.5,32.5,13,7.5,8,147,240,-67,5,38,15,240,436,449,-10,41.5947382,-71.066401 +20,97.4,105.8,00:30.3,02:02.2,4.09,01:52.9,4.43,32.5,14,7.4,8,151,227,-66,6,38,14,241,416,414,0,41.5948044,-71.0663949 +20,104.7,114.7,00:32.4,02:04.7,4.01,01:54.4,4.37,32.5,15,7.3,8.8,154,261,-68,4,37,14,265,472,466,-13,41.5948696,-71.0663914 +20,112.6,122.4,00:34.1,02:02.2,4.09,01:54.4,4.37,34,16,7.9,7.7,157,247,-67,5,36,12,248,455,455,-14,41.5949403,-71.0663868 +20,119.9,130.2,00:35.9,02:02.8,4.07,01:54.4,4.37,32.5,17,7.3,7.8,159,202,-66,6,37,17,207,366,378,-12,41.5950054,-71.0663805 +20,127.1,138,00:37.7,02:05.0,4,01:55.2,4.34,32.5,18,7.3,7.8,160,235,-67,4,37,16,235,425,439,-12,41.5950704,-71.0663749 +20,134.3,145.9,00:39.5,02:07.2,3.93,01:55.7,4.32,34,19,7.2,7.9,160,137,-50,5,44,11,153,554,660,13,41.5951347,-71.0663699 +20,---,---,---,---,---,---,---,---,19,---,---,---,---,-58,---,-48,---,-21,---,14,-58,---,--- +20,---,---,---,---,---,---,---,---,19,---,---,---,252,-68,5,38,14,257,451,444,-19,---,--- +21,4.9,4.7,00:02.7,09:09.5,0.91,03:01.2,2.76,9,1,4.9,4.7,144,313,-55,3,37,7,362,526,587,10,41.5949887,-71.0665595 +21,11.3,11.3,00:04.5,03:54.7,2.13,02:23.3,3.49,37,2,6.5,6.6,143,323,-62,2,37,8,318,534,513,10,41.5949322,-71.0665772 +21,18.3,18,00:06.1,02:13.7,3.74,02:01.1,4.13,36,3,7,6.7,142,325,-66,4,38,11,301,529,521,0,41.5948714,-71.0665966 +21,25.8,25.3,00:07.7,01:55.7,4.32,01:53.1,4.42,36,4,7.5,7.3,141,322,-67,3,37,10,293,538,549,-9,41.5948059,-71.0666173 +21,34.3,33.4,00:09.5,01:48.9,4.59,01:49.6,4.56,37,5,8.5,8.1,141,308,-69,5,38,12,282,514,475,-13,41.5947313,-71.0666412 +21,42.2,41,00:11.1,01:45.7,4.73,01:48.0,4.63,35.5,6,7.9,7.6,141,297,-68,5,37,11,268,481,461,-6,41.5946626,-71.0666638 +21,49.9,49.5,00:13.0,01:43.9,4.81,01:47.3,4.66,35.5,7,7.8,8.5,141,286,-68,7,37,11,260,474,461,6,41.5945949,-71.0666861 +21,58.6,56.7,00:14.5,01:41.2,4.94,01:46.8,4.68,36,8,8.7,7.2,141,298,-68,4,38,11,274,494,449,6,41.5945191,-71.0667108 +21,66.6,64.5,00:16.2,01:41.4,4.93,01:47.3,4.66,35.5,9,8,7.8,142,279,-70,8,40,14,265,489,467,-1,41.5944498,-71.0667337 +21,75.3,72.7,00:17.9,01:41.8,4.91,01:47.3,4.66,34,10,8.7,8.2,143,272,-68,4,39,14,260,481,453,3,41.5943742,-71.0667596 +21,83.8,80.8,00:19.7,01:43.3,4.84,01:48.9,4.59,34,11,8.5,8.2,145,283,-69,4,39,13,276,501,486,-15,41.5943,-71.0667864 +21,92.4,89.1,00:21.5,01:45.0,4.76,01:49.4,4.57,32.5,12,8.5,8.3,147,265,-69,5,37,12,261,474,454,-7,41.5942261,-71.0668144 +21,100,96.6,00:23.1,01:46.2,4.71,01:49.4,4.57,34,13,7.7,7.4,149,265,-68,4,38,15,254,464,456,-13,41.59416,-71.0668397 +21,107.8,104.8,00:24.9,01:47.1,4.67,01:50.4,4.53,34,14,7.8,8.2,152,259,-69,5,37,14,250,450,434,-19,41.5940932,-71.0668659 +21,116.8,112.7,00:26.7,01:44.6,4.78,01:51.1,4.5,34.5,15,9.1,7.9,154,255,-68,5,37,14,249,443,426,-14,41.5940151,-71.0668967 +21,125.2,120.7,00:28.5,01:45.5,4.74,01:51.4,4.49,33.5,16,8.3,8,156,240,-67,5,37,15,241,422,415,-13,41.5939435,-71.0669256 +21,132.8,128.1,00:30.1,01:48.2,4.62,01:51.9,4.47,34,17,7.6,7.4,157,233,-68,5,37,16,234,410,410,-12,41.593878,-71.0669517 +21,141,135.9,00:31.9,01:49.9,4.55,01:53.9,4.39,34,18,8.2,7.8,159,248,-67,5,35,13,248,431,436,-17,41.5938068,-71.0669783 +21,149.2,144.6,00:33.9,01:50.9,4.51,01:54.4,4.37,34.5,19,8.2,8.8,161,229,-68,5,35,14,231,411,395,-15,41.5937361,-71.0670053 +22,1.3,0,00:00.9,07:51.7,1.06,00:00.0,0,68,1,1.3,0,136,215,-45,1,38,6,261,560,681,11,41.5929694,-71.0673018 +22,3.8,1.5,00:01.4,03:45.2,2.22,03:04.5,2.71,96,2,2.5,1.5,135,321,-53,1,37,8,357,539,607,9,41.5929476,-71.067307 +22,10.2,7.9,00:03.2,02:36.7,3.19,02:24.1,3.47,37.5,3,6.5,6.4,134,354,-62,4,37,9,335,552,578,1,41.5928903,-71.0673196 +22,17.2,14.6,00:04.8,02:15.5,3.69,02:03.2,4.06,37.5,4,6.9,6.7,132,348,-65,4,39,11,321,557,541,-2,41.5928288,-71.0673322 +22,24.6,21.9,00:06.4,01:57.1,4.27,01:52.6,4.44,36,5,7.4,7.3,131,315,-66,4,38,13,288,510,503,-14,41.592763,-71.0673456 +22,32.2,29.3,00:08.0,01:48.9,4.59,01:48.7,4.6,37,6,7.6,7.4,130,298,-66,4,35,10,277,484,477,0,41.5926955,-71.0673597 +22,39.9,37.7,00:09.9,01:46.4,4.7,01:48.0,4.63,37.5,7,7.7,8.4,129,298,-67,5,38,12,271,482,453,-18,41.5926273,-71.0673743 +22,48.4,44.8,00:11.4,01:42.2,4.89,01:48.7,4.6,36,8,8.5,7.2,131,285,-67,6,39,12,265,479,488,0,41.5925516,-71.0673909 +22,56.2,52.5,00:13.1,01:42.2,4.89,01:49.4,4.57,34,9,7.9,7.6,132,271,-68,4,39,13,266,488,469,4,41.5924819,-71.0674057 +22,64.9,60.5,00:14.8,01:43.7,4.82,01:49.2,4.58,34,10,8.6,8,135,263,-69,5,38,12,257,476,447,3,41.5924055,-71.0674228 +22,74.2,69.3,00:16.8,01:44.4,4.79,01:51.4,4.49,31.5,11,9.3,8.8,138,241,-69,5,37,12,237,458,432,1,41.592323,-71.0674425 +22,82.7,78.5,00:18.9,01:46.4,4.7,01:51.9,4.47,34,12,8.5,9.1,141,244,-68,5,37,14,237,439,427,-10,41.5922475,-71.0674607 +22,91.2,85.3,00:20.4,01:46.8,4.68,01:52.1,4.46,32.5,13,8.5,6.9,144,241,-69,6,38,16,232,433,435,-3,41.5921726,-71.0674781 +22,98.8,92.9,00:22.1,01:47.1,4.67,01:53.1,4.42,33,14,7.6,7.5,145,254,-68,6,38,14,247,449,430,-4,41.5921048,-71.0674923 +22,107.9,101.2,00:24.0,01:46.8,4.68,01:53.1,4.42,33.5,15,9.1,8.3,148,250,-69,5,37,12,249,468,443,2,41.5920245,-71.0675098 +22,116.3,109,00:25.9,01:48.2,4.62,01:56.8,4.28,32.5,16,8.3,7.9,150,236,-69,6,37,15,234,432,442,-12,41.5919507,-71.0675278 +22,124.5,117.9,00:27.9,01:49.6,4.56,01:56.0,4.31,32.5,17,8.3,8.8,154,247,-70,5,36,13,250,446,426,-10,41.5918775,-71.0675463 +22,132.8,124.6,00:29.4,01:48.0,4.63,01:55.5,4.33,31.5,18,8.3,6.8,157,236,-69,5,36,15,238,441,444,-9,41.5918047,-71.0675653 +22,141.1,132.4,00:31.2,01:49.6,4.56,01:56.3,4.3,33.5,19,8.3,7.8,158,229,-69,5,36,15,234,412,409,-12,41.5917316,-71.0675845 +22,149.9,140.7,00:33.2,01:51.6,4.48,01:58.8,4.21,31.5,20,8.8,8.3,158,233,-68,5,38,17,236,438,439,-12,41.5916536,-71.0676047 +22,158,148.2,00:35.0,01:53.1,4.42,01:59.6,4.18,32.5,21,8,7.6,159,---,---,---,---,---,---,---,---,---,41.5915828,-71.0676242 +23,5.5,5.5,00:01.6,03:35.5,2.32,02:22.4,3.51,37.5,1,5.5,5.5,139,355,-60,3,37,9,362,553,589,-1,41.5907816,-71.0681228 +23,---,---,---,---,---,---,---,---,1,---,---,---,327,-51,2,36,7,381,532,622,6,---,--- +23,13,12,00:03.1,02:06.9,3.94,02:02.2,4.09,37.5,2,7.5,6.5,139,317,-64,4,37,10,298,519,500,3,41.5907277,-71.068177 +23,20.5,19.5,00:04.8,01:51.1,4.5,01:51.9,4.47,37,3,7.5,7.5,139,293,-65,4,36,11,280,470,465,7,41.5906741,-71.068231 +23,29,27.4,00:06.5,01:45.7,4.73,01:49.2,4.58,35.5,4,8.5,7.9,139,255,-65,5,37,14,247,426,430,-1,41.5906127,-71.0682926 +23,36.8,34.9,00:08.1,01:43.7,4.82,01:47.8,4.64,36,5,7.8,7.5,140,275,-68,6,37,11,258,462,445,-6,41.5905563,-71.0683484 +23,44.7,42.4,00:09.7,01:44.4,4.79,01:48.5,4.61,35.5,6,7.8,7.4,140,275,-68,6,38,13,262,468,458,-5,41.5904995,-71.0684042 +23,53.4,50.7,00:11.5,01:44.4,4.79,01:48.7,4.6,34,7,8.7,8.4,140,258,-69,7,37,13,253,457,439,-6,41.5904365,-71.0684663 +23,62,60,00:13.6,01:44.6,4.78,01:49.4,4.57,34,8,8.6,9.3,142,271,-69,6,38,13,263,477,474,0,41.590375,-71.0685283 +23,70.6,67.1,00:15.1,01:43.7,4.82,01:48.7,4.6,34,9,8.6,7.1,143,267,-69,6,38,13,262,473,459,-4,41.5903135,-71.0685903 +23,78.3,74.6,00:16.8,01:44.4,4.79,01:50.1,4.54,33,10,7.7,7.5,144,260,-69,5,37,14,256,464,443,-15,41.5902584,-71.0686468 +23,86.8,82.7,00:18.5,01:44.2,4.8,01:50.9,4.51,34,11,8.5,8,146,261,-69,5,36,13,255,457,429,-16,41.5901979,-71.068709 +23,95.2,90.7,00:20.3,01:45.3,4.75,01:49.9,4.55,35,12,8.4,8,149,281,-70,4,37,13,267,497,469,-9,41.5901384,-71.0687715 +23,103.7,98.9,00:22.1,01:46.2,4.71,01:49.4,4.57,34,13,8.5,8.2,152,264,-69,5,38,14,252,461,460,-7,41.5900787,-71.0688344 +23,112.1,107,00:23.9,01:46.4,4.7,01:50.1,4.54,34,14,8.4,8.1,155,253,-69,5,38,16,249,447,441,-8,41.5900204,-71.0688985 +23,119,114.3,00:25.6,01:47.5,4.65,01:53.6,4.4,32.5,15,6.9,7.3,156,255,-68,5,37,15,248,454,455,-14,41.5899723,-71.0689511 +23,128,122.2,00:27.3,01:45.7,4.73,01:53.1,4.42,34,16,9,7.9,157,210,-68,7,37,17,215,368,387,-16,41.5899113,-71.0690216 +23,136.1,129.8,00:29.1,01:48.2,4.62,01:55.2,4.34,34,17,8.2,7.7,159,231,-68,5,37,17,238,414,417,-16,41.589856,-71.0690861 +23,144.2,137.7,00:30.9,01:51.6,4.48,01:55.7,4.32,32.5,18,8.1,7.9,160,226,-68,5,37,16,232,421,411,-11,41.589801,-71.0691497 +23,153,146.1,00:32.9,01:52.6,4.44,01:56.8,4.28,32.5,19,8.7,8.4,162,340,-64,4,37,9,345,544,555,8,41.5897422,-71.069219 +23,---,---,---,---,---,---,---,---,19,---,---,---,315,-57,2,37,7,364,546,585,9,---,--- +23,---,---,---,---,---,---,---,---,19,---,---,---,149,-45,3,41,6,219,577,683,10,---,--- +23,---,---,---,---,---,---,---,---,19,---,---,---,---,-56,---,-43,---,-10,---,24,-55,---,--- +23,---,---,---,---,---,---,---,---,19,---,---,---,226,-68,6,38,16,231,410,410,-13,---,--- +24,17.9,18.7,00:06.1,02:37.2,3.18,01:58.8,4.21,36,1,17.9,18.7,134,321,-64,4,38,10,307,527,511,-9,41.5889021,-71.0697822 +24,25.2,26.1,00:07.7,01:57.6,4.25,01:50.1,4.54,37.5,2,7.2,7.4,134,316,-67,5,38,11,296,525,517,0,41.5888371,-71.0697777 +24,32.7,33.7,00:09.4,01:51.1,4.5,01:48.2,4.62,34,3,7.6,7.6,133,294,-68,5,37,11,283,502,499,-5,41.5887692,-71.0697726 +24,41.1,41.9,00:11.1,01:47.5,4.65,01:47.8,4.64,35.5,4,8.3,8.2,134,276,-68,6,37,12,267,468,445,3,41.5886946,-71.0697668 +24,47.9,49.6,00:12.8,01:46.8,4.68,01:48.2,4.62,34.5,5,6.8,7.7,135,262,-68,5,38,14,245,463,451,0,41.5886336,-71.0697611 +24,56.9,57.5,00:14.5,01:44.6,4.78,01:49.4,4.57,33.5,6,9,7.9,137,278,-69,6,38,12,267,487,469,-2,41.5885527,-71.0697527 +24,65.9,66.5,00:16.6,01:46.2,4.71,01:50.4,4.53,32.5,7,9,9,139,259,-70,6,38,12,260,487,469,-3,41.5884722,-71.0697444 +24,74.1,74.5,00:18.3,01:49.4,4.57,01:52.1,4.46,31.5,8,8.2,8,141,234,-68,5,37,13,241,444,436,-7,41.5883986,-71.069736 +24,82.3,82.4,00:20.1,01:51.4,4.49,01:53.6,4.4,32.5,9,8.2,7.9,144,265,-69,5,37,13,262,481,443,-6,41.588325,-71.0697282 +24,90.5,90.5,00:22.0,01:52.9,4.43,01:54.7,4.36,32.5,10,8.2,8.1,146,247,-68,6,37,13,250,457,452,-8,41.5882519,-71.0697205 +24,99.3,98.9,00:23.9,01:50.9,4.51,01:55.2,4.34,32.5,11,8.8,8.4,149,256,-69,6,37,13,256,477,456,-2,41.5881732,-71.0697122 +24,107.3,106.8,00:25.7,01:50.9,4.51,01:54.4,4.37,32.5,12,8.1,7.9,153,269,-69,5,38,14,267,479,471,-9,41.5881011,-71.0697056 +24,115.6,115.7,00:27.8,01:51.6,4.48,01:55.2,4.34,32.5,13,8.2,9,155,252,-69,5,38,14,255,471,441,-3,41.5880274,-71.0696991 +24,123.6,122.6,00:29.4,01:50.4,4.53,01:54.7,4.36,34,14,8,6.8,157,262,-69,4,38,15,257,472,464,-13,41.5879555,-71.0696932 +24,131.7,130.2,00:31.1,01:50.4,4.53,01:56.8,4.28,32.5,15,8.1,7.7,158,252,-68,5,38,15,254,452,441,-7,41.5878829,-71.0696888 +24,139.7,137.9,00:32.9,01:51.1,4.5,01:56.0,4.31,34,16,8.1,7.7,158,257,-68,5,37,15,250,448,466,-15,41.5878106,-71.0696836 +24,147.8,145.6,00:34.7,01:52.4,4.45,01:57.4,4.26,34,17,8.1,7.7,159,176,-56,5,39,7,196,644,717,0,41.5877381,-71.0696776 +24,---,---,---,---,---,---,---,---,17,---,---,---,260,-68,5,38,15,262,465,452,-12,---,--- +25,5.1,5.3,00:02.7,10:49.3,0.77,02:21.2,3.54,9.5,1,5.1,5.3,137,361,-58,2,38,6,400,617,651,7,41.58696,-71.0696239 +25,11.3,11.6,00:04.4,03:49.4,2.18,02:21.2,3.54,37,2,6.2,6.3,137,357,-64,3,37,9,344,574,551,-6,41.5869044,-71.069621 +25,18.4,18.1,00:05.9,02:07.6,3.92,02:00.5,4.15,37.5,3,7.1,6.6,136,363,-64,4,38,10,323,556,558,-7,41.5868404,-71.069618 +25,26,25.3,00:07.5,01:51.1,4.5,01:51.1,4.5,38,4,7.6,7.2,135,334,-65,3,37,10,305,511,509,-5,41.5867725,-71.0696145 +25,33.7,32.7,00:09.1,01:46.2,4.71,01:48.5,4.61,38.5,5,7.7,7.4,135,328,-67,4,36,10,321,522,503,-2,41.5867032,-71.0696103 +25,41.5,40.3,00:10.7,01:43.7,4.82,01:46.4,4.7,36,6,7.8,7.6,135,320,-68,3,37,10,299,538,537,-11,41.586633,-71.0696062 +25,49.4,47.9,00:12.3,01:43.1,4.85,01:46.4,4.7,37,7,7.9,7.6,135,308,-68,4,39,12,278,518,508,-5,41.5865626,-71.0696021 +25,58,56.2,00:14.1,01:44.2,4.8,01:47.5,4.65,34,8,8.6,8.3,136,282,-69,5,38,12,263,513,512,-4,41.5864853,-71.0695976 +25,66.6,65.5,00:16.1,01:45.3,4.75,01:49.6,4.56,32.5,9,8.6,9.3,137,292,-69,4,38,11,273,519,515,-4,41.5864082,-71.0695932 +25,75.1,72.5,00:17.7,01:43.9,4.81,01:49.9,4.55,34,10,8.5,7.1,140,275,-70,5,39,12,267,495,461,-13,41.5863316,-71.0695906 +25,84.3,81.5,00:19.7,01:45.7,4.73,01:49.6,4.56,32.5,11,9.2,9,143,290,-70,4,37,11,296,517,487,-14,41.5862489,-71.0695889 +25,92.7,89.7,00:21.5,01:47.8,4.64,01:50.6,4.52,32.5,12,8.4,8.2,145,250,-69,5,37,13,267,471,444,0,41.5861731,-71.0695889 +25,101,97.8,00:23.3,01:48.9,4.59,01:51.4,4.49,32.5,13,8.3,8.1,146,242,-69,5,37,14,240,444,425,2,41.5860985,-71.0695903 +25,108.5,106,00:25.1,01:49.9,4.55,01:51.9,4.47,32.5,14,7.5,8.2,149,275,-69,5,37,13,272,492,486,-6,41.5860313,-71.0695913 +25,117.4,113.7,00:26.9,01:47.8,4.64,01:53.4,4.41,34,15,8.8,7.7,153,248,-69,6,37,13,244,453,449,-8,41.5859519,-71.0695929 +25,125.5,121.6,00:28.7,01:49.6,4.56,01:54.4,4.37,32.5,16,8.1,7.9,156,250,-68,5,37,14,248,447,429,-4,41.585879,-71.0695956 +25,133.5,129.4,00:30.5,01:52.4,4.45,01:55.5,4.33,34,17,8,7.8,158,252,-69,5,36,13,249,455,430,-11,41.5858069,-71.069599 +25,141.5,137.2,00:32.3,01:52.9,4.43,01:54.7,4.36,32.5,18,8,7.8,158,254,-69,6,38,15,254,444,452,-16,41.5857353,-71.0696027 +25,148.7,145.2,00:34.1,01:53.9,4.39,01:54.9,4.35,34,19,7.2,8.1,160,241,-69,5,36,14,240,441,428,-7,41.5856707,-71.0696066 +26,5.6,5.7,00:01.7,04:05.1,2.04,02:27.1,3.4,35.5,1,5.6,5.7,134,329,-64,3,39,10,317,559,556,9,41.5848979,-71.069679 +26,---,---,---,---,---,---,---,---,1,---,---,---,314,-57,3,37,7,366,543,542,-2,---,--- +26,12.4,11.5,00:03.0,02:14.8,3.71,02:02.0,4.1,35.5,2,6.9,5.8,131,333,-66,4,38,9,303,543,542,7,41.5848363,-71.0696816 +26,19.1,18.9,00:04.6,01:56.0,4.31,01:52.6,4.44,36,3,6.7,7.4,131,323,-67,5,37,9,309,510,491,5,41.584776,-71.0696834 +26,28.2,27,00:06.4,01:46.2,4.71,01:49.4,4.57,36,4,9.1,8.1,130,292,-68,4,38,11,276,508,483,4,41.5846942,-71.0696864 +26,36,34.3,00:08.0,01:44.2,4.8,01:47.3,4.66,35.5,5,7.8,7.4,132,308,-69,5,37,10,287,512,482,1,41.5846243,-71.0696886 +26,44.6,42.6,00:09.8,01:45.0,4.76,01:48.2,4.62,35,6,8.6,8.3,132,294,-69,5,38,12,271,508,492,-4,41.5845469,-71.0696919 +26,52.4,50.2,00:11.4,01:44.4,4.79,01:47.3,4.66,36,7,7.8,7.6,133,312,-69,4,39,12,280,518,486,-2,41.5844769,-71.0696951 +26,61.1,58.6,00:13.2,01:44.6,4.78,01:47.1,4.67,34,8,8.6,8.4,135,276,-69,5,40,12,269,496,455,5,41.5843993,-71.0696991 +26,69.7,66.9,00:15.0,01:45.0,4.76,01:47.8,4.64,32.5,9,8.6,8.3,137,275,-69,5,38,12,280,503,490,-4,41.5843223,-71.0697038 +26,77.5,74.9,00:16.8,01:46.2,4.71,01:49.9,4.55,33,10,7.9,8,139,263,-68,5,37,12,256,476,450,-5,41.5842516,-71.0697082 +26,86.7,83.1,00:18.6,01:44.6,4.78,01:50.4,4.53,33.5,11,9.1,8.2,143,271,-70,4,37,12,261,491,441,1,41.5841696,-71.0697144 +26,95.1,91.2,00:20.4,01:45.9,4.72,01:51.6,4.48,34,12,8.4,8.1,146,281,-69,5,36,11,280,476,467,-11,41.5840943,-71.0697207 +26,103.4,99.2,00:22.2,01:48.0,4.63,01:52.1,4.46,33,13,8.3,8,150,261,-69,5,37,11,264,489,467,-7,41.5840199,-71.0697274 +26,111.7,107.2,00:24.0,01:49.2,4.58,01:52.9,4.43,33.5,14,8.3,7.9,153,281,-69,4,36,11,286,481,457,-9,41.5839457,-71.0697341 +26,118.6,114.6,00:25.6,01:49.2,4.58,01:53.6,4.4,33,15,6.9,7.4,155,256,-69,4,36,11,257,479,447,-9,41.5838836,-71.0697398 +26,128.3,123.1,00:27.6,01:45.7,4.73,01:52.9,4.43,33.5,16,9.7,8.5,157,272,-69,3,37,13,262,485,475,-8,41.5837965,-71.0697485 +26,135.9,130.3,00:29.2,01:46.4,4.7,01:52.4,4.45,34,17,7.6,7.3,159,260,-68,4,37,13,254,454,431,-4,41.5837282,-71.0697563 +26,144.3,138.3,00:31.0,01:48.9,4.59,01:53.6,4.4,34,18,8.3,8,160,267,-69,4,36,13,263,477,457,-12,41.5836538,-71.0697648 +26,152.6,146.2,00:32.8,01:49.9,4.55,01:52.6,4.44,34,19,8.4,7.9,161,265,-69,5,38,15,262,467,442,-17,41.5835788,-71.0697736 +27,4.6,0,00:07.8,13:01.2,0.64,00:00.0,0,7.5,1,4.6,0,138,153,-51,1,41,6,294,603,668,10,41.5828133,-71.069893 +27,6.5,1.4,00:08.4,04:17.7,1.94,03:03.8,2.72,95.5,2,1.9,1.4,136,316,-55,3,37,7,348,547,595,14,41.5827968,-71.069897 +27,12.5,7.4,00:10.0,02:30.1,3.33,02:24.5,3.46,37.5,3,6.1,6,135,389,-60,3,38,7,374,572,587,1,41.5827432,-71.0699096 +27,19.5,14.2,00:11.6,02:09.5,3.86,01:58.8,4.21,38,4,7,6.9,134,349,-63,3,39,10,333,545,516,10,41.5826812,-71.0699259 +27,27.2,21.5,00:13.2,01:51.1,4.5,01:50.9,4.51,37,5,7.6,7.3,133,335,-65,5,37,9,326,540,525,1,41.582614,-71.0699443 +27,35.1,29.1,00:14.8,01:45.3,4.75,01:47.5,4.65,37.5,6,7.9,7.6,133,301,-66,3,38,11,285,503,486,6,41.5825448,-71.0699649 +27,43.8,37.4,00:16.5,01:43.3,4.84,01:46.2,4.71,36,7,8.7,8.3,134,298,-67,5,38,11,278,492,469,6,41.5824683,-71.0699881 +27,51.7,45,00:18.2,01:42.7,4.87,01:45.7,4.73,36,8,7.9,7.6,136,298,-67,4,38,11,277,494,467,-2,41.5823988,-71.0700091 +27,60.4,53.4,00:20.0,01:42.7,4.87,01:46.6,4.69,35,9,8.7,8.4,139,290,-69,4,38,10,275,507,467,5,41.5823225,-71.0700319 +27,67.6,61,00:21.6,01:43.1,4.85,01:47.5,4.65,32.5,10,7.2,7.6,140,256,-68,5,37,10,246,477,450,-4,41.5822597,-71.0700521 +27,77.8,69.8,00:23.6,01:41.4,4.93,01:50.4,4.53,34,11,10.1,8.8,143,273,-69,6,39,12,265,481,461,0,41.5821713,-71.0700813 +27,86.3,78,00:25.4,01:42.9,4.86,01:50.6,4.52,32.5,12,8.5,8.2,146,271,-70,5,38,11,270,491,468,-4,41.582097,-71.0701052 +27,94.8,86.1,00:27.2,01:45.7,4.73,01:51.1,4.5,32.5,13,8.5,8.1,149,270,-70,6,37,10,267,497,471,-7,41.5820232,-71.0701304 +27,103.1,94.2,00:29.0,01:47.5,4.65,01:51.4,4.49,34,14,8.3,8.1,151,269,-69,5,38,14,257,490,458,-10,41.5819506,-71.0701553 +27,110.9,102.1,00:30.7,01:48.0,4.63,01:50.9,4.51,32.5,15,7.7,8,153,272,-70,5,37,13,269,488,451,-5,41.5818835,-71.0701803 +27,120.1,110.4,00:32.6,01:44.8,4.77,01:52.4,4.45,32.5,16,9.3,8.2,156,253,-69,4,37,13,256,463,434,-14,41.5818033,-71.0702113 +27,128.6,118.4,00:34.4,01:45.3,4.75,01:52.4,4.45,32.5,17,8.4,8,158,240,-68,5,37,14,236,441,430,-13,41.5817309,-71.07024 +27,136.9,126.1,00:36.2,01:48.2,4.62,01:53.9,4.39,33,18,8.4,7.7,159,264,-69,4,37,13,255,477,475,-16,41.5816589,-71.0702688 +27,145.3,134,00:38.0,01:49.4,4.57,01:55.2,4.34,33.5,19,8.4,7.9,160,261,-70,5,38,15,260,467,439,-10,41.581587,-71.0702979 +27,153,141.9,00:39.7,01:48.7,4.6,01:54.4,4.37,32.5,20,7.7,7.9,161,248,-69,4,37,14,253,453,435,-8,41.5815211,-71.0703254 +27,162.1,150,00:41.6,01:46.2,4.71,01:54.2,4.38,32.5,21,9.1,8.1,161,---,---,---,---,---,---,---,---,---,41.5814435,-71.0703598 +28,5.7,5.7,00:01.6,03:57.0,2.11,02:22.0,3.52,36,1,5.7,5.7,136,382,-62,2,37,6,374,603,589,-4,41.5806848,-71.0707818 +28,---,---,---,---,---,---,---,---,1,---,---,---,352,-57,3,38,6,375,566,612,10,---,--- +28,12.7,12.4,00:03.2,02:09.2,3.87,02:02.0,4.1,37,2,7,6.7,135,334,-65,4,38,10,314,551,522,6,41.5806284,-71.0708197 +28,20.3,19.6,00:04.8,01:53.6,4.4,01:52.6,4.44,37,3,7.5,7.3,135,329,-66,4,37,10,299,526,510,6,41.5805682,-71.0708613 +28,28.1,27.2,00:06.4,01:46.6,4.69,01:46.8,4.68,37.5,4,7.8,7.6,135,350,-67,3,38,9,315,560,528,-5,41.5805058,-71.0709045 +28,36.1,34.9,00:08.0,01:43.5,4.83,01:45.5,4.74,37.5,5,8,7.7,136,367,-68,3,38,9,335,569,532,-12,41.5804427,-71.0709495 +28,44.1,42.6,00:09.6,01:41.2,4.94,01:42.9,4.86,37.5,6,8.1,7.7,137,326,-67,3,38,10,298,532,495,-4,41.580379,-71.0709959 +28,53,51.1,00:11.4,01:39.6,5.02,01:44.2,4.8,35.5,7,8.8,8.5,139,304,-68,4,38,10,275,516,485,5,41.5803096,-71.0710476 +28,60.3,59.1,00:13.1,01:40.6,4.97,01:45.0,4.76,34,8,7.3,7.9,140,298,-69,5,38,10,280,530,492,-4,41.5802523,-71.0710902 +28,69.8,67.2,00:14.8,01:39.2,5.04,01:46.8,4.68,34,9,9.6,8.1,143,270,-69,5,38,13,264,478,442,-4,41.5801781,-71.071148 +28,78.5,75.3,00:16.6,01:40.6,4.97,01:50.1,4.54,32.5,10,8.6,8.2,147,267,-70,5,38,12,262,486,437,8,41.5801111,-71.0712002 +28,87,83.4,00:18.4,01:44.2,4.8,01:50.4,4.53,32.5,11,8.5,8.1,150,262,-69,5,37,12,262,478,442,0,41.5800453,-71.0712531 +28,95.5,91.5,00:20.2,01:46.8,4.68,01:52.4,4.45,34,12,8.5,8,151,265,-69,4,37,11,258,482,458,-3,41.5799804,-71.0713071 +28,103.3,99.7,00:22.1,01:47.3,4.66,01:51.9,4.47,32.5,13,7.8,8.2,153,261,-69,5,36,11,257,474,441,2,41.579921,-71.0713566 +28,113.3,108.2,00:24.0,01:43.9,4.81,01:53.4,4.41,32.5,14,10,8.6,156,283,-70,4,36,10,290,493,449,-11,41.5798458,-71.0714215 +28,121.8,116.2,00:25.8,01:45.0,4.76,01:53.4,4.41,34,15,8.5,8,158,259,-69,5,37,14,278,463,453,-13,41.5797827,-71.0714791 +28,130.2,124.2,00:27.6,01:47.3,4.66,01:53.4,4.41,32.5,16,8.4,8,160,253,-70,5,38,13,254,485,445,-15,41.5797207,-71.0715368 +28,138.7,132,00:29.4,01:47.8,4.64,01:53.9,4.39,32.5,17,8.5,7.8,160,266,-70,4,36,12,260,478,446,-8,41.5796588,-71.0715963 +28,145.6,139.6,00:31.1,01:48.0,4.63,01:52.9,4.43,34,18,6.9,7.5,160,260,-69,3,38,15,254,465,434,-14,41.5796089,-71.0716459 +28,155.5,148,00:33.0,01:44.4,4.79,01:53.9,4.39,32.5,19,9.9,8.4,161,---,---,---,---,---,---,---,---,---,41.5795385,-71.0717176 +29,4.2,6.7,00:07.3,11:15.7,0.74,13:39.7,0.61,8,1,4.2,6.7,142,196,-49,2,42,9,401,578,695,6,41.5788242,-71.0721609 +29,6.5,9.5,00:08.1,07:00.2,1.19,13:39.7,0.61,75,2,2.4,2.8,142,---,---,---,---,---,---,---,---,---,41.5788029,-71.0721575 +29,8.3,10.9,00:08.7,03:16.9,2.54,02:56.7,2.83,95.5,3,1.8,1.4,141,328,-59,3,38,5,380,584,634,8,41.5787872,-71.0721548 +29,15,17.5,00:10.5,02:32.0,3.29,02:23.7,3.48,34.5,4,6.7,6.6,141,349,-65,3,37,8,355,576,578,9,41.5787282,-71.0721418 +29,22,25.3,00:12.3,02:13.3,3.75,02:02.2,4.09,37,5,7.1,7.7,138,348,-66,3,37,9,343,568,540,5,41.5786659,-71.0721262 +29,30.3,32.5,00:13.9,01:50.9,4.51,01:51.4,4.49,35.5,6,8.3,7.2,136,333,-67,4,37,8,313,570,555,-4,41.5785925,-71.0721079 +29,37.4,39.8,00:15.4,01:43.5,4.83,01:48.0,4.63,35.5,7,7.1,7.4,135,337,-68,5,37,8,316,542,524,5,41.5785303,-71.0720909 +29,46.1,47.5,00:17.1,01:41.2,4.94,01:46.2,4.71,35.5,8,8.7,7.7,134,305,-68,6,37,9,289,532,526,-4,41.5784535,-71.0720701 +29,54.9,56,00:18.9,01:40.6,4.97,01:46.4,4.7,35.5,9,8.8,8.5,135,292,-68,5,36,10,276,485,436,-17,41.578376,-71.0720504 +29,62.9,63.5,00:20.5,01:41.2,4.94,01:45.9,4.72,34,10,8,7.5,136,294,-68,5,39,10,278,515,484,-5,41.5783053,-71.0720339 +29,71.7,71.8,00:22.3,01:42.2,4.89,01:48.5,4.61,32.5,11,8.8,8.3,137,273,-69,6,39,11,270,499,458,6,41.5782273,-71.0720167 +29,80.4,80.9,00:24.3,01:44.2,4.8,01:50.6,4.52,32.5,12,8.7,9.1,140,251,-69,6,38,12,253,485,480,-6,41.5781501,-71.0720016 +29,89.6,88.7,00:26.1,01:43.1,4.85,01:52.9,4.43,32.5,13,9.2,7.8,143,270,-69,6,38,12,264,481,448,-15,41.5780678,-71.0719868 +29,98.1,96.7,00:27.9,01:44.6,4.78,01:52.1,4.46,32.5,14,8.5,8,145,262,-70,6,37,11,256,490,460,-9,41.577992,-71.0719741 +29,106.6,104.8,00:29.7,01:46.8,4.68,01:52.4,4.45,32.5,15,8.5,8.1,150,273,-69,5,39,13,267,488,445,-5,41.5779161,-71.0719623 +29,115.1,113,00:31.5,01:48.2,4.62,01:52.4,4.45,32.5,16,8.5,8.1,153,263,-69,4,39,13,264,484,455,-9,41.57784,-71.0719516 +29,122.9,121.1,00:33.3,01:48.5,4.61,01:51.6,4.48,32.5,17,7.8,8.2,156,263,-69,5,39,13,264,492,458,-10,41.5777707,-71.0719423 +29,132.7,129.7,00:35.3,01:45.9,4.72,01:52.4,4.45,32.5,18,9.8,8.5,160,281,-69,5,37,10,278,516,504,-16,41.5776829,-71.0719324 +29,141,137.6,00:37.1,01:47.1,4.67,01:53.9,4.39,32.5,19,8.3,7.9,163,268,-69,4,38,12,263,485,447,-17,41.5776086,-71.0719259 +29,149,145.5,00:38.9,01:49.6,4.56,01:53.6,4.4,32.5,20,8,7.9,165,266,-69,5,39,14,262,481,477,-12,41.5775366,-71.0719217 +30,3.6,4.7,00:07.1,21:55.8,0.38,14:22.1,0.58,8.5,1,3.6,4.7,145,169,-51,2,42,8,207,580,639,13,41.576721,-71.0719792 +30,---,---,---,---,---,---,---,---,1,---,---,---,1,-55,---,-51,---,12,1,25,-54,---,--- +30,6,7.8,00:08.1,08:51.9,0.94,14:22.1,0.58,50,2,2.4,3,143,---,---,---,---,---,---,---,---,---,41.5766994,-71.0719803 +30,7.5,9.5,00:08.6,03:40.3,2.27,02:57.9,2.81,109.5,3,1.5,1.7,143,344,-57,2,37,6,383,567,576,10,41.576686,-71.071981 +30,14.6,16.4,00:10.5,02:28.4,3.37,02:15.1,3.7,36.5,4,7.1,6.9,139,367,-63,1,38,8,359,576,566,8,41.5766219,-71.0719842 +30,21.8,23.4,00:12.1,02:07.6,3.92,01:57.6,4.25,37,5,7.2,7.1,135,347,-66,3,39,8,321,569,528,10,41.5765569,-71.0719865 +30,29.6,30.9,00:13.7,01:51.1,4.5,01:48.5,4.61,37,6,7.8,7.4,133,316,-67,5,37,8,286,521,502,9,41.5764872,-71.0719885 +30,37.6,38.4,00:15.3,01:44.8,4.77,01:46.8,4.68,35.5,7,8,7.6,131,318,-69,7,38,9,291,529,486,8,41.5764155,-71.07199 +30,46.4,46.9,00:17.1,01:42.0,4.9,01:45.0,4.76,35.5,8,8.8,8.5,132,296,-68,4,38,10,275,491,461,2,41.5763367,-71.071993 +30,54.3,54.6,00:18.7,01:41.4,4.93,01:45.9,4.72,36,9,8,7.7,133,313,-68,6,39,9,282,523,487,2,41.576265,-71.0719962 +30,62.6,63.4,00:20.5,01:41.4,4.93,01:43.5,4.83,33.5,10,8.3,8.8,135,285,-69,4,39,11,273,519,469,8,41.5761909,-71.0719996 +30,72.2,71.8,00:22.3,01:38.8,5.06,01:46.4,4.7,32.5,11,9.6,8.4,137,285,-70,5,40,12,284,524,469,-7,41.5761045,-71.0720058 +30,81.8,80.8,00:24.3,01:40.4,4.98,01:48.0,4.63,31.5,12,9.6,9.1,140,272,-69,4,38,11,276,509,466,-4,41.5760188,-71.0720139 +30,90.6,89.1,00:26.1,01:43.5,4.83,01:48.9,4.59,32.5,13,8.8,8.2,143,261,-70,5,40,14,262,488,458,-3,41.5759403,-71.0720234 +30,99.2,97.3,00:27.9,01:45.3,4.75,01:50.4,4.53,32.5,14,8.6,8.2,146,268,-70,5,38,11,270,499,450,-3,41.5758634,-71.0720336 +30,107,105.3,00:29.7,01:45.7,4.73,01:49.9,4.55,32.5,15,7.8,8,148,280,-69,4,38,11,272,505,436,7,41.5757937,-71.0720435 +30,116.4,113.8,00:31.5,01:43.3,4.84,01:48.9,4.59,32.5,16,9.4,8.5,151,276,-70,4,40,12,270,503,464,-8,41.5757097,-71.0720566 +30,125.1,122,00:33.3,01:43.5,4.83,01:48.9,4.59,32.5,17,8.7,8.2,156,276,-70,5,37,10,278,505,476,-15,41.5756324,-71.0720697 +30,133.7,130.3,00:35.1,01:44.8,4.77,01:49.9,4.55,34,18,8.6,8.3,159,265,-69,4,37,12,260,480,440,-5,41.5755556,-71.0720833 +30,142.4,138.5,00:36.9,01:44.8,4.77,01:49.2,4.58,32.5,19,8.7,8.2,159,279,-70,3,38,14,270,500,461,-14,41.5754782,-71.0720978 +30,151,146.8,00:38.8,01:44.8,4.77,01:51.4,4.49,32.5,20,8.6,8.3,160,267,-70,4,37,12,267,489,446,-12,41.5754016,-71.0721136 \ No newline at end of file diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 0048006e..1541b4c4 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -40,7 +40,8 @@ def get_video_id(url): if url.startswith(('youtu', 'www')): url = 'http://' + url - elif 'http' not in url: + elif 'http' not in url: # pragma: no cover + # not sure if this is a valid case at all return url query = urlparse(url) @@ -88,7 +89,7 @@ def workout_video_view_mini(request,id=''): video_id = form.cleaned_data['url'] try: video_id = get_video_id(form.cleaned_data['url']) - except (TypeError,ValueError): + except (TypeError,ValueError): # pragma: no cover pass delay = form.cleaned_data['delay'] metricsgroups = metricsform.cleaned_data['groups'] @@ -98,7 +99,8 @@ def workout_video_view_mini(request,id=''): analysis.delay = delay analysis.metricsgroups = metricsgroups analysis.save() - else: + else: # pragma: no cover + # invalid forms video_id = id delay = 0 elif mayedit: @@ -121,7 +123,7 @@ def workout_video_view_mini(request,id=''): data, metrics, maxtime = dataprep.get_video_data(w,groups=metricsgroups,mode=mode) hascoordinates = pd.Series(data['latitude']).std() > 0 # create map - if hascoordinates: + if hascoordinates and mode=='water': mapscript, mapdiv = leaflet_chart_video(data['latitude'],data['longitude'], w.name) else: @@ -209,7 +211,7 @@ def workout_video_view(request,id=''): analysis.delay = delay analysis.metricsgroups = metricsgroups analysis.save() - else: + else: # pragma: no cover video_id = id delay = 0 elif mayedit: @@ -232,7 +234,7 @@ def workout_video_view(request,id=''): data, metrics, maxtime = dataprep.get_video_data(w,groups=metricsgroups,mode=mode) hascoordinates = pd.Series(data['latitude']).std() > 0 # create map - if hascoordinates: + if hascoordinates and mode=='water': mapscript, mapdiv = leaflet_chart_video(data['latitude'],data['longitude'], w.name) else: @@ -324,7 +326,7 @@ def workout_video_create_view(request,id=0): url = reverse('workout_video_create_view', kwargs={'id':encoder.encode_hex(w.id)}) return HttpResponseRedirect(url) - else: + else: # pragma: no cover video_id = None delay = 0 metricsgroups = ['basic'] @@ -340,7 +342,7 @@ def workout_video_create_view(request,id=0): hascoordinates = pd.Series(data['latitude']).std() > 0 # create map - if hascoordinates: + if hascoordinates and mode=='water': mapscript, mapdiv = leaflet_chart_video(data['latitude'],data['longitude'], w.name) else: @@ -412,7 +414,7 @@ def workout_forcecurve_view(request,id=0,workstrokesonly=False): includereststrokes = form.cleaned_data['includereststrokes'] plottype = form.cleaned_data['plottype'] workstrokesonly = not includereststrokes - else: + else: # pragma: no cover workstrokesonly = True plottype = 'line' else: @@ -599,30 +601,13 @@ def addmanual_view(request,raceid=0): avgpwr = metricsform.cleaned_data['avgpwr'] avgspm = metricsform.cleaned_data['avgspm'] - try: - ps = form.cleaned_data['plannedsession'] - except KeyError: # pragma: no cover - ps = None + ps = form.cleaned_data.get('plannedsession',None) + boattype = form.cleaned_data.get('boattype','1x') + privacy = form.cleaned_data.get('privacy','visible') + rankingpiece = form.cleaned_data.get('rankingpiece',False) + duplicate = form.cleaned_data.get('duplicate',False) - try: - boattype = request.POST['boattype'] - except KeyError: # pragma: no cover - boattype = '1x' - try: - privacy = request.POST['privacy'] - except KeyError: # pragma: no cover - privacy = 'visible' - try: - rankingpiece = form.cleaned_data['rankingpiece'] - except KeyError: # pragma: no cover - rankingpiece = False - - try: - duplicate = form.cleaned_data['duplicate'] - except KeyError: # pragma: no cover - duplicate = False - - if private: + if private: # pragma: no cover privacy = 'private' else: privacy = 'visible' From bfd7a5b6649baff2373d8000bf2766e5d5a5cc9e Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 12 Apr 2021 19:10:15 +0200 Subject: [PATCH 03/17] rdata fixes --- rowers/tests/statements.py | 2 +- rowers/tests/test_races.py | 150 ++++++++++++++++++++++++++++++++++- rowers/views/apiviews.py | 4 +- rowers/views/exportviews.py | 6 +- rowers/views/importviews.py | 2 +- rowers/views/racesviews.py | 4 +- rowers/views/statements.py | 8 +- rowers/views/workoutviews.py | 68 ++++++++-------- 8 files changed, 199 insertions(+), 45 deletions(-) diff --git a/rowers/tests/statements.py b/rowers/tests/statements.py index 1170cae6..fabc164f 100644 --- a/rowers/tests/statements.py +++ b/rowers/tests/statements.py @@ -105,7 +105,7 @@ def get_random_file(filename='rowers/tests/testdata/testdata.csv',name=''): except AttributeError: fromstring = 'none_' - row = rdata(filename) + row = rdata(csvfile=filename) totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[row.df.index[0],' ElapsedTime (sec)'] diff --git a/rowers/tests/test_races.py b/rowers/tests/test_races.py index fe78d0d9..876c9d3d 100644 --- a/rowers/tests/test_races.py +++ b/rowers/tests/test_races.py @@ -3,6 +3,8 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals +from django.test import RequestFactory + #from __future__ import print_function from .statements import * nu = datetime.datetime.now() @@ -14,8 +16,39 @@ import rowers.courses as courses import rowers.tasks as tasks from rowers.views.racesviews import * from rowers.utils import calculate_age +from rowers.views import addmanual_view -# to do - add test for manual form with image +from django.contrib.messages.storage.fallback import FallbackStorage + +from base64 import b64encode +import base64 + + +from django.core.files.base import File +from io import BytesIO + +from PIL import Image +from io import StringIO + +from django.core.files.uploadedfile import InMemoryUploadedFile +from django.core.files.uploadedfile import SimpleUploadedFile + +def create_image(storage, filename, size=(100, 100), image_mode='RGB', image_format='PNG'): + """ + Generate a test image, returning the filename that it was saved as. + + If ``storage`` is ``None``, the BytesIO containing the image data + will be passed instead. + """ + data = BytesIO() + Image.new(image_mode, size).save(data, image_format) + data.seek(0) + if not storage: + return data + image_file = ContentFile( + b64encode(data.read()) + ) + return storage.save(filename, image_file) @override_settings(TESTING=True) class ChallengesTest(TestCase): @@ -608,6 +641,14 @@ class ChallengesTest(TestCase): @override_settings(TESTING=True) class IndoorChallengesTest(TestCase): + @staticmethod + def get_image_file(name, ext='png', size=(50, 50), color=(256, 0, 0)): + file_obj = BytesIO() + image = Image.new("RGBA", size=size, color=color) + image.save(file_obj, ext) + file_obj.seek(0) + return File(file_obj, name=name) + def setUp(self): self.u = UserFactory() @@ -671,7 +712,7 @@ class IndoorChallengesTest(TestCase): contact_email=contact_email, country = 'Netherlands', manager=self.u, - sessionvalue=result['totaldist'], + sessionvalue=int(result['totaldist']), sessionunit='m', sessionmode='distance', ) @@ -740,6 +781,111 @@ class IndoorChallengesTest(TestCase): response = self.c.post(url) self.assertEqual(response.status_code,200) + @patch('rowers.dataprep.create_engine') + def test_upload_manual(self, mocked_sqlalchemy): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + + race = self.IndoorSpeedOrder + + # look at event + url = reverse('virtualevent_view',kwargs={'id':race.id}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + if self.r.birthdate: + age = calculate_age(self.r.birthdate) + else: + age = 25 + + # register + url = reverse('indoorvirtualevent_register_view',kwargs={'id':race.id}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + + form_data = { + 'teamname': 'ApeTeam', + 'boatclass': 'rower', + 'weightcategory': 'hwt', + 'adaptiveclass': 'None', + 'age': age, + 'mix': False, + 'acceptsocialmedia': True, + } + form = IndoorVirtualRaceResultForm(form_data) + + self.assertTrue(form.is_valid()) + + + response = self.c.post(url,form_data,follow=True) + expected_url = reverse('virtualevent_view',kwargs={'id':race.id}) + self.assertRedirects(response, expected_url=expected_url, + status_code=302,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + # submit result (manual) + + image = self.get_image_file('image.jpg') + + form_data = { + 'name': faker.word(), + 'date': nu.date().strftime("%Y-%m-%d"), + 'starttime': '10:01:43', + 'timezone': 'UTC', + 'duration': '00:02:00.0', + 'distance': race.sessionvalue, + 'workouttype': 'rower', + 'boattype': '1x', + 'weightcategory': 'hwt', + 'adaptiveclass': 'None', + 'notes': faker.text(), + 'rankingpiece': True, + 'duplicate': False, + 'avghr': '160', + 'avgpwr': 0, + 'rpe':4, + 'avgspm': 40, + } + + form = MetricsForm(form_data) + self.assertTrue(form.is_valid()) + + form = WorkoutForm(form_data) + self.assertTrue(form.is_valid()) + + file_data = {'file':image} + + form = ImageForm(form_data,file_data) + + self.assertTrue(form.is_valid()) + + url = '/rowers/workout/addmanual/'+str(race.id)+'/' + response = self.c.get(url) + + self.assertEqual(response.status_code,200) + + + #form_data['file'] = image + request = self.factory.post(url, + data=form_data, + files={'file':image}, + ) + setattr(request, 'session', 'session') + messages = FallbackStorage(request) + setattr(request, '_messages', messages) + + request.user = self.u + + response = addmanual_view(request,raceid=str(race.id)) + + expected = reverse('virtualevent_view',kwargs={'id':race.id}) + + self.assertEqual(response.status_code,302) + self.assertEqual(response.url,expected) + + @patch('rowers.views.racesviews.myqueue') def test_virtualevent_view(self,mocked_myqueue): login = self.c.login(username=self.u.username, password=self.password) diff --git a/rowers/views/apiviews.py b/rowers/views/apiviews.py index 4f532bc3..caf3457d 100644 --- a/rowers/views/apiviews.py +++ b/rowers/views/apiviews.py @@ -323,7 +323,7 @@ def strokedatajson_v2(request,id): hrut1=r.ut1,hrat=r.at, hrtr=r.tr,hran=r.an,ftp=ftp, powerperc=powerperc,powerzones=r.powerzones) - rowdata = rdata(row.csvfilename,rower=rr).df + rowdata = rdata(csvfile=row.csvfilename,rower=rr).df datadf = dataprep.dataprep(rowdata,id=row.id,bands=True,barchart=True,otwpower=True,empower=True) @@ -494,7 +494,7 @@ def strokedatajson(request,id): hrut1=r.ut1,hrat=r.at, hrtr=r.tr,hran=r.an,ftp=ftp, powerperc=powerperc,powerzones=r.powerzones) - rowdata = rdata(row.csvfilename,rower=rr).df + rowdata = rdata(csvfile=row.csvfilename,rower=rr).df datadf = dataprep.dataprep(rowdata,id=row.id,bands=True,barchart=True,otwpower=True,empower=True) # mangling diff --git a/rowers/views/exportviews.py b/rowers/views/exportviews.py index 1fa75bc4..e38e36cc 100644 --- a/rowers/views/exportviews.py +++ b/rowers/views/exportviews.py @@ -9,7 +9,7 @@ def workout_tcxemail_view(request,id=0): - row = rdata(w.csvfilename) + row = rdata(csvfile=w.csvfilename) code = str(uuid4()) tcxfilename = code+'.tcx' @@ -171,7 +171,7 @@ def workout_gpxemail_view(request,id=0): - row = rdata(w.csvfilename) + row = rdata(csvfile=w.csvfilename) code = str(uuid4()) gpxfilename = code+'.gpx' @@ -235,7 +235,7 @@ def workout_csvemail_view(request,id=0): w = get_workout(id) - rowdata = rdata(w.csvfilename) + rowdata = rdata(csvfile=w.csvfilename) code = str(uuid4()) filename = code+'.csv' diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index e644e53a..5fc3c2b9 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -2121,7 +2121,7 @@ def workout_getimportview(request,externalid,source = 'c2'): units = getlist(sa,sel='unit') types = getlist(sa,sel='type') - rowdata = rdata(w.csvfilename) + rowdata = rdata(csvfile=w.csvfilename) if rowdata: rowdata.updateintervaldata(values, units,types,results) diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 9118ffd7..bf6dcf3a 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -1022,7 +1022,7 @@ def virtualevent_disqualify_view(request,id=0,recordid=0): script, div = interactive_chart(record.workoutid) f1 = workout.csvfilename - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) hascoordinates = 1 if rowdata != 0: try: @@ -1166,7 +1166,7 @@ def virtualevent_withdrawresult_view(request,id=0,recordid=0): script, div = interactive_chart(record.workoutid) f1 = workout.csvfilename - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) hascoordinates = 1 if rowdata != 0: try: diff --git a/rowers/views/statements.py b/rowers/views/statements.py index b323beb1..ba806041 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -1110,7 +1110,7 @@ def rowhascoordinates(row): f1 = row.csvfilename u = row.user.user r = getrower(u) - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) hascoordinates = 1 if rowdata != 0: try: @@ -1129,9 +1129,11 @@ def rowhascoordinates(row): # Wrapper around the rowingdata call to catch some exceptions # Checks for CSV file, then for gzipped CSV file, and if all fails, returns 0 -def rdata(file,rower=rrower()): +def rdata(csvfile=None,rower=rrower()): + if csvfile is None: + return 0 try: - res = rrdata(csvfile=file,rower=rower) + res = rrdata(csvfile=csvfile,rower=rower) except pd.errors.EmptyDataError: res = 0 except (IOError, IndexError, EOFError,FileNotFoundError): diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 1541b4c4..69311627 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -468,7 +468,7 @@ def otw_use_impeller(request,id=0): w = get_workoutuser(id, request) - row = rdata(w.csvfilename) + row = rdata(csvfile=w.csvfilename) success = row.use_impellerdata() if success: row.write_csv(w.csvfilename) @@ -490,7 +490,7 @@ def otw_use_gps(request,id=0): w = get_workoutuser(id, request) - row = rdata(w.csvfilename) + row = rdata(csvfile=w.csvfilename) success = row.use_gpsdata() if success: row.write_csv(w.csvfilename) @@ -572,10 +572,12 @@ def addmanual_view(request,raceid=0): }, ] + if request.method == 'POST': # Form was submitted form = WorkoutForm(request.POST) metricsform = MetricsForm(request.POST) + if form.is_valid() and metricsform.is_valid(): # Get values from form name = form.cleaned_data['name'] @@ -601,7 +603,7 @@ def addmanual_view(request,raceid=0): avgpwr = metricsform.cleaned_data['avgpwr'] avgspm = metricsform.cleaned_data['avgspm'] - ps = form.cleaned_data.get('plannedsession',None) + #ps = form.cleaned_data.get('plannedsession',None) boattype = form.cleaned_data.get('boattype','1x') privacy = form.cleaned_data.get('privacy','visible') rankingpiece = form.cleaned_data.get('rankingpiece',False) @@ -620,8 +622,6 @@ def addmanual_view(request,raceid=0): pytz.timezone(thetimezone) ) - - id,message = dataprep.create_row_df(r, distance, duration,startdatetime, @@ -642,6 +642,7 @@ def addmanual_view(request,raceid=0): if message: # pragma: no cover messages.error(request,message) + if id: w = Workout.objects.get(id=id) w.rankingpiece = rankingpiece @@ -649,19 +650,23 @@ def addmanual_view(request,raceid=0): w.weightcategory = weightcategory w.adaptiveclass = adaptiveclass w.notes = notes - w.plannedsession = ps + #w.plannedsession = ps w.name = name w.rpe = rpe w.workouttype = workouttype w.boattype = boattype + w.distance = distance + w.duration = duration w.save() - if ps: - add_workouts_plannedsession([w],ps,w.user) + #if ps: + # add_workouts_plannedsession([w],ps,w.user) messages.info(request,'New workout created') + iform = ImageForm(request.POST,request.FILES) - if iform.is_valid(): + + if iform.is_valid(): # this works but cannot get the tests to work f = iform.cleaned_data['file'] if f is not None: @@ -682,7 +687,7 @@ def addmanual_view(request,raceid=0): if raceid != 0: try: race = VirtualRace.objects.get(id=raceid) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover messages.error(request,"Race does not exist") url = reverse('workout_edit_view', kwargs = {'id':encoder.encode_hex(id)}) @@ -690,11 +695,11 @@ def addmanual_view(request,raceid=0): can_submit = race_can_submit(r,race) or race_can_resubmit(r,race) can_submit = can_submit and race.sessiontype == 'indoorrace' - if not can_submit: + if not can_submit: # pragma: no cover messages.error(request,'You cannot submit a result for this race') if can_submit: records = IndoorVirtualRaceResult.objects.filter(race=race,userid=r.id) - if not records: + if not records: # pragma: no cover messages.error(request,'You have to register for the race first') url = reverse('virtualevent_view',kwargs = {'id':race.id}) return HttpResponseRedirect(url) @@ -704,12 +709,13 @@ def addmanual_view(request,raceid=0): result, comments, errors, jobid = add_workout_indoorrace( [w],race,r,recordid=recordid ) - for c in comments: + for c in comments: # pragma: no cover messages.info(request,c) - for er in errors: + for er in errors: # pragma: no cover messages.error(request,er) if result: + print('mies') otherrecords = IndoorVirtualRaceResult.objects.filter( race = race ).exclude(userid=r.id) @@ -800,7 +806,7 @@ def workout_recalcsummary_view(request,id=0): row = get_workoutuser(id, request) filename = row.csvfilename - rowdata = rdata(filename) + rowdata = rdata(csvfile=filename) if rowdata: row.summary = rowdata.allstats() row.save() @@ -1277,7 +1283,7 @@ def remove_power_view(request,id=0): hrtr=r.tr, hran=r.an, ftp=r.ftp, powerperc=powerperc, powerzones=r.powerzones, hrzones=r.hrzones) - row = rdata(f,rower=rr) + row = rdata(csvfile=f,rower=rr) row.df[' Power (watts)'] = 0 row.write_csv(f) res = dataprep.dataprep(row.df, id=workout.id) @@ -2319,7 +2325,7 @@ def workout_view(request,id=0,raceresult=0,sessionresult=0,nocourseraceresult=0) # get row row = get_workout_by_opaqueid(request,id) f1 = row.csvfilename - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) summary = row.summary comments = WorkoutComment.objects.filter(workout=row) @@ -2479,7 +2485,7 @@ def workout_undo_smoothenpace_view( r = getrower(request.user) filename = row.csvfilename - row = rdata(filename) + row = rdata(csvfile=filename) if row == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") @@ -2514,7 +2520,7 @@ def workout_smoothenpace_view(request,id=0,message="",successmessage=""): filename = row.csvfilename - row = rdata(filename) + row = rdata(csvfile=filename) if row == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") @@ -2575,7 +2581,7 @@ def workout_downloadwind_view(request,id=0, f1 = row.csvfilename # create bearing - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) if rowdata == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") @@ -2644,7 +2650,7 @@ def workout_downloadmetar_view(request,id=0, # create bearing - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) if rowdata == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") @@ -2732,7 +2738,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""): r = getrower(u) # create bearing - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) if row == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") @@ -2848,7 +2854,7 @@ def workout_stream_view(request,id=0,message="",successmessage=""): u = row.user.user r = getrower(u) - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) if rowdata == 0: # pragma: no cover messages.info(request,"Error: CSV data file not found") url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(row.id)}) @@ -2948,7 +2954,7 @@ def workout_otwsetpower_view(request,id=0,message="",successmessage=""): # load row data & create power/wind/bearing columns if not set f1 = w.csvfilename - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) if rowdata == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") try: @@ -3716,7 +3722,7 @@ def workout_workflow_view(request,id): if 'panel_map.html' in r.workflowmiddlepanel and rowhascoordinates(row): - rowdata = rdata(row.csvfilename) + rowdata = rdata(csvfile=row.csvfilename) mapscript,mapdiv = leaflet_chart2(rowdata.df[' latitude'], rowdata.df[' longitude'], row.name) @@ -3970,7 +3976,7 @@ def workout_flexchart3_view(request,*args,**kwargs): from rowers.metrics import nometrics - rowdata = rdata(row.csvfilename) + rowdata = rdata(csvfile=row.csvfilename) try: rowdata.set_instroke_metrics() except (AttributeError,TypeError): # pragma: no cover @@ -4495,7 +4501,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): # change data in csv file datachanged = (dragchanged or timechanged) if datachanged: - r = rdata(row.csvfilename) + r = rdata(csvfile=row.csvfilename) if dragchanged: try: r.change_drag(newdragfactor) @@ -4534,7 +4540,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): u = row.user.user r = getrower(u) - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) hascoordinates = 1 if rowdata != 0: @@ -4634,7 +4640,7 @@ def workout_map_view(request,id=0): f1 = w.csvfilename u = w.user.user r = getrower(u) - rowdata = rdata(f1) + rowdata = rdata(csvfile=f1) hascoordinates = 1 if rowdata != 0: try: @@ -5993,7 +5999,7 @@ def workout_summary_restore_view(request,id,message="",successmessage=""): hrtr=r.tr,hran=r.an,ftp=ftp, powerperc=powerperc,powerzones=r.powerzones, hrzones=r.hrzones) - rowdata = rdata(f1,rower=rr) + rowdata = rdata(csvfile=f1,rower=rr) if rowdata == 0: # pragma: no cover raise Http404("Error: CSV Data File Not Found") rowdata.restoreintervaldata() @@ -6251,7 +6257,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" hrtr=r.tr,hran=r.an,ftp=ftp, powerperc=powerperc,powerzones=r.powerzones, hrzones=r.hrzones) - rowdata = rdata(f1,rower=rr) + rowdata = rdata(csvfile=f1,rower=rr) if rowdata == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") intervalstats = rowdata.allstats() From 60c657f639ed7e56bdadb68a281a7c1426684fb5 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 12 Apr 2021 22:03:40 +0200 Subject: [PATCH 04/17] coverage changes --- rowers/templates/workflowconfig2.html | 6 +- rowers/tests/test_team.py | 89 +++++++++++++++++ rowers/urls.py | 4 +- rowers/views/workoutviews.py | 137 ++++++-------------------- 4 files changed, 125 insertions(+), 111 deletions(-) diff --git a/rowers/templates/workflowconfig2.html b/rowers/templates/workflowconfig2.html index 9dff8e1a..3924505a 100644 --- a/rowers/templates/workflowconfig2.html +++ b/rowers/templates/workflowconfig2.html @@ -29,16 +29,16 @@ {{ middlepanel_formset.as_table }} {% csrf_token %} - +
  • {% if rower.defaultlandingpage == 'workout_edit_view' %}

    Default landing page is Edit View. Set default landing page to

    - Workflow View + Workflow View {% else %}

    Default landing page is Workflow View. Set default landing page to

    - Edit View + Edit View {% endif %}
  • diff --git a/rowers/tests/test_team.py b/rowers/tests/test_team.py index 05d16b5a..16a7d96c 100644 --- a/rowers/tests/test_team.py +++ b/rowers/tests/test_team.py @@ -63,6 +63,7 @@ class TeamTest(TestCase): self.c = Client() self.u = self.users[0] + self.r = self.users[0].rower self.password = self.user_passwords[0] self.t = TeamFactory(manager=self.u) @@ -83,6 +84,29 @@ class TeamTest(TestCase): ) self.rekwest.save() + result = get_random_file(filename='rowers/tests/testdata/erg1.csv') + + self.werg1 = WorkoutFactory(user=self.r, + csvfilename=result['filename'], + starttime=result['starttime'], + startdatetime=result['startdatetime'], + duration=result['duration'], + distance=result['totaldist'], + workouttype = 'rower', + ) + + result = get_random_file(filename='rowers/tests/testdata/erg2.csv') + + self.werg2 = WorkoutFactory(user=self.r, + csvfilename=result['filename'], + starttime=result['starttime'], + startdatetime=result['startdatetime'], + duration=result['duration'], + distance=result['totaldist'], + workouttype = 'rower', + ) + + def tearDown(self): for csvfilename in self.csvfilenames: try: @@ -126,6 +150,71 @@ class TeamTest(TestCase): response = self.c.get(url) self.assertEqual(response.status_code, 200) + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db') + @patch('rowers.middleware.myqueue') + def test_compares(self, mocked_sqlalchemy, mocked_getsmallrowdata_db, + mocked_myqueue): + login = self.c.login(username=self.u.username, password=self.password) + self.assertTrue(login) + + + session = self.c.session + session['ids'] = [self.werg1.id,self.werg2.id] + session.save() + + response = self.c.get('/') + + url = reverse('team_comparison_select',kwargs={'teamid':self.t.id}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + d1 = self.werg1.date-timedelta(days=2) + d2 = self.werg2.date+timedelta(days=2) + + form_data = { + 'startdate': d1.strftime('%Y-%m-%d'), + 'enddate': d2.strftime('%Y-%m-%d'), + 'modality':'water', + 'waterboattype':['1x'], + } + + form = DateRangeForm(form_data) + self.assertTrue(form.is_valid()) + + form = TrendFlexModalForm(form_data) + self.assertTrue(form.is_valid()) + + response = self.c.post(url,form_data) + self.assertEqual(response.status_code,200) + + url = reverse('multi_compare_view',kwargs={ + 'userid':self.u.id, + 'id':encoder.encode_hex(self.werg1.id), + }) + + form_data = { + 'xparam':'time', + 'yparam':'power', + 'plottype':'line', + 'teamid': '', + } + + + response = self.c.post(url,form_data,follow=True) + self.assertEqual(response.status_code,200) + + session['plottype'] = 'scatter' + session['xparam'] = 'time' + session['yparam'] = 'hr' + + session.save() + + response = self.c.get('/') + + response = self.c.get(url,follow=True) + self.assertEqual(response.status_code,200) + def test_teamsview(self): url = '/rowers/me/teams/' diff --git a/rowers/urls.py b/rowers/urls.py index e36d55e0..b796cb97 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -344,7 +344,7 @@ urlpatterns = [ # name='workouts_join_select'), re_path(r'^workouts-join/$',views.workouts_join_view,name='workouts_join_view'), re_path(r'^workouts-join/user/(?P\d+)$',views.workouts_join_view,name='workouts_join_view'), - re_path(r'^workouts-join-select/team/(?P\d+)/$',views.workouts_join_select,name='workouts_join_select'), + #re_path(r'^workouts-join-select/team/(?P\d+)/$',views.workouts_join_select,name='workouts_join_select'), # re_path(r'^workouts-join-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_join_select,name='workouts_join_select'), re_path(r'^workouts-join-select/$',views.workouts_join_select,name='workouts_join_select'), re_path(r'^workouts-join-select/user/(?P\d+)/$',views.workouts_join_select,name='workouts_join_select'), @@ -454,7 +454,7 @@ urlpatterns = [ name='workout_edit_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/map/$',views.workout_map_view,name='workout_map_view'), # re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/setprivate/$',views.workout_setprivate_view), - re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/updatecp/$',views.workout_update_cp_view,name='workout_update_cp_view'), +# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/updatecp/$',views.workout_update_cp_view,name='workout_update_cp_view'), # re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/makepublic/$',views.workout_makepublic_view), # re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/geeky/$',views.workout_geeky_view), # re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/advanced/$',views.workout_advanced_view), diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 69311627..9d908aaa 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -744,7 +744,7 @@ def addmanual_view(request,raceid=0): kwargs={'id':encoder.encode_hex(id)} ) return HttpResponseRedirect(url) - else: + else: # pragma: no cover iform = ImageForm() return render(request,'manualadd.html', {'form':form, @@ -777,27 +777,6 @@ def addmanual_view(request,raceid=0): -@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -@user_passes_test(ispromember,login_url="/rowers/paidplans", - message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality", - redirect_field_name=None) -def workout_update_cp_view(request,id=0): - row = get_workoutuser(id, request) - - row.rankingpiece = True - row.save() - - r = getrower(request.user) - - dataprep.runcpupdate(r) - - if row.workouttype in mytypes.otwtypes: - url = reverse('otwrankings_view') - else: - url = reverse('oterankings_view') - - return HttpResponseRedirect(url) # Reload the workout and calculate the summary from the stroke data (lapIDx) @@ -872,12 +851,11 @@ def workouts_join_view(request,userid=0): return HttpResponseRedirect(url) - else: - return HttpResponse("form is not valid") + else: # pragma: no cover + messages.error("Form is not valid") - else: - url = reverse('workouts_join_select') - return HttpResponseRedirect(url) + url = reverse('workouts_join_select') + return HttpResponseRedirect(url) defaultoptions = { 'includereststrokes': False, @@ -891,17 +869,12 @@ defaultoptions = { message="This functionality requires a Pro plan or higher", redirect_field_name=None) @permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def video_selectworkout(request,userid=0,teamid=0): +def video_selectworkout(request,userid=0): r = getrequestrower(request, userid=userid) user = r.user userid = user.id workouts = Workout.objects.filter(user=r).order_by('-date') - try: - theteam = Team.objects.get(id=teamid) - except Team.DoesNotExist: - theteam = None - if 'options' in request.session: options = request.session['options'] @@ -914,7 +887,7 @@ def video_selectworkout(request,userid=0,teamid=0): except KeyError: # pragma: no cover workouttypes = ['rower','dynamic','slides'] - try: + try: # pragma: no cover modalities = options['modalities'] modality = modalities[0] except KeyError: # pragma: no cover @@ -975,7 +948,7 @@ def video_selectworkout(request,userid=0,teamid=0): url = reverse('workout_video_create_view', kwargs={'id':encoder.encode_hex(selectedworkout.id)}) return HttpResponseRedirect(url) - else: + else: # pragma: no cover id = 0 else: form = WorkoutSingleSelectForm(workouts=workouts) @@ -989,7 +962,7 @@ def video_selectworkout(request,userid=0,teamid=0): negtypes = [] for b in mytypes.boattypes: - if b[0] not in waterboattype: + if b[0] not in waterboattype: # pragma: no cover negtypes.append(b[0]) @@ -1003,29 +976,16 @@ def video_selectworkout(request,userid=0,teamid=0): negtypes = [] for b in mytypes.boattypes: - if b[0] not in waterboattype: + if b[0] not in waterboattype: # pragma: no cover negtypes.append(b[0]) - if theteam is not None and (theteam.viewing == 'allmembers' or theteam.manager == request.user): - workouts = Workout.objects.filter(team=theteam, - startdatetime__gte=startdate, - startdatetime__lte=enddate, - workouttype__in=modalities, - ) - elif theteam is not None and theteam.viewing == 'coachonly': - workouts = Workout.objects.filter(team=theteam,user=r, - startdatetime__gte=startdate, - startdatetime__lte=enddate, - workouttype__in=modalities, - ) - else: - workouts = Workout.objects.filter(user=r, - startdatetime__gte=startdate, - startdatetime__lte=enddate, - workouttype__in=modalities, - ) + workouts = Workout.objects.filter(user=r, + startdatetime__gte=startdate, + startdatetime__lte=enddate, + workouttype__in=modalities, + ) workouts = workouts.order_by( "-date", "-starttime" @@ -1035,17 +995,6 @@ def video_selectworkout(request,userid=0,teamid=0): if rankingonly: workouts = workouts.exclude(rankingpiece=False) - - - - optionsform = AnalysisOptionsForm(initial={ - 'modality':modality, - 'waterboattype':waterboattype, - 'rankingonly':rankingonly, - }) - - - startdatestring = startdate.strftime('%Y-%m-%d') enddatestring = enddate.strftime('%Y-%m-%d') request.session['startdate'] = startdatestring @@ -1091,7 +1040,7 @@ def workouts_join_select(request, userid=0, startdate=timezone.now()-datetime.timedelta(days=30), enddate=timezone.now()+datetime.timedelta(days=1), - teamid=0): + ): @@ -1105,7 +1054,7 @@ def workouts_join_select(request, if 'modalities' in request.session: modalities = request.session['modalities'] - if len(modalities) > 1: + if len(modalities) > 1: # pragma: no cover modality = 'all' else: modality = modalities[0] @@ -1126,12 +1075,12 @@ def workouts_join_select(request, if modalityform.is_valid(): modality = modalityform.cleaned_data['modality'] waterboattype = modalityform.cleaned_data['waterboattype'] - if modality == 'all': + if modality == 'all': # pragma: no cover modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] - if modality != 'water': + if modality != 'water': # pragma: no cover waterboattype = [b[0] for b in mytypes.boattypes] @@ -1164,32 +1113,14 @@ def workouts_join_select(request, enddate = startdate startdate = s - try: - theteam = Team.objects.get(id=teamid) - except Team.DoesNotExist: - theteam = 0 - if theteam and (theteam.viewing == 'allmembers' or theteam.manager == request.user): - workouts = Workout.objects.filter(team=theteam, - startdatetime__gte=startdate, - startdatetime__lte=enddate, - workouttype__in=modalities).order_by("-date", "-starttime").exclude(boattype__in=negtypes) - elif theteam and theteam.viewing == 'coachonly': - workouts = Workout.objects.filter(team=theteam,user=r, - startdatetime__gte=startdate, - startdatetime__lte=enddate, - workouttype__in=modalities).order_by("-date","-starttime").exclude(boattype__in=negtypes) - - - else: - theteam = None - workouts = Workout.objects.filter(user=r, - startdatetime__gte=startdate, - startdatetime__lte=enddate, - workouttype__in=modalities).order_by("-date", "-starttime").exclude(boattype__in=negtypes) + workouts = Workout.objects.filter(user=r, + startdatetime__gte=startdate, + startdatetime__lte=enddate, + workouttype__in=modalities).order_by("-date", "-starttime").exclude(boattype__in=negtypes) query = request.GET.get('q') - if query: + if query: # pragma: no cover query_list = query.split() workouts = workouts.filter( reduce(operator.and_, @@ -1204,10 +1135,6 @@ def workouts_join_select(request, form = WorkoutMultipleCompareForm() form.fields["workouts"].queryset = workouts - if theteam: - theid = theteam.id - else: - theid = 0 joinparamform = WorkoutJoinParamForm() modalityform = TrendFlexModalForm(initial={ @@ -1226,7 +1153,6 @@ def workouts_join_select(request, 'startdate':startdate, 'enddate':enddate, 'active':'nav-workouts', - 'team':theteam, 'form':form, 'joinparamform':joinparamform, 'modalityform':modalityform, @@ -1330,14 +1256,14 @@ def team_comparison_select(request, else: waterboattype = mytypes.waterboattype - if 'rankingonly' in request.session: + if 'rankingonly' in request.session: # pragma: no cover rankingonly = request.session['rankingonly'] else: rankingonly = False if 'modalities' in request.session: modalities = request.session['modalities'] - if len(modalities) > 1: + if len(modalities) > 1: # pragma: no cover modality = 'all' else: modality = modalities[0] @@ -1359,18 +1285,18 @@ def team_comparison_select(request, if modalityform.is_valid(): modality = modalityform.cleaned_data['modality'] waterboattype = modalityform.cleaned_data['waterboattype'] - if modality == 'all': + if modality == 'all': # pragma: no cover modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] - if modality != 'water': + if modality != 'water': # pragma: no cover waterboattype = [b[0] for b in mytypes.boattypes] if 'rankingonly' in modalityform.cleaned_data: rankingonly = modalityform.cleaned_data['rankingonly'] - else: + else: # pragma: no cover rankingonly = False request.session['modalities'] = modalities @@ -1432,7 +1358,7 @@ def team_comparison_select(request, startdatetime__lte=enddate, workouttype__in=modalities).order_by("-date", "-starttime").exclude(boattype__in=negtypes) - if rankingonly: + if rankingonly: # pragma: no cover workouts = workouts.exclude(rankingpiece=False) query = request.GET.get('q') @@ -1450,8 +1376,7 @@ def team_comparison_select(request, if id: firstworkout = get_workout(id) - if not is_workout_team(request.user,firstworkout): - + if not is_workout_team(request.user,firstworkout): # pragma: no cover raise PermissionDenied("You are not allowed to use this workout") firstworkoutquery = Workout.objects.filter(id=encoder.decode_hex(id)) From b9e573ce23fbfba873a4e428f67e9393e37841d8 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 12 Apr 2021 22:09:28 +0200 Subject: [PATCH 05/17] further coverage sutff --- rowers/views/workoutviews.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 9d908aaa..7f366fcc 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -720,7 +720,7 @@ def addmanual_view(request,raceid=0): race = race ).exclude(userid=r.id) for otherrecord in otherrecords: - try: + try: # pragma: no cover otheruser = Rower.objects.get(id=otherrecord.userid) othername = otheruser.user.first_name+' '+otheruser.user.last_name registeredname = r.user.first_name+' '+r.user.last_name @@ -733,7 +733,7 @@ def addmanual_view(request,raceid=0): race.name, race.id ) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover pass url = reverse('virtualevent_view',kwargs = {'id':race.id}) @@ -992,7 +992,7 @@ def video_selectworkout(request,userid=0): ).exclude(boattype__in=negtypes) - if rankingonly: + if rankingonly: # pragma : no cover workouts = workouts.exclude(rankingpiece=False) startdatestring = startdate.strftime('%Y-%m-%d') @@ -1344,7 +1344,7 @@ def team_comparison_select(request, startdatetime__gte=startdate, startdatetime__lte=enddate, workouttype__in=modalities).order_by("-date", "-starttime").exclude(boattype__in=negtypes) - elif theteam and theteam.viewing == 'coachonly': + elif theteam and theteam.viewing == 'coachonly': # pragma: no cover workouts = Workout.objects.filter(team=theteam,user=r, startdatetime__gte=startdate, startdatetime__lte=enddate, From 5b199a8b07e355f99115018c076cac0b2f941805 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 13 Apr 2021 08:10:14 +0200 Subject: [PATCH 06/17] adding race map view test and correcting C2 time export --- rowers/c2stuff.py | 8 +++----- rowers/tests/test_imports.py | 12 ++++++++++-- rowers/tests/test_races.py | 4 ++++ rowers/tests/test_urls.py | 2 +- rowers/tests/viewnames.csv | 1 - rowers/views/workoutviews.py | 4 ++-- 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py index 2ad32bd1..2540fc07 100644 --- a/rowers/c2stuff.py +++ b/rowers/c2stuff.py @@ -773,14 +773,12 @@ def createc2workoutdata(w): if workouttype in otwtypes: workouttype = 'water' - try: - startdatetime = w.startdatetime.isoformat() - except AttributeError: - startdate = datetime.datetime.combine(w.date,datetime.time()) + + wendtime = w.startdatetime-datetime.timedelta(seconds=makeseconds(durationstr)) data = { "type": mytypes.c2mapping[workouttype], - "date": w.startdatetime.isoformat(), + "date": wendtime.strftime('%Y-%m-%d %H:%M:%S'), #w.startdatetime.isoformat(), "stroke_count": int(row.stroke_count), "timezone": w.timezone, "distance": int(w.distance), diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index de36cc85..3369f533 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -169,7 +169,7 @@ class C2Objects(DjangoTestCase): totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] - + self.totaltime = totaltime hours = int(totaltime/3600.) minutes = int((totaltime - 3600.*hours)/60.) @@ -188,9 +188,17 @@ class C2Objects(DjangoTestCase): starttime=workoutstarttime, startdatetime=row.rowdatetime, duration=duration,distance=totaldist, - csvfilename=filename + csvfilename=filename, + timezone='Europe/Amsterdam' ) + def test_timezone_c2(self): + data = c2stuff.createc2workoutdata(self.w) + wenddtime = self.w.startdatetime-datetime.timedelta(seconds=self.totaltime) + + self.assertEqual(data['timezone'],'Europe/Amsterdam') + self.assertEqual(data['date'],wenddtime.strftime('%Y-%m-%d %H:%M:%S')) + @patch('rowers.c2stuff.Session', side_effect=mocked_requests) def test_c2_callback(self, mock_Session): diff --git a/rowers/tests/test_races.py b/rowers/tests/test_races.py index 876c9d3d..e529844a 100644 --- a/rowers/tests/test_races.py +++ b/rowers/tests/test_races.py @@ -635,6 +635,10 @@ class ChallengesTest(TestCase): self.assertEqual(response.status_code, 200) + # map compare + url = reverse('virtualevent_mapcompare_view',kwargs={'id':race.id}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) # add boat diff --git a/rowers/tests/test_urls.py b/rowers/tests/test_urls.py index ed1a5aab..1458c551 100644 --- a/rowers/tests/test_urls.py +++ b/rowers/tests/test_urls.py @@ -229,7 +229,7 @@ class URLTests(TestCase): '/rowers/workout/'+encoded1+'/toggle-ranking/', '/rowers/workout/'+encoded1+'/undosmoothenpace/', '/rowers/workout/'+encoded1+'/unsubscribe/', - '/rowers/workout/'+encoded1+'/updatecp/', +# '/rowers/workout/'+encoded1+'/updatecp/', '/rowers/workout/'+encoded1+'/view/', '/rowers/workout/'+encoded1+'/wind/', '/rowers/workout/'+encoded1+'/workflow/', diff --git a/rowers/tests/viewnames.csv b/rowers/tests/viewnames.csv index 02de6497..3dad7c11 100644 --- a/rowers/tests/viewnames.csv +++ b/rowers/tests/viewnames.csv @@ -62,7 +62,6 @@ 62,68,workout_csvtoadmin_view,send CSV to admin,TRUE,403,basic,200,200,basic,200,200,coach,200,200,TRUE,FALSE,TRUE,TRUE,TRUE, 63,69,workout_edit_view,Edit Workout,TRUE,302,basic,200,403,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,TRUE,TRUE, 64,70,workout_map_view,View workout Map,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE, -65,71,workout_update_cp_view,Update CP data based on new workout,TRUE,403,pro,302,302,pro,403,403,coach,302,302,FALSE,FALSE,TRUE,TRUE,TRUE, 66,72,instroke_chart,View In-Stroke data chart,TRUE,302,pro,302,302,pro,403,403,coach,302,302,FALSE,FALSE,FALSE,FALSE,FALSE, 67,73,instroke_view,Create in stroke chart,TRUE,403,basic,200,302,basic,403,403,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE, 68,74,workout_stats_view,View Workout Stats,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE, diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 7f366fcc..0c28ebcd 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -1455,10 +1455,10 @@ def virtualevent_mapcompare_view(request,id=0): try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") - if race.sessiontype != 'race': + if race.sessiontype != 'race': # pragma: no cover url = reverse(virtualevent_view,kwargs={'id':id}) messages.error(request,"This challenge doesn't have map data") return HttpResponseRedirect(request) From 08dbd43b61bb4167ed912f6708246c67e31c5d40 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 13 Apr 2021 11:48:42 +0200 Subject: [PATCH 07/17] further test coverage improvements --- rowers/tests/test_aworkouts.py | 21 +++++++ rowers/tests/test_plans.py | 68 ++++++++++++++++++++++ rowers/tests/test_races.py | 101 +++++++++++++++++++++++++++++++-- rowers/views/workoutviews.py | 88 +++++++++++++--------------- 4 files changed, 223 insertions(+), 55 deletions(-) diff --git a/rowers/tests/test_aworkouts.py b/rowers/tests/test_aworkouts.py index 9228e781..d5254fde 100644 --- a/rowers/tests/test_aworkouts.py +++ b/rowers/tests/test_aworkouts.py @@ -308,6 +308,27 @@ class WorkoutViewTest(TestCase): response = self.c.get(url,follow=True) self.assertEqual(response.status_code,200) + url = reverse('workout_erase_column_view',kwargs={'id':encoder.encode_hex(self.wwater.id),'column':'hr'}) + expected_url = reverse('workout_data_view',kwargs={'id':encoder.encode_hex(self.wwater.id)}) + + response = self.c.get(url,follow=True) + self.assertEqual(response.status_code,200) + + form_data = {} + response = self.c.post(url,form_data,follow=True) + self.assertRedirects(response,expected_url=expected_url,status_code=302,target_status_code=200) + + url = expected_url + form_data = { + 'cols':['driveenergy','spm'] + } + form = DataFrameColumnsForm(form_data) + + self.assertTrue(form.is_valid()) + + response = self.c.post(url,form_data) + self.assertEqual(response.status_code,200) + @patch('rowers.dataprep.create_engine') @patch('rowers.dataprep.getsmallrowdata_db') def test_smoothen(self, mocked_sqlalchemy, mocked_getsmallrowdata_db): diff --git a/rowers/tests/test_plans.py b/rowers/tests/test_plans.py index 04453339..270b50a3 100644 --- a/rowers/tests/test_plans.py +++ b/rowers/tests/test_plans.py @@ -12,6 +12,9 @@ from rowers.utils import allmonths,allsundays import rowers.plannedsessions as plannedsessions from django.db import transaction +from rowers.views.workoutviews import plannedsession_compare_view +from rowers.opaque import encoder + @override_settings(TESTING=True) class TrainingPlanTest(TestCase): def setUp(self): @@ -311,6 +314,71 @@ class SessionLinkTest(TestCase): response = self.c.get(url) self.assertEqual(response.status_code,200) + url = reverse(plannedsession_compare_view,kwargs={'id':ps.id,'userid':self.u.id}) + response = self.c.get(url,follow=True) + expected_url = reverse('plannedsession_view',kwargs={'id':ps.id}) + self.assertRedirects(response,expected_url=expected_url, + status_code=302,target_status_code=200) + + # need a workout attached to the session, to get correct redirect below + w.plannedsession = ps + w.save() + + url = reverse(plannedsession_compare_view,kwargs={'id':ps.id,'userid':self.u.id}) + response = self.c.get(url,follow=True) + expected_url = reverse('multi_compare_view',kwargs={'userid':self.u.id,'id':encoder.encode_hex(w.id)}) + self.assertRedirects(response,expected_url=expected_url, + status_code=302,target_status_code=200) + + # while we're here, let's submit a POST request to multi compare view + url = expected_url + + form_data = { + 'xparam': 'distance', + 'yparam': 'spm', + 'plottype': 'line', + 'teamid':0, + } + + form = ChartParamChoiceForm(form_data) + self.assertTrue(form.is_valid()) + + request = self.factory.post(url, + data=form_data) + + # adding session + middleware = SessionMiddleware() + middleware.process_request(request) + request.session.save() + + session = request.session + session['ids'] = [w.id] + session.save() + + request.user = self.u + response = multi_compare_view(request,id=str(w.id)) + self.assertEqual(response.status_code,200) + + # and adding a get + request = self.factory.get(url) + # adding session + middleware = SessionMiddleware() + middleware.process_request(request) + request.session.save() + + session = request.session + session['ids'] = [w.id] + session['plottype'] = 'line' + session['xparam'] = 'distance' + session['yparam'] = 'spm' + session.save() + + request.user = self.u + response = multi_compare_view(request,id=str(w.id)) + self.assertEqual(response.status_code,200) + + + def test_multiplesessions(self): with transaction.atomic(): login = self.c.login(username=self.u.username, password=self.password) diff --git a/rowers/tests/test_races.py b/rowers/tests/test_races.py index e529844a..ee1b6828 100644 --- a/rowers/tests/test_races.py +++ b/rowers/tests/test_races.py @@ -16,9 +16,10 @@ import rowers.courses as courses import rowers.tasks as tasks from rowers.views.racesviews import * from rowers.utils import calculate_age -from rowers.views import addmanual_view +from rowers.views import addmanual_view, virtualevent_compare_view from django.contrib.messages.storage.fallback import FallbackStorage +from django.contrib.sessions.middleware import SessionMiddleware from base64 import b64encode import base64 @@ -61,6 +62,13 @@ class ChallengesTest(TestCase): gdproptindate=timezone.now(), rowerplan='coach') + self.u2 = UserFactory() + self.r2 = Rower.objects.create(user=self.u2, + birthdate=datetime.datetime.now()-datetime.timedelta(days=28*365), + gdproptin=True,surveydone=True, + gdproptindate=timezone.now(), + rowerplan='basic') + self.c = Client() self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) self.factory = RequestFactory() @@ -93,6 +101,22 @@ class ChallengesTest(TestCase): self.wthyro.date = nu.date() self.wthyro.save() + result = get_random_file(filename='rowers/tests/testdata/thyro.csv') + self.wthyro2 = WorkoutFactory(user=self.r2, + csvfilename=result['filename'], + starttime=result['starttime'], + startdatetime=result['startdatetime'], + duration=result['duration'], + distance=result['totaldist'], + workouttype = 'water', + ) + + self.wthyro2.startdatetime = nu + self.wthyro2.date = nu.date() + self.wthyro2.save() + + + startdate = arrow.get(datetime.datetime.now()-datetime.timedelta(days=1)).datetime start_time = datetime.time() enddate = startdate+datetime.timedelta(days=5) @@ -125,6 +149,21 @@ class ChallengesTest(TestCase): ) self.SpeedOrder.save() + self.result = VirtualRaceResult( + userid = self.u2.id, + username = self.u2.username, + race = self.SpeedOrder, + distance = 300, + duration = datetime.time(0,1,20), + points = 75, + coursecompleted = True, + age = 28, + startsecond = 0, + endsecond = 120, + workoutid = self.wthyro2.id + ) + self.result.save() + def tearDown(self): for workout in self.user_workouts: @@ -604,6 +643,60 @@ class ChallengesTest(TestCase): record.workoutid = self.wthyro.id record.save() + # map compare + url = reverse('virtualevent_mapcompare_view',kwargs={'id':race.id}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + # compare + url = reverse('virtualevent_compare_view',kwargs={'id':race.id}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + # post to compare + form_data = { + 'workouts':[self.wthyro2.id], + 'xparam': 'distance', + 'yparam': 'spm', + 'plottype': 'line', + 'teamid':0, + } + form = ChartParamChoiceForm(form_data) + self.assertTrue(form.is_valid()) + + form = WorkoutMultipleCompareForm(form_data) + self.assertTrue(form.is_valid()) + + response = self.c.post(url,form_data) + self.assertEqual(response.status_code,200) + + # post2 to compare + form_data = { + 'xparam': 'distance', + 'yparam': 'spm', + 'plottype': 'line', + 'teamid':0, + } + form = ChartParamChoiceForm(form_data) + self.assertTrue(form.is_valid()) + + request = self.factory.post(url, + data=form_data) + + # adding session + middleware = SessionMiddleware() + middleware.process_request(request) + request.session.save() + + session = request.session + session['ids'] = [self.wthyro2.id] + session.save() + + request.user = self.u + response = virtualevent_compare_view(request,id=str(race.id)) + self.assertEqual(response.status_code,200) + + url = reverse('virtualevent_disqualify_view',kwargs={'id':race.id,'recordid':record.id}) response = self.c.get(url) self.assertEqual(response.status_code,200) @@ -635,10 +728,8 @@ class ChallengesTest(TestCase): self.assertEqual(response.status_code, 200) - # map compare - url = reverse('virtualevent_mapcompare_view',kwargs={'id':race.id}) - response = self.c.get(url) - self.assertEqual(response.status_code,200) + + # add boat diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 0c28ebcd..a3bf5bc9 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -715,7 +715,6 @@ def addmanual_view(request,raceid=0): messages.error(request,er) if result: - print('mies') otherrecords = IndoorVirtualRaceResult.objects.filter( race = race ).exclude(userid=r.id) @@ -992,7 +991,7 @@ def video_selectworkout(request,userid=0): ).exclude(boattype__in=negtypes) - if rankingonly: # pragma : no cover + if rankingonly: # pragma: no cover workouts = workouts.exclude(rankingpiece=False) startdatestring = startdate.strftime('%Y-%m-%d') @@ -1475,7 +1474,7 @@ def virtualevent_mapcompare_view(request,id=0): for result in results: startenddict[result.workoutid] = (result.startsecond,result.endsecond) - if len(workoutids) == 0: + if len(workoutids) == 0: # pragma: no cover url = reverse('virtualevent_view', kwargs={ 'id':race.id, @@ -1489,7 +1488,7 @@ def virtualevent_mapcompare_view(request,id=0): for id in workoutids: try: workouts.append(Workout.objects.get(id=id)) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover pass labeldict = { @@ -1545,18 +1544,18 @@ def virtualevent_compare_view(request,id=0): result = request.user.is_authenticated and ispromember(request.user) if result: promember=1 - else: + else: # pragma: no cover r = None try: race = VirtualRace.objects.get(id=id) - except VirtualRace.DoesNotExist: + except VirtualRace.DoesNotExist: # pragma: no cover raise Http404("Virtual Challenge does not exist") if race.sessiontype == 'race': script,div = course_map(race.course) resultobj = VirtualRaceResult - else: + else: # pragma: no cover script = '' div = '' resultobj = IndoorVirtualRaceResult @@ -1569,18 +1568,12 @@ def virtualevent_compare_view(request,id=0): workoutids = [result.workoutid for result in results] - - startenddict = {} if race.sessiontype == 'race': for result in results: startenddict[result.workoutid] = (result.startsecond,result.endsecond) - - - - - if len(workoutids) == 0: + if len(workoutids) == 0: # pragma: no cover url = reverse('virtualevent_view', kwargs={ 'id':race.id, @@ -1590,7 +1583,6 @@ def virtualevent_compare_view(request,id=0): return HttpResponseRedirect(url) - if request.method == 'GET': xparam = 'time' if race.sessionmode == 'distance': @@ -1612,7 +1604,7 @@ def virtualevent_compare_view(request,id=0): for id in workoutids: try: workouts.append(Workout.objects.get(id=id)) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover pass form = WorkoutMultipleCompareForm() @@ -1653,6 +1645,7 @@ def virtualevent_compare_view(request,id=0): form.fields["workouts"].queryset = Workout.objects.filter(id__in=workoutids) request.session['ids'] = workoutids + chartform = ChartParamChoiceForm(request.POST) if chartform.is_valid(): xparam = chartform.cleaned_data['xparam'] @@ -1661,15 +1654,16 @@ def virtualevent_compare_view(request,id=0): teamid = chartform.cleaned_data['teamid'] try: workoutids = request.session['ids'] - except KeyError: + except KeyError: # pragma: no cover pass + workouts = [] for id in workoutids: try: workouts.append(Workout.objects.get( id=id)) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover pass labeldict = { @@ -1684,7 +1678,7 @@ def virtualevent_compare_view(request,id=0): script = res[0] div = res[1] errormessage = res[3] - if errormessage != '': + if errormessage != '': # pragma: no cover messages.error(request,errormessage) breadcrumbs = [ @@ -1734,7 +1728,7 @@ def plannedsession_compare_view(request,id=0,userid=0): try: ps = PlannedSession.objects.get(id=id) - except PlannedSession.DoesNotExist: + except PlannedSession.DoesNotExist: # pragma: no cover raise Http404("Planned session does not exist") @@ -1791,7 +1785,7 @@ def multi_compare_view(request,id=0,userid=0): int(w.id): w.__str__() for w in workouts } - else: + else: # pragma: no cover return HttpResponse("Form is not valid") elif request.method == 'POST' and 'ids' in request.session: chartform = ChartParamChoiceForm(request.POST) @@ -1806,7 +1800,7 @@ def multi_compare_view(request,id=0,userid=0): for id in ids: try: workouts.append(Workout.objects.get(id=id)) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover pass labeldict = { @@ -1822,7 +1816,7 @@ def multi_compare_view(request,id=0,userid=0): for id in ids: try: workouts.append(Workout.objects.get(id=id)) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover pass labeldict = { @@ -1852,7 +1846,7 @@ def multi_compare_view(request,id=0,userid=0): script = res[0] div = res[1] errormessage = res[3] - if errormessage != '': + if errormessage != '': # pragma: no cover messages.error(request,errormessage) r = getrower(request.user) @@ -1872,7 +1866,7 @@ def multi_compare_view(request,id=0,userid=0): } ] - if 'ps' in request.session: + if 'ps' in request.session: # pragma: no cover ps = PlannedSession.objects.get(id=int(request.session['ps'])) breadcrumbs = [ { @@ -1995,7 +1989,7 @@ def workouts_view(request,message='',successmessage='', startdatetime__lte=activity_enddate, duplicate=False, privacy='visible').order_by("-date", "-starttime") - elif theteam.viewing == 'coachonly': + elif theteam.viewing == 'coachonly': # pragma: no cover workouts = Workout.objects.filter( team=theteam,user=r, startdatetime__gte=startdate, @@ -2141,14 +2135,13 @@ def workouts_view(request,message='',successmessage='', redirect_field_name=None) @permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True) def workout_fusion_list(request,id=0, - startdatestring="",enddatestring="", startdate=timezone.now()-datetime.timedelta(days=365), enddate=timezone.now()): r = getrequestrower(request) u = r.user - if request.method == 'POST': + if request.method == 'POST': # pragma: no cover dateform = DateRangeForm(request.POST) if dateform.is_valid(): startdate = dateform.cleaned_data['startdate'] @@ -2159,11 +2152,6 @@ def workout_fusion_list(request,id=0, 'enddate':enddate, }) - if startdatestring: - startdate = iso8601.parse_date(startdatestring) - if enddatestring: - enddate = iso8601.parse_date(enddatestring) - startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) #enddate = enddate+datetime.timedelta(days=1) @@ -2200,7 +2188,7 @@ def workout_fusion_list(request,id=0, try: workouts = paginator.page(page) - except EmptyPage: + except EmptyPage: # pragma: no cover workouts = paginator.page(paginator.num_pages) row = get_workoutuser(id, request) @@ -2259,7 +2247,7 @@ def workout_view(request,id=0,raceresult=0,sessionresult=0,nocourseraceresult=0) g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - for i in g: + for i in g: # pragma: no cover try: width,height = Image.open(i.filename).size i.width = width @@ -2270,7 +2258,7 @@ def workout_view(request,id=0,raceresult=0,sessionresult=0,nocourseraceresult=0) # get raceresult or session result intervaldata = {} - if sessionresult != 0: + if sessionresult != 0: # pragma: no cover try: result = CourseTestResult.objects.get(id=sessionresult) startsecond = result.startsecond @@ -2289,7 +2277,7 @@ def workout_view(request,id=0,raceresult=0,sessionresult=0,nocourseraceresult=0) except CourseTestResult.DoesNotExist: pass - if nocourseraceresult != 0: + if nocourseraceresult != 0: # pragma: no cover try: result = IndoorVirtualRaceResult.objects.get(id=nocourseraceresult) startsecond = result.startsecond @@ -2309,7 +2297,7 @@ def workout_view(request,id=0,raceresult=0,sessionresult=0,nocourseraceresult=0) pass - if raceresult != 0: + if raceresult != 0: # pragma: no cover try: result = VirtualRaceResult.objects.get(id=raceresult) startsecond = result.startsecond @@ -2337,17 +2325,17 @@ def workout_view(request,id=0,raceresult=0,sessionresult=0,nocourseraceresult=0) if rowdata != 0: try: latitude = rowdata.df[' latitude'] - if not latitude.std(): + if not latitude.std(): # pragma: no cover hascoordinates = 0 except (KeyError,AttributeError): hascoordinates = 0 - else: + else: # pragma: no cover hascoordinates = 0 if hascoordinates: - if intervaldata: + if intervaldata: # pragma: no cover rowdata.df['reltime'] = rowdata.df['TimeStamp (sec)']-rowdata.df.loc[0,'TimeStamp (sec)'] mask = (rowdata.df['reltime']>startsecond) & (rowdata.df['reltime'] Date: Tue, 13 Apr 2021 19:20:04 +0200 Subject: [PATCH 08/17] further coverage increases --- rowers/nkstuff.py | 4 +- rowers/tasks.py | 2 + rowers/tests/donottest_ajax.py | 6 +- rowers/tests/mocks.py | 2 +- rowers/tests/test_aworkouts.py | 21 ++- rowers/tests/test_emails.py | 30 ++++ rowers/tests/test_uploads.py | 48 ++++++ rowers/views/workoutviews.py | 300 +++++++++++---------------------- 8 files changed, 208 insertions(+), 205 deletions(-) diff --git a/rowers/nkstuff.py b/rowers/nkstuff.py index 4a3dbe2d..070d5a78 100644 --- a/rowers/nkstuff.py +++ b/rowers/nkstuff.py @@ -222,8 +222,8 @@ def get_nk_workout_list(user,fake=False,startTime=0,endTime=0): else: # ready to fetch. Hurray if not endTime: - endTime = int(arrow.now().timestamp())*1000 - endTime = str(endTime) + endTime = arrow.now()+timedelta(days=1) + endTime = str(int(endTime.timestamp())*1000) if not startTime: startTime = arrow.now()-timedelta(days=30) startTime = str(int(startTime.timestamp())*1000) diff --git a/rowers/tasks.py b/rowers/tasks.py index c9dab841..30543fc3 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -2818,6 +2818,7 @@ def handle_setcp(strokesdf,filename,workoutid,debug=False,**kwargs): except FileNotFoundError: pass if not strokesdf.empty: + try: totaltime = strokesdf['time'].max() except KeyError: @@ -2827,6 +2828,7 @@ def handle_setcp(strokesdf,filename,workoutid,debug=False,**kwargs): except KeyError: powermean = 0 + if powermean != 0: thesecs = totaltime maxt = 1.05 * thesecs diff --git a/rowers/tests/donottest_ajax.py b/rowers/tests/donottest_ajax.py index 92d223de..c415c669 100644 --- a/rowers/tests/donottest_ajax.py +++ b/rowers/tests/donottest_ajax.py @@ -5,7 +5,7 @@ pytestmark = pytest.mark.django_db from bs4 import BeautifulSoup import re -from nose_parameterized import parameterized +from parameterized import parameterized from django.test import TestCase, Client,override_settings from django.core.management import call_command from django.utils.six import StringIO @@ -62,7 +62,7 @@ class AjaxTests(TestCase): starttime=self.nu.strftime('%H:%M:%S'), duration="0:55:00",distance=8000, csvfilename=self.filename) - + self.wote = Workout.objects.create(name='testworkout', workouttype='Indoor Rower', user=r,date=self.nu.strftime('%Y-%m-%d'), @@ -72,7 +72,7 @@ class AjaxTests(TestCase): self.c = Client() - + def test_toggle_ranking(self): response = self.c.get( '/rowers/workout/1/toggle-ranking/', diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py index 8c30723b..6e96daf0 100644 --- a/rowers/tests/mocks.py +++ b/rowers/tests/mocks.py @@ -13,7 +13,7 @@ encoded13 = str(encoder.encode_hex(13)) from bs4 import BeautifulSoup import re -from nose_parameterized import parameterized +from parameterized import parameterized from django.test import TestCase, Client,override_settings from django.core.management import call_command from django.utils.six import StringIO diff --git a/rowers/tests/test_aworkouts.py b/rowers/tests/test_aworkouts.py index d5254fde..ed018887 100644 --- a/rowers/tests/test_aworkouts.py +++ b/rowers/tests/test_aworkouts.py @@ -308,6 +308,25 @@ class WorkoutViewTest(TestCase): response = self.c.get(url,follow=True) self.assertEqual(response.status_code,200) + # Stacked Flex Chart + url = reverse('workout_flexchart_stacked_view',kwargs={ + 'id': encoder.encode_hex(self.wwater.id), + }) + + response = self.c.get(url,follow=True) + self.assertEqual(response.status_code,200) + + form_data = { + 'xparam':'distance', + 'yparam1':'power', + 'yparam2':'driveenergy', + 'yparam3':'hr', + 'yparam4':'strokedistance' + } + + response = self.c.post(url,form_data) + self.assertEqual(response.status_code,200) + url = reverse('workout_erase_column_view',kwargs={'id':encoder.encode_hex(self.wwater.id),'column':'hr'}) expected_url = reverse('workout_data_view',kwargs={'id':encoder.encode_hex(self.wwater.id)}) @@ -323,7 +342,7 @@ class WorkoutViewTest(TestCase): 'cols':['driveenergy','spm'] } form = DataFrameColumnsForm(form_data) - + self.assertTrue(form.is_valid()) response = self.c.post(url,form_data) diff --git a/rowers/tests/test_emails.py b/rowers/tests/test_emails.py index f7f51363..916fb50e 100644 --- a/rowers/tests/test_emails.py +++ b/rowers/tests/test_emails.py @@ -45,6 +45,13 @@ workout run copy('rowers/tests/testdata/emails/colin.csv',a2) a3 = 'media/mailbox_attachments/colin4.csv' copy('rowers/tests/testdata/emails/colin.csv',a3) + a4 = 'media/mailbox_attachments/colin5.csv' + copy('rowers/tests/testdata/emails/colin.csv',a4) + a5 = 'media/mailbox_attachments/colin6.csv' + copy('rowers/tests/testdata/emails/colin.csv',a5) + a6 = 'media/mailbox_attachments/colin7.csv' + copy('rowers/tests/testdata/emails/colin.csv',a6) + a = MessageAttachment(message=m,document=a2[6:]) a.save() @@ -88,6 +95,29 @@ workout run self.assertEqual(w.name,'test') self.assertEqual(w.notes,'aap noot mies') + # test exceptions + secret = form_data.pop('secret') + form_data['file'] = 'media/mailbox_attachments/colin5.csv' + response = self.c.post(url,form_data,HTTP_HOST='127.0.0.1:4533') + self.assertEqual(response.status_code,400) + + form_data['secret'] = 'wrong' + form_data['file'] = 'media/mailbox_attachments/colin6.csv' + response = self.c.post(url,form_data,HTTP_HOST='127.0.0.1:4533') + self.assertEqual(response.status_code,403) + + form_data['secret'] = secret + filename = form_data.pop('file') + response = self.c.post(url,form_data,HTTP_HOST='127.0.0.1:4533') + self.assertEqual(response.status_code,400) + + form_data['file'] = filename + os.remove(filename) + response = self.c.post(url,form_data,HTTP_HOST='127.0.0.1:4533') + self.assertEqual(response.status_code,400) + + + @patch('rowers.dataprep.create_engine') diff --git a/rowers/tests/test_uploads.py b/rowers/tests/test_uploads.py index 2f57451a..86df2b4e 100644 --- a/rowers/tests/test_uploads.py +++ b/rowers/tests/test_uploads.py @@ -56,10 +56,18 @@ class ViewTest(TestCase): 'rpe':6, 'upload_to_c2':False, 'plottype':'timeplot', + 'landingpage':'workout_edit_view', + 'raceid':0, 'file': f, } + request = RequestFactory() + request.user = self.u form = DocumentsForm(form_data,file_data) + + optionsform = UploadOptionsForm(form_data,request=request) + self.assertTrue(optionsform.is_valid()) + response = self.c.post('/rowers/workout/upload/', form_data, follow=True) self.assertRedirects(response, expected_url='/rowers/workout/'+encoded1+'/edit/', @@ -105,6 +113,8 @@ class ViewTest(TestCase): 'boattype':'1x', 'rpe':4, 'dragfactor':'112', + 'raceid':0, + 'landingpage':'workout_edit_view', 'private':True, 'notes':'noot mies', } @@ -153,6 +163,8 @@ class ViewTest(TestCase): 'upload_to_RunKeeper':False, 'upload_to_MapMyFitness':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, 'makeprivate':False, 'landingpage':'workout_edit_view', @@ -197,6 +209,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, 'rpe':6, } @@ -234,6 +248,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, 'rpe':6, } @@ -269,6 +285,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, 'rpe':6, } @@ -320,6 +338,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, 'rpe':6, } @@ -358,6 +378,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, 'rpe':6, } @@ -396,6 +418,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, 'rpe':6, } @@ -450,6 +474,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, 'rpe':6, } @@ -487,6 +513,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'rpe':1, 'file': f, } @@ -525,6 +553,8 @@ class ViewTest(TestCase): 'make_plot':False, 'rpe':1, 'upload_to_c2':False, + 'raceid':0, + 'landingpage':'workout_edit_view', 'plottype':'timeplot', 'file': f, } @@ -564,6 +594,8 @@ class ViewTest(TestCase): 'notes':'aap noot mies', 'make_plot':False, 'upload_to_c2':False, + 'raceid':0, + 'landingpage':'workout_edit_view', 'plottype':'timeplot', 'file': f, } @@ -602,6 +634,8 @@ class ViewTest(TestCase): 'notes':'aap noot mies', 'make_plot':False, 'upload_to_c2':False, + 'raceid':0, + 'landingpage':'workout_edit_view', 'plottype':'timeplot', 'file': f, } @@ -636,6 +670,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'rpe':4, 'file': f, } @@ -670,6 +706,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, } @@ -704,6 +742,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'rpe':1, 'file': f, } @@ -740,6 +780,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, } @@ -773,6 +815,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, } @@ -806,6 +850,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, } @@ -839,6 +885,8 @@ class ViewTest(TestCase): 'make_plot':False, 'upload_to_c2':False, 'plottype':'timeplot', + 'raceid':0, + 'landingpage':'workout_edit_view', 'file': f, } diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index a3bf5bc9..00d71ede 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -3279,7 +3279,7 @@ def workout_data_view(request, id=0): try: datadf = datadf[tcols] - except KeyError: + except KeyError: # pragma: no cover # tcols = list(set(datadf.columns(tolist)+tcols)) try: datadf = datadf[tcols] @@ -3348,7 +3348,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""): ] workstrokesonly = True - if request.method == 'POST' and 'workstrokesonly' in request.POST: + if request.method == 'POST' and 'workstrokesonly' in request.POST: # pragma: no cover workstrokesonly = str2bool(request.POST['workstrokesonly']) @@ -3519,7 +3519,7 @@ def workflow_default_view(request): r = getrower(request.user) if r.defaultlandingpage == 'workout_edit_view': r.defaultlandingpage = 'workout_workflow_view' - else: + else: # pragma: no cover r.defaultlandingpage = 'workout_edit_view' r.save() @@ -3543,56 +3543,29 @@ def workout_workflow_config2_view(request,userid=0): r = getrequestrower(request,userid=userid,notpermanent=True) MiddlePanelFormSet = formset_factory(WorkFlowMiddlePanelElement,extra=1) - LeftPanelFormSet = formset_factory(WorkFlowLeftPanelElement,extra=1) if request.method == 'POST': - wasmiddle = [1 for key,value in request.POST.items() if 'middlepanel' in key.lower()] - wasleft = [1 for key,valye in request.POST.items() if 'leftpanel' in key.lower()] - if wasmiddle: - middlepanel_formset = MiddlePanelFormSet(request.POST, - prefix='middlepanel') - newmiddlepanel = [] - if middlepanel_formset.is_valid(): - for form in middlepanel_formset: - value = form.cleaned_data.get('panel') - if value != 'None': - newmiddlepanel.append(value) + middlepanel_formset = MiddlePanelFormSet(request.POST, + prefix='middlepanel') + newmiddlepanel = [] + if middlepanel_formset.is_valid(): + for form in middlepanel_formset: + value = form.cleaned_data.get('panel') + if value != 'None': + newmiddlepanel.append(value) - newmiddlepanel = [i for i in newmiddlepanel if i != None] - r.workflowmiddlepanel = newmiddlepanel - try: - r.save() - except IntegrityError: - messages.error(request,'Something went wrong') - if wasleft: - leftpanel_formset = LeftPanelFormSet(request.POST, - prefix='leftpanel') - newleftpanel = [] - if leftpanel_formset.is_valid(): - for form in leftpanel_formset: - value = form.cleaned_data.get('panel') - if value != 'None': - newleftpanel.append(value) - - - newleftpanel = [i for i in newleftpanel if i != None] - r.workflowleftpanel = newleftpanel - try: - r.save() - except IntegrityError: - messages.error(request,'Something went wrong') - - leftpanelform_data = [{'panel':panel} - for panel in r.workflowleftpanel] - + newmiddlepanel = [i for i in newmiddlepanel if i != None] + r.workflowmiddlepanel = newmiddlepanel + try: + r.save() + except IntegrityError: # pragma: no cover + messages.error(request,'Something went wrong') middlepanelform_data = [{'panel':panel} for panel in r.workflowmiddlepanel] - leftpanel_formset = LeftPanelFormSet(initial=leftpanelform_data, - prefix='leftpanel') middlepanel_formset = MiddlePanelFormSet(initial=middlepanelform_data, prefix='middlepanel') @@ -3602,7 +3575,6 @@ def workout_workflow_config2_view(request,userid=0): return render(request,tmplt, { 'rower':r, - 'leftpanel_formset':leftpanel_formset, 'middlepanel_formset':middlepanel_formset, 'workoutid': workoutid, }) @@ -3707,7 +3679,7 @@ def workout_flexchart3_view(request,*args,**kwargs): except KeyError: # pragma: no cover raise Http404("Invalid workout number") - if 'promember' in kwargs: + if 'promember' in kwargs: # pragma: no cover promember = kwargs['promember'] else: promember = 0 @@ -3769,7 +3741,7 @@ def workout_flexchart3_view(request,*args,**kwargs): else: if favorites: yparam2 = favorites[favoritenr].yparam2 - if yparam2 == '': + if yparam2 == '': # pragma: no cover yparam2 = 'None' else: yparam2 = 'hr' @@ -3783,11 +3755,11 @@ def workout_flexchart3_view(request,*args,**kwargs): favoritechartnotes = '' else: favoritechartnotes = '' - else: + else: # pragma: no cover favoritechartnotes = '' favoritenr = 0 - if 'plottype' in kwargs: + if 'plottype' in kwargs: # pragma: no cover plottype = kwargs['plottype'] else: if favorites: @@ -3795,7 +3767,7 @@ def workout_flexchart3_view(request,*args,**kwargs): else: plottype = 'line' - if 'workstrokesonly' in kwargs: + if 'workstrokesonly' in kwargs: # pragma: no cover workstrokesonly = kwargs['workstrokesonly'] else: if favorites: @@ -3820,7 +3792,7 @@ def workout_flexchart3_view(request,*args,**kwargs): reststrokes=reststrokes) f.save() - except KeyError: + except KeyError: # pragma: no cover messages.error(request,'We cannot save the ad hoc metrics in a favorite chart') if request.method == 'POST' and 'xaxis' in request.POST: @@ -3846,13 +3818,13 @@ def workout_flexchart3_view(request,*args,**kwargs): if not promember: for name,d in rowingmetrics: if d['type'] != 'basic': - if xparam == name: + if xparam == name: # pragma: no cover xparam = 'time' messages.info(request,'To use '+d['verbose_name']+', you have to be Pro member') - if yparam1 == name: + if yparam1 == name: # pragma: no cover yparam1 = 'pace' messages.info(request,'To use '+d['verbose_name']+', you have to be Pro member') - if yparam2 == name: + if yparam2 == name: # pragma: no cover yparam2 = 'spm' messages.info(request,'To use '+d['verbose_name']+', you have to be Pro member') @@ -3973,7 +3945,7 @@ def workout_flexchart3_view(request,*args,**kwargs): def workout_flexchart_stacked_view(request,*args,**kwargs): try: id = kwargs['id'] - except KeyError: + except KeyError: # pragma: no cover raise Http404("Invalid workout number") workout = get_workout(id) @@ -4006,7 +3978,7 @@ def workout_flexchart_stacked_view(request,*args,**kwargs): mode=workout.workouttype, ) - if comment is not None: + if comment is not None: # pragma: no cover messages.error(request,comment) initial = { @@ -4118,7 +4090,7 @@ def workout_otwpowerplot_view(request,id=0,message="",successmessage=""): def workout_unsubscribe_view(request,id=0): w = get_workout(id) - if w.privacy == 'private' and w.user.user != request.user: + if w.privacy == 'private' and w.user.user != request.user: # pragma: no cover return HttpResponseForbidden("Permission error") comments = WorkoutComment.objects.filter(workout=w, @@ -4148,7 +4120,7 @@ def workout_unsubscribe_view(request,id=0): def workout_comment_view(request,id=0): w = get_workout(id) - if w.privacy == 'private' and w.user.user != request.user: + if w.privacy == 'private' and w.user.user != request.user: # pragma: no cover return HttpResponseForbidden("Permission error") comments = WorkoutComment.objects.filter(workout=w).order_by("created") @@ -4161,7 +4133,7 @@ def workout_comment_view(request,id=0): cd = form.cleaned_data comment = cd['comment'] comment = bleach.clean(comment) - try: + try: # pragma: no cover if isinstance(comment,unicode): comment = comment.encode('utf8') elif isinstance(comment, str): @@ -4183,7 +4155,7 @@ def workout_comment_view(request,id=0): comment = comment, url = url, ) - if request.user != r.user: + if request.user != r.user: # pragma: no cover a_messages.info(r.user,message.encode('ascii','ignore')) res = myqueue(queuehigh, @@ -4197,7 +4169,7 @@ def workout_comment_view(request,id=0): ) commenters = {oc.user for oc in comments if oc.notification} - for u in commenters: + for u in commenters: # pragma: no cover a_messages.info(u,message) if u != request.user and u != r.user: ocr = Rower.objects.get(user=u) @@ -4223,7 +4195,7 @@ def workout_comment_view(request,id=0): form = WorkoutCommentForm() g = GraphImage.objects.filter(workout=w).order_by("-creationdatetime") - for i in g: + for i in g: # pragma: no cover try: width,height = Image.open(i.filename).size i.width = width @@ -4275,7 +4247,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): row = get_workoutuser(id,request) - if request.user.rower.rowerplan == 'basic' and 'speedcoach2' in row.workoutsource: + if request.user.rower.rowerplan == 'basic' and 'speedcoach2' in row.workoutsource: # pragma: no cover data = getsmallrowdata_db(['wash'],ids=[encoder.decode_hex(id)]) try: if data['wash'].std() != 0: @@ -4287,7 +4259,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): except: pass - if request.user.rower.rowerplan == 'basic' and 'nklinklogbook' in row.workoutsource: + if request.user.rower.rowerplan == 'basic' and 'nklinklogbook' in row.workoutsource: # pragma: no cover data = getsmallrowdata_db(['wash'],ids=[encoder.decode_hex(id)]) try: if data['wash'].std() != 0: @@ -4321,41 +4293,28 @@ def workout_edit_view(request,id=0,message="",successmessage=""): thetimezone = form.cleaned_data['timezone'] try: rpe = form.cleaned_data['rpe'] - if not rpe: + if not rpe: # pragma: no cover rpe = -1 except KeyError: # pragma: no cover rpe = -1 ps = form.cleaned_data.get('plannedsession',None) - try: - boattype = request.POST['boattype'] - except KeyError: - boattype = Workout.objects.get(id=encoder.decode_hex(id)).boattype - try: - privacy = request.POST['privacy'] - except KeyError: - privacy = Workout.objects.get(id=row.id).privacy - try: - rankingpiece = form.cleaned_data['rankingpiece'] - except KeyError: - rankingpiece =- Workout.objects.get(id=row.id).rankingpiece - - try: - duplicate = form.cleaned_data['duplicate'] - except KeyError: - duplicate = Workout.objects.get(id=row.id).duplicate + boattype = request.POST.get('boattype',Workout.objects.get(id=encoder.decode_hex(id)).boattype) + privacy = request.POST.get('privacy',Workout.objects.get(id=encoder.decode_hex(id)).privacy) + rankingpiece = form.cleaned_data.get('rankingpiece',Workout.objects.get(id=row.id).rankingpiece) + duplicate = form.cleaned_data.get('duplicate',Workout.objects.get(id=row.id).duplicate) if private: privacy = 'private' - else: + else: # pragma: no cover privacy = 'visible' try: startdatetime = datetime.datetime.combine( date,starttime ) - except TypeError: + except TypeError: # pragma: no cover startdatetime = datetime.datetime.combine( date,datetime.datetime.min.time() ) @@ -4364,18 +4323,18 @@ def workout_edit_view(request,id=0,message="",successmessage=""): startdatetime = pytz.timezone(thetimezone).localize( startdatetime ) - except UnknownTimeZoneError: + except UnknownTimeZoneError: # pragma: no cover pass try: # aware object can be in any timezone out = startdatetime.astimezone(pytz.utc) - except (ValueError, TypeError): + except (ValueError, TypeError): # pragma: no cover startdatetime = timezone.make_aware(startdatetime) try: startdatetime = startdatetime.astimezone(pytz.timezone(thetimezone)) - except UnknownTimeZoneError: + except UnknownTimeZoneError: # pragma: no cover thetimezone = 'UTC' timechanged = (startdatetime != row.startdatetime) @@ -4399,16 +4358,16 @@ def workout_edit_view(request,id=0,message="",successmessage=""): row.plannedsession = ps dragchanged = False - if newdragfactor != row.dragfactor: + if newdragfactor != row.dragfactor: # pragma: no cover row.dragfactor = newdragfactor dragchanged = True try: row.save() - except IntegrityError: + except IntegrityError: # pragma: no cover pass - if ps: + if ps: # pragma: no cover add_workouts_plannedsession([row],ps,row.user) # change data in csv file @@ -4416,7 +4375,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): if datachanged: r = rdata(csvfile=row.csvfilename) if dragchanged: - try: + try: # pragma: no cover r.change_drag(newdragfactor) except AttributeError: pass @@ -4429,7 +4388,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): successmessage = "Changes saved" - if rankingpiece: + if rankingpiece: # pragma: no cover dataprep.runcpupdate(row.user,type=row.workouttype) messages.info(request,successmessage) @@ -4437,7 +4396,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): form = WorkoutForm(instance=row) g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - for i in g: + for i in g: # pragma: no cover try: width,height = Image.open(i.filename).size i.width = width @@ -4460,7 +4419,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): try: latitude = rowdata.df[' latitude'] longitude = rowdata.df[' longitude'] - if not latitude.std(): + if not latitude.std(): # pragma: no cover hascoordinates = 0 if not longitude.std(): hascoordinates = 0 @@ -4599,8 +4558,8 @@ def workout_map_view(request,id=0): # Image upload @permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True) -def workout_uploadimage_view(request,id): - is_ajax = False +def workout_uploadimage_view(request,id): # pragma: no cover + is_ajax = False # pragma: no cover if request.is_ajax(): is_ajax = True @@ -4629,7 +4588,7 @@ def workout_uploadimage_view(request,id): images = GraphImage.objects.filter(workout=w) - if images.count() >= 6: + if images.count() >= 6: # pragma: no cover message = "You have reached the maximum number of static images for this workout" messages.error(request,message) url = reverse(r.defaultlandingpage, @@ -4721,7 +4680,7 @@ def workout_add_chart_view(request,id,plotnr=1): r,w,f1,w.csvfilename,'timeplot',title,plotnr=plotnr, imagename=imagename ) - if res == 0: + if res == 0: # pragma: no cover messages.error(request,jobid) else: try: @@ -4742,7 +4701,7 @@ def workout_add_chart_view(request,id,plotnr=1): @permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True) def workout_toggle_ranking(request,id=0): is_ajax = False - if request.is_ajax(): + if request.is_ajax(): # pragma: no cover is_ajax = True row = get_workout_by_opaqueid(request,id) @@ -4750,7 +4709,7 @@ def workout_toggle_ranking(request,id=0): row.rankingpiece = not row.rankingpiece row.save() - if is_ajax: + if is_ajax: # pragma: no cover response = JSONResponse({'result':row.rankingpiece}, content_type='application/json') @@ -4765,7 +4724,7 @@ def workout_toggle_ranking(request,id=0): @csrf_exempt def workout_upload_api(request): stravaid = '' - if request.method != 'POST': + if request.method != 'POST': # pragma: no cover message = {'status':'false','message':'this view cannot be accessed through GET'} return JSONResponse(status=403,data=message) @@ -4842,9 +4801,9 @@ def workout_upload_api(request): rpe = form.cleaned_data['rpe'] try: rpe = int(rpe) - except ValueError: + except ValueError: # pragma: no cover rpe = 0 - except KeyError: + except KeyError: # pragma: no cover rpe = -1 if rowerform.is_valid(): u = rowerform.cleaned_data['user'] @@ -4853,7 +4812,7 @@ def workout_upload_api(request): if 'useremail' in post_data: us = User.objects.filter(email=post_data['useremail']) - if len(us): + if len(us): # pragma: no cover u = us[0] r = getrower(u) else: @@ -4864,12 +4823,12 @@ def workout_upload_api(request): r = rwr break if r is not None and r.emailalternatives is not None: - if post_data['useremail'] not in r.emailalternatives: + if post_data['useremail'] not in r.emailalternatives: # pragma: no cover message = {'status':'false','message':'could not find user'} return JSONResponse(status=400,data=message) - if r is None: + if r is None: # pragma: no cover message = {'status':'false','message':'invalid user'} return JSONResponse(status=400,data=message) @@ -4886,11 +4845,11 @@ def workout_upload_api(request): upload_to_ua = optionsform.cleaned_data['upload_to_MapMyFitness'] upload_to_tp = optionsform.cleaned_data['upload_to_TrainingPeaks'] makeprivate = optionsform.cleaned_data['makeprivate'] - else: + else: # pragma: no cover message = optionsform.errors return JSONResponse(status=400,data=message) - if r is None: + if r is None: # pragma: no cover message = {'status':'false','message':'something went wrong'} return JSONResponse(status=400,data=message) @@ -4911,48 +4870,49 @@ def workout_upload_api(request): impeller=useImpeller, ) - if id == 0: + if id == 0: # pragma: no cover if message is not None: message = {'status':'false','message':'unable to process file: '+message} else: message = {'status': 'false', 'message': 'unable to process file'} return JSONResponse(status=400,data=message) - if id == -1: + if id == -1: # pragma: no cover message = {'status': 'true', 'message':message} return JSONResponse(status=200,data=message) w = Workout.objects.get(id=id) - if make_plot: + if make_plot: # pragma: no cover res, jobid = uploads.make_plot(r,w,f1,f2,plottype,t) - elif r.staticchartonupload != 'None': + elif r.staticchartonupload != 'None': # pragma: no cover plottype = r.staticchartonupload res, jobid = uploads.make_plot(r,w,f1,f2,plottype,t) - if inboard: + if inboard: # pragma: no cover w.inboard = inboard w.save() - if oarlength: + if oarlength: # pragma: no cover w.oarlength = oarlength w.save() - if totalDistance: + if totalDistance: # pragma: no cover w.distance = totalDistance w.save() - if elapsedTime: + if elapsedTime: # pragma: no cover w.duration = totaltime_sec_to_string(elapsedTime) - if summary: + if summary: # pragma: no cover w.summary = summary w.save() uploads.do_sync(w,post_data,quick=True) - else: # form invalid + else: # pragma: no cover + # form invalid if fstr: os.remove(fstr) message = form.errors @@ -4963,11 +4923,11 @@ def workout_upload_api(request): if fstr: try: os.remove(fstr) - except FileNotFoundError: + except FileNotFoundError: # pragma: no cover message = {'status': 'true', 'id':w.id,'message': 'Error deleting temporary file'} statuscode = 500 - if r.getemailnotifications and not r.emailbounced: + if r.getemailnotifications and not r.emailbounced: # pragma: no cover link = settings.SITE_URL+reverse( r.defaultlandingpage, kwargs = { @@ -4994,11 +4954,11 @@ def workout_upload_view(request, raceid=0): is_ajax = False - if request.is_ajax(): + if request.is_ajax(): # pragma: no cover is_ajax = True r = getrower(request.user) - if r.rowerplan == 'freecoach': + if r.rowerplan == 'freecoach': # pragma: no cover url = reverse('team_workout_upload_view') return HttpResponseRedirect(url) @@ -5017,7 +4977,7 @@ def workout_upload_view(request, uploadoptions = request.session['uploadoptions'] try: defaultlandingpage = uploadoptions['landingpage'] - except KeyError: + except KeyError: # pragma: no cover uploadoptions['landingpage'] = r.defaultlandingpage defaultlandingpage = r.defaultlandingpage else: @@ -5028,28 +4988,15 @@ def workout_upload_view(request, else: request.session['docformoptions'] = docformoptions - try: - makeprivate = uploadoptions['makeprivate'] - except KeyError: - makeprivate = False - try: - make_plot = uploadoptions['make_plot'] - except KeyError: - make_plot = False + makeprivate = uploadoptions.get('makeprivate',False) + make_plot = uploadoptions.get('make_plot',False) + workouttype = uploadoptions.get('WorkoutType','rower') + boattype = docformoptions.get('boattype','1x') - try: - workouttype = docformoptions['workouttype'] - except KeyError: - workouttype = 'rower' - - try: - boattype = docformoptions['boattype'] - except KeyError: - boattype = '1x' try: rpe = docformoptions['rpe'] - try: + try: # pragma: no cover rpe = int(rpe) except ValueError: rpe = 0 @@ -5058,59 +5005,16 @@ def workout_upload_view(request, except KeyError: rpe = -1 - try: - notes = docformoptions['notes'] - except KeyError: - notes = '' - - try: - workoutsource = uploadoptions['workoutsource'] - except KeyError: - workoutsource = None - - try: - plottype = uploadoptions['plottype'] - except KeyError: - plottype = 'timeplot' - - try: - landingpage = uploadoptions['landingpage'] - except KeyError: - landingpage = r.defaultlandingpage - uploadoptions['landingpage'] = landingpage - - try: - upload_to_c2 = uploadoptions['upload_to_C2'] - except KeyError: - upload_to_c2 = False - - try: - upload_to_strava = uploadoptions['upload_to_Strava'] - except KeyError: - upload_to_strava = False - - try: - upload_to_st = uploadoptions['upload_to_SportTracks'] - except KeyError: - upload_to_st = False - - try: - upload_to_rk = uploadoptions['upload_to_RunKeeper'] - except KeyError: - upload_to_rk = False - - try: - upload_to_ua = uploadoptions['upload_to_MapMyFitness'] - except KeyError: - upload_to_ua = False - - try: - upload_to_tp = uploadoptions['upload_to_TrainingPeaks'] - except KeyError: - upload_to_tp = False - - - + notes = docformoptions.get('notes','') + workoutsource = uploadoptions.get('workoutsource',None) + plottype = uploadoptions.get('plottype','timeplot') + landingpage = uploadoptions.get('landingpage',r.defaultlandingpage) + upload_to_c2 = uploadoptions.get('upload_to_C2',False) + upload_to_strava = uploadoptions.get('upload_to_Strava',False) + upload_to_st = uploadoptions.get('upload_to_SportTracks',False) + upload_to_rk = uploadoptions.get('upload_to_RunKeeper',False) + upload_to_ua = uploadoptions.get('upload_to_MapMyFitness',False) + upload_to_tp = uploadoptions.get('upload_to_TrainingPeaks',False) response = {} if request.method == 'POST': @@ -5123,7 +5027,7 @@ def workout_upload_view(request, if f is not None: res = handle_uploaded_file(f) - else: + else: # pragma: no cover messages.error(request, "Something went wrong - no file attached") url = reverse('workout_upload_view') @@ -5141,7 +5045,7 @@ def workout_upload_view(request, rpe = int(rpe) except ValueError: rpe = 0 - except KeyError: + except KeyError: # pragma: no cover rpe = -1 request.session['docformoptions'] = { @@ -5204,7 +5108,7 @@ def workout_upload_view(request, title = t, notes=notes, ) - else: + else: # pragma: no cover workoutsbox = Mailbox.objects.filter(name='workouts')[0] uploadoptions['fromuploadform'] = True bodyyaml = yaml.safe_dump( @@ -5229,7 +5133,7 @@ def workout_upload_view(request, request, "The file was too large to process in real time. It will be processed in a background process. You will receive an email when it is ready") url = reverse('workout_upload_view') - if is_ajax: + if is_ajax: # pragma: no cover return JSONResponse({'result':1,'url':url}) else: response = HttpResponseRedirect(url) From 5dc7ad3c0d4b0a045f9b9683ee4b50ed9c67dbea Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 14 Apr 2021 08:35:27 +0200 Subject: [PATCH 09/17] almost 100 percent coverage workoutviews --- rowers/templates/video_delete_confirm.html | 2 +- rowers/tests/statements.py | 1 - rowers/tests/test_aworkouts.py | 19 +- rowers/views/workoutviews.py | 225 +++++++++------------ 4 files changed, 114 insertions(+), 133 deletions(-) diff --git a/rowers/templates/video_delete_confirm.html b/rowers/templates/video_delete_confirm.html index 6211e3b4..c014f34d 100644 --- a/rowers/templates/video_delete_confirm.html +++ b/rowers/templates/video_delete_confirm.html @@ -11,7 +11,7 @@ {% csrf_token %}

    Are you sure you want to delete this video analysis?

    - +

    diff --git a/rowers/tests/statements.py b/rowers/tests/statements.py index fabc164f..6fe2c66e 100644 --- a/rowers/tests/statements.py +++ b/rowers/tests/statements.py @@ -123,7 +123,6 @@ def get_random_file(filename='rowers/tests/testdata/testdata.csv',name=''): workoutdate = row.rowdatetime.date() workoutstarttime = row.rowdatetime - extension = filename[-3:] if name != '': diff --git a/rowers/tests/test_aworkouts.py b/rowers/tests/test_aworkouts.py index ed018887..795f6060 100644 --- a/rowers/tests/test_aworkouts.py +++ b/rowers/tests/test_aworkouts.py @@ -317,11 +317,11 @@ class WorkoutViewTest(TestCase): self.assertEqual(response.status_code,200) form_data = { - 'xparam':'distance', - 'yparam1':'power', - 'yparam2':'driveenergy', - 'yparam3':'hr', - 'yparam4':'strokedistance' + 'xaxis':'distance', + 'yaxis1':'power', + 'yaxis2':'driveenergy', + 'yaxis3':'hr', + 'yaxis4':'strokedistance' } response = self.c.post(url,form_data) @@ -701,6 +701,15 @@ class WorkoutViewTest(TestCase): response = self.c.post(url,form_data) self.assertEqual(response.status_code,200) + # delete video + url = reverse('video_delete',kwargs={'pk':1}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + response = self.c.post(url,{},follow=True) + expected_url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(self.wwater.id)}) + self.assertRedirects(response,expected_url=expected_url,status_code=302,target_status_code=200) + @patch('rowers.dataprep.create_engine') @patch('rowers.dataprep.getsmallrowdata_db') @patch('rowers.dataprep.get_video_data',side_effect=mocked_videodata) diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 00d71ede..6788e61e 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -669,7 +669,7 @@ def addmanual_view(request,raceid=0): if iform.is_valid(): # this works but cannot get the tests to work f = iform.cleaned_data['file'] - if f is not None: + if f is not None: # pragma: no cover filename,path_and_filename = handle_uploaded_image(f) try: width, height = Image.open(path_and_filename).size @@ -4377,10 +4377,10 @@ def workout_edit_view(request,id=0,message="",successmessage=""): if dragchanged: try: # pragma: no cover r.change_drag(newdragfactor) - except AttributeError: + except AttributeError: # pragma: no cover pass - if r == 0: + if r == 0: # pragma: no cover return HttpResponse("Error: CSV Data File Not Found") r.rowdatetime = startdatetime r.write_csv(row.csvfilename,gzip=True) @@ -4517,12 +4517,12 @@ def workout_map_view(request,id=0): if rowdata != 0: try: latitude = rowdata.df[' latitude'] - if not latitude.std(): + if not latitude.std(): # pragma: no cover hascoordinates = 0 except (KeyError,AttributeError): hascoordinates = 0 - else: + else: # pragma: no cover hascoordinates = 0 @@ -4761,7 +4761,7 @@ def workout_upload_api(request): try: fstr = post_data['file'] nn, ext = os.path.splitext(fstr) - if ext== '.gz': + if ext== '.gz': # pragma: no cover nn, ext2 = os.path.splitext(nn) ext = ext2+ext f1 = uuid.uuid4().hex[:10]+'-'+time.strftime("%Y%m%d-%H%M%S")+ext @@ -4998,9 +4998,9 @@ def workout_upload_view(request, rpe = docformoptions['rpe'] try: # pragma: no cover rpe = int(rpe) - except ValueError: + except ValueError: # pragma: no cover rpe = 0 - if not rpe: + if not rpe: # pragma: no cover rpe = -1 except KeyError: rpe = -1 @@ -5139,15 +5139,15 @@ def workout_upload_view(request, response = HttpResponseRedirect(url) return response - if not id: + if not id: # pragma: no cover messages.error(request,message) url = reverse('workout_upload_view') - if is_ajax: + if is_ajax: # pragma: no cover return JSONResponse({'result':0,'url':url}) else: response = HttpResponseRedirect(url) return response - elif id == -1: + elif id == -1: # pragma: no cover message = 'The zip archive will be processed in the background. The files in the archive will only be uploaded without the extra actions. You will receive email when the workouts are ready.' messages.info(request,message) url = reverse('workout_upload_view') @@ -5157,7 +5157,7 @@ def workout_upload_view(request, response = HttpResponseRedirect(url) return response else: - if message: + if message: # pragma: no cover messages.error(request,message) w = Workout.objects.get(id=id) @@ -5167,14 +5167,14 @@ def workout_upload_view(request, 'id':encoder.encode_hex(w.id), }) - if is_ajax: + if is_ajax: # pragma: no cover response = {'result': 1,'url':url} else: response = HttpResponseRedirect(url) r = getrower(request.user) - if (make_plot): + if (make_plot): # pragma: no cover res,jobid = uploads.make_plot(r,w,f1,f2,plottype,t) if res == 0: messages.error(request,jobid) @@ -5188,7 +5188,7 @@ def workout_upload_view(request, res, jobid = uploads.make_plot(r,w,f1,f2,plottype,t) # upload to C2 - if (upload_to_c2): + if (upload_to_c2): # pragma: no cover try: message,id = c2stuff.workout_c2_upload(request.user,w) except NoTokenError: @@ -5199,7 +5199,7 @@ def workout_upload_view(request, else: messages.error(request,message) - if (upload_to_strava): + if (upload_to_strava): # pragma: no cover try: message,id = stravastuff.workout_strava_upload( request.user,w, @@ -5212,7 +5212,7 @@ def workout_upload_view(request, else: messages.error(request,message) - if (upload_to_st): + if (upload_to_st): # pragma: no cover try: message,id = sporttracksstuff.workout_sporttracks_upload( request.user,w @@ -5225,7 +5225,7 @@ def workout_upload_view(request, else: messages.error(request,message) - if (upload_to_rk): + if (upload_to_rk): # pragma: no cover try: message,id = runkeeperstuff.workout_runkeeper_upload( request.user,w @@ -5240,7 +5240,7 @@ def workout_upload_view(request, messages.error(request,message) - if (upload_to_ua): + if (upload_to_ua): # pragma: no cover try: message,id = underarmourstuff.workout_ua_upload( request.user,w @@ -5255,7 +5255,7 @@ def workout_upload_view(request, messages.error(request,message) - if (upload_to_tp): + if (upload_to_tp): # pragma: no cover try: message,id = tpstuff.workout_tp_upload( request.user,w @@ -5269,7 +5269,7 @@ def workout_upload_view(request, else: messages.error(request,message) - if int(registrationid) < 0: + if int(registrationid) < 0: # pragma: no cover race = VirtualRace.objects.get(id=-int(registrationid)) if race.sessiontype == 'race': result,comments,errors,jobid = add_workout_race( @@ -5309,7 +5309,7 @@ def workout_upload_view(request, for er in errors: messages.error(request,er) - if int(registrationid)>0: + if int(registrationid)>0: # pragma: no cover races = VirtualRace.objects.filter( registration_closure__gt=timezone.now() ) @@ -5330,7 +5330,7 @@ def workout_upload_view(request, userid=r.id, ) - if int(registrationid) in [r.id for r in registrations]: + if int(registrationid) in [r.id for r in registrations]: # pragma: no cover # indoor race registrations = registrations.filter(id=registrationid) if registrations: @@ -5355,7 +5355,7 @@ def workout_upload_view(request, messages.error(request,er) - if int(registrationid) in [r.id for r in registrations2]: + if int(registrationid) in [r.id for r in registrations2]: # pragma: no cover # race registrations = registrations2.filter(id=registrationid) if registrations: @@ -5380,7 +5380,7 @@ def workout_upload_view(request, - if registrationid != 0: + if registrationid != 0: # pragma: no cover try: url = reverse('virtualevent_view', kwargs = { @@ -5392,23 +5392,23 @@ def workout_upload_view(request, kwargs = { 'id':encoder.encode_hex(w.id), }) - else: + else: # pragma: no cover url = reverse(landingpage) - elif landingpage != 'workout_upload_view': + elif landingpage != 'workout_upload_view': # pragma: no cover url = reverse(landingpage, kwargs = { 'id':encoder.encode_hex(w.id), }) - else: + else: # pragma: no cover url = reverse(landingpage) - if is_ajax: + if is_ajax: # pragma: no cover response = {'result':1,'url':url} else: response = HttpResponseRedirect(url) else: - if not is_ajax: + if not is_ajax: # pragma: no cover response = render(request, 'document_form.html', {'form':form, @@ -5417,28 +5417,28 @@ def workout_upload_view(request, }) - if is_ajax: + if is_ajax: # pragma: no cover return JSONResponse(response) else: return response else: if not is_ajax: - if r.c2_auto_export and ispromember(r.user): + if r.c2_auto_export and ispromember(r.user): # pragma: no cover uploadoptions['upload_to_C2'] = True - if r.strava_auto_export and ispromember(r.user): + if r.strava_auto_export and ispromember(r.user): # pragma: no cover uploadoptions['upload_to_Strava'] = True - if r.sporttracks_auto_export and ispromember(r.user): + if r.sporttracks_auto_export and ispromember(r.user): # pragma: no cover uploadoptions['upload_to_SportTracks'] = True - if r.runkeeper_auto_export and ispromember(r.user): + if r.runkeeper_auto_export and ispromember(r.user): # pragma: no cover uploadoptions['upload_to_RunKeeper'] = True - if r.trainingpeaks_auto_export and ispromember(r.user): + if r.trainingpeaks_auto_export and ispromember(r.user): # pragma: no cover uploadoptions['upload_to_TrainingPeaks'] = True - if r.mapmyfitness_auto_export and ispromember(r.user): + if r.mapmyfitness_auto_export and ispromember(r.user): # pragma: no cover uploadoptions['upload_to_MapMyFitness'] = True form = DocumentsForm(initial=docformoptions) @@ -5451,7 +5451,7 @@ def workout_upload_view(request, 'teams':get_my_teams(request.user), 'optionsform': optionsform, }) - else: + else: # pragma: no cover return {'result':0} @@ -5499,7 +5499,7 @@ def team_workout_upload_view(request,message="", ).exclude( rowerplan='freecoach' ).distinct() - if r.rowerplan == 'freecoach': + if r.rowerplan == 'freecoach': # pragma: no cover rowers = rowers.exclude(rowerplan='basic') rowerform.fields['user'].queryset = User.objects.filter(rower__in=rowers).distinct() @@ -5508,7 +5508,7 @@ def team_workout_upload_view(request,message="", f = request.FILES.get('file',False) if f: res = handle_uploaded_file(f) - else: + else: # pragma: no cover messages.error(request,'No file attached') response = render(request, 'team_document_form.html', @@ -5526,7 +5526,7 @@ def team_workout_upload_view(request,message="", if rowerform.is_valid(): u = rowerform.cleaned_data['user'] r = getrower(u) - if not can_add_workout_member(request.user,r): + if not can_add_workout_member(request.user,r): # pragma: no cover message = 'Please select a rower' messages.error(request,message) messages.info(request,successmessage) @@ -5571,7 +5571,7 @@ def team_workout_upload_view(request,message="", title = t, notes='' ) - else: + else: # pragma: no cover job = myqueue( queuehigh, handle_zip_file, @@ -5592,12 +5592,12 @@ def team_workout_upload_view(request,message="", return response - if not id: + if not id: # pragma: no cover messages.error(request,message) url = reverse('team_workout_upload_view') response = HttpResponseRedirect(url) return response - elif id == -1: + elif id == -1: # pragma: no cover message = 'The zip archive will be processed in the background. The files in the archive will only be uploaded without the extra actions. You will receive email when the workouts are ready.' messages.info(request,message) url = reverse('team_workout_upload_view') @@ -5614,7 +5614,7 @@ def team_workout_upload_view(request,message="", w = Workout.objects.get(id=id) r = getrower(request.user) - if (make_plot): + if (make_plot): # pragma: no cover id,jobid = uploads.make_plot(r,w,f1,f2,plottype,t) elif r.staticchartonupload: plottype = r.staticchartonupload @@ -5647,7 +5647,7 @@ def team_workout_upload_view(request,message="", ).exclude( rowerplan='freecoach' ).distinct() - if r.rowerplan == 'freecoach': + if r.rowerplan == 'freecoach': # pragma: no cover rowers = rowers.exclude(rowerplan='basic') rowerform.fields['user'].queryset = User.objects.filter(rower__in=rowers).distinct() @@ -5673,7 +5673,7 @@ def list_videos(request,userid=0): r = getrequestrower(request,userid=userid) workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime") query = request.GET.get('q') - if query: + if query: # pragma: no cover query_list = query.split() if query: query_list = query.split() @@ -5695,7 +5695,7 @@ def list_videos(request,userid=0): try: g = paginator.page(page) - except EmptyPage: + except EmptyPage: # pragma: no cover g = paginator.page(paginator.num_pages) return render(request, 'list_videos.html', @@ -5712,7 +5712,7 @@ def graphs_view(request,userid=0): r = getrequestrower(request,userid=userid) workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime") query = request.GET.get('q') - if query: + if query: # pragma: no cover query_list = query.split() workouts = workouts.filter( reduce(operator.and_, @@ -5734,7 +5734,7 @@ def graphs_view(request,userid=0): g = paginator.page(page) except PageNotAnInteger: g = paginator.page(1) - except EmptyPage: + except EmptyPage: # pragma: no cover g = paginator.page(paginator.num_pages) return render(request, 'list_graphs.html', @@ -5751,7 +5751,7 @@ def graphs_view(request,userid=0): def graph_show_view(request,id): try: g = GraphImage.objects.get(id=id) - try: + try: # pragma: no cover width,height = Image.open(g.filename).size g.width = width g.height = height @@ -5787,9 +5787,9 @@ def graph_show_view(request,id): 'active':'nav-workouts', 'rower':r,}) - except GraphImage.DoesNotExist: + except GraphImage.DoesNotExist: # pragma: no cover raise Http404("This graph doesn't exist") - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover raise Http404("This workout doesn't exist") # Restore original stroke data and summary @@ -5888,13 +5888,13 @@ def workout_split_view(request,id=0): messages.error(request,"Something went wrong in Split") - if request.user == r: + if request.user == r: # pragma: no cover url = reverse('workouts_view') else: mgrids = [team.id for team in Team.objects.filter(manager=request.user)] rwrids = [team.id for team in r.team.all()] teamids = list(set(mgrids) & set(rwrids)) - if len(teamids) > 0: + if len(teamids) > 0: # pragma: no cover teamid = teamids[0] url = reverse('workouts_view', @@ -5907,9 +5907,9 @@ def workout_split_view(request,id=0): rowname = row.name try: - if isinstance(rowname,unicode): + if isinstance(rowname,unicode): # pragma: no cover rowname = rowname.encode('utf8') - elif isinstance(rowname, str): + elif isinstance(rowname, str): # pragma: no cover rowname = rowname.decode('utf8') except: pass @@ -5947,7 +5947,7 @@ def workout_fusion_view(request,id1=0,id2=1): try: id1 = encoder.decode_hex(id1) id2 = encoder.decode_hex(id2) - except: + except: # pragma: no cover pass r = getrower(request.user) @@ -5957,9 +5957,9 @@ def workout_fusion_view(request,id1=0,id2=1): w2 = Workout.objects.get(id=id2) r = w1.user if (is_workout_user(request.user,w1)==False) or \ - (is_workout_user(request.user,w2)==False): + (is_workout_user(request.user,w2)==False): # pragma: no cover raise PermissionDenied("You are not allowed to use these workouts") - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover raise Http404("One of the workouts doesn't exist") if request.method == 'POST': @@ -5969,7 +5969,7 @@ def workout_fusion_view(request,id1=0,id2=1): columns = cd['columns'] timeoffset = cd['offset'] posneg = cd['posneg'] - if posneg == 'neg': + if posneg == 'neg': # pragma: no cover timeoffset = -timeoffset # Create DataFrame @@ -5980,7 +5980,7 @@ def workout_fusion_view(request,id1=0,id2=1): title='Fused data', parent=w1, forceunit=forceunit) - if message != None: + if message != None: # pragma: no cover messages.error(request,message) else: successmessage = 'Data fused' @@ -6124,12 +6124,12 @@ def workout_summary_edit_view(request,id,message="",successmessage="" try: normw = int(normw) - except ValueError: + except ValueError: # pragma: no cover normw = 100 try: normp = int(normp) - except ValueError: + except ValueError: # pragma: no cover normp = 100 data = { @@ -6160,7 +6160,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" s = cd["intervalstring"] try: rowdata.updateinterval_string(s) - except: + except: # pragma: no cover messages.error(request,'Parsing error') intervalstats = rowdata.allstats() itime,idist,itype = rowdata.intervalstats_values() @@ -6170,51 +6170,34 @@ def workout_summary_edit_view(request,id,message="",successmessage="" # we are saving the results obtained from the split by power/pace interpreter elif request.method == 'POST' and "savepowerpaceform" in request.POST: - try: - powerorpace = request.POST['powerorpace'] - except: - powerorpace = 'pace' - try: - value_pace = request.POST['value_pace'] - except: - value_pace = avpace - try: - value_power = request.POST['value_power'] - except: - value_power = int(normp) - try: - value_work = request.POST['value_work'] - except: - value_work = int(normw) - try: - value_spm = request.POST['value_spm'] - except: - value_spm = int(normspm) - try: - activeminutesmin = request.POST['activeminutesmin'] - except: - activeminutesmin = 0 + powerorpace = request.POST.get('powerorpace','pace') + value_pace = request.POST.get('value_pace',avpace) + value_power = request.POST.get('value_power',int(normp)) + value_work = request.POST.get('value_work',int(normw)) + value_spm = request.POST.get('value_spm',int(normspm)) + activeminutesmin = request.POST.get('activeminutesmin',0) + try: activeminutesmax = request.POST['activeminutesmax'] - except: + except: # pragma: no cover pass try: activesecondsmin = 60.*float(activeminutesmin) activesecondsmax = 60.*float(activeminutesmax) - except ValueError: + except ValueError: # pragma: no cover activesecondsmin = 0 activeminutesmin = 0 activeminutesmax = maxminutes activesecondsmax = rowdata.duration - if abs(rowdata.duration-activesecondsmax) < 60.: + if abs(rowdata.duration-activesecondsmax) < 60.: # pragma: no cover activesecondsmax = rowdata.duration if powerorpace == 'power': try: power = int(value_power) - except ValueError: + except ValueError: # pragma: no cover int(normp) - elif powerorpace == 'pace': + elif powerorpace == 'pace': # pragma: no cover try: pace_secs = float(value_pace) except ValueError: @@ -6222,12 +6205,12 @@ def workout_summary_edit_view(request,id,message="",successmessage="" pace_secs = float(value_pace.replace(',','.')) except ValueError: pace_secs = int(500./normv) - elif powerorpace == 'work': + elif powerorpace == 'work': # pragma: no cover try: work = int(value_work) except ValueError: work = int(normw) - elif powerorpace == 'spm': + elif powerorpace == 'spm': # pragma: no cover try: spm = int(value_spm) except ValueError: @@ -6240,9 +6223,9 @@ def workout_summary_edit_view(request,id,message="",successmessage="" debug=False,smoothwindow=15., activewindow=[activesecondsmin,activesecondsmax], ) - except: + except: # pragma: no cover messages.error(request,'Error updating power') - elif powerorpace == 'pace': + elif powerorpace == 'pace': # pragma: no cover try: velo = 500./pace_secs rowdata.updateinterval_metric( @@ -6252,7 +6235,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" ) except: messages.error(request,'Error updating pace') - elif powerorpace == 'work': + elif powerorpace == 'work': # pragma: no cover try: rowdata.updateinterval_metric( 'driveenergy',work,mode='larger', @@ -6261,7 +6244,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" ) except: messages.error(request,'Error updating Work per Stroke') - elif powerorpace == 'spm': + elif powerorpace == 'spm': # pragma: no cover try: rowdata.updateinterval_metric( ' Cadence (stokes/min)',spm,mode='larger', @@ -6307,7 +6290,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" s = request.POST["savestringform"] try: rowdata.updateinterval_string(s) - except (ParseException,err): + except (ParseException,err): # pragma: no cover messages.error(request,'Parsing error in column '+str(err.col)) intervalstats = rowdata.allstats() @@ -6321,7 +6304,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" n = row.notes, s = s ) - except TypeError: + except TypeError: # pragma: no cover pass row.save() @@ -6355,11 +6338,11 @@ def workout_summary_edit_view(request,id,message="",successmessage="" activeminutesmax = cd['activeminutesmax'] activesecondsmin = 60.*activeminutesmin activesecondsmax = 60.*activeminutesmax - if abs(rowdata.duration-activesecondsmax) < 60.: + if abs(rowdata.duration-activesecondsmax) < 60.: # pragma: no cover activesecondsmax = rowdata.duration try: pace_secs = pace.seconds+pace.microseconds/1.0e6 - except AttributeError: + except AttributeError: # pragma: no cover pace_secs = 120. if powerorpace == 'power' and power is not None: @@ -6368,7 +6351,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" activewindow=[activesecondsmin,activesecondsmax], ) - elif powerorpace == 'pace': + elif powerorpace == 'pace': # pragma: no cover try: velo = 500./pace_secs rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',velo,mode='larger', @@ -6377,7 +6360,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" ) except: messages.error(request,'Error updating pace') - elif powerorpace == 'work': + elif powerorpace == 'work': # pragma: no cover try: rowdata.updateinterval_metric( 'driveenergy',work,mode='larger', @@ -6385,7 +6368,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" activewindow=[activesecondsmin,activesecondsmax],) except: messages.error(request,'Error updating Work per Stroke') - elif powerorpace == 'spm': + elif powerorpace == 'spm': # pragma: no cover try: rowdata.updateinterval_metric(' Cadence (stokes/min)',spm,mode='larger', debug=False,smoothwindow=2., @@ -6415,7 +6398,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" form = SummaryStringForm() # we are saving the results obtained from the detailed form - elif request.method == 'POST' and "savedetailform" in request.POST: + elif request.method == 'POST' and "savedetailform" in request.POST: # pragma: no cover savebutton = 'savedetailform' form = SummaryStringForm() nrintervals = int(request.POST['nrintervals']) @@ -6481,7 +6464,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" # we are processing the details form - elif request.method == 'POST' and "nrintervals" in request.POST: + elif request.method == 'POST' and "nrintervals" in request.POST: # pragma: no cover savebutton = 'savedetailform' nrintervals = int(request.POST['nrintervals']) detailform = IntervalUpdateForm(request.POST,aantal=nrintervals) @@ -6533,7 +6516,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" initial['intervald_%s' % i] = idist[i] initial['intervalt_%s' % i] = get_time(itime[i]) initial['type_%s' % i] = itype[i] - except IndexError: + except IndexError: # pragma: no cover pass @@ -6552,7 +6535,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" res = interactive_chart(encoder.decode_hex(id),promember=1,intervaldata=intervaldata) script = res[0] div = res[1] - except ValueError: + except ValueError: # pragma: no cover script = '' div = '' @@ -6620,14 +6603,14 @@ class VideoDelete(DeleteView): w = self.object.workout try: w = Workout.objects.get(id=w.id) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover return reverse('workouts_view') return reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)}) def get_object(self, *args, **kwargs): obj = super(VideoDelete, self).get_object(*args, **kwargs) - if not is_coach_user(self.request.user,obj.workout.user): + if not is_coach_user(self.request.user,obj.workout.user.user): # pragma: no cover raise PermissionDenied('You are not allowed to delete this analysis') return obj @@ -6673,7 +6656,7 @@ class GraphDelete(DeleteView): w = self.object.workout try: w = Workout.objects.get(id=w.id) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover return reverse('workouts_view') return reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)}) @@ -6681,21 +6664,11 @@ class GraphDelete(DeleteView): def get_object(self, *args, **kwargs): obj = super(GraphDelete, self).get_object(*args, **kwargs) - if not is_workout_user(self.request.user,obj.workout): + if not is_workout_user(self.request.user,obj.workout): # pragma: no cover raise PermissionDenied('You are not allowed to delete this chart') return obj -def workout_code_delete_view(request,id=0): - pk = encoder.decode_hex(id) - - try: - w = Workout.objects.get(pk=pk) - url = reverse('workout_delete',kwargs={'pk':pk}) - except Workout.DoesNotExist: - url = reverse('workout_delete',kwargs={'pk':id}) - - return HttpResponseRedirect(url) class WorkoutDelete(PermissionRequiredMixin,DeleteView): login_required = True @@ -6753,7 +6726,7 @@ class WorkoutDelete(PermissionRequiredMixin,DeleteView): workout_pk = encoder.decode_hex(workout_pk) try: obj = Workout.objects.get(pk=workout_pk) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover raise Http404("One of the workouts doesn't exist") # obj = super(WorkoutDelete, self).get_object(*args, **kwargs) From 196548fdccceca06246e5abf1867cdc6007efd22 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 14 Apr 2021 10:00:14 +0200 Subject: [PATCH 10/17] staticfiles to static --- cvkbrno/templates/cvkbrno_boat_add_form.html | 2 +- cvkbrno/templates/cvkbrno_boat_delete_confirm.html | 2 +- cvkbrno/templates/cvkbrno_boat_edit_form.html | 2 +- cvkbrno/templates/cvkbrno_boats_admin.html | 2 +- cvkbrno/templates/cvkbrno_categories_admin.html | 2 +- cvkbrno/templates/cvkbrno_categories_delete_confirm.html | 2 +- cvkbrno/templates/cvkbrno_categories_edit_form.html | 2 +- cvkbrno/templates/cvkbrno_category_add_form.html | 2 +- cvkbrno/templates/cvkbrno_member_add_form.html | 2 +- cvkbrno/templates/cvkbrno_member_edit_form.html | 2 +- cvkbrno/templates/cvkbrno_members_admin.html | 2 +- cvkbrno/templates/cvkbrno_members_delete_confirm.html | 2 +- cvkbrno/templates/cvkbrno_memberswork_add_form.html | 2 +- cvkbrno/templates/cvkbrno_memberswork_admin.html | 2 +- cvkbrno/templates/cvkbrno_memberwork_edit_form.html | 2 +- cvkbrno/templates/cvkbrno_meterboard.html | 2 +- cvkbrno/templates/cvkbrno_outing_admin.html | 2 +- cvkbrno/templates/cvkbrno_outing_closeform.html | 2 +- cvkbrno/templates/cvkbrno_outing_form.html | 2 +- cvkbrno/templates/cvkbrno_races_form.html | 2 +- cvkbrno/templates/cvkbrno_races_list.html | 2 +- cvkbrno/templates/cvkbrno_reservation_form.html | 2 +- cvkbrno/templates/cvkbrno_setlanguage.html | 2 +- rowers/templates/add_instantplan.html | 2 +- rowers/templates/add_result.html | 2 +- rowers/templates/agegroupchart.html | 2 +- rowers/templates/agegroupcp.html | 2 +- rowers/templates/alert_create.html | 2 +- rowers/templates/alert_delete_confirm.html | 2 +- rowers/templates/alert_edit.html | 2 +- rowers/templates/alert_stats.html | 2 +- rowers/templates/alerts.html | 2 +- rowers/templates/analysis.html | 2 +- rowers/templates/async_tasks.html | 2 +- rowers/templates/boxplot.html | 2 +- rowers/templates/c2_list_import.html | 2 +- rowers/templates/c2_list_import2.html | 2 +- rowers/templates/cn_form.html | 2 +- rowers/templates/comparison_list.html | 2 +- rowers/templates/course_edit_view.html | 2 +- rowers/templates/course_form.html | 2 +- rowers/templates/course_form_update.html | 2 +- rowers/templates/course_replace.html | 2 +- rowers/templates/course_replace_confirm.html | 2 +- rowers/templates/course_view.html | 2 +- rowers/templates/coursemap.html | 2 +- rowers/templates/cum_flex.html | 2 +- rowers/templates/cumstats.html | 2 +- rowers/templates/dashboard.html | 2 +- rowers/templates/disqualification_view.html | 2 +- rowers/templates/document_form.html | 2 +- rowers/templates/dropathleteconfirm.html | 2 +- rowers/templates/dropcoachconfirm.html | 2 +- rowers/templates/embedded_video.html | 2 +- rowers/templates/embedded_video_mini.html | 2 +- rowers/templates/empower_fix.html | 2 +- rowers/templates/entryedit.html | 2 +- rowers/templates/export.html | 2 +- rowers/templates/export_workouts.html | 2 +- rowers/templates/failed_jobs.html | 2 +- rowers/templates/fastestvirtualeventcreate.html | 2 +- rowers/templates/fitnessfit.html | 2 +- rowers/templates/fitnessmetric.html | 2 +- rowers/templates/flexchart3otw.html | 2 +- rowers/templates/flexchartstacked.html | 2 +- rowers/templates/followerform.html | 2 +- rowers/templates/forcecurve_single.html | 2 +- rowers/templates/freecoach_registration_form.html | 2 +- rowers/templates/frontpage.html | 2 +- rowers/templates/frontpageblogs.html | 2 +- rowers/templates/fusion.html | 2 +- rowers/templates/fusion_list.html | 2 +- rowers/templates/gdpr_optin.html | 2 +- rowers/templates/goldmedalscores.html | 2 +- rowers/templates/graphimage_delete_confirm.html | 2 +- rowers/templates/help.html | 2 +- rowers/templates/histo.html | 2 +- rowers/templates/histo_single.html | 2 +- rowers/templates/history.html | 2 +- rowers/templates/image_form.html | 2 +- rowers/templates/image_page.html | 2 +- rowers/templates/indoorvirtualeventcreate.html | 2 +- rowers/templates/instantplan.html | 2 +- rowers/templates/instantplans.html | 2 +- rowers/templates/instroke.html | 2 +- rowers/templates/laboratory.html | 2 +- rowers/templates/list_courses.html | 2 +- rowers/templates/list_graphs.html | 2 +- rowers/templates/list_standards.html | 2 +- rowers/templates/list_videos.html | 2 +- rowers/templates/list_workouts.html | 2 +- rowers/templates/logo_form.html | 2 +- rowers/templates/manualadd.html | 2 +- rowers/templates/map_view.html | 2 +- rowers/templates/mapcompare.html | 2 +- rowers/templates/menu_analytics.html | 2 +- rowers/templates/menu_other.html | 2 +- rowers/templates/menu_payments.html | 2 +- rowers/templates/menu_plan.html | 2 +- rowers/templates/menu_profile.html | 2 +- rowers/templates/menu_teams.html | 2 +- rowers/templates/menu_workouts.html | 2 +- rowers/templates/menublogs.html | 2 +- rowers/templates/multicompare.html | 2 +- rowers/templates/multiflex.html | 2 +- rowers/templates/newchallengechoice.html | 2 +- rowers/templates/nk_list_import.html | 2 +- rowers/templates/oterankings.html | 2 +- rowers/templates/otwgeeky.html | 2 +- rowers/templates/otwinteractive.html | 2 +- rowers/templates/otwrankings.html | 2 +- rowers/templates/otwsetpower.html | 2 +- rowers/templates/performancemanager.html | 2 +- rowers/templates/plannedsession_comments.html | 2 +- rowers/templates/plannedsession_message.html | 2 +- rowers/templates/plannedsession_multicreate.html | 2 +- rowers/templates/plannedsessioncreate.html | 2 +- rowers/templates/plannedsessiondeleteconfirm.html | 2 +- rowers/templates/plannedsessionedit.html | 2 +- rowers/templates/plannedsessions.html | 2 +- rowers/templates/plannedsessions_multiclone_select.html | 2 +- rowers/templates/plannedsessions_print.html | 2 +- rowers/templates/plannedsessionscoach.html | 2 +- rowers/templates/plannedsessionscoach2.html | 2 +- rowers/templates/plannedsessionsmanage.html | 2 +- rowers/templates/plannedsessionteamcreate.html | 2 +- rowers/templates/plannedsessionteamedit.html | 2 +- rowers/templates/plannedsessiontemplatecreate.html | 2 +- rowers/templates/plannedsessiontemplateedit.html | 2 +- rowers/templates/plannedsessionview.html | 2 +- rowers/templates/polar_list_import.html | 2 +- rowers/templates/race_submit.html | 2 +- rowers/templates/rankings.html | 2 +- rowers/templates/redesign.html | 2 +- rowers/templates/redesign_analysis.html | 2 +- rowers/templates/redesign_plan.html | 2 +- rowers/templates/redesign_profile.html | 2 +- rowers/templates/redesign_racing.html | 2 +- rowers/templates/redesign_teams.html | 2 +- rowers/templates/redesign_workout.html | 2 +- rowers/templates/redesign_workouts.html | 2 +- rowers/templates/registration_form.html | 2 +- rowers/templates/rower_form.html | 2 +- rowers/templates/rower_preferences.html | 2 +- rowers/templates/rp3_list_import.html | 2 +- rowers/templates/runkeeper_list_import.html | 2 +- rowers/templates/share.html | 2 +- rowers/templates/show_graph.html | 2 +- rowers/templates/splitworkout.html | 2 +- rowers/templates/sporttracks_list_import.html | 2 +- rowers/templates/standard_form.html | 2 +- rowers/templates/standard_view.html | 2 +- rowers/templates/strava_list_import.html | 2 +- rowers/templates/streamedit.html | 2 +- rowers/templates/summary_edit.html | 2 +- rowers/templates/survey.html | 2 +- rowers/templates/survey2.html | 2 +- rowers/templates/team_compare_select.html | 2 +- rowers/templates/team_document_form.html | 2 +- rowers/templates/teamcreate.html | 2 +- rowers/templates/teamdeleteconfirm.html | 2 +- rowers/templates/teamedit.html | 2 +- rowers/templates/teamleaveconfirm.html | 2 +- rowers/templates/templatelibrary.html | 2 +- rowers/templates/trainingplan.html | 2 +- rowers/templates/trainingplan2.html | 2 +- rowers/templates/trainingplan_chart.html | 2 +- rowers/templates/trainingplan_create.html | 2 +- rowers/templates/trainingplan_delete.html | 2 +- rowers/templates/trainingplan_edit.html | 2 +- rowers/templates/transactions.html | 2 +- rowers/templates/underarmour_list_import.html | 2 +- rowers/templates/user_analysis_select.html | 2 +- rowers/templates/user_boxplot_select.html | 2 +- rowers/templates/user_multiflex_select.html | 2 +- rowers/templates/userprofile_deactivate.html | 2 +- rowers/templates/userprofile_delete.html | 2 +- rowers/templates/video_delete_confirm.html | 2 +- rowers/templates/video_selectworkout.html | 2 +- rowers/templates/virtualevent.html | 2 +- rowers/templates/virtualeventcreate.html | 2 +- rowers/templates/virtualeventedit.html | 2 +- rowers/templates/virtualeventranking.html | 2 +- rowers/templates/virtualeventregister.html | 2 +- rowers/templates/virtualevents.html | 2 +- rowers/templates/waiting_page.html | 2 +- rowers/templates/windedit.html | 2 +- rowers/templates/withdraw_view.html | 2 +- rowers/templates/workflow.html | 2 +- rowers/templates/workout_comments.html | 2 +- rowers/templates/workout_data.html | 2 +- rowers/templates/workout_delete_confirm.html | 2 +- rowers/templates/workout_erase_column.html | 2 +- rowers/templates/workout_form.html | 2 +- rowers/templates/workout_join_select.html | 2 +- rowers/templates/workout_remove_power_confirm.html | 2 +- rowers/templates/workout_view.html | 2 +- rowers/templates/workoutstats.html | 2 +- rowers/tests/test_aworkouts.py | 8 ++++++-- rowers/views/workoutviews.py | 2 ++ templates/400.html | 2 +- templates/403.html | 2 +- templates/404.html | 2 +- templates/500.html | 2 +- templates/502.html | 2 +- templates/analysismenu.html | 2 +- 206 files changed, 212 insertions(+), 206 deletions(-) diff --git a/cvkbrno/templates/cvkbrno_boat_add_form.html b/cvkbrno/templates/cvkbrno_boat_add_form.html index 9cb2478b..9327fabd 100644 --- a/cvkbrno/templates/cvkbrno_boat_add_form.html +++ b/cvkbrno/templates/cvkbrno_boat_add_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Create Boat" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_boat_delete_confirm.html b/cvkbrno/templates/cvkbrno_boat_delete_confirm.html index 351a4293..7f032a70 100644 --- a/cvkbrno/templates/cvkbrno_boat_delete_confirm.html +++ b/cvkbrno/templates/cvkbrno_boat_delete_confirm.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} diff --git a/cvkbrno/templates/cvkbrno_boat_edit_form.html b/cvkbrno/templates/cvkbrno_boat_edit_form.html index 52e08559..1a74b248 100644 --- a/cvkbrno/templates/cvkbrno_boat_edit_form.html +++ b/cvkbrno/templates/cvkbrno_boat_edit_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Edit Boat" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_boats_admin.html b/cvkbrno/templates/cvkbrno_boats_admin.html index a9598bf6..972bdc56 100644 --- a/cvkbrno/templates/cvkbrno_boats_admin.html +++ b/cvkbrno/templates/cvkbrno_boats_admin.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Boats Admin" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_categories_admin.html b/cvkbrno/templates/cvkbrno_categories_admin.html index d1f245a2..3d6d24ae 100644 --- a/cvkbrno/templates/cvkbrno_categories_admin.html +++ b/cvkbrno/templates/cvkbrno_categories_admin.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Boat Category Admin" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_categories_delete_confirm.html b/cvkbrno/templates/cvkbrno_categories_delete_confirm.html index d9415b2b..a4b1aca1 100644 --- a/cvkbrno/templates/cvkbrno_categories_delete_confirm.html +++ b/cvkbrno/templates/cvkbrno_categories_delete_confirm.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Delete Boat Category" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_categories_edit_form.html b/cvkbrno/templates/cvkbrno_categories_edit_form.html index 29715c8a..fba0ee92 100644 --- a/cvkbrno/templates/cvkbrno_categories_edit_form.html +++ b/cvkbrno/templates/cvkbrno_categories_edit_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Edit Category" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_category_add_form.html b/cvkbrno/templates/cvkbrno_category_add_form.html index 697e89f5..655bc4ff 100644 --- a/cvkbrno/templates/cvkbrno_category_add_form.html +++ b/cvkbrno/templates/cvkbrno_category_add_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Create Category" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_member_add_form.html b/cvkbrno/templates/cvkbrno_member_add_form.html index 9f035086..673467f6 100644 --- a/cvkbrno/templates/cvkbrno_member_add_form.html +++ b/cvkbrno/templates/cvkbrno_member_add_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Create Member" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_member_edit_form.html b/cvkbrno/templates/cvkbrno_member_edit_form.html index fa3e6ae7..f1aed60b 100644 --- a/cvkbrno/templates/cvkbrno_member_edit_form.html +++ b/cvkbrno/templates/cvkbrno_member_edit_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Edit Member" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_members_admin.html b/cvkbrno/templates/cvkbrno_members_admin.html index a9c24caa..7f83aa51 100644 --- a/cvkbrno/templates/cvkbrno_members_admin.html +++ b/cvkbrno/templates/cvkbrno_members_admin.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Members Admin" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_members_delete_confirm.html b/cvkbrno/templates/cvkbrno_members_delete_confirm.html index 414a9c87..11b360e9 100644 --- a/cvkbrno/templates/cvkbrno_members_delete_confirm.html +++ b/cvkbrno/templates/cvkbrno_members_delete_confirm.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Delete Member" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_memberswork_add_form.html b/cvkbrno/templates/cvkbrno_memberswork_add_form.html index f5f3c004..831fb127 100644 --- a/cvkbrno/templates/cvkbrno_memberswork_add_form.html +++ b/cvkbrno/templates/cvkbrno_memberswork_add_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Create Members Work" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_memberswork_admin.html b/cvkbrno/templates/cvkbrno_memberswork_admin.html index f2af7385..3414bc23 100644 --- a/cvkbrno/templates/cvkbrno_memberswork_admin.html +++ b/cvkbrno/templates/cvkbrno_memberswork_admin.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Members Work Admin" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_memberwork_edit_form.html b/cvkbrno/templates/cvkbrno_memberwork_edit_form.html index 8a4baf4b..c27ccfeb 100644 --- a/cvkbrno/templates/cvkbrno_memberwork_edit_form.html +++ b/cvkbrno/templates/cvkbrno_memberwork_edit_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Edit Member Work" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_meterboard.html b/cvkbrno/templates/cvkbrno_meterboard.html index 618914de..b88b3120 100644 --- a/cvkbrno/templates/cvkbrno_meterboard.html +++ b/cvkbrno/templates/cvkbrno_meterboard.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Meterboard" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_outing_admin.html b/cvkbrno/templates/cvkbrno_outing_admin.html index 6d702066..6dbccf9b 100644 --- a/cvkbrno/templates/cvkbrno_outing_admin.html +++ b/cvkbrno/templates/cvkbrno_outing_admin.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load filter %} {% load tz %} diff --git a/cvkbrno/templates/cvkbrno_outing_closeform.html b/cvkbrno/templates/cvkbrno_outing_closeform.html index 02bb3cf1..a6b38809 100644 --- a/cvkbrno/templates/cvkbrno_outing_closeform.html +++ b/cvkbrno/templates/cvkbrno_outing_closeform.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Return from outing" %} diff --git a/cvkbrno/templates/cvkbrno_outing_form.html b/cvkbrno/templates/cvkbrno_outing_form.html index d10da855..6c04a751 100644 --- a/cvkbrno/templates/cvkbrno_outing_form.html +++ b/cvkbrno/templates/cvkbrno_outing_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/cvkbrno/templates/cvkbrno_races_form.html b/cvkbrno/templates/cvkbrno_races_form.html index 7c0b7ab9..cd6b343e 100644 --- a/cvkbrno/templates/cvkbrno_races_form.html +++ b/cvkbrno/templates/cvkbrno_races_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Create Races Event" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_races_list.html b/cvkbrno/templates/cvkbrno_races_list.html index 48aa8cd6..8fcd3393 100644 --- a/cvkbrno/templates/cvkbrno_races_list.html +++ b/cvkbrno/templates/cvkbrno_races_list.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{% trans "Races Admin" %}{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_reservation_form.html b/cvkbrno/templates/cvkbrno_reservation_form.html index 50dbfa56..d7a45bbe 100644 --- a/cvkbrno/templates/cvkbrno_reservation_form.html +++ b/cvkbrno/templates/cvkbrno_reservation_form.html @@ -1,6 +1,6 @@ {% extends "cvkbrnobase.html" %} {% load i18n %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/cvkbrno/templates/cvkbrno_setlanguage.html b/cvkbrno/templates/cvkbrno_setlanguage.html index 9f93455d..d05f741e 100644 --- a/cvkbrno/templates/cvkbrno_setlanguage.html +++ b/cvkbrno/templates/cvkbrno_setlanguage.html @@ -1,5 +1,5 @@ {% extends "cvkbrnobase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Jdu na vodu {% endblock %} diff --git a/rowers/templates/add_instantplan.html b/rowers/templates/add_instantplan.html index 4fb4e298..7617ab23 100644 --- a/rowers/templates/add_instantplan.html +++ b/rowers/templates/add_instantplan.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Add Instant Plan{% endblock %} diff --git a/rowers/templates/add_result.html b/rowers/templates/add_result.html index d0fa8aa7..45082bec 100644 --- a/rowers/templates/add_result.html +++ b/rowers/templates/add_result.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Here's your result{% endblock %} diff --git a/rowers/templates/agegroupchart.html b/rowers/templates/agegroupchart.html index e7e499db..6d4d01df 100644 --- a/rowers/templates/agegroupchart.html +++ b/rowers/templates/agegroupchart.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Age Group Records{% endblock %} diff --git a/rowers/templates/agegroupcp.html b/rowers/templates/agegroupcp.html index 253eff4f..2308f5fb 100644 --- a/rowers/templates/agegroupcp.html +++ b/rowers/templates/agegroupcp.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Age Group CP{% endblock %} diff --git a/rowers/templates/alert_create.html b/rowers/templates/alert_create.html index d2d5da48..9940fa8e 100644 --- a/rowers/templates/alert_create.html +++ b/rowers/templates/alert_create.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Metric Alert{% endblock %} diff --git a/rowers/templates/alert_delete_confirm.html b/rowers/templates/alert_delete_confirm.html index dc9a5417..8871a27d 100644 --- a/rowers/templates/alert_delete_confirm.html +++ b/rowers/templates/alert_delete_confirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Planned Session{% endblock %} diff --git a/rowers/templates/alert_edit.html b/rowers/templates/alert_edit.html index 7849f3b4..04f92ce2 100644 --- a/rowers/templates/alert_edit.html +++ b/rowers/templates/alert_edit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Metric Alert{% endblock %} diff --git a/rowers/templates/alert_stats.html b/rowers/templates/alert_stats.html index 94cb4294..22d0492e 100644 --- a/rowers/templates/alert_stats.html +++ b/rowers/templates/alert_stats.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Metric Alert{% endblock %} diff --git a/rowers/templates/alerts.html b/rowers/templates/alerts.html index 1ac3b2dc..b6830a63 100644 --- a/rowers/templates/alerts.html +++ b/rowers/templates/alerts.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall - Analysis {% endblock %} diff --git a/rowers/templates/analysis.html b/rowers/templates/analysis.html index 68579114..d77796f8 100644 --- a/rowers/templates/analysis.html +++ b/rowers/templates/analysis.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall - Analysis {% endblock %} diff --git a/rowers/templates/async_tasks.html b/rowers/templates/async_tasks.html index 83c916f0..524f621a 100644 --- a/rowers/templates/async_tasks.html +++ b/rowers/templates/async_tasks.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall - Tasks {% endblock %} diff --git a/rowers/templates/boxplot.html b/rowers/templates/boxplot.html index e5574916..7f8bd9db 100644 --- a/rowers/templates/boxplot.html +++ b/rowers/templates/boxplot.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Box Plot {% endblock %} diff --git a/rowers/templates/c2_list_import.html b/rowers/templates/c2_list_import.html index 69a81cc7..e8015401 100644 --- a/rowers/templates/c2_list_import.html +++ b/rowers/templates/c2_list_import.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/c2_list_import2.html b/rowers/templates/c2_list_import2.html index 5e1ffa68..42bae8e7 100644 --- a/rowers/templates/c2_list_import2.html +++ b/rowers/templates/c2_list_import2.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/cn_form.html b/rowers/templates/cn_form.html index 5a32d235..5523eb51 100644 --- a/rowers/templates/cn_form.html +++ b/rowers/templates/cn_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}CrewNerd Summary loading{% endblock %} diff --git a/rowers/templates/comparison_list.html b/rowers/templates/comparison_list.html index 804fd6b9..354257d0 100644 --- a/rowers/templates/comparison_list.html +++ b/rowers/templates/comparison_list.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/course_edit_view.html b/rowers/templates/course_edit_view.html index 797a2924..58b2cb64 100644 --- a/rowers/templates/course_edit_view.html +++ b/rowers/templates/course_edit_view.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/course_form.html b/rowers/templates/course_form.html index 1c5b25b6..f5d92337 100644 --- a/rowers/templates/course_form.html +++ b/rowers/templates/course_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}File loading{% endblock %} diff --git a/rowers/templates/course_form_update.html b/rowers/templates/course_form_update.html index 7a5dca80..7ba554cc 100644 --- a/rowers/templates/course_form_update.html +++ b/rowers/templates/course_form_update.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}File loading{% endblock %} diff --git a/rowers/templates/course_replace.html b/rowers/templates/course_replace.html index 17ad92c4..53569c1f 100644 --- a/rowers/templates/course_replace.html +++ b/rowers/templates/course_replace.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/course_replace_confirm.html b/rowers/templates/course_replace_confirm.html index b0b010c4..965b9180 100644 --- a/rowers/templates/course_replace_confirm.html +++ b/rowers/templates/course_replace_confirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/course_view.html b/rowers/templates/course_view.html index b7c9da70..06c3a1ec 100644 --- a/rowers/templates/course_view.html +++ b/rowers/templates/course_view.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/coursemap.html b/rowers/templates/coursemap.html index b5b162e6..d926f731 100644 --- a/rowers/templates/coursemap.html +++ b/rowers/templates/coursemap.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/cum_flex.html b/rowers/templates/cum_flex.html index c718372e..e78b002f 100644 --- a/rowers/templates/cum_flex.html +++ b/rowers/templates/cum_flex.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall {% endblock %} diff --git a/rowers/templates/cumstats.html b/rowers/templates/cumstats.html index 7841874a..7e5c5b83 100644 --- a/rowers/templates/cumstats.html +++ b/rowers/templates/cumstats.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall {% endblock %} diff --git a/rowers/templates/dashboard.html b/rowers/templates/dashboard.html index 1d3d0829..bfa4930d 100644 --- a/rowers/templates/dashboard.html +++ b/rowers/templates/dashboard.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} diff --git a/rowers/templates/disqualification_view.html b/rowers/templates/disqualification_view.html index bd1894b7..e0a984ee 100644 --- a/rowers/templates/disqualification_view.html +++ b/rowers/templates/disqualification_view.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block scripts %} {% include "monitorjobs.html" %} diff --git a/rowers/templates/document_form.html b/rowers/templates/document_form.html index b5dd35ba..2a6befb5 100644 --- a/rowers/templates/document_form.html +++ b/rowers/templates/document_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}File loading{% endblock %} diff --git a/rowers/templates/dropathleteconfirm.html b/rowers/templates/dropathleteconfirm.html index 73077b69..2e85294a 100644 --- a/rowers/templates/dropathleteconfirm.html +++ b/rowers/templates/dropathleteconfirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Remove Athlete {% endblock %} diff --git a/rowers/templates/dropcoachconfirm.html b/rowers/templates/dropcoachconfirm.html index 863c0e2c..b582aabb 100644 --- a/rowers/templates/dropcoachconfirm.html +++ b/rowers/templates/dropcoachconfirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Remove Coach {% endblock %} diff --git a/rowers/templates/embedded_video.html b/rowers/templates/embedded_video.html index 5543733b..0ff08fbe 100644 --- a/rowers/templates/embedded_video.html +++ b/rowers/templates/embedded_video.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load i18n %} {% load leaflet_tags %} diff --git a/rowers/templates/embedded_video_mini.html b/rowers/templates/embedded_video_mini.html index 20288285..db87e5ce 100644 --- a/rowers/templates/embedded_video_mini.html +++ b/rowers/templates/embedded_video_mini.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load i18n %} {% load leaflet_tags %} diff --git a/rowers/templates/empower_fix.html b/rowers/templates/empower_fix.html index 5fd1101e..9fbc66c3 100644 --- a/rowers/templates/empower_fix.html +++ b/rowers/templates/empower_fix.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Empower FIX{% endblock %} diff --git a/rowers/templates/entryedit.html b/rowers/templates/entryedit.html index fc1d5848..5adbce18 100644 --- a/rowers/templates/entryedit.html +++ b/rowers/templates/entryedit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Register for a Virtual Race{% endblock %} diff --git a/rowers/templates/export.html b/rowers/templates/export.html index 59c952e5..e28275c0 100644 --- a/rowers/templates/export.html +++ b/rowers/templates/export.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Export {% endblock %} diff --git a/rowers/templates/export_workouts.html b/rowers/templates/export_workouts.html index b45dc2f5..0addb835 100644 --- a/rowers/templates/export_workouts.html +++ b/rowers/templates/export_workouts.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Workouts Summary Export{% endblock %} diff --git a/rowers/templates/failed_jobs.html b/rowers/templates/failed_jobs.html index 42080a36..526fa5f3 100644 --- a/rowers/templates/failed_jobs.html +++ b/rowers/templates/failed_jobs.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Failed Que{% endblock %} diff --git a/rowers/templates/fastestvirtualeventcreate.html b/rowers/templates/fastestvirtualeventcreate.html index 7034c3f3..00eb120f 100644 --- a/rowers/templates/fastestvirtualeventcreate.html +++ b/rowers/templates/fastestvirtualeventcreate.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}New Virtual Challenge{% endblock %} diff --git a/rowers/templates/fitnessfit.html b/rowers/templates/fitnessfit.html index 8c15d925..010f8e09 100644 --- a/rowers/templates/fitnessfit.html +++ b/rowers/templates/fitnessfit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Fitness Progress {% endblock %} diff --git a/rowers/templates/fitnessmetric.html b/rowers/templates/fitnessmetric.html index 647f49be..c3a0a4d6 100644 --- a/rowers/templates/fitnessmetric.html +++ b/rowers/templates/fitnessmetric.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Fitness Progress {% endblock %} diff --git a/rowers/templates/flexchart3otw.html b/rowers/templates/flexchart3otw.html index d7fdf3af..bbae4c43 100644 --- a/rowers/templates/flexchart3otw.html +++ b/rowers/templates/flexchart3otw.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/rowers/templates/flexchartstacked.html b/rowers/templates/flexchartstacked.html index 665453ac..d44b9c33 100644 --- a/rowers/templates/flexchartstacked.html +++ b/rowers/templates/flexchartstacked.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/rowers/templates/followerform.html b/rowers/templates/followerform.html index 15b2231c..c64e5abc 100644 --- a/rowers/templates/followerform.html +++ b/rowers/templates/followerform.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/rowers/templates/forcecurve_single.html b/rowers/templates/forcecurve_single.html index ed7f9c5a..547b2bc5 100644 --- a/rowers/templates/forcecurve_single.html +++ b/rowers/templates/forcecurve_single.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/rowers/templates/freecoach_registration_form.html b/rowers/templates/freecoach_registration_form.html index a1746819..737ee4dc 100644 --- a/rowers/templates/freecoach_registration_form.html +++ b/rowers/templates/freecoach_registration_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}New Coach Registration{% endblock title %} {% block meta %} diff --git a/rowers/templates/frontpage.html b/rowers/templates/frontpage.html index dcd397c2..52f3a7c9 100644 --- a/rowers/templates/frontpage.html +++ b/rowers/templates/frontpage.html @@ -1,5 +1,5 @@ {% extends "newbasefront.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Rowing Data{% endblock %} diff --git a/rowers/templates/frontpageblogs.html b/rowers/templates/frontpageblogs.html index dd65e3ff..bc0e9eea 100644 --- a/rowers/templates/frontpageblogs.html +++ b/rowers/templates/frontpageblogs.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% for blog in blogposts %} diff --git a/rowers/templates/fusion.html b/rowers/templates/fusion.html index 89a11a4b..d5185cf8 100644 --- a/rowers/templates/fusion.html +++ b/rowers/templates/fusion.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/fusion_list.html b/rowers/templates/fusion_list.html index a1d1d497..84cb64d5 100644 --- a/rowers/templates/fusion_list.html +++ b/rowers/templates/fusion_list.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/gdpr_optin.html b/rowers/templates/gdpr_optin.html index a5a68a63..9e084f75 100644 --- a/rowers/templates/gdpr_optin.html +++ b/rowers/templates/gdpr_optin.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}GDPR Opt-In{% endblock %} diff --git a/rowers/templates/goldmedalscores.html b/rowers/templates/goldmedalscores.html index 2cd05773..020db44c 100644 --- a/rowers/templates/goldmedalscores.html +++ b/rowers/templates/goldmedalscores.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Gold Medal Score {% endblock %} diff --git a/rowers/templates/graphimage_delete_confirm.html b/rowers/templates/graphimage_delete_confirm.html index 8e8a6c02..d1f39b21 100644 --- a/rowers/templates/graphimage_delete_confirm.html +++ b/rowers/templates/graphimage_delete_confirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Delete Graph Image {% endblock %} diff --git a/rowers/templates/help.html b/rowers/templates/help.html index cf49d2f7..85f1b893 100644 --- a/rowers/templates/help.html +++ b/rowers/templates/help.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block main %} diff --git a/rowers/templates/histo.html b/rowers/templates/histo.html index be333c76..cbb641c7 100644 --- a/rowers/templates/histo.html +++ b/rowers/templates/histo.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall {% endblock %} diff --git a/rowers/templates/histo_single.html b/rowers/templates/histo_single.html index fce8843e..85539731 100644 --- a/rowers/templates/histo_single.html +++ b/rowers/templates/histo_single.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}View Workout {% endblock %} diff --git a/rowers/templates/history.html b/rowers/templates/history.html index e66e58ca..819b0ff5 100644 --- a/rowers/templates/history.html +++ b/rowers/templates/history.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall {% endblock %} diff --git a/rowers/templates/image_form.html b/rowers/templates/image_form.html index 43182ced..23804475 100644 --- a/rowers/templates/image_form.html +++ b/rowers/templates/image_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}File loading{% endblock %} diff --git a/rowers/templates/image_page.html b/rowers/templates/image_page.html index 96c34955..b56bd322 100644 --- a/rowers/templates/image_page.html +++ b/rowers/templates/image_page.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Here's your plot{% endblock %} diff --git a/rowers/templates/indoorvirtualeventcreate.html b/rowers/templates/indoorvirtualeventcreate.html index 8ec29004..336990c5 100644 --- a/rowers/templates/indoorvirtualeventcreate.html +++ b/rowers/templates/indoorvirtualeventcreate.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}New Virtual Challenge{% endblock %} diff --git a/rowers/templates/instantplan.html b/rowers/templates/instantplan.html index b581bd5d..5cfbe7fc 100644 --- a/rowers/templates/instantplan.html +++ b/rowers/templates/instantplan.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{{ plan.name }}{% endblock %} diff --git a/rowers/templates/instantplans.html b/rowers/templates/instantplans.html index 6382fbd5..6176d9b9 100644 --- a/rowers/templates/instantplans.html +++ b/rowers/templates/instantplans.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Training Plans{% endblock %} diff --git a/rowers/templates/instroke.html b/rowers/templates/instroke.html index 09282e17..10c526be 100644 --- a/rowers/templates/instroke.html +++ b/rowers/templates/instroke.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Advanced Features {% endblock %} diff --git a/rowers/templates/laboratory.html b/rowers/templates/laboratory.html index 41fe9cb0..15b27e02 100644 --- a/rowers/templates/laboratory.html +++ b/rowers/templates/laboratory.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall - Analysis {% endblock %} diff --git a/rowers/templates/list_courses.html b/rowers/templates/list_courses.html index bd99a4f7..bab2409f 100644 --- a/rowers/templates/list_courses.html +++ b/rowers/templates/list_courses.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Courses List{% endblock %} diff --git a/rowers/templates/list_graphs.html b/rowers/templates/list_graphs.html index 8daf3046..1dfa9d78 100644 --- a/rowers/templates/list_graphs.html +++ b/rowers/templates/list_graphs.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Recent Graphs{% endblock %} diff --git a/rowers/templates/list_standards.html b/rowers/templates/list_standards.html index b99ac07f..e30d8492 100644 --- a/rowers/templates/list_standards.html +++ b/rowers/templates/list_standards.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Course Standards List{% endblock %} diff --git a/rowers/templates/list_videos.html b/rowers/templates/list_videos.html index 4e1dfa33..748db1c1 100644 --- a/rowers/templates/list_videos.html +++ b/rowers/templates/list_videos.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Recent Video Analyses{% endblock %} diff --git a/rowers/templates/list_workouts.html b/rowers/templates/list_workouts.html index 991ff27a..21c5944d 100644 --- a/rowers/templates/list_workouts.html +++ b/rowers/templates/list_workouts.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Workouts List{% endblock %} diff --git a/rowers/templates/logo_form.html b/rowers/templates/logo_form.html index 9482267a..82929c99 100644 --- a/rowers/templates/logo_form.html +++ b/rowers/templates/logo_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}File loading{% endblock %} diff --git a/rowers/templates/manualadd.html b/rowers/templates/manualadd.html index 09a435f0..0ec7f110 100644 --- a/rowers/templates/manualadd.html +++ b/rowers/templates/manualadd.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/rowers/templates/map_view.html b/rowers/templates/map_view.html index 93d9677c..676aa566 100644 --- a/rowers/templates/map_view.html +++ b/rowers/templates/map_view.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/mapcompare.html b/rowers/templates/mapcompare.html index be79b5c3..4d219412 100644 --- a/rowers/templates/mapcompare.html +++ b/rowers/templates/mapcompare.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/menu_analytics.html b/rowers/templates/menu_analytics.html index 2bf2760f..0f12d35d 100644 --- a/rowers/templates/menu_analytics.html +++ b/rowers/templates/menu_analytics.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% load rowerfilters %}

    Analysis

      diff --git a/rowers/templates/menu_other.html b/rowers/templates/menu_other.html index a3961006..b565018e 100644 --- a/rowers/templates/menu_other.html +++ b/rowers/templates/menu_other.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% load rowerfilters %}

      Workouts

        diff --git a/rowers/templates/menu_payments.html b/rowers/templates/menu_payments.html index bad5cd53..7d280b5a 100644 --- a/rowers/templates/menu_payments.html +++ b/rowers/templates/menu_payments.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% load rowerfilters %}

        Profile

          diff --git a/rowers/templates/menu_plan.html b/rowers/templates/menu_plan.html index 765861fa..da163066 100644 --- a/rowers/templates/menu_plan.html +++ b/rowers/templates/menu_plan.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% load rowerfilters %}

          Plan

            diff --git a/rowers/templates/menu_profile.html b/rowers/templates/menu_profile.html index 692c1c97..7f357789 100644 --- a/rowers/templates/menu_profile.html +++ b/rowers/templates/menu_profile.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% load rowerfilters %}

            Profile

              diff --git a/rowers/templates/menu_teams.html b/rowers/templates/menu_teams.html index 8464df9f..9665d742 100644 --- a/rowers/templates/menu_teams.html +++ b/rowers/templates/menu_teams.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% load rowerfilters %}

              Teams

              diff --git a/rowers/templates/menu_workouts.html b/rowers/templates/menu_workouts.html index 73c22bdf..833e6fac 100644 --- a/rowers/templates/menu_workouts.html +++ b/rowers/templates/menu_workouts.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% load rowerfilters %}

              Workouts

                diff --git a/rowers/templates/menublogs.html b/rowers/templates/menublogs.html index dd65e3ff..bc0e9eea 100644 --- a/rowers/templates/menublogs.html +++ b/rowers/templates/menublogs.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% for blog in blogposts %} diff --git a/rowers/templates/multicompare.html b/rowers/templates/multicompare.html index df363159..6024d130 100644 --- a/rowers/templates/multicompare.html +++ b/rowers/templates/multicompare.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}View Comparison {% endblock %} diff --git a/rowers/templates/multiflex.html b/rowers/templates/multiflex.html index ea02452c..e9638577 100644 --- a/rowers/templates/multiflex.html +++ b/rowers/templates/multiflex.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}View Comparison {% endblock %} diff --git a/rowers/templates/newchallengechoice.html b/rowers/templates/newchallengechoice.html index b08c0395..6f56fd22 100644 --- a/rowers/templates/newchallengechoice.html +++ b/rowers/templates/newchallengechoice.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}New Virtual Challenge{% endblock %} diff --git a/rowers/templates/nk_list_import.html b/rowers/templates/nk_list_import.html index f8689b06..e97d711b 100644 --- a/rowers/templates/nk_list_import.html +++ b/rowers/templates/nk_list_import.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/oterankings.html b/rowers/templates/oterankings.html index 4fc7d4ac..76c07327 100644 --- a/rowers/templates/oterankings.html +++ b/rowers/templates/oterankings.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block scripts %} diff --git a/rowers/templates/otwgeeky.html b/rowers/templates/otwgeeky.html index 403be27d..4ed742ab 100644 --- a/rowers/templates/otwgeeky.html +++ b/rowers/templates/otwgeeky.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Advanced Features {% endblock %} diff --git a/rowers/templates/otwinteractive.html b/rowers/templates/otwinteractive.html index ef2d13da..5c5164cb 100644 --- a/rowers/templates/otwinteractive.html +++ b/rowers/templates/otwinteractive.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}View Workout {% endblock %} diff --git a/rowers/templates/otwrankings.html b/rowers/templates/otwrankings.html index 9e5184b8..bd0186b4 100644 --- a/rowers/templates/otwrankings.html +++ b/rowers/templates/otwrankings.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block scripts %} diff --git a/rowers/templates/otwsetpower.html b/rowers/templates/otwsetpower.html index c01631a4..8021191b 100644 --- a/rowers/templates/otwsetpower.html +++ b/rowers/templates/otwsetpower.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Advanced Features {% endblock %} diff --git a/rowers/templates/performancemanager.html b/rowers/templates/performancemanager.html index 9e336622..43a98877 100644 --- a/rowers/templates/performancemanager.html +++ b/rowers/templates/performancemanager.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Fitness Progress {% endblock %} diff --git a/rowers/templates/plannedsession_comments.html b/rowers/templates/plannedsession_comments.html index 1236e0c5..8060acf0 100644 --- a/rowers/templates/plannedsession_comments.html +++ b/rowers/templates/plannedsession_comments.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/rowers/templates/plannedsession_message.html b/rowers/templates/plannedsession_message.html index db759697..bfb0ca40 100644 --- a/rowers/templates/plannedsession_message.html +++ b/rowers/templates/plannedsession_message.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/rowers/templates/plannedsession_multicreate.html b/rowers/templates/plannedsession_multicreate.html index 66c761be..97bab57e 100644 --- a/rowers/templates/plannedsession_multicreate.html +++ b/rowers/templates/plannedsession_multicreate.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Plan entire microcycle{% endblock %} diff --git a/rowers/templates/plannedsessioncreate.html b/rowers/templates/plannedsessioncreate.html index b51ffed7..64c2bc6b 100644 --- a/rowers/templates/plannedsessioncreate.html +++ b/rowers/templates/plannedsessioncreate.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}New Planned Session{% endblock %} diff --git a/rowers/templates/plannedsessiondeleteconfirm.html b/rowers/templates/plannedsessiondeleteconfirm.html index f196304f..52ccd481 100644 --- a/rowers/templates/plannedsessiondeleteconfirm.html +++ b/rowers/templates/plannedsessiondeleteconfirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Planned Session{% endblock %} diff --git a/rowers/templates/plannedsessionedit.html b/rowers/templates/plannedsessionedit.html index 7f5ccd12..8ec4a578 100644 --- a/rowers/templates/plannedsessionedit.html +++ b/rowers/templates/plannedsessionedit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Update Planned Session{% endblock %} diff --git a/rowers/templates/plannedsessions.html b/rowers/templates/plannedsessions.html index d9ceb02d..2f9f48e8 100644 --- a/rowers/templates/plannedsessions.html +++ b/rowers/templates/plannedsessions.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Planned Sessions{% endblock %} diff --git a/rowers/templates/plannedsessions_multiclone_select.html b/rowers/templates/plannedsessions_multiclone_select.html index 674dd7a3..054618a3 100644 --- a/rowers/templates/plannedsessions_multiclone_select.html +++ b/rowers/templates/plannedsessions_multiclone_select.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/plannedsessions_print.html b/rowers/templates/plannedsessions_print.html index 63fba42d..901a82b1 100644 --- a/rowers/templates/plannedsessions_print.html +++ b/rowers/templates/plannedsessions_print.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Planned Sessions{% endblock %} diff --git a/rowers/templates/plannedsessionscoach.html b/rowers/templates/plannedsessionscoach.html index cc9a747a..0ff672f1 100644 --- a/rowers/templates/plannedsessionscoach.html +++ b/rowers/templates/plannedsessionscoach.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Planned Sessions{% endblock %} diff --git a/rowers/templates/plannedsessionscoach2.html b/rowers/templates/plannedsessionscoach2.html index 5c38503e..339dcc56 100644 --- a/rowers/templates/plannedsessionscoach2.html +++ b/rowers/templates/plannedsessionscoach2.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Planned Sessions{% endblock %} diff --git a/rowers/templates/plannedsessionsmanage.html b/rowers/templates/plannedsessionsmanage.html index fa78f7b1..6ec1c3fa 100644 --- a/rowers/templates/plannedsessionsmanage.html +++ b/rowers/templates/plannedsessionsmanage.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Planned Sessions{% endblock %} diff --git a/rowers/templates/plannedsessionteamcreate.html b/rowers/templates/plannedsessionteamcreate.html index 784f3881..46043c98 100644 --- a/rowers/templates/plannedsessionteamcreate.html +++ b/rowers/templates/plannedsessionteamcreate.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}New Planned Session{% endblock %} diff --git a/rowers/templates/plannedsessionteamedit.html b/rowers/templates/plannedsessionteamedit.html index 260af903..42ce3aed 100644 --- a/rowers/templates/plannedsessionteamedit.html +++ b/rowers/templates/plannedsessionteamedit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}New Planned Session{% endblock %} diff --git a/rowers/templates/plannedsessiontemplatecreate.html b/rowers/templates/plannedsessiontemplatecreate.html index 573dfdca..fbda21b5 100644 --- a/rowers/templates/plannedsessiontemplatecreate.html +++ b/rowers/templates/plannedsessiontemplatecreate.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Create Library Session{% endblock %} diff --git a/rowers/templates/plannedsessiontemplateedit.html b/rowers/templates/plannedsessiontemplateedit.html index 9fa47d07..d3c15a01 100644 --- a/rowers/templates/plannedsessiontemplateedit.html +++ b/rowers/templates/plannedsessiontemplateedit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Update Library Session{% endblock %} diff --git a/rowers/templates/plannedsessionview.html b/rowers/templates/plannedsessionview.html index 3a9e2ca3..21d57028 100644 --- a/rowers/templates/plannedsessionview.html +++ b/rowers/templates/plannedsessionview.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/polar_list_import.html b/rowers/templates/polar_list_import.html index 9e6a3817..f8754284 100644 --- a/rowers/templates/polar_list_import.html +++ b/rowers/templates/polar_list_import.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/race_submit.html b/rowers/templates/race_submit.html index f38bc57a..4eedefa6 100644 --- a/rowers/templates/race_submit.html +++ b/rowers/templates/race_submit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Submit challenge Result{% endblock %} diff --git a/rowers/templates/rankings.html b/rowers/templates/rankings.html index cc573e39..74591842 100644 --- a/rowers/templates/rankings.html +++ b/rowers/templates/rankings.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/redesign.html b/rowers/templates/redesign.html index 79779d35..69ac9321 100644 --- a/rowers/templates/redesign.html +++ b/rowers/templates/redesign.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block main %} diff --git a/rowers/templates/redesign_analysis.html b/rowers/templates/redesign_analysis.html index 20dfc9c7..17384d12 100644 --- a/rowers/templates/redesign_analysis.html +++ b/rowers/templates/redesign_analysis.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block main %} diff --git a/rowers/templates/redesign_plan.html b/rowers/templates/redesign_plan.html index 72057cd1..f33f1928 100644 --- a/rowers/templates/redesign_plan.html +++ b/rowers/templates/redesign_plan.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block main %} diff --git a/rowers/templates/redesign_profile.html b/rowers/templates/redesign_profile.html index 896712fa..2c82f205 100644 --- a/rowers/templates/redesign_profile.html +++ b/rowers/templates/redesign_profile.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block main %} diff --git a/rowers/templates/redesign_racing.html b/rowers/templates/redesign_racing.html index dacdee63..1d749333 100644 --- a/rowers/templates/redesign_racing.html +++ b/rowers/templates/redesign_racing.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block main %} diff --git a/rowers/templates/redesign_teams.html b/rowers/templates/redesign_teams.html index 46e03a4b..546f8059 100644 --- a/rowers/templates/redesign_teams.html +++ b/rowers/templates/redesign_teams.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block main %} diff --git a/rowers/templates/redesign_workout.html b/rowers/templates/redesign_workout.html index 669cd281..cc894544 100644 --- a/rowers/templates/redesign_workout.html +++ b/rowers/templates/redesign_workout.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block main %} diff --git a/rowers/templates/redesign_workouts.html b/rowers/templates/redesign_workouts.html index 3205bcc2..166c2208 100644 --- a/rowers/templates/redesign_workouts.html +++ b/rowers/templates/redesign_workouts.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block main %} diff --git a/rowers/templates/registration_form.html b/rowers/templates/registration_form.html index d7c27f4c..29328f81 100644 --- a/rowers/templates/registration_form.html +++ b/rowers/templates/registration_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}New User Registration{% endblock title %} {% block meta %} diff --git a/rowers/templates/rower_form.html b/rowers/templates/rower_form.html index 3097ab60..d83d8a59 100644 --- a/rowers/templates/rower_form.html +++ b/rowers/templates/rower_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Change Rower {% endblock %} diff --git a/rowers/templates/rower_preferences.html b/rowers/templates/rower_preferences.html index cce14a1f..28f27dc2 100644 --- a/rowers/templates/rower_preferences.html +++ b/rowers/templates/rower_preferences.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Change Rower Preferences{% endblock %} diff --git a/rowers/templates/rp3_list_import.html b/rowers/templates/rp3_list_import.html index 5827dda7..24404971 100644 --- a/rowers/templates/rp3_list_import.html +++ b/rowers/templates/rp3_list_import.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/runkeeper_list_import.html b/rowers/templates/runkeeper_list_import.html index 8af34266..d25a509d 100644 --- a/rowers/templates/runkeeper_list_import.html +++ b/rowers/templates/runkeeper_list_import.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/share.html b/rowers/templates/share.html index 4f8850a3..4abda35a 100644 --- a/rowers/templates/share.html +++ b/rowers/templates/share.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/show_graph.html b/rowers/templates/show_graph.html index c3a1a8b8..50ce40b0 100644 --- a/rowers/templates/show_graph.html +++ b/rowers/templates/show_graph.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}{{ workout.name }}{% endblock %} diff --git a/rowers/templates/splitworkout.html b/rowers/templates/splitworkout.html index 5c93f159..6a2994df 100644 --- a/rowers/templates/splitworkout.html +++ b/rowers/templates/splitworkout.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/rowers/templates/sporttracks_list_import.html b/rowers/templates/sporttracks_list_import.html index 8400d5ff..ef97b2fb 100644 --- a/rowers/templates/sporttracks_list_import.html +++ b/rowers/templates/sporttracks_list_import.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/standard_form.html b/rowers/templates/standard_form.html index 282ba443..afb374e4 100644 --- a/rowers/templates/standard_form.html +++ b/rowers/templates/standard_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}File loading{% endblock %} diff --git a/rowers/templates/standard_view.html b/rowers/templates/standard_view.html index 222282e5..dc35c345 100644 --- a/rowers/templates/standard_view.html +++ b/rowers/templates/standard_view.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/strava_list_import.html b/rowers/templates/strava_list_import.html index a3c1c97b..f6b1bea0 100644 --- a/rowers/templates/strava_list_import.html +++ b/rowers/templates/strava_list_import.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/streamedit.html b/rowers/templates/streamedit.html index 18306667..16a0e59a 100644 --- a/rowers/templates/streamedit.html +++ b/rowers/templates/streamedit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Advanced Features {% endblock %} diff --git a/rowers/templates/summary_edit.html b/rowers/templates/summary_edit.html index 844e3272..422f34bc 100644 --- a/rowers/templates/summary_edit.html +++ b/rowers/templates/summary_edit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/rowers/templates/survey.html b/rowers/templates/survey.html index 39433159..001b9483 100644 --- a/rowers/templates/survey.html +++ b/rowers/templates/survey.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}File loading{% endblock %} diff --git a/rowers/templates/survey2.html b/rowers/templates/survey2.html index 109fc78e..cd2941dd 100644 --- a/rowers/templates/survey2.html +++ b/rowers/templates/survey2.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall {% endblock %} diff --git a/rowers/templates/team_compare_select.html b/rowers/templates/team_compare_select.html index 0480f481..19140d18 100644 --- a/rowers/templates/team_compare_select.html +++ b/rowers/templates/team_compare_select.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/team_document_form.html b/rowers/templates/team_document_form.html index 899e62da..54260f6d 100644 --- a/rowers/templates/team_document_form.html +++ b/rowers/templates/team_document_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}File loading{% endblock %} diff --git a/rowers/templates/teamcreate.html b/rowers/templates/teamcreate.html index 7014ef5c..c361ff73 100644 --- a/rowers/templates/teamcreate.html +++ b/rowers/templates/teamcreate.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}New Team{% endblock %} diff --git a/rowers/templates/teamdeleteconfirm.html b/rowers/templates/teamdeleteconfirm.html index 20120bc3..2bf8d5b8 100644 --- a/rowers/templates/teamdeleteconfirm.html +++ b/rowers/templates/teamdeleteconfirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Delete Team {% endblock %} diff --git a/rowers/templates/teamedit.html b/rowers/templates/teamedit.html index 3219025b..ab34f726 100644 --- a/rowers/templates/teamedit.html +++ b/rowers/templates/teamedit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Edit Team{% endblock %} diff --git a/rowers/templates/teamleaveconfirm.html b/rowers/templates/teamleaveconfirm.html index cae64c93..aa795a7b 100644 --- a/rowers/templates/teamleaveconfirm.html +++ b/rowers/templates/teamleaveconfirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Leave Team {% endblock %} diff --git a/rowers/templates/templatelibrary.html b/rowers/templates/templatelibrary.html index 7fe46fa4..c8c72041 100644 --- a/rowers/templates/templatelibrary.html +++ b/rowers/templates/templatelibrary.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Planned Sessions{% endblock %} diff --git a/rowers/templates/trainingplan.html b/rowers/templates/trainingplan.html index 181f22cc..f6a7c73d 100644 --- a/rowers/templates/trainingplan.html +++ b/rowers/templates/trainingplan.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Training Plans{% endblock %} diff --git a/rowers/templates/trainingplan2.html b/rowers/templates/trainingplan2.html index 8a54c518..cb06f4f8 100644 --- a/rowers/templates/trainingplan2.html +++ b/rowers/templates/trainingplan2.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Training Plans{% endblock %} diff --git a/rowers/templates/trainingplan_chart.html b/rowers/templates/trainingplan_chart.html index 14c62309..aca80898 100644 --- a/rowers/templates/trainingplan_chart.html +++ b/rowers/templates/trainingplan_chart.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Training Plans{% endblock %} diff --git a/rowers/templates/trainingplan_create.html b/rowers/templates/trainingplan_create.html index 74f81e90..7f683aa4 100644 --- a/rowers/templates/trainingplan_create.html +++ b/rowers/templates/trainingplan_create.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Training Plans{% endblock %} diff --git a/rowers/templates/trainingplan_delete.html b/rowers/templates/trainingplan_delete.html index d39d971f..045411e4 100644 --- a/rowers/templates/trainingplan_delete.html +++ b/rowers/templates/trainingplan_delete.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Training Plans{% endblock %} diff --git a/rowers/templates/trainingplan_edit.html b/rowers/templates/trainingplan_edit.html index 3f24d8d7..0ff2f815 100644 --- a/rowers/templates/trainingplan_edit.html +++ b/rowers/templates/trainingplan_edit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Training Plans{% endblock %} diff --git a/rowers/templates/transactions.html b/rowers/templates/transactions.html index 1cb1375e..8bdf1db1 100644 --- a/rowers/templates/transactions.html +++ b/rowers/templates/transactions.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block main %} diff --git a/rowers/templates/underarmour_list_import.html b/rowers/templates/underarmour_list_import.html index 424f7feb..1bbd5c2d 100644 --- a/rowers/templates/underarmour_list_import.html +++ b/rowers/templates/underarmour_list_import.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/user_analysis_select.html b/rowers/templates/user_analysis_select.html index 3c5bc554..f952b9b2 100644 --- a/rowers/templates/user_analysis_select.html +++ b/rowers/templates/user_analysis_select.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Analysis{% endblock %} diff --git a/rowers/templates/user_boxplot_select.html b/rowers/templates/user_boxplot_select.html index f29d3fda..bd290f55 100644 --- a/rowers/templates/user_boxplot_select.html +++ b/rowers/templates/user_boxplot_select.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/user_multiflex_select.html b/rowers/templates/user_multiflex_select.html index 9b4478fa..d73cf985 100644 --- a/rowers/templates/user_multiflex_select.html +++ b/rowers/templates/user_multiflex_select.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/userprofile_deactivate.html b/rowers/templates/userprofile_deactivate.html index de600442..16efc99a 100644 --- a/rowers/templates/userprofile_deactivate.html +++ b/rowers/templates/userprofile_deactivate.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Deactivate your account{% endblock %} diff --git a/rowers/templates/userprofile_delete.html b/rowers/templates/userprofile_delete.html index d5099477..08d4c466 100644 --- a/rowers/templates/userprofile_delete.html +++ b/rowers/templates/userprofile_delete.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Delete your account{% endblock %} diff --git a/rowers/templates/video_delete_confirm.html b/rowers/templates/video_delete_confirm.html index c014f34d..d26907e8 100644 --- a/rowers/templates/video_delete_confirm.html +++ b/rowers/templates/video_delete_confirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Delete Graph Image {% endblock %} diff --git a/rowers/templates/video_selectworkout.html b/rowers/templates/video_selectworkout.html index 1902ca5e..b4e68a34 100644 --- a/rowers/templates/video_selectworkout.html +++ b/rowers/templates/video_selectworkout.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index d98ba3e4..80dc9195 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} {% load tz %} diff --git a/rowers/templates/virtualeventcreate.html b/rowers/templates/virtualeventcreate.html index 6bd65d53..6dfdddd1 100644 --- a/rowers/templates/virtualeventcreate.html +++ b/rowers/templates/virtualeventcreate.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}New Virtual Challenge{% endblock %} diff --git a/rowers/templates/virtualeventedit.html b/rowers/templates/virtualeventedit.html index 7a923c6b..42682017 100644 --- a/rowers/templates/virtualeventedit.html +++ b/rowers/templates/virtualeventedit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Edit Virtual Challenge{% endblock %} diff --git a/rowers/templates/virtualeventranking.html b/rowers/templates/virtualeventranking.html index 9053c269..ce0b4dcd 100644 --- a/rowers/templates/virtualeventranking.html +++ b/rowers/templates/virtualeventranking.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/virtualeventregister.html b/rowers/templates/virtualeventregister.html index d5c2ee00..c89040d7 100644 --- a/rowers/templates/virtualeventregister.html +++ b/rowers/templates/virtualeventregister.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Register for a Virtual Race{% endblock %} diff --git a/rowers/templates/virtualevents.html b/rowers/templates/virtualevents.html index 9fb5856f..0a9179a3 100644 --- a/rowers/templates/virtualevents.html +++ b/rowers/templates/virtualevents.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Rowsandall Virtual Challenges{% endblock %} diff --git a/rowers/templates/waiting_page.html b/rowers/templates/waiting_page.html index bda459af..db53aaca 100644 --- a/rowers/templates/waiting_page.html +++ b/rowers/templates/waiting_page.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Waiting{% endblock %} {% block meta %}{% endblock %} diff --git a/rowers/templates/windedit.html b/rowers/templates/windedit.html index ff1f5f30..6ba3d3d1 100644 --- a/rowers/templates/windedit.html +++ b/rowers/templates/windedit.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Advanced Features {% endblock %} diff --git a/rowers/templates/withdraw_view.html b/rowers/templates/withdraw_view.html index 05e890ee..91b0809d 100644 --- a/rowers/templates/withdraw_view.html +++ b/rowers/templates/withdraw_view.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block scripts %} {% include "monitorjobs.html" %} diff --git a/rowers/templates/workflow.html b/rowers/templates/workflow.html index 0ed796ce..75bd7179 100644 --- a/rowers/templates/workflow.html +++ b/rowers/templates/workflow.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} {% load leaflet_tags %} diff --git a/rowers/templates/workout_comments.html b/rowers/templates/workout_comments.html index e8fd8630..e802eada 100644 --- a/rowers/templates/workout_comments.html +++ b/rowers/templates/workout_comments.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load tz %} diff --git a/rowers/templates/workout_data.html b/rowers/templates/workout_data.html index a5ce5581..94d6a79e 100644 --- a/rowers/templates/workout_data.html +++ b/rowers/templates/workout_data.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workout Data{% endblock %} diff --git a/rowers/templates/workout_delete_confirm.html b/rowers/templates/workout_delete_confirm.html index 348de945..23685d99 100644 --- a/rowers/templates/workout_delete_confirm.html +++ b/rowers/templates/workout_delete_confirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Change Workout {% endblock %} diff --git a/rowers/templates/workout_erase_column.html b/rowers/templates/workout_erase_column.html index 12d13549..0663fd91 100644 --- a/rowers/templates/workout_erase_column.html +++ b/rowers/templates/workout_erase_column.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workout Data{% endblock %} diff --git a/rowers/templates/workout_form.html b/rowers/templates/workout_form.html index 51a5a83b..4dddb8b2 100644 --- a/rowers/templates/workout_form.html +++ b/rowers/templates/workout_form.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/workout_join_select.html b/rowers/templates/workout_join_select.html index 73ccca7c..4baa15d5 100644 --- a/rowers/templates/workout_join_select.html +++ b/rowers/templates/workout_join_select.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} diff --git a/rowers/templates/workout_remove_power_confirm.html b/rowers/templates/workout_remove_power_confirm.html index a6b3b9e0..5d301c6a 100644 --- a/rowers/templates/workout_remove_power_confirm.html +++ b/rowers/templates/workout_remove_power_confirm.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Change Workout {% endblock %} diff --git a/rowers/templates/workout_view.html b/rowers/templates/workout_view.html index e240cb70..bb790ef3 100644 --- a/rowers/templates/workout_view.html +++ b/rowers/templates/workout_view.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% load leaflet_tags %} diff --git a/rowers/templates/workoutstats.html b/rowers/templates/workoutstats.html index 088b6af3..13407497 100644 --- a/rowers/templates/workoutstats.html +++ b/rowers/templates/workoutstats.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Workout Statistics{% endblock %} diff --git a/rowers/tests/test_aworkouts.py b/rowers/tests/test_aworkouts.py index 795f6060..65aba97e 100644 --- a/rowers/tests/test_aworkouts.py +++ b/rowers/tests/test_aworkouts.py @@ -14,6 +14,8 @@ from django.utils.six import BytesIO from PIL import Image from io import StringIO +import warnings +warnings.simplefilter("error") def create_image(storage, filename, size=(100, 100), image_mode='RGB', image_format='PNG'): """ @@ -317,13 +319,15 @@ class WorkoutViewTest(TestCase): self.assertEqual(response.status_code,200) form_data = { - 'xaxis':'distance', + 'xaxis':'time', 'yaxis1':'power', 'yaxis2':'driveenergy', 'yaxis3':'hr', - 'yaxis4':'strokedistance' + 'yaxis4':'spm' } + + response = self.c.post(url,form_data) self.assertEqual(response.status_code,200) diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 6788e61e..13f40ea5 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -3959,6 +3959,8 @@ def workout_flexchart_stacked_view(request,*args,**kwargs): if request.method == 'POST': flexaxesform = StravaChartForm(request,request.POST) + if not flexaxesform.is_valid(): + print(flexaxesform.errors) if flexaxesform.is_valid(): cd = flexaxesform.cleaned_data xparam = cd['xaxis'] diff --git a/templates/400.html b/templates/400.html index 6c1096f1..3927e3f3 100644 --- a/templates/400.html +++ b/templates/400.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Error {% endblock %} diff --git a/templates/403.html b/templates/403.html index 182685d7..0bbdba76 100644 --- a/templates/403.html +++ b/templates/403.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% load rowerfilters %} {% block title %}Error {% endblock %} diff --git a/templates/404.html b/templates/404.html index 9e064e10..c5f765c6 100644 --- a/templates/404.html +++ b/templates/404.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Change Workout {% endblock %} diff --git a/templates/500.html b/templates/500.html index 6373fba8..855afcb9 100644 --- a/templates/500.html +++ b/templates/500.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Error {% endblock %} diff --git a/templates/502.html b/templates/502.html index 2fd17d50..256a7c62 100644 --- a/templates/502.html +++ b/templates/502.html @@ -1,5 +1,5 @@ {% extends "newbase.html" %} -{% load staticfiles %} +{% load static %} {% block title %}Error{% endblock %} diff --git a/templates/analysismenu.html b/templates/analysismenu.html index becf84f7..a2bd239a 100644 --- a/templates/analysismenu.html +++ b/templates/analysismenu.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} {% load rowerfilters %} Analysis of workouts over a period of time From aa2315cb9b35eb730139ec5805473ed4e0f113f2 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 14 Apr 2021 13:06:34 +0200 Subject: [PATCH 11/17] removing some warnings --- rowers/dataprep.py | 2 - rowers/dataprepnodjango.py | 3 - rowers/interactiveplots.py | 53 +++++++------ rowers/tasks.py | 4 +- rowers/tests/statements.py | 3 + rowers/tests/test_analysis.py | 132 +++++++++++++++++++++++++++++-- rowers/tests/test_async_tasks.py | 3 + rowers/tests/test_aworkouts.py | 7 +- rowers/tests/test_imports.py | 16 ++-- rowers/tests/test_races.py | 6 +- rowers/views/analysisviews.py | 52 +++++++++--- rowers/views/workoutviews.py | 31 +++++++- 12 files changed, 250 insertions(+), 62 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index c91ea326..d7d7ae4b 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1858,7 +1858,6 @@ def parsenonpainsled(fileformat,f2,summary,startdatetime='',empowerfirmware=None if fileformat == 'nklinklogbook' and empowerfirmware is not None: if inboard is not None and oarlength is not None: row = NKLiNKLogbookParser(f2,firmware=empowerfirmware,inboard=inboard,oarlength=oarlength) - print(row,'aap') else: row = NKLiNKLogbookParser(f2) else: @@ -3038,7 +3037,6 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True, df = dd.from_pandas(data,npartitions=1) df.to_parquet(filename,engine='fastparquet',compression='GZIP') - return data diff --git a/rowers/dataprepnodjango.py b/rowers/dataprepnodjango.py index e892d896..4c08ebb4 100644 --- a/rowers/dataprepnodjango.py +++ b/rowers/dataprepnodjango.py @@ -754,9 +754,6 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True, print("empty") return 0 - if debug: - print("dataprep",id) - # rowdatadf.set_index([range(len(rowdatadf))],inplace=True) t = rowdatadf.loc[:,'TimeStamp (sec)'] t = pd.Series(t-rowdatadf.loc[:,'TimeStamp (sec)'].iloc[0]) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 3887e29d..7c89a0bf 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -1556,13 +1556,13 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): slider_dist_max.js_on_change('value',callback) callback.args["maxdist"] = slider_dist_max - annotation.sizing_mode = 'fixed' - slider_spm_min.sizing_mode = 'fixed' - slider_spm_max.sizing_mode = 'fixed' - slider_work_min.sizing_mode = 'fixed' - slider_work_max.sizing_mode = 'fixed' - slider_dist_min.sizing_mode = 'fixed' - slider_dist_max.sizing_mode = 'fixed' + #annotation.sizing_mode = 'fixed' + #slider_spm_min.sizing_mode = 'fixed' + #slider_spm_max.sizing_mode = 'fixed' + #slider_work_min.sizing_mode = 'fixed' + #slider_work_max.sizing_mode = 'fixed' + #slider_dist_min.sizing_mode = 'fixed' + #slider_dist_max.sizing_mode = 'fixed' thesliders = layoutcolumn([annotation, slider_spm_min, @@ -1573,7 +1573,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): slider_work_max, ] ) - thesliders.sizing_mode = 'fixed' + #thesliders.sizing_mode = 'fixed' layout = layoutrow([thesliders, plot]) @@ -3663,7 +3663,12 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, success = 0 p1 = p0 if len(thesecs)>=4: - p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower)) + try: + p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower)) + except (RuntimeError,RuntimeWarning): + factor = fitfunc(p0,thesecs.mean())/theavpower.mean() + p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] + success = 0 else: factor = fitfunc(p0,thesecs.mean())/theavpower.mean() p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] @@ -4889,12 +4894,12 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, slider_dist_max.js_on_change('value',callback) callback.args["maxdist"] = slider_dist_max - slider_spm_min.sizing_mode = 'fixed' - slider_spm_max.sizing_mode = 'fixed' - slider_work_min.sizing_mode = 'fixed' - slider_work_max.sizing_mode = 'fixed' - slider_dist_min.sizing_mode = 'fixed' - slider_dist_max.sizing_mode = 'fixed' + #slider_spm_min.sizing_mode = 'fixed' + #slider_spm_max.sizing_mode = 'fixed' + #slider_work_min.sizing_mode = 'fixed' + #slider_work_max.sizing_mode = 'fixed' + #slider_dist_min.sizing_mode = 'fixed' + #slider_dist_max.sizing_mode = 'fixed' thesliders = layoutcolumn([slider_spm_min, slider_spm_max, @@ -4905,7 +4910,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, ], ) - thesliders.sizing_mode = 'fixed' + #thesliders.sizing_mode = 'fixed' layout = layoutrow([thesliders, plot]) @@ -5917,13 +5922,13 @@ def interactive_flex_chart2(id,r,promember=0, slider_dist_max.js_on_change('value',callback) callback.args["maxdist"] = slider_dist_max - annotation.sizing_mode = 'fixed' - slider_spm_min.sizing_mode = 'fixed' - slider_spm_max.sizing_mode = 'fixed' - slider_work_min.sizing_mode = 'fixed' - slider_work_max.sizing_mode = 'fixed' - slider_dist_min.sizing_mode = 'fixed' - slider_dist_max.sizing_mode = 'fixed' + #annotation.sizing_mode = 'fixed' + #slider_spm_min.sizing_mode = 'fixed' + #slider_spm_max.sizing_mode = 'fixed' + #slider_work_min.sizing_mode = 'fixed' + #slider_work_max.sizing_mode = 'fixed' + #slider_dist_min.sizing_mode = 'fixed' + #slider_dist_max.sizing_mode = 'fixed' thesliders = layoutcolumn([ annotation, @@ -5935,7 +5940,7 @@ def interactive_flex_chart2(id,r,promember=0, slider_work_max, ]) - thesliders.sizing_mode = 'fixed' + #thesliders.sizing_mode = 'fixed' layout = layoutrow([thesliders, plot]) diff --git a/rowers/tasks.py b/rowers/tasks.py index 30543fc3..4d8d4415 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -2205,6 +2205,7 @@ def cp_from_workoutids(workoutids,debug=False): if len(data)>1: df = pd.concat(data,axis=0) + df = df[df['cp'] == df.groupby(['delta'])['cp'].transform('max')] df = df.sort_values(['delta']).reset_index() @@ -2250,6 +2251,7 @@ def cp_from_workoutids(workoutids,debug=False): power2k = fitfunc(p1,t3) + return powerfourmin,power2k,powerhour @@ -2818,7 +2820,7 @@ def handle_setcp(strokesdf,filename,workoutid,debug=False,**kwargs): except FileNotFoundError: pass if not strokesdf.empty: - + try: totaltime = strokesdf['time'].max() except KeyError: diff --git a/rowers/tests/statements.py b/rowers/tests/statements.py index 6fe2c66e..40ebeefd 100644 --- a/rowers/tests/statements.py +++ b/rowers/tests/statements.py @@ -15,6 +15,9 @@ except NameError: import pytest +import warnings +#warnings.filterwarnings("error",category=RuntimeWarning) + pytestmark = pytest.mark.django_db from bs4 import BeautifulSoup diff --git a/rowers/tests/test_analysis.py b/rowers/tests/test_analysis.py index e7696316..f6204402 100644 --- a/rowers/tests/test_analysis.py +++ b/rowers/tests/test_analysis.py @@ -10,7 +10,6 @@ nu = datetime.datetime.now() from rowers.views import * - class WorkoutCompareTest(TestCase): def setUp(self): self.u = UserFactory() @@ -212,6 +211,9 @@ class ListWorkoutTest(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + startdate = arrow.get(startdate).datetime + enddate = arrow.get(startdate).datetime + form_data = { 'startdate':startdate, 'enddate':enddate, @@ -345,6 +347,16 @@ class CumStatsTest(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + url = '/rowers/cumstats/' response = self.c.get(url) @@ -382,6 +394,16 @@ class CumFlexTest(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + waterboattype = [u'1x', u'2x', u'2x+', @@ -402,7 +424,7 @@ class CumFlexTest(TestCase): 'modality':u'all', 'waterboattype': waterboattype, 'xaxis':'spm', - 'yaxis1':'driveenergy', + 'yaxis1':'hr', 'yaxis2':'power', } @@ -442,7 +464,7 @@ class CumFlexTest(TestCase): u'8+', u'8x+'], 'xparam': u'spm', - 'yparam1': u'driveenergy', + 'yparam1': u'hr', 'yparam2': u'power'} session = self.c.session @@ -487,6 +509,16 @@ class MultiFlexTest(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + waterboattype = [u'1x', u'2x', u'2x+', @@ -516,7 +548,7 @@ class MultiFlexTest(TestCase): 'workoutselectform':'Create Chart', 'xparam':'spm', 'yparam':'power', - 'groupby':'driveenergy', + 'groupby':'spm', } form = MultiFlexChoiceForm(form_data) @@ -536,7 +568,7 @@ class MultiFlexTest(TestCase): 'ploterrorbars':True, 'userid':0, 'palette': 'monochrome_blue', - 'groupby': 'driveenergy', + 'groupby': 'power', 'binsize': 1, 'xparam': 'spm', 'yparam': 'power', @@ -592,6 +624,16 @@ class HistoTest(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + waterboattype = [u'1x', u'2x', u'2x+', @@ -694,6 +736,16 @@ class WorkoutCompareTestNew(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + form_data = { 'function':'compare', 'xparam':'hr', @@ -783,6 +835,16 @@ class WorkoutBoxPlotTestNew(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + form_data = { 'function':'boxplot', 'xparam':'hr', @@ -871,6 +933,16 @@ class WorkoutHistoTestNew(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + form_data = { 'function':'histo', 'xparam':'hr', @@ -964,6 +1036,16 @@ class History(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=50)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=50)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + form_data = { 'startdate':startdate, 'enddate':enddate, @@ -1061,6 +1143,16 @@ class GoldMedalScores(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=50)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=50)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + form_data = { 'startdate':startdate, 'enddate':enddate, @@ -1126,6 +1218,16 @@ class WorkoutFlexallTestNew(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + form_data = { 'function':'flexall', 'xparam':'hr', @@ -1215,6 +1317,16 @@ class WorkoutStatsTestNew(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + options = { 'function':'flexall', 'xparam':'hr', @@ -1266,6 +1378,16 @@ class WorkoutStatsTestNew(TestCase): startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + form_data = { 'function':'stats', 'xparam':'hr', diff --git a/rowers/tests/test_async_tasks.py b/rowers/tests/test_async_tasks.py index 948385be..2fb6f2c1 100644 --- a/rowers/tests/test_async_tasks.py +++ b/rowers/tests/test_async_tasks.py @@ -34,6 +34,9 @@ class AsyncTaskTests(TestCase): self.c = Client() self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) + for w in self.user_workouts: + res = dataprep.setcp(w) + self.factory = RequestFactory() self.password = faker.word() self.u.set_password(self.password) diff --git a/rowers/tests/test_aworkouts.py b/rowers/tests/test_aworkouts.py index 65aba97e..95c46902 100644 --- a/rowers/tests/test_aworkouts.py +++ b/rowers/tests/test_aworkouts.py @@ -14,8 +14,7 @@ from django.utils.six import BytesIO from PIL import Image from io import StringIO -import warnings -warnings.simplefilter("error") + def create_image(storage, filename, size=(100, 100), image_mode='RGB', image_format='PNG'): """ @@ -321,7 +320,7 @@ class WorkoutViewTest(TestCase): form_data = { 'xaxis':'time', 'yaxis1':'power', - 'yaxis2':'driveenergy', + 'yaxis2':'pace', 'yaxis3':'hr', 'yaxis4':'spm' } @@ -343,7 +342,7 @@ class WorkoutViewTest(TestCase): url = expected_url form_data = { - 'cols':['driveenergy','spm'] + 'cols':['hr','spm'] } form = DataFrameColumnsForm(form_data) diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index 3369f533..4bfaa939 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -154,7 +154,7 @@ class C2Objects(DjangoTestCase): self.r.c2token = '12' self.r.c2refreshtoken = 'ab' - self.r.tokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) + self.r.tokenexpirydate = arrow.get(datetime.datetime.now()+datetime.timedelta(days=1)).datetime self.r.save() self.c.login(username='john',password='koeinsloot') @@ -195,7 +195,7 @@ class C2Objects(DjangoTestCase): def test_timezone_c2(self): data = c2stuff.createc2workoutdata(self.w) wenddtime = self.w.startdatetime-datetime.timedelta(seconds=self.totaltime) - + self.assertEqual(data['timezone'],'Europe/Amsterdam') self.assertEqual(data['date'],wenddtime.strftime('%Y-%m-%d %H:%M:%S')) @@ -309,7 +309,7 @@ class C2ObjectsTokenExpired(DjangoTestCase): self.r.c2token = '12' self.r.c2refreshtoken = 'ab' - self.r.tokenexpirydate = datetime.datetime.now()-datetime.timedelta(days=1) + self.r.tokenexpirydate = arrow.get(datetime.datetime.now()-datetime.timedelta(days=1)).datetime self.r.save() self.c.login(username='john',password='koeinsloot') @@ -386,7 +386,7 @@ class NKObjects(DjangoTestCase): self.r.nktoken = '12' self.r.nkrefreshtoken = '123' - self.r.nktokenexpirydate = datetime.datetime.now()-datetime.timedelta(days=1) + self.r.nktokenexpirydate = arrow.get(datetime.datetime.now()-datetime.timedelta(days=1)).datetime self.r.save() self.c.login(username='john',password='koeinsloot') @@ -532,7 +532,7 @@ class StravaObjects(DjangoTestCase): self.r.stravatoken = '12' self.r.stravarefreshtoken = '123' - self.r.stravatokenexpirydate = datetime.datetime.now()-datetime.timedelta(days=1) + self.r.stravatokenexpirydate = arrow.get(datetime.datetime.now()-datetime.timedelta(days=1)).datetime self.r.save() self.c.login(username='john',password='koeinsloot') @@ -639,7 +639,7 @@ class STObjects(DjangoTestCase): self.r.sporttrackstoken = '12' self.r.sporttracksrefreshtoken = '12' - self.r.sporttrackstokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) + self.r.sporttrackstokenexpirydate = arrow.get(datetime.datetime.now()+datetime.timedelta(days=1)).datetime self.r.save() self.c.login(username='john',password='koeinsloot') @@ -880,7 +880,7 @@ class UAObjects(DjangoTestCase): self.r.underarmourtoken = '12' self.r.underarmourrefreshtoken = '12' - self.r.underarmourtokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) + self.r.underarmourtokenexpirydate = arrow.get(datetime.datetime.now()+datetime.timedelta(days=1)).datetime self.r.save() self.c.login(username='john',password='koeinsloot') @@ -983,7 +983,7 @@ class TPObjects(DjangoTestCase): self.r.tptoken = '12' self.r.tprefreshtoken = '12' - self.r.tptokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1) + self.r.tptokenexpirydate = arrow.get(datetime.datetime.now()+datetime.timedelta(days=1)).datetime self.r.save() self.c.login(username='john',password='koeinsloot') diff --git a/rowers/tests/test_races.py b/rowers/tests/test_races.py index ee1b6828..6f31a102 100644 --- a/rowers/tests/test_races.py +++ b/rowers/tests/test_races.py @@ -97,7 +97,7 @@ class ChallengesTest(TestCase): workouttype = 'water', ) - self.wthyro.startdatetime = nu + self.wthyro.startdatetime = arrow.get(nu).datetime self.wthyro.date = nu.date() self.wthyro.save() @@ -111,7 +111,7 @@ class ChallengesTest(TestCase): workouttype = 'water', ) - self.wthyro2.startdatetime = nu + self.wthyro2.startdatetime = arrow.get(nu).datetime self.wthyro2.date = nu.date() self.wthyro2.save() @@ -776,7 +776,7 @@ class IndoorChallengesTest(TestCase): workouttype = 'water', ) - self.werg.startdatetime = nu + self.werg.startdatetime = arrow.get(nu).datetime self.werg.date = nu.date() self.werg.save() diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 0b745133..113c5d69 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -182,6 +182,16 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): enddate = startdate startdate = s + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + negtypes = [] for b in mytypes.boattypes: if b[0] not in waterboattype: @@ -366,7 +376,7 @@ def trendflexdata(workouts, options,userid=0): datadf[groupby].max()+binsize, binsize) groups = datadf.groupby(pd.cut(datadf[groupby],bins,labels=False)) - except ValueError: + except (ValueError, AttributeError): return ('','Error: not enough data') else: bins = np.arange(datadf['days ago'].min()-binsize, @@ -426,7 +436,7 @@ def trendflexdata(workouts, options,userid=0): df['groupval'].loc[mask] = np.nan groupcols = df['groupval'] - except ValueError: + except (ValueError, AttributeError): df['groupval'] = groups.mean()[groupby].fillna(value=0) df['groupval'].loc[mask] = np.nan groupcols = df['groupval'] @@ -1917,6 +1927,8 @@ def rankings_view(request,userid=0, startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) #enddate = enddate+datetime.timedelta(days=1) + startdate = arrow.get(startdate).datetime + enddate = arrow.get(enddate).datetime thedistances = [] theworkouts = [] @@ -2324,7 +2336,8 @@ def rankings_view2(request,userid=0, startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) #enddate = enddate+datetime.timedelta(days=1) - + startdate = arrow.get(startdate).datetime + enddate = arrow.get(enddate).datetime thedistances = [] theworkouts = [] @@ -2438,7 +2451,7 @@ def rankings_view2(request,userid=0, pwr = 2.8*(velo**3) try: pwr = int(pwr) - except ValueError: + except (ValueError, AttributeError): pwr = 0 a = {'distance':rankingdistance, @@ -2675,7 +2688,8 @@ def otwrankings_view(request,userid=0, enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) #enddate = enddate+datetime.timedelta(days=1) - + startdate = arrow.get(startdate).datetime + enddate = arrow.get(enddate).datetime thedistances = [] theworkouts = [] @@ -3087,7 +3101,8 @@ def oterankings_view(request,userid=0, startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - + startdate = arrow.get(startdate).datetime + enddate = arrow.get(enddate).datetime thedistances = [] theworkouts = [] @@ -3436,6 +3451,16 @@ def user_multiflex_select(request, else: rankingpiece = [True,False] + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + workouts = Workout.objects.filter( user=r, startdatetime__gte=startdate, @@ -3638,7 +3663,7 @@ def multiflex_data(request,userid=0, datadf[groupby].max()+binsize, binsize) groups = datadf.groupby(pd.cut(datadf[groupby],bins,labels=False)) - except ValueError: + except (ValueError, AttributeError): messages.error( request, "Unable to compete. Probably not enough data selected" @@ -3703,7 +3728,7 @@ def multiflex_data(request,userid=0, df['groupval'].loc[mask] = np.nan groupcols = df['groupval'] - except ValueError: + except (ValueError, AttributeError): df['groupval'] = groups.mean()[groupby].fillna(value=0) df['groupval'].loc[mask] = np.nan groupcols = df['groupval'] @@ -4079,6 +4104,15 @@ def user_boxplot_select(request, if b[0] not in waterboattype: negtypes.append(b[0]) + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass workouts = Workout.objects.filter(user=r, startdatetime__gte=startdate, @@ -5338,7 +5372,7 @@ def history_view_data(request,userid=0): ddict['hrmean'] = int(wavg(ddf,'hr','deltat')) try: ddict['hrmax'] = ddf['hr'].max().astype(int) - except ValueError: + except (ValueError, AttributeError): ddict['hrmax'] = 0 ddict['powermean'] = int(wavg(ddf,'power','deltat')) diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 13f40ea5..683ebb1a 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -968,6 +968,10 @@ def video_selectworkout(request,userid=0): startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) + # make sure the dates are not naive + startdate = pytz.utc.localize(startdate) + enddate = pytz.utc.localize(enddate) + if enddate < startdate: # pragma: no cover s = enddate enddate = startdate @@ -1112,6 +1116,16 @@ def workouts_join_select(request, enddate = startdate startdate = s + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except ValueError: + pass + try: + enddate = pytz.utc.localize(enddate) + except ValueError: + pass + workouts = Workout.objects.filter(user=r, startdatetime__gte=startdate, @@ -1338,6 +1352,16 @@ def team_comparison_select(request, except Team.DoesNotExist: theteam = 0 + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except ValueError: + pass + try: + enddate = pytz.utc.localize(enddate) + except ValueError: + pass + if theteam and (theteam.viewing == 'allmembers' or theteam.manager == request.user): workouts = Workout.objects.filter(team=theteam, startdatetime__gte=startdate, @@ -1964,7 +1988,7 @@ def workouts_view(request,message='',successmessage='', activity_startdate = activity_startdate.replace(hour=0,minute=0,second=0) else: activity_enddate = enddate - except ValueError: # pragma: no cover + except (ValueError, AttributeError): # pragma: no cover activity_enddate = enddate g_startdate = activity_startdate @@ -2156,6 +2180,9 @@ def workout_fusion_list(request,id=0, enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) #enddate = enddate+datetime.timedelta(days=1) + startdate = arrow.get(startdate).datetime + enddate = arrow.get(enddate).datetime + if enddate < startdate: # pragma: no cover s = enddate enddate = startdate @@ -3959,8 +3986,6 @@ def workout_flexchart_stacked_view(request,*args,**kwargs): if request.method == 'POST': flexaxesform = StravaChartForm(request,request.POST) - if not flexaxesform.is_valid(): - print(flexaxesform.errors) if flexaxesform.is_valid(): cd = flexaxesform.cleaned_data xparam = cd['xaxis'] From 39a196b94974bb5e2df8069f23971a9b478d3ef2 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 14 Apr 2021 17:42:12 +0200 Subject: [PATCH 12/17] coverage info --- rowers/interactiveplots.py | 605 +++++++++---------------- rowers/tests/test_emails.py | 5 +- rowers/tests/test_interactivecharts.py | 9 - rowers/tests/test_permissions2.py | 28 -- rowers/tests/test_plans.py | 4 + rowers/views/workoutviews.py | 6 +- 6 files changed, 232 insertions(+), 425 deletions(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 7c89a0bf..271fec56 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -145,7 +145,7 @@ def errorbar(fig, x, y, source=ColumnDataSource(), yerrvalues = source.data['yerror'] try: colorvalues = source.data['color'] - except KeyError: + except KeyError: # pragma: no cover colorvalues = ["#%02x%02x%02x" % (255,0,0) for x in xvalues] @@ -168,7 +168,7 @@ def errorbar(fig, x, y, source=ColumnDataSource(), fig.multi_line(x_err_x, x_err_y, color=err_color, name='xerr', **error_kwargs) - except TypeError: + except TypeError: # pragma: no cover pass try: @@ -189,7 +189,7 @@ def errorbar(fig, x, y, source=ColumnDataSource(), fig.multi_line(y_err_x, y_err_y, color=err_color, name='yerr',**error_kwargs) - except TypeError: + except TypeError: # pragma: no cover pass fig.circle(x, y, source=source, name='data',color=color, @@ -317,7 +317,7 @@ def pretty_timedelta(secs): def mapcolors(x): try: return mytypes.color_map[x] - except KeyError: + except KeyError: # pragma: no cover return mytypes.colors[-1] def interactive_workouttype_piechart(workouts): @@ -331,7 +331,7 @@ def interactive_workouttype_piechart(workouts): try: # label = mytypes.workouttypes_ordered[w.workouttype] label = w.workouttype - except KeyError: + except KeyError: # pragma: no cover label = w.workouttype try: datadict[label] += 60*(60*w.duration.hour+w.duration.minute)+w.duration.second @@ -350,7 +350,7 @@ def interactive_workouttype_piechart(workouts): data['totaltime'] = data['value'].apply(lambda x:pretty_timedelta(x)) try: data['type'] = data['type'].apply(lambda x:mytypes.workouttypes_ordered[x]) - except KeyError: + except KeyError: # pragma: no cover pass @@ -376,15 +376,15 @@ def interactive_workouttype_piechart(workouts): def interactive_boxchart(datadf,fieldname,extratitle='', spmmin=0,spmmax=0,workmin=0,workmax=0): - if datadf.empty: + if datadf.empty: # pragma: no cover return '','It looks like there are no data matching your filter' columns = datadf.columns - if not fieldname in columns: + if not fieldname in columns: # pragma: no cover return '','It looks like there are no data matching your filter' - if not 'date' in columns: + if not 'date' in columns: # pragma: no cover return '','Not enough data' @@ -402,7 +402,7 @@ def interactive_boxchart(datadf,fieldname,extratitle='', try: boxwhiskers = hv.BoxWhisker(datadf,'date',fieldname) boxwhiskers.opts(tools=TOOLS,outlier_color='white') - except DataError: + except DataError: # pragma: no cover return "","Invalid Data" @@ -422,7 +422,7 @@ def interactive_boxchart(datadf,fieldname,extratitle='', years=["%d %B %Y"], ) - if fieldname == 'pace': + if fieldname == 'pace': # pragma: no cover plot.yaxis[0].formatter = DatetimeTickFormatter( seconds = ["%S"], minutes = ["%M"] @@ -458,10 +458,10 @@ def interactive_planchart(data,startdate,enddate): yaxmaximum = data['executed'].max() - if data['planned'].max() > yaxmaximum: + if data['planned'].max() > yaxmaximum: # pragma: no cover yaxmaximum = data['planned'].max() - if yaxmaximum == 0: + if yaxmaximum == 0: # pragma: no cover yaxmaximum = 250 yrange1 = Range1d(start=0,end=1.1*yaxmaximum) @@ -513,7 +513,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo aantal=1 initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal] if w.user.id not in idseen: - while initials in seen: + while initials in seen: # pragma: no cover aantal += 1 initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal] @@ -531,13 +531,13 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo rscore = w.rscore trimp = w.trimp - if rscore == 0: + if rscore == 0: # pragma: no cover rscore = w.hrtss if totaldays<30: dates.append(dd) dates_sorting.append(dd2) - else: + else: # pragma: no cover dates.append(dd3) dates_sorting.append(dd3) durations.append(du) @@ -554,17 +554,17 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo types.append(w.workouttype) try: rowers.append(rowersinitials[w.user.id]) - except IndexError: + except IndexError: # pragma: no cover rowers.append(str(w.user)) try: d = utc.localize(startdate) - except (ValueError,AttributeError): + except (ValueError,AttributeError): # pragma: no cover d = startdate try: enddate = utc.localize(enddate) - except (ValueError,AttributeError): + except (ValueError,AttributeError): # pragma: no cover pass # add dates with no activity @@ -575,7 +575,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo if totaldays<30: dates.append(d.strftime('%m/%d')) dates_sorting.append(d.strftime('%Y/%m/%d')) - else: + else: # pragma: no cover dates.append(d.strftime('%Y/%m')) dates_sorting.append(d.strftime('%Y/%m')) durations.append(0) @@ -699,7 +699,7 @@ def interactive_activitychart2(workouts,startdate,enddate,stack='type',toolbar_l aantal=1 initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal] if w.user.id not in idseen: - while initials in seen: + while initials in seen: # pragma: no cover aantal += 1 initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal] @@ -716,10 +716,10 @@ def interactive_activitychart2(workouts,startdate,enddate,stack='type',toolbar_l du = w.duration.hour*60+w.duration.minute trimp = w.trimp rscore = w.rscore - if rscore == 0: + if rscore == 0: # pragma: no cover rscore = w.hrtss - if totaldays<30: + if totaldays<30: # pragma: no cover dates.append(dd) dates_sorting.append(dd2) else: @@ -739,17 +739,17 @@ def interactive_activitychart2(workouts,startdate,enddate,stack='type',toolbar_l types.append(w.workouttype) try: rowers.append(rowersinitials[w.user.id]) - except IndexError: + except IndexError: # pragma: no cover rowers.append(str(w.user)) try: d = utc.localize(startdate) - except (ValueError,AttributeError): + except (ValueError,AttributeError): # pragma: no cover d = startdate try: enddate = utc.localize(enddate) - except (ValueError,AttributeError): + except (ValueError,AttributeError): # pragma: no cover pass # add dates with no activity @@ -875,7 +875,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): if workstrokesonly: try: rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)] - except KeyError: + except KeyError: # pragma: no cover pass if rowdata.empty: @@ -886,7 +886,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): # peakforce = slope*peakforceangle + intercept try: slope, intercept, r,p,stderr = linregress(rowdata['peakforceangle'],rowdata['peakforce']) - except KeyError: + except KeyError: # pragma: no cover slope = 0 intercept = 0 @@ -938,7 +938,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): a95b = Rinv[0,1]*y95 + rowdata['peakforceangle'].median() F95b = Rinv[1,1]*y95 + rowdata['peakforce'].median() - except KeyError: + except KeyError: # pragma: no cover a25 = 0 F25 = 0 @@ -972,7 +972,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): catch75 = rowdata['catch'].quantile(q=0.75) catch05 = rowdata['catch'].quantile(q=0.05) catch95 = rowdata['catch'].quantile(q=0.95) - except KeyError: + except KeyError: # pragma: no cover catchav = 0 catch25 = 0 catch75 = 0 @@ -985,7 +985,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): finish75 = rowdata['finish'].quantile(q=0.75) finish05 = rowdata['finish'].quantile(q=0.05) finish95 = rowdata['finish'].quantile(q=0.95) - except KeyError: + except KeyError: # pragma: no cover finishav = 0 finish25 = 0 finish75 = 0 @@ -998,7 +998,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): wash75 = (rowdata['finish']-rowdata['wash']).quantile(q=0.75) wash05 = (rowdata['finish']-rowdata['wash']).quantile(q=0.05) wash95 = (rowdata['finish']-rowdata['wash']).quantile(q=0.95) - except KeyError: + except KeyError: # pragma: no cover washav = 0 wash25 = 0 wash75 = 0 @@ -1011,7 +1011,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): slip75 = (rowdata['slip']+rowdata['catch']).quantile(q=0.75) slip05 = (rowdata['slip']+rowdata['catch']).quantile(q=0.05) slip95 = (rowdata['slip']+rowdata['catch']).quantile(q=0.95) - except KeyError: + except KeyError: # pragma: no cover slipav = 0 slip25 = 0 slip75 = 0 @@ -1024,7 +1024,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): peakforce75 = rowdata['peakforce'].quantile(q=0.75) peakforce05 = rowdata['peakforce'].quantile(q=0.05) peakforce95 = rowdata['peakforce'].quantile(q=0.95) - except KeyError: + except KeyError: # pragma: no cover peakforceav = 0 peakforce25 = 0 peakforce75 = 0 @@ -1034,7 +1034,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): try: averageforceav = rowdata['averageforce'].median() - except KeyError: + except KeyError: # pragma: no cover averageforceav = 0 try: @@ -1043,7 +1043,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): peakforceangle25 = rowdata['peakforceangle'].quantile(q=0.25) peakforceangle75 = rowdata['peakforceangle'].quantile(q=0.75) peakforceangle95 = rowdata['peakforceangle'].quantile(q=0.95) - except KeyError: + except KeyError: # pragma: no cover peakforceangleav = 0 peakforceangle25 = 0 peakforceangle75 = 0 @@ -1147,7 +1147,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): rowdata ) - if plottype == 'scatter': + if plottype == 'scatter': # pragma: no cover try: sourcepoints = ColumnDataSource( data = dict( @@ -1240,7 +1240,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): rowdata['peakforce'].values[i], thresholdforce, 0] - except KeyError: + except KeyError: # pragma: no cover x = [0,0] y = [0,0] @@ -1259,7 +1259,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'): glyph = MultiLine(xs='x',ys='y',line_color='black',line_alpha=0.05) plot.add_glyph(sourcemultiline,glyph) - else: + else: # pragma: no cover sourcemultiline = ColumnDataSource(dict( x=[],y=[])) @@ -1613,12 +1613,12 @@ def getfatigues( if getattr(w,metricchoice) > 0: weight += getattr(w,metricchoice) if getattr(w,metricchoice) <= 0: - if metricchoice == 'rscore' and w.hrtss > 0: + if metricchoice == 'rscore' and w.hrtss > 0: # pragma: no cover weight+= w.hrtss else: trimp,hrtss = dataprep.workout_trimp(w) rscore,normp = dataprep.workout_rscore(w) - if w.rpe and w.rpe > 0: + if w.rpe and w.rpe > 0: # pragma: no cover dd = 3600*w.duration.hour+60*w.duration.minute+w.duration.second dd = dd/3600 weight += rpetotss[w.rpe]*dd @@ -1886,7 +1886,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7, endfatigue = fatigues[-2] endform = endfitness-endfatigue - if modelchoice == 'banister': + if modelchoice == 'banister': # pragma: no cover df['fatigue'] = k2*df['fatigue'] df['fitness'] = p0+k1*df['fitness'] @@ -1949,7 +1949,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7, y_range_name = "watermark", ) - if modelchoice == 'banister': + if modelchoice == 'banister': # pragma: no cover fitlabel = 'PTE (fitness)' fatiguelabel = 'NTE (fatigue)' formlabel = 'Performance' @@ -1963,7 +1963,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7, fatiguelabel = 'Fatigue' formlabel = 'Freshness' rightaxlabel = 'Freshness' - if dofatigue: + if dofatigue: # pragma: no cover yaxlabel = 'Fitness/Fatigue' else: yaxlabel = 'Fitness' @@ -1985,14 +1985,14 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7, #elif showtests: # y1rangemin = df.loc[:,['testpower','fitness']].min().min() # y1rangemax = df.loc[:,['testpower','fitness']].max().max()*1.02 - if dofatigue: + if dofatigue: # pragma: no cover y1rangemin = df.loc[:,['fitness','fatigue']].min().min() y1rangemax = df.loc[:,['fitness','fatigue']].max().max()*1.02 else: y1rangemin = df.loc[:,['fitness']].min().min() y1rangemax = df.loc[:,['fitness']].max().max()*1.02 - if doform: + if doform: # pragma: no cover plot.extra_y_ranges["yax2"] = Range1d(start=y2rangemin,end=y2rangemax) plot.add_layout(LinearAxis(y_range_name="yax2",axis_label=rightaxlabel),"right") @@ -2003,10 +2003,10 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7, plot.add_layout(band) - if dofatigue: + if dofatigue: # pragma: no cover plot.line('date','fatigue',source=source,color='red', legend_label=fatiguelabel) - if doform: + if doform: # pragma: no cover plot.line('date','form',source=source,color='green', legend_label=formlabel,y_range_name="yax2") @@ -2079,7 +2079,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7, try: script,div = components(layout) - except Exception as e: + except Exception as e: # pragma: no cover df.dropna(inplace=True,axis=0,how='any') return ( '', @@ -2120,7 +2120,7 @@ def interactive_histoall(theworkouts,histoparam,includereststrokes, histopwr = rowdata[histoparam].values except KeyError: return "","No data" - if len(histopwr) == 0: + if len(histopwr) == 0: # pragma: no cover return "","No valid data available" # throw out nans @@ -2226,7 +2226,7 @@ def interactive_histoall(theworkouts,histoparam,includereststrokes, try: script, div = components(layout) - except ValueError: + except ValueError: # pragma: no cover script = '' div = '' @@ -2388,7 +2388,7 @@ def course_map(course): return script,div def leaflet_chart(lat,lon,name=""): - if lat.empty or lon.empty: + if lat.empty or lon.empty: # pragma: no cover return [0,"invalid coordinate data"] @@ -2404,7 +2404,7 @@ def leaflet_chart(lat,lon,name=""): df.fillna(method='ffill',axis=0,inplace=True) lat = df['lat'] lon = df['lon'] - if lat.empty or lon.empty: + if lat.empty or lon.empty: # pragma: no cover return [0,"invalid coordinate data"] latmean = lat.mean() @@ -2542,7 +2542,7 @@ def leaflet_chart_compare(course,workoutids,labeldict={},startenddict={}): 'time':time-time[0], }) data.append(df) - except (Workout.DoesNotExist,KeyError): + except (Workout.DoesNotExist,KeyError): # pragma: no cover pass @@ -2607,7 +2607,7 @@ def leaflet_chart_compare(course,workoutids,labeldict={},startenddict={}): lat = df['lat'] lon = df['lon'] - if lat.empty or lon.empty: + if lat.empty or lon.empty: # pragma: no cover return [0,"invalid coordinate data"] latbegin = lat.values[0] @@ -2715,13 +2715,13 @@ var navionics = new JNC.Leaflet.NavionicsOverlay({{ group = df[df['workoutid']==int(id)].copy() try: startsecond,endsecond = startenddict[id] - except KeyError: + except KeyError: # pragma: no cover startsecond = 0 endsecond = 0 try: label = labeldict[id] - except KeyError: + except KeyError: # pragma: no cover label = str(id) group.sort_values(by='time',ascending=True,inplace=True) @@ -2780,7 +2780,7 @@ var navionics = new JNC.Leaflet.NavionicsOverlay({{ return script,div def leaflet_chart2(lat,lon,name=""): - if lat.empty or lon.empty: + if lat.empty or lon.empty: # pragma: no cover return [0,"invalid coordinate data"] @@ -2796,7 +2796,7 @@ def leaflet_chart2(lat,lon,name=""): df.fillna(method='ffill',axis=0,inplace=True) lat = df['lat'] lon = df['lon'] - if lat.empty or lon.empty: + if lat.empty or lon.empty: # pragma: no cover return [0,"invalid coordinate data"] latmean = lat.mean() @@ -2919,7 +2919,7 @@ def leaflet_chart2(lat,lon,name=""): return script,div def leaflet_chart_video(lat,lon,name=""): - if not len(lat) or not len(lon): + if not len(lat) or not len(lon): # pragma: no cover return [0,"invalid coordinate data"] @@ -2935,7 +2935,7 @@ def leaflet_chart_video(lat,lon,name=""): df.fillna(method='ffill',axis=0,inplace=True) lat = df['lat'] lon = df['lon'] - if lat.empty or lon.empty: + if lat.empty or lon.empty: # pragma: no cover return [0,"invalid coordinate data"] latmean = lat.mean() @@ -3072,7 +3072,7 @@ def interactive_agegroupcpchart(age,normalized=False): weightcategory='hwt' ) velo = (worldclasspower/2.8)**(1./3.) - try: + try: # pragma: no cover duration = distance/velo fhduration.append(duration) fhpower.append(worldclasspower) @@ -3090,7 +3090,7 @@ def interactive_agegroupcpchart(age,normalized=False): distance = int(60*duration*velo) fhduration.append(60.*duration) fhpower.append(worldclasspower) - except ValueError: + except ValueError: # pragma: no cover pass flduration = [] @@ -3104,7 +3104,7 @@ def interactive_agegroupcpchart(age,normalized=False): weightcategory='lwt' ) velo = (worldclasspower/2.8)**(1./3.) - try: + try: # pragma: no cover duration = distance/velo flduration.append(duration) flpower.append(worldclasspower) @@ -3122,7 +3122,7 @@ def interactive_agegroupcpchart(age,normalized=False): distance = int(60*duration*velo) flduration.append(60.*duration) flpower.append(worldclasspower) - except ValueError: + except ValueError: # pragma: no cover pass mlduration = [] @@ -3136,7 +3136,7 @@ def interactive_agegroupcpchart(age,normalized=False): weightcategory='lwt' ) velo = (worldclasspower/2.8)**(1./3.) - try: + try: # pragma: no cover duration = distance/velo mlduration.append(duration) mlpower.append(worldclasspower) @@ -3154,7 +3154,7 @@ def interactive_agegroupcpchart(age,normalized=False): distance = int(60*duration*velo) mlduration.append(60.*duration) mlpower.append(worldclasspower) - except ValueError: + except ValueError: # pragma: no cover pass @@ -3169,7 +3169,7 @@ def interactive_agegroupcpchart(age,normalized=False): weightcategory='hwt' ) velo = (worldclasspower/2.8)**(1./3.) - try: + try: # pragma: no cover duration = distance/velo mhduration.append(duration) mhpower.append(worldclasspower) @@ -3187,7 +3187,7 @@ def interactive_agegroupcpchart(age,normalized=False): distance = int(60*duration*velo) mhduration.append(60.*duration) mhpower.append(worldclasspower) - except ValueError: + except ValueError: # pragma: no cover pass @@ -3201,27 +3201,27 @@ def interactive_agegroupcpchart(age,normalized=False): if len(fhduration)>=4: p1fh, success = optimize.leastsq(errfunc, p0[:], args = (fhduration,fhpower)) - else: + else: # pragma: no cover p1fh = None # fitting WC data to three parameter CP model if len(flduration)>=4: p1fl, success = optimize.leastsq(errfunc, p0[:], args = (flduration,flpower)) - else: + else: # pragma: no cover p1fl = None # fitting WC data to three parameter CP model if len(mlduration)>=4: p1ml, success = optimize.leastsq(errfunc, p0[:], args = (mlduration,mlpower)) - else: + else: # pragma: no cover p1ml = None if len(mhduration)>=4: p1mh, success = optimize.leastsq(errfunc, p0[:], args = (mhduration,mhpower)) - else: + else: # pragma: no cover p1mh = None fitt = pd.Series(10**(4*np.arange(100)/100.)) @@ -3317,7 +3317,7 @@ def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data', powerdf = powerdf[~(powerdf == 0).any(axis=1)] # plot tools - if (promember==1): + if (promember==1): # pragma: no cover TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' else: TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' @@ -3348,7 +3348,7 @@ def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data', if type == 'water': p1 = [r.p0,r.p1,r.p2,r.p3] ratio = r.cpratio - elif type == 'erg' : + elif type == 'erg' : # pragma: no cover p1 = [r.ep0,r.ep1,r.ep2,r.ep3] ratio = r.ecpratio @@ -3371,7 +3371,7 @@ def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data', # fitting WC data to three parameter CP model - if len(wcdurations)>=4: + if len(wcdurations)>=4: # pragma: no cover fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3])) errfunc = lambda pars,x,y: fitfunc(pars,x)-y p1wc, success = optimize.leastsq(errfunc, p0[:], @@ -3379,7 +3379,7 @@ def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data', else: p1wc = None - if p1wc is not None and cpoverlay: + if p1wc is not None and cpoverlay: # pragma: no cover fitpowerwc = fitfunc(p1wc,fitt) fitpowerexcellent = 0.7*fitfunc(p1wc,fitt) fitpowergood = 0.6*fitfunc(p1wc,fitt) @@ -3480,7 +3480,7 @@ def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data', plot.line('duration','CPmax',source=sourcecomplex,legend_label="CP Model", color='red') - if p1wc is not None: + if p1wc is not None: # pragma: no cover plot.line('duration','fitpowerwc',source=sourcecomplex, legend_label="Gold Medal Standard", color='darkgoldenrod',line_dash='dotted') @@ -3516,7 +3516,7 @@ def interactive_agegroup_plot(df,distance=2000,duration=None, name = df['name'] season = df['season'] - if duration: + if duration: # pragma: no cover duration2 = int(duration/60.) plottitle = sex+' '+weightcategory+' %s min' % duration2 else: @@ -3584,7 +3584,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, # plot tools if (promember==1): TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - else: + else: # pragma: no cover TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' @@ -3615,7 +3615,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, # fitting the data to Paul if len(thedistances)>=2: paulslope, paulintercept,r,p,stderr = linregress(np.log10(thedistances),p) - else: + else: # pragma: no cover paulslope = 5.0/np.log10(2.0) paulintercept = p[0]-paulslope*np.log10(thedistances[0]) @@ -3655,7 +3655,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, if len(wcdurations)>=4: p1wc, success = optimize.leastsq(errfunc, p0[:], args = (wcdurations,wcpower)) - else: + else: # pragma: no cover p1wc = None # fitting the data to three parameter CP model @@ -3665,18 +3665,18 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, if len(thesecs)>=4: try: p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower)) - except (RuntimeError,RuntimeWarning): + except (RuntimeError,RuntimeWarning): # pragma: no cover factor = fitfunc(p0,thesecs.mean())/theavpower.mean() p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] success = 0 - else: + else: # pragma: no cover factor = fitfunc(p0,thesecs.mean())/theavpower.mean() p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] success = 0 # Get stayer score - if success == 1: + if success == 1: # pragma: no cover power1min = fitfunc(p1,60.) power4min = fitfunc(p1,240.) power6min = fitfunc(p1,360.) @@ -3711,7 +3711,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, fitpowerfair = 0.5*fitfunc(p1wc,fitt) fitpoweraverage = 0.4*fitfunc(p1wc,fitt) - else: + else: # pragma: no cover fitpowerwc = 0*fitpower fitpowerexcellent = 0*fitpower fitpowergood = 0*fitpower @@ -3721,7 +3721,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, message = "" - if len(fitpower[fitpower<0]) > 0: + if len(fitpower[fitpower<0]) > 0: # pragma: no cover message = "CP model fit didn't give correct results" fitvelo = (fitpower/2.8)**(1./3.) @@ -3786,7 +3786,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, plot.xaxis.axis_label = "Duration (seconds)" plot.yaxis.axis_label = "Power (W)" - if stayerscore is not None: + if stayerscore is not None: # pragma: no cover plot.add_layout( Label(x=100,y=100,x_units='screen',y_units='screen', text='Stayer Score '+str(stayerscore)+'%', @@ -3805,7 +3805,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, cpdata = dataprep.fetchcperg(rower, theworkouts) - if cpdata.empty: + if cpdata.empty: # pragma: no cover message = 'Calculations are running in the background. Please refresh this page to see updated results' return ['','',paulslope,paulintercept,p1,message,p1wc] @@ -3899,7 +3899,7 @@ def interactive_windchart(id=0,promember=0): hrtr=r.tr,hran=r.an,ftp=r.ftp) rowdata = rdata(f1,rower=rr) - if rowdata == 0: + if rowdata == 0: # pragma: no cover return 0 try: @@ -3907,7 +3907,7 @@ def interactive_windchart(id=0,promember=0): except KeyError: return ['','No Data Found'] - try: + try: # pragma: no cover vwind = rowdata.df.loc[:,'vwind'] winddirection = rowdata.df.loc[:,'winddirection'] bearing = rowdata.df.loc[:,'bearing'] @@ -3938,7 +3938,7 @@ def interactive_windchart(id=0,promember=0): # plot tools if (promember==1): TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair' - else: + else: # pragma: no cover TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' @@ -3992,7 +3992,7 @@ def interactive_streamchart(id=0,promember=0): hrtr=r.tr,hran=r.an,ftp=r.ftp) rowdata = rdata(f1,rower=rr) - if rowdata == 0: + if rowdata == 0: # pragma: no cover return "","No Valid Data Available" try: @@ -4011,7 +4011,7 @@ def interactive_streamchart(id=0,promember=0): # plot tools if (promember==1): TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair' - else: + else: # pragma: no cover TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' @@ -4059,12 +4059,12 @@ def interactive_chart(id=0,promember=0,intervaldata = {}): try: spm = datadf['spm'] - except KeyError: + except KeyError: # pragma: no cover datadf['spm'] = 0 try: pace = datadf['pace'] - except KeyError: + except KeyError: # pragma: no cover datadf['pace'] = 0 source = ColumnDataSource( @@ -4180,7 +4180,7 @@ def interactive_chart(id=0,promember=0,intervaldata = {}): def interactive_chart_video(videodata): try: spm = videodata['spm'] - except KeyError: + except KeyError: # pragma: no cover return "","No SPM data" time = range(len(spm)) @@ -4293,22 +4293,22 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', title=None,binsize=1,colorlegend=[], spmmin=0,spmmax=0,workmin=0,workmax=0): - if datadf.empty: + if datadf.empty: # pragma: no cover return ['','

                No non-zero data in selection

                '] - if xparam == 'workoutid': + if xparam == 'workoutid': # pragma: no cover xparamname = 'Workout' else: xparamname = axlabels[xparam] - if yparam == 'workoutid': + if yparam == 'workoutid': # pragma: no cover yparamname = 'Workout' else: yparamname = axlabels[yparam] - if groupby == 'workoutid': + if groupby == 'workoutid': # pragma: no cover groupname = 'Workout' - elif groupby == 'date': + elif groupby == 'date': # pragma: no cover groupname = 'Date' else: groupname = axlabels[groupby] @@ -4321,31 +4321,31 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', gr = groupname, ) - if xparam == 'cumdist': + if xparam == 'cumdist': # pragma: no cover res = make_cumvalues(datadf[xparam]) datadf[xparam] = res[0] - if xparam=='distance': + if xparam=='distance': # pragma: no cover xaxmax = datadf[xparam].max() xaxmin = datadf[xparam].min() - elif xparam=='time': + elif xparam=='time': # pragma: no cover tseconds = datadf.loc[:,'time'] xaxmax = tseconds.max() xaxmin = 0 - elif xparam == 'workoutid': + elif xparam == 'workoutid': # pragma: no cover xaxmax = datadf[xparam].max()-5 xaxmin = datadf[xparam].min()+5 else: xaxmax = yaxmaxima[xparam] xaxmin = yaxminima[xparam] - if yparam=='distance': + if yparam=='distance':# pragma: no cover yaxmax = datadf[yparam].max() yaxmin = datadf[yparam].min() - elif yparam=='time': + elif yparam=='time': # pragma: no cover tseconds = datadf.loc[:,'time'] yaxmax = tseconds.max() yaxmin = 0 - elif yparam == 'workoutid': + elif yparam == 'workoutid': # pragma: no cover yaxmax = datadf[yparam].max()-5 yaxmin = datadf[yparam].min()+5 else: @@ -4354,7 +4354,7 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', x_axis_type = 'linear' y_axis_type = 'linear' - if xparam == 'time': + if xparam == 'time': # pragma: no cover x_axis_type = 'datetime' if yparam == 'pace': y_axis_type = 'datetime' @@ -4375,7 +4375,7 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', (xparamname,'@x{1.1}'), (yparamname,'@y') ]) - else: + else: # pragma: no cover hover = HoverTool(names=['data'], tooltips = [ (groupby,'@groupval'), @@ -4465,12 +4465,12 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', angle=90, angle_units='deg') - if xparam == 'workoutid': + if xparam == 'workoutid': # pragma: no cover plot.xaxis.axis_label = 'Workout' else: plot.xaxis.axis_label = axlabels[xparam] - if yparam == 'workoutid': + if yparam == 'workoutid': # pragma: no cover plot.xaxis.axis_label = 'Workout' else: plot.yaxis.axis_label = axlabels[yparam] @@ -4529,7 +4529,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, try: tests = datadf[yparam2] - except KeyError: + except KeyError: # pragma: no cover yparam2 = 'None' try: @@ -4563,19 +4563,19 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, # check if dataframe not empty - if datadf.empty: + if datadf.empty: # pragma: no cover return ['','

                No non-zero data in selection

                ','',''] try: datadf['x1'] = datadf.loc[:,xparam] - except KeyError: + except KeyError: # pragma: no cover try: datadf['x1'] = datadf['distance'] except KeyError: try: datadf['x1'] = datadf['time'] - except KeyError: + except KeyError: # pragma: no cover return ['','

                No non-zero data in selection

                ','',''] try: @@ -4583,18 +4583,18 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, except KeyError: try: datadf['y1'] = datadf['pace'] - except KeyError: + except KeyError: # pragma: no cover return ['','

                No non-zero data in selection

                ','',''] if yparam2 != 'None': try: datadf['y2'] = datadf.loc[:,yparam2] - except KeyError: + except KeyError: # pragma: no cover datadf['y2'] = datadf['y1'] - else: + else: # pragma: no cover datadf['y2'] = datadf['y1'] - if xparam=='distance': + if xparam=='distance': # pragma: no cover xaxmax = datadf['x1'].max() xaxmin = datadf['x1'].min() else: @@ -4615,7 +4615,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, if xparam == 'time': x_axis_type = 'datetime' - if yparam1 == 'pace': + if yparam1 == 'pace': # pragma: no cover y_axis_type = 'datetime' y1mean = datadf.loc[:,'pace'].mean() @@ -4623,7 +4623,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, datadf['yname1'] = axlabels[yparam1] if yparam2 != 'None': datadf['yname2'] = axlabels[yparam2] - else: + else: # pragma: no cover datadf['yname2'] = axlabels[yparam1] @@ -4638,7 +4638,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, # Add hover to this comma-separated string and see what changes if (promember==1): TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair' - else: + else: # pragma: no cover TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, @@ -4725,7 +4725,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) plot.x_range = xrange1 - if yparam1 == 'pace': + if yparam1 == 'pace': # pragma: no cover plot.yaxis[0].formatter = DatetimeTickFormatter( seconds = ["%S"], minutes = ["%M"] @@ -4880,7 +4880,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, try: distmax = 100+100*int(datadf['distance'].max()/100.) - except KeyError: + except KeyError: # pragma: no cover distmax = 1000. slider_dist_min = Slider(width=140, start=0,end=distmax,value=0,step=50, @@ -4944,7 +4944,7 @@ def interactive_flexchart_stacked(id,r,xparam='time', workstrokesonly=False) - if r.usersmooth > 1: + if r.usersmooth > 1: # pragma: no cover for column in columns: try: if metricsdicts[column]['maysmooth']: @@ -4965,23 +4965,23 @@ def interactive_flexchart_stacked(id,r,xparam='time', try: tseconds = rowdata.loc[:,'time'] - except KeyError: + except KeyError: # pragma: no cover return '','No time data - cannot make flex plot','','',comment try: rowdata['x1'] = rowdata.loc[:,xparam] rowmin = rowdata[xparam].min() - except KeyError: + except KeyError: # pragma: no cover rowdata['x1'] = 0*rowdata.loc[:,'time'] try: rowdata['y1'] = rowdata.loc[:,yparam1] rowmin = rowdata[yparam1].min() - except KeyError: + except KeyError: # pragma: no cover rowdata['y1'] = 0*rowdata.loc[:,'time'] rowdata[yparam1] = rowdata['y1'] - try: + try: # pragma: no cover rowdata['y2'] = rowdata.loc[:,yparam2] rowmin = rowdata[yparam2].min() except KeyError: @@ -4991,24 +4991,24 @@ def interactive_flexchart_stacked(id,r,xparam='time', try: rowdata['y3'] = rowdata.loc[:,yparam3] rowmin = rowdata[yparam3].min() - except KeyError: + except KeyError: # pragma: no cover rowdata['y3'] = 0*rowdata.loc[:,'time'] rowdata[yparam3] = rowdata['y3'] try: rowdata['y4'] = rowdata.loc[:,yparam4] rowmin = rowdata[yparam4].min() - except KeyError: + except KeyError: # pragma: no cover rowdata['y4'] = 0*rowdata.loc[:,'time'] rowdata[yparam4] = rowdata['y4'] if xparam=='time': xaxmax = tseconds.max() xaxmin = tseconds.min() - elif xparam=='distance' or xparam=='cumdist': + elif xparam=='distance' or xparam=='cumdist': # pragma: no cover xaxmax = rowdata['x1'].max() xaxmin = rowdata['x1'].min() - else: + else: # pragma: no cover try: xaxmax = get_yaxmaxima(r,xparam,mode) xaxmin = get_yaxminima(r,xparam,mode) @@ -5025,41 +5025,41 @@ def interactive_flexchart_stacked(id,r,xparam='time', if xparam == 'time': x_axis_type = 'datetime' - if yparam1 == 'pace': + if yparam1 == 'pace': # pragma: no cover y1_axis_type = 'datetime' - if yparam2 == 'pace': + if yparam2 == 'pace': # pragma: no cover y2_axis_type = 'datetime' - if yparam3 == 'pace': + if yparam3 == 'pace': # pragma: no cover y3_axis_type = 'datetime' - if yparam4 == 'pace': + if yparam4 == 'pace': # pragma: no cover y4_axis_type = 'datetime' try: rowdata['xname'] = axlabels[xparam] - except KeyError: + except KeyError: # pragma: no cover rowdata['xname'] = xparam try: rowdata['yname1'] = axlabels[yparam1] - except KeyError: + except KeyError: # pragma: no cover rowdata['yname1'] = yparam1 try: rowdata['yname2'] = axlabels[yparam2] - except KeyError: + except KeyError: # pragma: no cover rowdata['yname2'] = yparam2 try: rowdata['yname3'] = axlabels[yparam3] - except KeyError: + except KeyError: # pragma: no cover rowdata['yname3'] = yparam3 try: rowdata['yname4'] = axlabels[yparam4] - except KeyError: + except KeyError: # pragma: no cover rowdata['yname4'] = yparam4 # prepare data @@ -5094,56 +5094,21 @@ def interactive_flexchart_stacked(id,r,xparam='time', plot3.add_tools(linked_crosshair) plot4.add_tools(linked_crosshair) - try: - xaxlabel = axlabels[xparam] - except KeyError: - xaxlabel = xparam - - try: - yax1label = axlabels[yparam1] - except KeyError: - yax1label = yparam1 + xaxlabel = axlabels.get(xparam,xparam) + yax1label = axlabels.get(yparam1,yparam1) plot1.yaxis.axis_label = yax1label - try: - xaxlabel = axlabels[xparam] - except KeyError: - xaxlabel = xparam - - try: - yax2label = axlabels[yparam2] - except KeyError: - yax2label = yparam2 + yax2label = axlabels.get(yparam2,yparam2) plot2.yaxis.axis_label = yax2label - try: - xaxlabel = axlabels[xparam] - except KeyError: - xaxlabel = xparam + yax3label = axlabels.get(yparam3,yparam3) - try: - yax3label = axlabels[yparam3] - except KeyError: - yax3label = yparam3 plot3.yaxis.axis_label = yax3label - try: - xaxlabel = axlabels[xparam] - except KeyError: - xaxlabel = xparam - - try: - yax4label = axlabels[yparam4] - except KeyError: - yax4label = yparam4 - - try: - xaxlabel = axlabels[xparam] - except KeyError: - xaxlabel = xparam + yax4label = axlabels.get(yparam4,yparam4) plot4.yaxis.axis_label = yax4label @@ -5173,49 +5138,49 @@ def interactive_flexchart_stacked(id,r,xparam='time', if yparam1 == 'pace': y1tooltip = '@fpace' - elif yparam1 != 'None': + elif yparam1 != 'None': # pragma: no cover y1tooltip = '@{yparam1}'.format(yparam1=yparam1) if metricsdicts[yparam1]['numtype'] == 'integer' or yparam1 == 'power': y1tooltip+='{int}' - else: + else: # pragma: no cover y1tooltip+='{0.00}' - else: + else: # pragma: no cover y1tooltip = '' comment = 'The metric in the first chart is only accessible with a Pro plan or higher' - if yparam2 == 'pace': + if yparam2 == 'pace': # pragma: no cover y2tooltip = '@fpace' elif yparam2 != 'None': y2tooltip = '@{yparam2}'.format(yparam2=yparam2) if metricsdicts[yparam2]['numtype'] == 'integer' or yparam2 == 'power': y2tooltip+='{int}' - else: + else: # pragma: no cover y2tooltip+='{0.00}' - else: + else: # pragma: no cover y2tooltip = '' comment = 'The metric in the second chart is only accessible with a Pro plan or higher' - if yparam3 == 'pace': + if yparam3 == 'pace': # pragma: no cover y3tooltip = '@fpace' elif yparam3 != 'None': y3tooltip = '@{yparam3}'.format(yparam3=yparam3) if metricsdicts[yparam3]['numtype'] == 'integer' or yparam3 == 'power': y3tooltip+='{int}' - else: + else: # pragma: no cover y3tooltip+='{0.00}' - else: + else: # pragma: no cover y3tooltip = '' comment = 'The metric in the third chart is only accessible with a Pro plan or higher' - if yparam4 == 'pace': + if yparam4 == 'pace': # pragma: no cover y4tooltip = '@fpace' elif yparam4 != 'None': y4tooltip = '@{yparam4}'.format(yparam4=yparam4) - if metricsdicts[yparam4]['numtype'] == 'integer' or yparam4 == 'power': + if metricsdicts[yparam4]['numtype'] == 'integer' or yparam4 == 'power': # pragma: no cover y4tooltip+='{int}' - else: + else: # pragma: no cover y4tooltip+='{0.00}' - else: + else: # pragma: no cover y4tooltip = '' comment = 'The metric in the fourth chart is only accessible with a Pro plan or higher' @@ -5285,7 +5250,7 @@ def interactive_flexchart_stacked(id,r,xparam='time', ) plot1.y_range = Range1d(y1min,y1max) - if yparam2 == 'pace': + if yparam2 == 'pace': # pragma: no cover plot2.yaxis[0].formatter = DatetimeTickFormatter( seconds = ["%S"], minutes = ["%M"] @@ -5293,14 +5258,14 @@ def interactive_flexchart_stacked(id,r,xparam='time', plot2.y_range = Range1d(y2min,y2max) - if yparam3 == 'pace': + if yparam3 == 'pace': # pragma: no cover plot3.yaxis[0].formatter = DatetimeTickFormatter( seconds = ["%S"], minutes = ["%M"] ) plot3.y_range = Range1d(y3min,y3max) - if yparam4 == 'pace': + if yparam4 == 'pace': # pragma: no cover plot4.yaxis[0].formatter = DatetimeTickFormatter( seconds = ["%S"], minutes = ["%M"] @@ -5359,7 +5324,7 @@ def interactive_flex_chart2(id,r,promember=0, rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True, workstrokesonly=workstrokesonly) - if r.usersmooth > 1: + if r.usersmooth > 1: # pragma: no cover for column in columns: try: if metricsdicts[column]['maysmooth']: @@ -5382,14 +5347,14 @@ def interactive_flex_chart2(id,r,promember=0, workstrokesonly=False try: tests = rowdata[yparam2] - except KeyError: + except KeyError: # pragma: no cover yparam2 = 'None' try: tests = rowdata[yparam1] - except KeyError: + except KeyError: # pragma: no cover yparam1 = 'None' @@ -5421,7 +5386,7 @@ def interactive_flex_chart2(id,r,promember=0, workoutstatesrest = [3] workoutstatetransition = [0,2,10,11,12,13] - if workstrokesonly: + if workstrokesonly: # pragma: no cover try: rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)] except KeyError: @@ -5429,20 +5394,20 @@ def interactive_flex_chart2(id,r,promember=0, try: tseconds = rowdata.loc[:,'time'] - except KeyError: + except KeyError: # pragma: no cover return '','No time data - cannot make flex plot','','',workstrokesonly try: rowdata['x1'] = rowdata.loc[:,xparam] rowmin = rowdata[xparam].min() - except KeyError: + except KeyError: # pragma: no cover rowdata['x1'] = 0*rowdata.loc[:,'time'] try: rowdata['y1'] = rowdata.loc[:,yparam1] rowmin = rowdata[yparam1].min() - except KeyError: + except KeyError: # pragma: no cover rowdata['y1'] = 0*rowdata.loc[:,'time'] rowdata[yparam1] = rowdata['y1'] @@ -5450,10 +5415,10 @@ def interactive_flex_chart2(id,r,promember=0, try: rowdata['y2'] = rowdata.loc[:,yparam2] rowmin = rowdata[yparam2].min() - except KeyError: + except KeyError: # pragma: no cover rowdata['y2'] = 0*rowdata.loc[:,'time'] rowdata[yparam2] = rowdata['y2'] - else: + else: # pragma: no cover rowdata['y2'] = rowdata['y1'] if xparam=='time': @@ -5462,7 +5427,7 @@ def interactive_flex_chart2(id,r,promember=0, elif xparam=='distance' or xparam=='cumdist': xaxmax = rowdata['x1'].max() xaxmin = rowdata['x1'].min() - else: + else: # pragma: no cover try: xaxmax = get_yaxmaxima(r,xparam,mode) xaxmin = get_yaxminima(r,xparam,mode) @@ -5474,9 +5439,9 @@ def interactive_flex_chart2(id,r,promember=0, if xparam != 'time': try: x1mean = rowdata['x1'].mean() - except TypeError: + except TypeError: # pragma: no cover x1mean = 0 - else: + else: # pragma: no cover x1mean = 0 y1mean = rowdata['y1'].mean() @@ -5489,7 +5454,7 @@ def interactive_flex_chart2(id,r,promember=0, # constant power plot if yparam1 == 'driveenergy': - if xparam == 'spm': + if xparam == 'spm': # pragma: no cover yconstantpower = rowdata['y1'].mean()*rowdata['x1'].mean()/xvals x_axis_type = 'linear' @@ -5501,23 +5466,23 @@ def interactive_flex_chart2(id,r,promember=0, y_axis_type = 'datetime' try: y1mean = rowdata.loc[:,'pace'].mean() - except KeyError: + except KeyError: # pragma: no cover y1mean = 0 try: rowdata['xname'] = axlabels[xparam] - except KeyError: + except KeyError: # pragma: no cover rowdata['xname'] = xparam try: rowdata['yname1'] = axlabels[yparam1] - except KeyError: + except KeyError: # pragma: no cover rowdata['yname1'] = yparam1 if yparam2 != 'None': try: rowdata['yname2'] = axlabels[yparam2] - except KeyError: + except KeyError: # pragma: no cover rowdata['yname2'] = yparam2 - else: + else: # pragma: no cover rowdata['yname2'] = rowdata['yname1'] @@ -5587,7 +5552,7 @@ def interactive_flex_chart2(id,r,promember=0, xlabeltext = axlabels[xparam]+": {x1mean:6.2f}".format( x1mean=x1mean ) - except KeyError: + except KeyError: # pragma: no cover xlabeltext = xparam+": {x1mean:6.2f}".format(x1mean=x1mean) xlabel = Label(x=50,y=80,x_units='screen',y_units='screen', @@ -5612,7 +5577,7 @@ def interactive_flex_chart2(id,r,promember=0, ) - if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): + if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): # pragma: no cover plot.add_layout(x1means) plot.add_layout(xlabel) @@ -5623,12 +5588,12 @@ def interactive_flex_chart2(id,r,promember=0, try: yaxlabel = axlabels[yparam1] - except KeyError: + except KeyError: # pragma: no cover yaxlabel = str(yparam1)+' ' try: xaxlabel = axlabels[xparam] - except KeyError: + except KeyError: # pragma: no cover xaxlabel = xparam y1label = Label(x=50,y=50,x_units='screen',y_units='screen', @@ -5637,18 +5602,18 @@ def interactive_flex_chart2(id,r,promember=0, background_fill_color='white', text_color='blue', ) - if yparam1 != 'time' and yparam1 != 'pace': + if yparam1 != 'time' and yparam1 != 'pace': # pragma: no cover plot.add_layout(y1label) y2label = y1label # average values - if yparam1 == 'driveenergy': + if yparam1 == 'driveenergy': # pragma: no cover if xparam == 'spm': plot.line(xvals,yconstantpower,color="green",legend_label="Constant Power") if plottype=='line': plot.line('x1','y1',source=source2,legend_label=yaxlabel) - elif plottype=='scatter': + elif plottype=='scatter': # pragma: no cover plot.scatter('x1','y1',source=source2,legend_label=yaxlabel,fill_alpha=0.4, line_color=None) @@ -5665,13 +5630,13 @@ def interactive_flex_chart2(id,r,promember=0, try: yrange1 = Range1d(start=get_yaxminima(r,yparam1,mode), end=get_yaxmaxima(r,yparam1,mode)) - except KeyError: + except KeyError: # pragma: no cover yrange1 = Range1d(start=rowdata[yparam1].min(), end=rowdata[yparam1].max()) plot.y_range = yrange1 - if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): + if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): # pragma: no cover try: xrange1 = Range1d(start=get_yaxminima(r,xparam,mode), end=get_yaxmaxima(r,xparam,mode)) @@ -5705,7 +5670,7 @@ def interactive_flex_chart2(id,r,promember=0, try: yrange2 = Range1d(start=get_yaxminima(r,yparam2,mode), end=get_yaxmaxima(r,yparam2,mode)) - except KeyError: + except KeyError: # pragma: no cover yrange2 = Range1d(start=rowdata[yparam2].min(), end=rowdata[yparam2].max()) @@ -5713,7 +5678,7 @@ def interactive_flex_chart2(id,r,promember=0, #= {"yax2": yrange2} try: axlegend = axlabels[yparam2] - except KeyError: + except KeyError: # pragma: no cover axlegend = str(yparam2)+' ' if plottype=='line': @@ -5721,7 +5686,7 @@ def interactive_flex_chart2(id,r,promember=0, legend_label=axlegend, source=source2) - elif plottype=='scatter': + elif plottype=='scatter': # pragma: no cover plot.scatter('x1','y2',source=source2,legend_label=axlegend, fill_alpha=0.4, line_color=None,color="red",y_range_name="yax2") @@ -5908,7 +5873,7 @@ def interactive_flex_chart2(id,r,promember=0, try: distmax = 100+100*int(rowdata['distance'].max()/100.) - except (KeyError,ValueError): + except (KeyError,ValueError): # pragma: no cover distmax = 100 slider_dist_min = Slider(width=140, start=0,end=distmax,value=0,step=50, @@ -5970,7 +5935,7 @@ def thumbnails_set(r,id,favorites): try: rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=False, workstrokesonly=False) - except: + except: # pragma: no cover return [ {'script':"", 'div':"", @@ -5997,7 +5962,7 @@ def thumbnails_set(r,id,favorites): bins = np.linspace(rowdata['time'].min(),rowdata['time'].max(),maxlength) groups = rowdata.groupby(np.digitize(rowdata['time'],bins)) rowdata = groups.mean() - except KeyError: + except KeyError: # pragma: no cover pass for f in favorites: @@ -6042,24 +6007,24 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, try: tseconds = rowdata.loc[:,'time'] - except KeyError: + except KeyError: # pragma: no cover return '','No time data - cannot make flex plot' try: rowdata['x1'] = rowdata.loc[:,xparam] - except KeyError: + except KeyError: # pragma: no cover rowdata['x1'] = 0*rowdata.loc[:,'time'] try: rowdata['y1'] = rowdata.loc[:,yparam1] - except KeyError: + except KeyError: # pragma: no cover rowdata['y1'] = 0*rowdata.loc[:,'time'] if yparam2 != 'None': try: rowdata['y2'] = rowdata.loc[:,yparam2] - except KeyError: + except KeyError: # pragma: no cover rowdata['y2'] = 0*rowdata.loc[:,'time'] else: rowdata['y2'] = rowdata['y1'] @@ -6067,7 +6032,7 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, if xparam=='time': xaxmax = tseconds.max() xaxmin = tseconds.min() - elif xparam=='distance' or xparam=='cumdist': + elif xparam=='distance' or xparam=='cumdist': # pragma: no cover xaxmax = rowdata['x1'].max() xaxmin = rowdata['x1'].min() else: @@ -6079,7 +6044,7 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, if xparam == 'time': x_axis_type = 'datetime' - if yparam1 == 'pace': + if yparam1 == 'pace': # pragma: no cover y_axis_type = 'datetime' y1mean = rowdata.loc[:,'pace'].mean() @@ -6087,7 +6052,7 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, rowdata['xname'] = axlabels[xparam] try: rowdata['yname1'] = axlabels[yparam1] - except KeyError: + except KeyError: # pragma: no cover rowdata['yname1'] = axlabels[xparam] if yparam2 != 'None': rowdata['yname2'] = axlabels[yparam2] @@ -6126,17 +6091,17 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, try: plot.xaxis.axis_label = axlabels[xparam] - except KeyError: + except KeyError: # pragma: no cover plot.xaxis.axis_label = 'X' try: plot.yaxis.axis_label = axlabels[yparam1] - except KeyError: + except KeyError: # pragma: no cover plot.yaxis.axis_label = 'Y' try: yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1]) - except KeyError: + except KeyError: # pragma: no cover yrange1 = Range1d(start=yparam1.min(), end=yparam1.max()) plot.y_range = yrange1 @@ -6158,7 +6123,7 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, ) - if yparam1 == 'pace': + if yparam1 == 'pace': # pragma: no cover plot.yaxis[0].formatter = DatetimeTickFormatter( seconds = ["%S"], minutes = ["%M"] @@ -6174,7 +6139,7 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, plot.line('x1','y2',color="red",y_range_name="yax2", source=source) - elif plottype=='scatter': + elif plottype=='scatter': # pragma: no cover plot.scatter('x1','y2',source=source, fill_alpha=0.4, line_color=None,color="red",y_range_name="yax2") @@ -6191,128 +6156,6 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, return [script,div] - -def interactive_bar_chart(id=0,promember=0): - # check if valid ID exists (workout exists) - rowdata,row = dataprep.getrowdata_db(id=id) - rowdata.dropna(axis=1,how='all',inplace=True) - rowdata.dropna(axis=0,how='any',inplace=True) - - if rowdata.empty: - return "","No Valid Data Available" - - # Add hover to this comma-separated string and see what changes - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - - source = ColumnDataSource( - rowdata - ) - - plot = Figure(x_axis_type="datetime",y_axis_type="datetime", - toolbar_sticky=False, - plot_width=920, - tools=TOOLS) - - # add watermark - watermarkurl = "/static/img/logo7.png" - watermarksource = ColumnDataSource(dict( - url = [watermarkurl],)) - - watermarkrange = Range1d(start=0,end=1) - watermarkalpha = 0.6 - watermarkx = 0.99 - watermarky = 0.01 - watermarkw = 184 - watermarkh = 35 - watermarkanchor = 'bottom_right' - plot.extra_y_ranges = {"watermark": watermarkrange} - plot.extra_x_ranges = {"watermark": watermarkrange} - plot.sizing_mode = 'stretch_both' - - plot.image_url([watermarkurl],0.01,0.99, - watermarkw,watermarkh, - global_alpha=watermarkalpha, - w_units='screen', - h_units='screen', - anchor='top_left', - dilate=True, - x_range_name = "watermark", - y_range_name = "watermark", - ) - - plot.title.text = row.name - plot.title.text_font_size=value("1.0em") - plot.xaxis.axis_label = "Time" - plot.yaxis.axis_label = "Pace (/500m)" - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours ="", - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) - - plot.yaxis[0].formatter = DatetimeTickFormatter( - hours = "", - seconds = ["%S"], - minutes = ["%M"], - ) - ymax = 1.0e3*90 - ymin = 1.0e3*180 - - if row.workouttype == 'water': - ymax = 1.0e3*90 - ymin = 1.0e3*210 - - plot.y_range = Range1d(ymin,ymax) - - - hover = plot.select(dict(type=HoverTool)) - - - hover.tooltips = OrderedDict([ - ('Time','@ftime'), - ('Pace','@fpace'), - ('HR','@hr{int}'), - ('SPM','@spm{1.1}'), - ]) - - hover.mode = 'mouse' - - plot.extra_y_ranges["hr"] = Range1d(start=100,end=200) - plot.quad(left='time',top='hr_ut2',bottom='hr_bottom', - right='x_right',source=source,color="gray", - y_range_name="hr", legend_label=" 0] # check if dataframe not empty - if datadf.empty: + if datadf.empty: # pragma: no cover return ['','

                No non-zero data in selection

                ','','No non-zero data in selection'] - if xparam != 'distance' and xparam != 'time' and xparam != 'cumdist': + if xparam != 'distance' and xparam != 'time' and xparam != 'cumdist': # pragma: no cover xaxmax = yaxmaxima[xparam] xaxmin = yaxminima[xparam] elif xparam == 'time' and not startenddict: xaxmax = tseconds.max() xaxmin = tseconds.min() - elif xparam == 'time' and startenddict: + elif xparam == 'time' and startenddict: # pragma: no cover deltas = [pair[1]-pair[0] for key,pair in startenddict.items()] xaxmin = 0 xaxmax = pd.Series(deltas).max()*1000. @@ -6373,10 +6216,10 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', xaxmax = datadf['distance'].max() xaxmin = datadf['distance'].min() - if yparam == 'distance': + if yparam == 'distance': # pragma: no cover yaxmin = datadf['distance'].min() yaxmax = datadf['distance'].max() - elif yparam == 'cumdist': + elif yparam == 'cumdist': # pragma: no cover yaxmin = datadf['cumdist'].min() yaxmax = datadf['cumdist'].max() else: @@ -6389,7 +6232,7 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', # Add hover to this comma-separated string and see what changes if (promember==1): TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair' - else: + else: # pragma: no cover TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' if yparam == 'pace': @@ -6476,7 +6319,7 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', try: group['x'] = group[xparam] - except KeyError: + except KeyError: # pragma: no cover group['x'] = group['time'] errormessage = xparam+' has no values. Plot invalid' try: @@ -6495,7 +6338,7 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', if windowsize > 3 and windowsize < len(group['y']): try: group['y'] = savgol_filter(group['y'],windowsize,3) - except ValueError: + except ValueError: # pragma: no cover pass ylabel = Label(x=100,y=60+nrworkouts*20-20*cntr, @@ -6526,9 +6369,9 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', if labeldict: try: legend_label=labeldict[id] - except KeyError: + except KeyError: # pragma: no cover legend = str(id) - else: + else: # pragma: no cover legend_label=str(id) if plottype=='line': @@ -6544,7 +6387,7 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', plot.xaxis.axis_label = axlabels[xparam] plot.yaxis.axis_label = axlabels[yparam] - if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): + if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): # pragma: no cover xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) plot.x_range = xrange1 @@ -6589,7 +6432,7 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0): # Add hover to this comma-separated string and see what changes if (promember==1): TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - else: + else: # pragma: no cover TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' source = ColumnDataSource( @@ -6673,7 +6516,7 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0): try: script, div = components(plot) - except: + except: # pragma: no cover script = '' div = '' diff --git a/rowers/tests/test_emails.py b/rowers/tests/test_emails.py index 916fb50e..8b8bf8ca 100644 --- a/rowers/tests/test_emails.py +++ b/rowers/tests/test_emails.py @@ -575,10 +575,7 @@ race 1 self.assertIn('Successfully processed email attachments',out.getvalue()) ws = Workout.objects.filter(name="johnsworkout") - if not len(ws): - for w in Workout.objects.all(): - print(w) - + self.assertEqual(len(ws),1) w = ws[0] diff --git a/rowers/tests/test_interactivecharts.py b/rowers/tests/test_interactivecharts.py index 522b716d..319f901d 100644 --- a/rowers/tests/test_interactivecharts.py +++ b/rowers/tests/test_interactivecharts.py @@ -63,15 +63,6 @@ class InteractiveChartTest(TestCase): mocked_getsmallrowdata_db): res = iplots.interactive_chart(self.wote.id,promember=1) - @patch('rowers.dataprep.create_engine') - @patch('rowers.dataprep.read_df_sql') - def test_interactive_chart3(self, mocked_sqlalchemy,mocked_read_df_sql): - res = iplots.interactive_bar_chart(self.wote.id) - - @patch('rowers.dataprep.create_engine') - @patch('rowers.dataprep.read_df_sql') - def test_interactive_chart4(self, mocked_sqlalchemy,mocked_read_df_sql): - res = iplots.interactive_bar_chart(self.wote.id,promember=1) @patch('rowers.dataprep.create_engine') @patch('rowers.dataprep.read_df_sql') diff --git a/rowers/tests/test_permissions2.py b/rowers/tests/test_permissions2.py index 8d193337..fee5d5e7 100644 --- a/rowers/tests/test_permissions2.py +++ b/rowers/tests/test_permissions2.py @@ -234,10 +234,6 @@ class PermissionsViewTests(TestCase): mocked_get_video_data, ): - print() - print(view,'anonymous',permissions['anonymous'],permissions['is_staff'],permissions['dotest']) - print() - if permissions['anonymous'] and not permissions['is_staff'] and permissions['dotest']: urlstotest = [] if permissions['workoutid']: @@ -247,8 +243,6 @@ class PermissionsViewTests(TestCase): url = reverse(view) urlstotest.append(url) - print(view,'anonymous',urlstotest) - for url in urlstotest: result = self.c.get(url) self.assertEqual(result.status_code,permissions['anonymous_response']) @@ -275,10 +269,6 @@ class PermissionsViewTests(TestCase): mocked_get_video_data, ): - print() - print(view,'own') - print() - if permissions['own'] in plans and not permissions['is_staff'] and permissions['dotest']: urlstotest = [] falseurlstotest = [] @@ -288,8 +278,6 @@ class PermissionsViewTests(TestCase): memberuser = self.uplan notuser = None - print(view,'own') - if permissions['own'] == 'basic': thisuser = self.ubasic memberuser = self.uplan @@ -323,8 +311,6 @@ class PermissionsViewTests(TestCase): url = reverse(view) urlstotest.append(url) - print(view,'own',urlstotest,falseurlstotest,otheruserurls) - # test logged in as user who has permissions for url in urlstotest: login = self.c.login(username = thisuser['username'],password = thisuser['password']) @@ -365,10 +351,6 @@ class PermissionsViewTests(TestCase): mocked_get_video_data, ): - print() - print(view,'member') - print() - if permissions['member'] in plans and permissions['is_staff'] is False and permissions['dotest']: urlstotest = [] falseurlstotest = [] @@ -378,8 +360,6 @@ class PermissionsViewTests(TestCase): memberuser = self.uplan notuser = None - print(view,'member') - if permissions['member'] == 'basic': thisuser = self.ubasic memberuser = self.uplan @@ -414,8 +394,6 @@ class PermissionsViewTests(TestCase): url = reverse(view) urlstotest.append(url) - print('member',urlstotest,falseurlstotest,otheruserurls) - # test logged in as user who has permissions for url in urlstotest: login = self.c.login(username = thisuser['username'],password = thisuser['password']) @@ -456,10 +434,6 @@ class PermissionsViewTests(TestCase): mocked_get_video_data, ): - print() - print(view,'coachee') - print() - if permissions['coachee'] in plans and not permissions['is_staff'] and permissions['dotest']: urlstotest = [] falseurlstotest = [] @@ -486,8 +460,6 @@ class PermissionsViewTests(TestCase): url = reverse(view) urlstotest.append(url) - print('coachee',urlstotest,falseurlstotest,otheruserurls) - # test logged in as user who has permissions for url in urlstotest: login = self.c.login(username = thisuser['username'],password = thisuser['password']) diff --git a/rowers/tests/test_plans.py b/rowers/tests/test_plans.py index 270b50a3..a961e0bb 100644 --- a/rowers/tests/test_plans.py +++ b/rowers/tests/test_plans.py @@ -83,6 +83,10 @@ class TrainingPlanTest(TestCase): response = self.c.get(urlplan) self.assertEqual(response.status_code,200) + url = reverse('rower_trainingplan_execution_view',kwargs={'id':1}) + response = self.c.get(url) + self.assertEqual(response.status_code,200) + html = BeautifulSoup(response.content,'html.parser') urls = [a['href'] for a in html.find_all('a')] diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 683ebb1a..a5ad0253 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -1951,7 +1951,7 @@ def workouts_view(request,message='',successmessage='', if request.method == 'POST': dateform = DateRangeForm(request.POST) searchform = SearchForm(request.POST) - if dateform.is_valid(): + if dateform.is_valid(): # pragma: no cover startdate = dateform.cleaned_data['startdate'] enddate = dateform.cleaned_data['enddate'] if searchform.is_valid(): @@ -1986,7 +1986,7 @@ def workouts_view(request,message='',successmessage='', activity_enddate = activity_enddate.replace(hour=23,minute=59,second=59).astimezone(usertimezone) activity_startdate = activity_enddate-datetime.timedelta(days=15) activity_startdate = activity_startdate.replace(hour=0,minute=0,second=0) - else: + else: # pragma: no cover activity_enddate = enddate except (ValueError, AttributeError): # pragma: no cover activity_enddate = enddate @@ -2064,7 +2064,7 @@ def workouts_view(request,message='',successmessage='', workouts = workouts.exclude(rankingpiece=False) workoutsnohr = workouts.exclude(averagehr__isnull=False) - for w in workoutsnohr: + for w in workoutsnohr: # pragma: no cover res = dataprep.workout_trimp(w) # ids = [w.id for w in workouts] From eb32394d0b70ae6d8d77f8b99bda08a0ff52c2d5 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 14 Apr 2021 18:01:01 +0200 Subject: [PATCH 13/17] better coverage, removed some warnings --- rowers/tasks.py | 12 ++++++------ rowers/tests/statements.py | 2 +- rowers/tests/test_imports.py | 16 ++++++++-------- rowers/tests/test_interactivecharts.py | 2 +- rowers/tests/test_user.py | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/rowers/tasks.py b/rowers/tasks.py index 4d8d4415..fe6bd1ec 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -2040,12 +2040,12 @@ def handle_otwsetpower(self,f1, boattype, boatclass, coastalbrand, weightvalue, # do something with boat type try: - rowdata = rdata(csvfile) + rowdata = rdata(csvfile=csvfile) except IOError: try: - rowdata = rdata(csvfile) + rowdata = rdata(csvfile=csvfile) except IOError: - rowdata = rdata(csvfile) + rowdata = rdata(csvfile=csvfile) # do calculation, but do not overwrite NK Empower Power data powermeasured = False @@ -2097,12 +2097,12 @@ def handle_otwsetpower(self,f1, boattype, boatclass, coastalbrand, weightvalue, return 0 # do something with boat type try: - rowdata = rdata(csvfile) + rowdata = rdata(csvfile=csvfile) except IOError: try: - rowdata = rdata(csvfile) + rowdata = rdata(csvfile=csvfile) except IOError: - rowdata = rdata(csvfile) + rowdata = rdata(csvfile=csvfile) update_strokedata(workoutid, rowdata.df, debug=debug) diff --git a/rowers/tests/statements.py b/rowers/tests/statements.py index 40ebeefd..4c73cefe 100644 --- a/rowers/tests/statements.py +++ b/rowers/tests/statements.py @@ -16,7 +16,7 @@ except NameError: import pytest import warnings -#warnings.filterwarnings("error",category=RuntimeWarning) +warnings.filterwarnings("error",category=UserWarning) pytestmark = pytest.mark.django_db diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index 4bfaa939..f0a85235 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -165,7 +165,7 @@ class C2Objects(DjangoTestCase): rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, hrut1=self.r.ut1,hrat=self.r.at, hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) + row = rdata(csvfile=filename,rower=rr) totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] @@ -320,7 +320,7 @@ class C2ObjectsTokenExpired(DjangoTestCase): rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, hrut1=self.r.ut1,hrat=self.r.at, hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) + row = rdata(csvfile=filename,rower=rr) totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] @@ -397,7 +397,7 @@ class NKObjects(DjangoTestCase): rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, hrut1=self.r.ut1,hrat=self.r.at, hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) + row = rdata(csvfile=filename,rower=rr) totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] @@ -543,7 +543,7 @@ class StravaObjects(DjangoTestCase): rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, hrut1=self.r.ut1,hrat=self.r.at, hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) + row = rdata(csvfile=filename,rower=rr) totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] @@ -651,7 +651,7 @@ class STObjects(DjangoTestCase): rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, hrut1=self.r.ut1,hrat=self.r.at, hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) + row = rdata(csvfile=filename,rower=rr) totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] @@ -798,7 +798,7 @@ class RunKeeperObjects(DjangoTestCase): rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, hrut1=self.r.ut1,hrat=self.r.at, hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) + row = rdata(csvfile=filename,rower=rr) totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] @@ -892,7 +892,7 @@ class UAObjects(DjangoTestCase): rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, hrut1=self.r.ut1,hrat=self.r.at, hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) + row = rdata(csvfile=filename,rower=rr) totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] @@ -995,7 +995,7 @@ class TPObjects(DjangoTestCase): rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, hrut1=self.r.ut1,hrat=self.r.at, hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) + row = rdata(csvfile=filename,rower=rr) totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] diff --git a/rowers/tests/test_interactivecharts.py b/rowers/tests/test_interactivecharts.py index 319f901d..b254fce1 100644 --- a/rowers/tests/test_interactivecharts.py +++ b/rowers/tests/test_interactivecharts.py @@ -45,7 +45,7 @@ class InteractiveChartTest(TestCase): rr = rrower(hrmax=r.max,hrut2=r.ut2, hrut1=r.ut1,hrat=r.at, hrtr=r.tr,hran=r.an,ftp=r.ftp) - row = rdata(self.filename,rower=rr) + row = rdata(csvfile=self.filename,rower=rr) fig1 = plots.mkplot(row,'test') diff --git a/rowers/tests/test_user.py b/rowers/tests/test_user.py index 998beea4..ca4aa5b6 100644 --- a/rowers/tests/test_user.py +++ b/rowers/tests/test_user.py @@ -28,7 +28,7 @@ class UserMiddleWareTest(TestCase): rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2, hrut1=self.r.ut1,hrat=self.r.at, hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp) - row = rdata(filename,rower=rr) + row = rdata(csvfile=filename,rower=rr) totaldist = row.df['cum_dist'].max() totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] From 2f1c85427ab8737c2babb631e476394803819211 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 14 Apr 2021 21:39:21 +0200 Subject: [PATCH 14/17] f --- rowers/interactiveplots.py | 95 ++++++++++++++++++++++++----------- rowers/tests/statements.py | 2 +- rowers/tests/test_analysis.py | 3 +- rowers/tests/test_uploads.py | 3 ++ rowers/utils.py | 7 +++ rowers/views/analysisviews.py | 68 ++++++++++++------------- rowers/views/statements.py | 3 +- rowers/views/workoutviews.py | 14 ++---- 8 files changed, 118 insertions(+), 77 deletions(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 271fec56..b406619d 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -1900,9 +1900,6 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7, df['date'] = df.index.values - #for row in df.iterrows(): - # print(row) - source = ColumnDataSource( data = dict( testpower = df['testpower'], @@ -3141,7 +3138,8 @@ def interactive_agegroupcpchart(age,normalized=False): mlduration.append(duration) mlpower.append(worldclasspower) except ZeroDivisionError: - pass + mlduration.append(duration) + mlpower.append(np.nan) for duration in durations: worldclasspower = c2stuff.getagegrouprecord( age, @@ -3155,7 +3153,8 @@ def interactive_agegroupcpchart(age,normalized=False): mlduration.append(60.*duration) mlpower.append(worldclasspower) except ValueError: # pragma: no cover - pass + mlduration.append(60.*duration) + mlpower.append(np.nan) mhduration = [] @@ -3174,7 +3173,8 @@ def interactive_agegroupcpchart(age,normalized=False): mhduration.append(duration) mhpower.append(worldclasspower) except ZeroDivisionError: - pass + mhduration.append(duration) + mhpower.append(np.nan) for duration in durations: worldclasspower = c2stuff.getagegrouprecord( age, @@ -3188,7 +3188,8 @@ def interactive_agegroupcpchart(age,normalized=False): mhduration.append(60.*duration) mhpower.append(worldclasspower) except ValueError: # pragma: no cover - pass + mhduration.append(60.*duration) + mhpower.append(np.nan) @@ -3247,23 +3248,43 @@ def interactive_agegroupcpchart(age,normalized=False): - source = ColumnDataSource( + sourcemh = ColumnDataSource( + data = dict( + mhduration = mhduration, + mhpower = mhpower, + ) + ) + + sourcefl = ColumnDataSource( + data = dict( + flduration = flduration, + flpower = flpower, + ) + ) + + sourcefh = ColumnDataSource( + data = dict( + fhduration = fhduration, + fhpower = fhpower, + ) + ) + + sourceml = ColumnDataSource( + data = dict( + mlduration = mlduration, + mlpower = mlpower, + ) + ) + + sourcefit = ColumnDataSource( data = dict( duration = fitt, fitpowerfh = fitpowerfh, fitpowerfl = fitpowerfl, fitpowerml = fitpowerml, fitpowermh = fitpowermh, - flduration = flduration, - flpower = flpower, - fhduration = fhduration, - fhpower = fhpower, - mlduration = mlduration, - mlpower = mlpower, - mhduration = mhduration, - mhpower = mhpower, - ) ) + ) x_axis_type = 'log' y_axis_type = 'linear' @@ -3274,28 +3295,28 @@ def interactive_agegroupcpchart(age,normalized=False): tools=TOOLS) plot.sizing_mode = 'stretch_both' - plot.line('duration','fitpowerfh',source=source, + plot.line('duration','fitpowerfh',source=sourcefit, legend_label='Female HW',color='blue') - plot.line('duration','fitpowerfl',source=source, + plot.line('duration','fitpowerfl',source=sourcefit, legend_label='Female LW',color='red') - plot.line('duration','fitpowerml',source=source, + plot.line('duration','fitpowerml',source=sourcefit, legend_label='Male LW',color='green') - plot.line('duration','fitpowermh',source=source, + plot.line('duration','fitpowermh',source=sourcefit, legend_label='Male HW',color='orange') - plot.circle('flduration','flpower',source=source, + plot.circle('flduration','flpower',source=sourcefl, fill_color='red',size=15) - plot.circle('fhduration','fhpower',source=source, + plot.circle('fhduration','fhpower',source=sourcefh, fill_color='blue',size=15) - plot.circle('mlduration','mlpower',source=source, + plot.circle('mlduration','mlpower',source=sourceml, fill_color='green',size=15) - plot.circle('mhduration','mhpower',source=source, + plot.circle('mhduration','mhpower',source=sourcemh, fill_color='orange',size=15) plot.title.text = 'age '+str(age) @@ -3400,16 +3421,23 @@ def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data', CPmax = ratio*fitpower, duration = fitt/60., ftime = ftime, - workout = workouts, +# workout = workouts, fitpowerwc = fitpowerwc, fitpowerexcellent = fitpowerexcellent, fitpowergood = fitpowergood, fitpowerfair = fitpowerfair, fitpoweraverage = fitpoweraverage, - url = urls, +# url = urls, ) ) + sourceannot= ColumnDataSource( + data = dict( + workout = workouts, + url = urls, + ) + ) + # making the plot plot = Figure(tools=TOOLS,x_axis_type=x_axis_type, plot_width=900, @@ -3544,13 +3572,20 @@ def interactive_agegroup_plot(df,distance=2000,duration=None, data = dict( age = age, power = power, - age2 = age2, - expo_vals = expo_vals, + #age2 = age2, + #expo_vals = expo_vals, season = season, name=name, ) ) + sourcefit = ColumnDataSource( + data = dict( + age2 = age2, + expo_vals = expo_vals, + ) + ) + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' plot = Figure(tools=TOOLS,plot_width=900) @@ -3558,7 +3593,7 @@ def interactive_agegroup_plot(df,distance=2000,duration=None, plot.circle('age','power',source=source,fill_color='red',size=15, legend_label='World Record') - plot.line(age2,expo_vals) + plot.line('age2','expo_vals',source=sourcefit) plot.xaxis.axis_label = "Age" plot.yaxis.axis_label = "Concept2 power" plot.title.text = plottitle diff --git a/rowers/tests/statements.py b/rowers/tests/statements.py index 4c73cefe..a0226334 100644 --- a/rowers/tests/statements.py +++ b/rowers/tests/statements.py @@ -16,7 +16,7 @@ except NameError: import pytest import warnings -warnings.filterwarnings("error",category=UserWarning) +#warnings.filterwarnings("error",category=UserWarning) pytestmark = pytest.mark.django_db diff --git a/rowers/tests/test_analysis.py b/rowers/tests/test_analysis.py index f6204402..84e4234f 100644 --- a/rowers/tests/test_analysis.py +++ b/rowers/tests/test_analysis.py @@ -9,6 +9,7 @@ from .statements import * nu = datetime.datetime.now() from rowers.views import * +from rowers.views.analysisviews import histodata class WorkoutCompareTest(TestCase): def setUp(self): @@ -1360,7 +1361,7 @@ class WorkoutStatsTestNew(TestCase): script, div = boxplotdata(workouts,options) script, div = trendflexdata(workouts,options) -# script, div = histodata(workouts,options) + script, div = histodata(workouts,options) script, div = flexalldata(workouts,options) script, div = statsdata(workouts,options) script, div = comparisondata(workouts,options) diff --git a/rowers/tests/test_uploads.py b/rowers/tests/test_uploads.py index 86df2b4e..46a96555 100644 --- a/rowers/tests/test_uploads.py +++ b/rowers/tests/test_uploads.py @@ -216,6 +216,9 @@ class ViewTest(TestCase): } form = DocumentsForm(form_data,file_data) + if not form.is_valid(): + print(form.errors) + self.assertTrue(form.is_valid()) response = self.c.post('/rowers/workout/upload/', form_data, follow=True) diff --git a/rowers/utils.py b/rowers/utils.py index 79b38130..fc0b6c61 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -1108,3 +1108,10 @@ def strfdelta(tdelta): ) return res + +def request_is_ajax(request): + is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' + if settings.TESTING: + is_ajax = True + + return is_ajax diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 113c5d69..827b50ac 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -44,7 +44,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): firstworkout = None if id: firstworkout = get_workout(id) - if not is_workout_team(request.user,firstworkout): + if not is_workout_team(request.user,firstworkout): # pragma: no cover raise PermissionDenied("You are not allowed to use this workout") firstworkoutquery = Workout.objects.filter(id=encoder.decode_hex(id)) @@ -62,7 +62,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): options['userid'] = userid try: workouttypes = options['workouttypes'] - except KeyError: + except KeyError: # pragma: no cover workouttypes = ['rower','dynamic','slides'] try: @@ -80,12 +80,12 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): try: rankingonly = options['rankingonly'] - except KeyError: + except KeyError: # pragma: no cover rankingonly = False try: includereststrokes = options['includereststrokes'] - except KeyError: + except KeyError: # pragma: no cover includereststrokes = False if 'startdate' in request.session: @@ -93,7 +93,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): else: startdate=timezone.now()-datetime.timedelta(days=42) - if function not in [c[0] for c in analysischoices]: + if function not in [c[0] for c in analysischoices]: # pragma: no cover function = 'boxplot' if 'enddate' in request.session: @@ -124,7 +124,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): waterboattype = optionsform.cleaned_data['waterboattype'] if modality == 'all': modalities = [m[0] for m in mytypes.workouttypes] - else: + else: # pragma: no cover modalities = [modality] if modality != 'water': waterboattype = [b[0] for b in mytypes.boattypes] @@ -132,7 +132,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): if 'rankingonly' in optionsform.cleaned_data: rankingonly = optionsform.cleaned_data['rankingonly'] - else: + else: # pragma: no cover rankingonly = False options['modalities'] = modalities @@ -156,7 +156,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): selectedworkouts = cd['workouts'] ids = [int(w.id) for w in selectedworkouts] options['ids'] = ids - else: + else: # pragma: no cover ids = [] options['ids'] = ids else: @@ -170,14 +170,14 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): negtypes = [] for b in mytypes.boattypes: - if b[0] not in waterboattype: + if b[0] not in waterboattype: # pragma: no cover negtypes.append(b[0]) startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - if enddate < startdate: + if enddate < startdate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -185,27 +185,27 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): # make sure the dates are not naive try: startdate = pytz.utc.localize(startdate) - except (ValueError, AttributeError): + except (ValueError, AttributeError): # pragma: no cover pass try: enddate = pytz.utc.localize(enddate) - except (ValueError, AttributeError): + except (ValueError, AttributeError): # pragma: no cover pass negtypes = [] for b in mytypes.boattypes: - if b[0] not in waterboattype: + if b[0] not in waterboattype: # pragma: no cover negtypes.append(b[0]) - if theteam is not None and (theteam.viewing == 'allmembers' or theteam.manager == request.user): + if theteam is not None and (theteam.viewing == 'allmembers' or theteam.manager == request.user): # pragma: no cover workouts = Workout.objects.filter(team=theteam, startdatetime__gte=startdate, startdatetime__lte=enddate, workouttype__in=modalities, ) - elif theteam is not None and theteam.viewing == 'coachonly': + elif theteam is not None and theteam.viewing == 'coachonly': # pragma: no cover workouts = Workout.objects.filter(team=theteam,user=r, startdatetime__gte=startdate, startdatetime__lte=enddate, @@ -224,11 +224,11 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''): ).exclude(boattype__in=negtypes) - if rankingonly: + if rankingonly: # pragma: no cover workouts = workouts.exclude(rankingpiece=False) query = request.POST.get('q') - if query: + if query: # pragma: no cover query_list = query.split() try: workouts = workouts.filter( @@ -334,7 +334,7 @@ def trendflexdata(workouts, options,userid=0): # prepare data frame datadf,extracols = dataprep.read_cols_df_sql(ids,fieldlist) - if xparam == groupby: + if xparam == groupby: # pragma: no cover datadf['groupby'] = datadf[xparam] groupy = 'groupby' @@ -376,9 +376,9 @@ def trendflexdata(workouts, options,userid=0): datadf[groupby].max()+binsize, binsize) groups = datadf.groupby(pd.cut(datadf[groupby],bins,labels=False)) - except (ValueError, AttributeError): + except (ValueError, AttributeError): # pragma: no cover return ('','Error: not enough data') - else: + else: # pragma: no cover bins = np.arange(datadf['days ago'].min()-binsize, datadf['days ago'].max()+binsize, binsize, @@ -407,7 +407,7 @@ def trendflexdata(workouts, options,userid=0): yerror.dropna(inplace=True) groupsize.dropna(inplace=True) - if len(groupsize) == 0: + if len(groupsize) == 0: # pragma: no cover messages.error(request,'No data in selection') url = reverse(user_multiflex_select) return HttpResponseRedirect(url) @@ -436,15 +436,15 @@ def trendflexdata(workouts, options,userid=0): df['groupval'].loc[mask] = np.nan groupcols = df['groupval'] - except (ValueError, AttributeError): + except (ValueError, AttributeError): # pragma: no cover df['groupval'] = groups.mean()[groupby].fillna(value=0) df['groupval'].loc[mask] = np.nan groupcols = df['groupval'] - except KeyError: + except KeyError: # pragma: no cover messages.error(request,'Data selection error') url = reverse(user_multiflex_select) return HttpResponseRedirect(url) - else: + else: # pragma: no cover try: dates = groups.min()[groupby] dates.loc[mask] = np.nan @@ -459,7 +459,7 @@ def trendflexdata(workouts, options,userid=0): groupcols = (groupcols-groupcols.min())/(groupcols.max()-groupcols.min()) - if aantal == 1: + if aantal == 1: # pragma: no cover groupcols = np.array([1.]) @@ -471,7 +471,7 @@ def trendflexdata(workouts, options,userid=0): legcolors = range_to_color_hex(clegendx,palette=palette) if groupby != 'date': clegendy = df['groupval'].min()+clegendx*(df['groupval'].max()-df['groupval'].min()) - else: + else: # pragma: no cover clegendy = df.index.min()+clegendx*(df.index.max()-df.index.min()) @@ -481,7 +481,7 @@ def trendflexdata(workouts, options,userid=0): if userid == 0: extratitle = '' - else: + else: # pragma: no cover u = User.objects.get(id=userid) extratitle = ' '+u.first_name+' '+u.last_name @@ -888,7 +888,8 @@ def boxplotdata(workouts,options): redirect_field_name=None) @permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) def analysis_view_data(request,userid=0): - if not request.is_ajax(): + is_ajax = request_is_ajax(request) + if not is_ajax: url = reverse('analysis_new') return HttpResponseRedirect(url) @@ -1581,9 +1582,7 @@ def goldmedalscores_view(request,userid=0, startdate=timezone.now()-timezone.timedelta(days=365), enddate=timezone.now()): - is_ajax = False - if request.is_ajax(): - is_ajax = True + is_ajax = request_is_ajax(request) therower = getrequestrower(request,userid=userid) theuser = therower.user @@ -1649,9 +1648,7 @@ def performancemanager_view(request,userid=0,mode='rower', startdate=timezone.now()-timezone.timedelta(days=365), enddate=timezone.now()): - is_ajax = False - if request.is_ajax(): - is_ajax = True + is_ajax = request_is_ajax(request) therower = getrequestrower(request,userid=userid) @@ -4914,7 +4911,8 @@ def alert_report_view(request,id=0,userid=0,nperiod=0): stats = alert_get_stats(alert,nperiod=nperiod) - if request.is_ajax(): + is_ajax = request_is_ajax(request) + if not is_ajax: return JSONResponse({ "stats":stats, }) diff --git a/rowers/views/statements.py b/rowers/views/statements.py index ba806041..adfb169e 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -1197,7 +1197,8 @@ from rowers.utils import ( geo_distance,serialize_list,deserialize_list,uniqify, str2bool,range_to_color_hex,absolute,myqueue,get_call, calculate_age,rankingdistances,rankingdurations, - is_ranking_piece,my_dict_from_instance,wavg,NoTokenError + is_ranking_piece,my_dict_from_instance,wavg,NoTokenError, + request_is_ajax ) import rowers.datautils as datautils diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index a5ad0253..b10631e9 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -4586,9 +4586,8 @@ def workout_map_view(request,id=0): # Image upload @permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True) def workout_uploadimage_view(request,id): # pragma: no cover - is_ajax = False # pragma: no cover - if request.is_ajax(): - is_ajax = True + is_ajax = request_is_ajax(request) + r = getrower(request.user) @@ -4727,9 +4726,8 @@ def workout_add_chart_view(request,id,plotnr=1): @login_required @permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True) def workout_toggle_ranking(request,id=0): - is_ajax = False - if request.is_ajax(): # pragma: no cover - is_ajax = True + is_ajax = request_is_ajax(request) + row = get_workout_by_opaqueid(request,id) @@ -4980,9 +4978,7 @@ def workout_upload_view(request, }, raceid=0): - is_ajax = False - if request.is_ajax(): # pragma: no cover - is_ajax = True + is_ajax = request_is_ajax(request) r = getrower(request.user) if r.rowerplan == 'freecoach': # pragma: no cover From 15cc8bebb6a050be447146569594dc94154939fd Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 14 Apr 2021 21:45:30 +0200 Subject: [PATCH 15/17] fixing the testing --- rowers/tests/test_uploads.py | 5 +---- rowers/views/workoutviews.py | 4 +++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/rowers/tests/test_uploads.py b/rowers/tests/test_uploads.py index 46a96555..c6f9e5b1 100644 --- a/rowers/tests/test_uploads.py +++ b/rowers/tests/test_uploads.py @@ -216,10 +216,7 @@ class ViewTest(TestCase): } form = DocumentsForm(form_data,file_data) - if not form.is_valid(): - print(form.errors) - self.assertTrue(form.is_valid()) - + response = self.c.post('/rowers/workout/upload/', form_data, follow=True) f.close() diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index b10631e9..8f2a820b 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -4978,7 +4978,9 @@ def workout_upload_view(request, }, raceid=0): - is_ajax = request_is_ajax(request) + is_ajax = request_is_ajax + if settings.TESTING: + is_ajax = False r = getrower(request.user) if r.rowerplan == 'freecoach': # pragma: no cover From ce5ec9a6322a449e53e97a3539a77046506d1122 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 15 Apr 2021 08:33:00 +0200 Subject: [PATCH 16/17] furhter cleaning up tests --- rowers/tests/test_analysis.py | 86 +++++++++++++++++++++++- rowers/utils.py | 4 +- rowers/views/analysisviews.py | 121 +++++++++++++++++----------------- 3 files changed, 149 insertions(+), 62 deletions(-) diff --git a/rowers/tests/test_analysis.py b/rowers/tests/test_analysis.py index 84e4234f..42ef4a03 100644 --- a/rowers/tests/test_analysis.py +++ b/rowers/tests/test_analysis.py @@ -4,7 +4,7 @@ from __future__ import print_function from __future__ import unicode_literals from .statements import * - +from http.cookies import SimpleCookie nu = datetime.datetime.now() @@ -653,6 +653,10 @@ class HistoTest(TestCase): 'startdate':startdate, 'enddate':enddate, 'modality':u'all', + 'histoparam':'power', + 'rankingonly': False, + 'includereststrokes':False, + 'workouttypes': ['water'], 'waterboattype': waterboattype } @@ -1349,6 +1353,8 @@ class WorkoutStatsTestNew(TestCase): 'workmax':1500, 'cpfit':'data', 'piece': 4, + 'cpoverlay':True, + 'cpfit':'data', 'includereststrokes':False, 'modality':'all', 'waterboattype':['1x','2x','4x'], @@ -1362,10 +1368,88 @@ class WorkoutStatsTestNew(TestCase): script, div = boxplotdata(workouts,options) script, div = trendflexdata(workouts,options) script, div = histodata(workouts,options) + script, div = cpdata(workouts,options) script, div = flexalldata(workouts,options) script, div = statsdata(workouts,options) script, div = comparisondata(workouts,options) + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db) + @patch('rowers.dataprep.read_cols_df_sql', side_effect=mocked_read_cols_df_sql) + def test_analysis_data2(self, + mocked_sqlalchemy, + mocked_getsmallrowdata_db, + mocked_read_cols_df_sql, + ): + + startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() + enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + + # make sure the dates are not naive + try: + startdate = pytz.utc.localize(startdate) + except (ValueError, AttributeError): + pass + try: + enddate = pytz.utc.localize(enddate) + except (ValueError, AttributeError): + pass + + options = { + 'function':'flexall', + 'xparam':'hr', + 'plotfield':'spm', + 'yparam':'pace', + 'groupby':'spm', + 'binsize':1, + 'ploterrorbars':True, + 'palette':'monochrome_blue', + 'xaxis':'time', + 'yaxis1':'power', + 'yaxis2':'hr', + 'startdate':startdate.strftime('%Y-%m-%d'), + 'enddate':enddate.strftime('%Y-%m-%d'), + 'plottype':'scatter', + 'spmmin':15, + 'spmmax':55, + 'workmin':0, + 'workmax':1500, + 'cpfit':'data', + 'piece': 4, + 'cpoverlay':True, + 'cpfit':'data', + 'includereststrokes':False, + 'modality':'all', + 'waterboattype':['1x','2x','4x'], + 'rankingonly':False, + 'ids':[1,2,3], + 'userid':self.u.id, + 'function':'boxplot' + } + + workouts = self.user_workouts + + request = self.factory + request.user = self.u + request.META = { + 'HTTP_X_REQUESTED_WITH':'XMLHttpRequest' + } + request.COOKIES = SimpleCookie({'name': 'bla'}) + # adding session + middleware = SessionMiddleware() + middleware.process_request(request) + + + request.session.save() + + session = request.session + options['ids'] = [w.id for w in workouts] + session['options'] = options + session.save() + + + response = analysis_view_data(request) + self.assertEqual(response.status_code,200) @patch('rowers.dataprep.create_engine') diff --git a/rowers/utils.py b/rowers/utils.py index fc0b6c61..235c15dc 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -1111,7 +1111,7 @@ def strfdelta(tdelta): def request_is_ajax(request): is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' - if settings.TESTING: - is_ajax = True + #if settings.TESTING: + # is_ajax = True return is_ajax diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 827b50ac..5111cd9d 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -9,7 +9,7 @@ import collections import simplejson from jinja2 import Template,Environment,FileSystemLoader -def floatformat(x,prec=2): +def floatformat(x,prec=2): # pragma: no cover return '{x}'.format(x=round(x,prec)) import time @@ -566,7 +566,7 @@ def cpdata(workouts, options): - if powerdf.empty: + if powerdf.empty: # pragma: no cover return('','

                No valid data found

                ') powerdf = powerdf[powerdf['CP']>0] @@ -588,16 +588,16 @@ def cpdata(workouts, options): d2 = datelast, ) wtype = 'water' - if workouts[0].workouttype in mytypes.otetypes: + if workouts[0].workouttype in mytypes.otetypes: # pragma: no cover wtype = 'erg' - if workouts[0].workouttype == 'bikeerg': + if workouts[0].workouttype == 'bikeerg': # pragma: no cover # for Mike wtype = 'erg' if cpoverlay: if r.birthdate: age = calculate_age(r.birthdate) - else: + else: # pragma: no cover worldclasspower = None age = 0 @@ -610,7 +610,7 @@ def cpdata(workouts, options): if len(agerecords) == 0: wcpower = [] wcdurations = [] - else: + else: # pragma: no cover wcdurations = [] wcpower = [] for record in agerecords: @@ -633,7 +633,7 @@ def cpdata(workouts, options): paulslope = 1 paulintercept = 1 message = res[4] - else: + else: # pragma: no cover script = '' div = '

                No ranking pieces found.

                ' paulslope = 1 @@ -650,22 +650,22 @@ def cpdata(workouts, options): # minutes = 77 try: hourvalue,tvalue = divmod(minutes,60) - except: + except: # pragma: no cover hourvalue = 0 tvalue = minutes # hourvalue = 1, tvalue = 17 try: hourvalue = int(hourvalue) - except TypeError: + except TypeError: # pragma: no cover hourvalue = 0 try: minutevalue = int(tvalue) - except TypeError: + except TypeError: # pragma: no cover minutevalue = 0 tvalue = int(60*(tvalue-minutevalue)) - if hourvalue >= 24: + if hourvalue >= 24: # pragma: no cover hourvalue = 23 pieceduration = datetime.time( minute = minutevalue, @@ -678,19 +678,19 @@ def cpdata(workouts, options): pwr = p1[0]/(1+pieceseconds/p1[2]) pwr += p1[1]/(1+pieceseconds/p1[3]) - if pwr <= 0: + if pwr <= 0: # pragma: no cover pwr = 50. if not np.isnan(pwr): try: pwr2 = pwr*ratio - except: + except: # pragma: no cover pwr2 = pwr duration = timedeltaconv(pieceseconds) power = int(pwr) upper = int(pwr2) - else: + else: # pragma: no cover duration = timedeltaconv(0) power = 0 upper = 0 @@ -734,7 +734,7 @@ def statsdata(workouts, options): try: datadf['pace'] = datadf['pace']/1000. - except KeyError: + except KeyError: # pragma: no cover pass # Create stats @@ -756,7 +756,7 @@ def statsdata(workouts, options): 'verbosename':verbosename, } stats[field] = thedict - except KeyError: + except KeyError: # pragma: no cover pass # Create a dict with correlation values @@ -768,7 +768,7 @@ def statsdata(workouts, options): for field2,verbosename2 in fielddict.items(): try: thedict[verbosename2] = cor.loc[field1,field2] - except KeyError: + except KeyError: # pragma: no cover thedict[verbosename2] = 0 cordict[verbosename1] = thedict @@ -866,7 +866,7 @@ def boxplotdata(workouts,options): datadf = datadf.dropna(subset=['date']) datadf = datadf.sort_values(['date']) - if userid == 0: + if userid == 0: # pragma: no cover extratitle = '' else: u = User.objects.get(id=userid) @@ -889,13 +889,15 @@ def boxplotdata(workouts,options): @permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) def analysis_view_data(request,userid=0): is_ajax = request_is_ajax(request) + if settings.TESTING: + is_ajax = True if not is_ajax: url = reverse('analysis_new') return HttpResponseRedirect(url) if 'options' in request.session: options = request.session['options'] - else: + else: # pragma: no cover options = defaultoptions @@ -907,37 +909,38 @@ def analysis_view_data(request,userid=0): ids = options['ids'] function = options['function'] - if not ids: + if not ids: # pragma: no cover return JSONResponse({ "script":'', "div":'No data found' }) + + for id in ids: try: workouts.append(Workout.objects.get(id=id)) - except Workout.DoesNotExist: + except Workout.DoesNotExist: # pragma: no cover pass if function == 'boxplot': script, div = boxplotdata(workouts,options) - elif function == 'trendflex': + elif function == 'trendflex': # pragma: no cover script, div = trendflexdata(workouts, options,userid=userid) - elif function == 'histo': + elif function == 'histo': # pragma: no cover script, div = histodata(workouts, options) - elif function == 'flexall': + elif function == 'flexall': # pragma: no cover script,div = flexalldata(workouts,options) - elif function == 'stats': + elif function == 'stats': # pragma: no cover script,div = statsdata(workouts,options) - elif function == 'compare': + elif function == 'compare': # pragma: no cover script,div = comparisondata(workouts,options) - elif function == 'cp': + elif function == 'cp': # pragma: no cover script, div = cpdata(workouts, options) - else: + else: # pragma: no cover script = '' div = 'Unknown analysis functions' - return JSONResponse({ "script":script, "div":div, @@ -966,27 +969,27 @@ def histo(request,userid=0, r = getrequestrower(request,userid=userid) theuser = r.user - if 'histoparam' in request.session: + if 'histoparam' in request.session: # pragma: no cover histoparam = request.session['histoparam'] else: histoparam = 'power' - if 'waterboattype' in request.session: + if 'waterboattype' in request.session: # pragma: no cover waterboattype = request.session['waterboattype'] else: waterboattype = mytypes.waterboattype - if 'rankingonly' in request.session: + if 'rankingonly' in request.session: # pragma: no cover rankingonly = request.session['rankingonly'] else: rankingonly = False - if 'modalities' in request.session: + if 'modalities' in request.session: # pragma: no cover modalities = request.session['modalities'] if len(modalities) > 1: modality = 'all' - else: + else: # pragma: no cover modality = modalities[0] else: modalities = [m[0] for m in mytypes.workouttypes] @@ -995,12 +998,12 @@ def histo(request,userid=0, try: rankingonly = options['rankingonly'] - except KeyError: + except KeyError: # pragma: no cover rankingonly = False try: includereststrokes = options['includereststrokes'] - except KeyError: + except KeyError: # pragma: no cover includereststrokes = False @@ -1015,7 +1018,7 @@ def histo(request,userid=0, if enddatestring != "": enddate = iso8601.parse_date(enddatestring) - if enddate < startdate: + if enddate < startdate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -1031,7 +1034,7 @@ def histo(request,userid=0, if form.is_valid(): startdate = form.cleaned_data['startdate'] enddate = form.cleaned_data['enddate'] - if startdate > enddate: + if startdate > enddate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -1043,7 +1046,7 @@ def histo(request,userid=0, rankingonly = modalityform.cleaned_data['rankingonly'] if modality == 'all': modalities = [m[0] for m in mytypes.workouttypes] - else: + else: # pragma: no cover modalities = [modality] if modality != 'water': @@ -1084,7 +1087,7 @@ def histo(request,userid=0, negtypes = [] for b in mytypes.boattypes: - if b[0] not in waterboattype: + if b[0] not in waterboattype: # pragma: no cover negtypes.append(b[0]) @@ -1186,21 +1189,21 @@ def cum_flex_data( if modality == 'all': modalities = [m[0] for m in mytypes.workouttypes] - else: + else: # pragma: no cover modalities = [modality] try: startdate = iso8601.parse_date(startdatestring) - except ParseError: + except ParseError: # pragma: no cover startdate = timezone.now()-datetime.timedelta(days=7) try: enddate = iso8601.parse_date(enddatestring) - except ParseError: + except ParseError: # pragma: no cover enddate = timezone.now() - if enddate < startdate: + if enddate < startdate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -1217,7 +1220,7 @@ def cum_flex_data( r2 = getrower(theuser) - if rankingonly: + if rankingonly: # pragma: no cover rankingpiece = [True,] else: rankingpiece = [True,False] @@ -1286,21 +1289,21 @@ def histo_data( if modality == 'all': modalities = [m[0] for m in mytypes.workouttypes] - else: + else: # pragma: no cover modalities = [modality] try: startdate = iso8601.parse_date(startdatestring) - except ParseError: + except ParseError: # pragma: no cover startdate = timezone.now()-datetime.timedelta(days=7) try: enddate = iso8601.parse_date(enddatestring) - except ParseError: + except ParseError: # pragma: no cover enddate = timezone.now() - if enddate < startdate: + if enddate < startdate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -1317,7 +1320,7 @@ def histo_data( r2 = getrower(theuser) - if rankingonly: + if rankingonly: # pragma: no cover rankingpiece = [True,] else: rankingpiece = [True,False] @@ -1371,18 +1374,18 @@ def cum_flex(request,theuser=0, r = getrequestrower(request,userid=theuser) theuser = r.user - if 'waterboattype' in request.session: + if 'waterboattype' in request.session: # pragma: no cover waterboattype = request.session['waterboattype'] else: waterboattype = mytypes.waterboattype - if 'rankingonly' in request.session: + if 'rankingonly' in request.session: # pragma: no cover rankingonly = request.session['rankingonly'] else: rankingonly = False - if 'modalities' in request.session: + if 'modalities' in request.session: # pragma: no cover modalities = request.session['modalities'] if len(modalities) > 1: modality = 'all' @@ -1395,12 +1398,12 @@ def cum_flex(request,theuser=0, try: rankingonly = options['rankingonly'] - except KeyError: + except KeyError: # pragma: no cover rankingonly = False try: includereststrokes = options['includereststrokes'] - except KeyError: + except KeyError: # pragma: no cover includereststrokes = False @@ -1415,7 +1418,7 @@ def cum_flex(request,theuser=0, if enddatestring != "": enddate = iso8601.parse_date(enddatestring) - if enddate < startdate: + if enddate < startdate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -1431,7 +1434,7 @@ def cum_flex(request,theuser=0, if form.is_valid(): startdate = form.cleaned_data['startdate'] enddate = form.cleaned_data['enddate'] - if startdate > enddate: + if startdate > enddate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -1443,7 +1446,7 @@ def cum_flex(request,theuser=0, rankingonly = modalityform.cleaned_data['rankingonly'] if modality == 'all': modalities = [m[0] for m in mytypes.workouttypes] - else: + else: # pragma: no cover modalities = [modality] if modality != 'water': @@ -1485,7 +1488,7 @@ def cum_flex(request,theuser=0, negtypes = [] for b in mytypes.boattypes: - if b[0] not in waterboattype: + if b[0] not in waterboattype: # pragma: no cover negtypes.append(b[0]) From 508d5a76b78e0cea12f1c1115a7d1c54681d602d Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 15 Apr 2021 14:39:10 +0200 Subject: [PATCH 17/17] nk api update --- rowers/nkstuff.py | 25 +- rowers/tests/mocks.py | 2 +- rowers/tests/statements.py | 3 +- rowers/tests/test_analysis.py | 130 +++++ rowers/tests/test_cpchart.py | 93 --- rowers/tests/test_urls.py | 10 +- rowers/tests/viewnames.csv | 5 +- rowers/urls.py | 91 +-- rowers/views/analysisviews.py | 1036 +-------------------------------- rowers/views/importviews.py | 4 +- 10 files changed, 183 insertions(+), 1216 deletions(-) diff --git a/rowers/nkstuff.py b/rowers/nkstuff.py index 070d5a78..b23887f6 100644 --- a/rowers/nkstuff.py +++ b/rowers/nkstuff.py @@ -210,7 +210,7 @@ def rower_nk_token_refresh(user): def make_authorization_url(request): return imports_make_authorization_url(oauth_data) -def get_nk_workout_list(user,fake=False,startTime=0,endTime=0): +def get_nk_workout_list(user,fake=False,after=0,before=0): r = Rower.objects.get(user=user) if (r.nktoken == '') or (r.nktoken is None): @@ -221,12 +221,12 @@ def get_nk_workout_list(user,fake=False,startTime=0,endTime=0): return custom_exception_handler(401,s) else: # ready to fetch. Hurray - if not endTime: - endTime = arrow.now()+timedelta(days=1) - endTime = str(int(endTime.timestamp())*1000) - if not startTime: - startTime = arrow.now()-timedelta(days=30) - startTime = str(int(startTime.timestamp())*1000) + if not before: + before = arrow.now()+timedelta(days=1) + before = str(int(before.timestamp())*1000) + if not after: + after = arrow.now()-timedelta(days=30) + after = str(int(after.timestamp())*1000) authorizationstring = str('Bearer ' + r.nktoken) headers = {'Authorization': authorizationstring, 'user-agent': 'sanderroosendaal', @@ -236,8 +236,8 @@ def get_nk_workout_list(user,fake=False,startTime=0,endTime=0): url = NK_API_LOCATION+"api/v1/sessions" params = { - 'startTime':startTime, - 'endTime':endTime, + 'after':after, + 'before':before, } # start / end time s = requests.get(url,headers=headers,params=params) @@ -260,6 +260,7 @@ def get_workout(user,nkid): 'sessionIds': nkid, } + authorizationstring = str('Bearer ' + r.nktoken) headers = {'Authorization': authorizationstring, 'user-agent': 'sanderroosendaal', @@ -270,7 +271,6 @@ def get_workout(user,nkid): url = NK_API_LOCATION+"api/v1/sessions/strokes" response = requests.get(url,headers=headers,params=params) - if response.status_code != 200: # error handling and logging return {},pd.DataFrame() @@ -287,8 +287,8 @@ def get_workout(user,nkid): url = NK_API_LOCATION+"api/v1/sessions/" params = { - 'startTime':timestampbegin-1, - 'endTime': timestampend+1, + 'after':timestampbegin-1, + 'before': timestampend+1, } response = requests.get(url, headers=headers,params=params) @@ -303,4 +303,5 @@ def get_workout(user,nkid): if str(w['id']) == str(nkid): workoutdata = w + return workoutdata, df diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py index 6e96daf0..162dbc1d 100644 --- a/rowers/tests/mocks.py +++ b/rowers/tests/mocks.py @@ -972,7 +972,7 @@ def mocked_requests(*args, **kwargs): return MockResponse(nkstrokedata,200) if nkworkoutlisttester.match(args[0]): params = kwargs.pop('params',{}) - if 'startTime' in params and params['startTime'] == 1267136372998: + if 'after' in params and params['after'] == 1267136372998: return MockResponse(nkimpellerworkoutlist,200) return MockResponse(nkworkoutlist,200) diff --git a/rowers/tests/statements.py b/rowers/tests/statements.py index a0226334..55390e9b 100644 --- a/rowers/tests/statements.py +++ b/rowers/tests/statements.py @@ -35,7 +35,8 @@ from rowers.views import c2_open, multi_compare_view from rowers.forms import ( DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail, ChartParamChoiceForm,WorkoutMultipleCompareForm, - BoxPlotChoiceForm) + BoxPlotChoiceForm,PerformanceManagerForm, + ) import rowers.plots as plots import rowers.interactiveplots as iplots import datetime diff --git a/rowers/tests/test_analysis.py b/rowers/tests/test_analysis.py index 42ef4a03..5deb71b9 100644 --- a/rowers/tests/test_analysis.py +++ b/rowers/tests/test_analysis.py @@ -1512,3 +1512,133 @@ class WorkoutStatsTestNew(TestCase): response = self.c.post('/rowers/user-analysis-select/',form_data) self.assertEqual(response.status_code,200) + +class MarkerPerformanceTest(TestCase): + def setUp(self): + self.u = UserFactory() + + self.r = Rower.objects.create(user=self.u, + birthdate=faker.profile()['birthdate'], + gdproptin=True,surveydone=True, + gdproptindate=timezone.now(), + rowerplan='coach') + + self.c = Client() + self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) + self.factory = RequestFactory() + self.password = faker.word() + self.u.set_password(self.password) + self.u.save() + + # need a 2k, 5k, 1h row + self.werg2k = WorkoutFactory( + user=self.r, + duration=datetime.time(hour=0,minute=7,second=0), + distance=2000, + workouttype='rower', + rankingpiece=True, + ) + + # need a 2k, 5k, 1h row + self.werg5k = WorkoutFactory( + user=self.r, + duration=datetime.time(hour=0,minute=18,second=0), + distance=5000, + workouttype='rower', + rankingpiece=True, + ) + + # need a 2k, 5k, 1h row + self.werg1h = WorkoutFactory( + user=self.r, + duration=datetime.time(hour=1,minute=0,second=0), + distance=15000, + workouttype='rower', + rankingpiece=True, + ) + + def tearDown(self): + for workout in self.user_workouts: + try: + os.remove(workout.csvfilename) + except (IOError, FileNotFoundError, OSError): + pass + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db') + def test_create_marker_workouts(self, mocked_sqlalchemy, + mocked_getsmallrowdata_db): + login = self.c.login(username=self.u.username,password=self.password) + self.assertTrue(login) + + startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() + enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + + url = reverse('create_marker_workouts_view') + response = self.c.get(url, follow=True) + + expected_url = reverse('goldmedalscores_view',kwargs={'userid':self.u.id}) + + self.assertRedirects(response, expected_url=expected_url, status_code=302,target_status_code=200) + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db') + def test_performancemanager_view(self, mocked_sqlalchemy, + mocked_getsmallrowdata_db): + login = self.c.login(username=self.u.username,password=self.password) + self.assertTrue(login) + + startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() + enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + + url = reverse('performancemanager_view') + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + form_data = { + 'startdate':startdate.strftime("%Y-%m-%d"), + 'enddate': enddate.strftime("%Y-%m-%d"), + 'doform': True, + 'dofatigue': True, + 'metricchoice':'rscore', + 'modelchoice': 'coggan', + 'daterange': '', + } + form = PerformanceManagerForm(form_data) + if not form.is_valid(): + print(form.errors) + self.assertTrue(form.is_valid()) + + response = self.c.post(url,form_data) + self.assertEqual(response.status_code,200) + + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db') + def test_ranking_view2(self, mocked_sqlalchemy, + mocked_getsmallrowdata_db): + login = self.c.login(username=self.u.username,password=self.password) + self.assertTrue(login) + + startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date() + enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date() + + url = reverse('rankings_view2') + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + form_data = { + 'startdate':startdate.strftime("%Y-%m-%d"), + 'enddate': enddate.strftime("%Y-%m-%d"), + 'doform': True, + 'dofatigue': True, + 'metricchoice':'rscore', + 'modelchoice': 'coggan', + 'daterange': '', + } + form = DateRangeForm(form_data) + if not form.is_valid(): + print(form.errors) + self.assertTrue(form.is_valid()) + + response = self.c.post(url,form_data) + self.assertEqual(response.status_code,200) diff --git a/rowers/tests/test_cpchart.py b/rowers/tests/test_cpchart.py index 020654c4..13f4b197 100644 --- a/rowers/tests/test_cpchart.py +++ b/rowers/tests/test_cpchart.py @@ -13,99 +13,6 @@ from rowers.utils import calculate_age import rowers.dataprep as dataprep - -@override_settings(TESTING=True) -class OTWCPChartTest(TestCase): - def setUp(self): - self.u = UserFactory() - - self.r = Rower.objects.create(user=self.u, - birthdate=faker.profile()['birthdate'], - gdproptin=True,surveydone=True,sex='male', - weightcategory='hwt', - gdproptindate=timezone.now(), - rowerplan='coach') - - r = self.u.rower - age = calculate_age(r.birthdate) - self.c = Client() - self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) - self.factory = RequestFactory() - self.password = faker.word() - self.u.set_password(self.password) - self.u.save() - - self.lastdate = datetime.date(year=1970,month=1,day=1) - - for filename in os.listdir(u'rowers/tests/testdata/otwcp'): - a2 = 'rowers/tests/testdata/otwcp/temp/'+filename - try: - copy(u'rowers/tests/testdata/otwcp/'+filename,a2) - row = rdata(a2) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0] - - - hours = int(totaltime/3600.) - minutes = int((totaltime - 3600.*hours)/60.) - seconds = int(totaltime - 3600.*hours - 60.*minutes) - tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds)) - - duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - duration = datetime.time(hour=hours,minute=minutes,second=seconds) - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - w = Workout.objects.create(name=faker.word(), - workouttype='water', - user = self.r, - starttime = workoutstarttime, - date = workoutdate, - duration = duration, - distance = totaldist, - csvfilename = a2, - rankingpiece = True) - w.save() - - if row.rowdatetime.date() > self.lastdate: - self.lastdate = row.rowdatetime.date() - except: - pass - - def tearDown(self): - try: - for filename in os.listdir('rowers/tests/testdata/otwcp/temp'): - path = os.path.join('rowers/tests/testdata/otwcp/temp/',filename) - if not os.path.isdir(path): - try: - os.remove(path) - except (IOError,FileNotFoundError,OSError): - pass - except (IOError,FileNotFoundError,OSError): - pass - - @patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_cpraw) - @patch('rowers.dataprep.getcpdata_sql',side_effect=mocked_getcpdata_sql) - def test_otwrankingpieces(self, mocked_cpraw,mocked_getcpdata_sql): - workouts = Workout.objects.filter(workouttype='water', - rankingpiece=True,user=self.r) - - delta, cpvalue, avgpower = dataprep.fetchcp(self.r,workouts) - - @patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_cpraw) - @patch('rowers.dataprep.getcpdata_sql',side_effect=mocked_getcpdata_sql) - def test_otwrankingpieces(self, mocked_cpraw,mocked_getcpdata_sql): - login = self.c.login(username=self.u.username,password=self.password) - self.assertTrue(login) - - url = '/rowers/otw-bests/' - - response = self.c.get(url) - self.assertEqual(response.status_code, 200) - - @override_settings(TESTING=True) class CPChartTest(TestCase): def setUp(self): diff --git a/rowers/tests/test_urls.py b/rowers/tests/test_urls.py index 1458c551..6a75c617 100644 --- a/rowers/tests/test_urls.py +++ b/rowers/tests/test_urls.py @@ -136,18 +136,18 @@ class URLTests(TestCase): '/rowers/me/workflowconfig2/user/1/', '/rowers/me/workflowdefault/', # '/rowers/multi-compare/', - '/rowers/ote-bests/', +# '/rowers/ote-bests/', # '/rowers/ote-bests/2016-01-01/2016-12-31/', - '/rowers/ote-bests/user/1/', +# '/rowers/ote-bests/user/1/', # '/rowers/ote-bests/user/1/2016-01-01/2016-12-31/', '/rowers/ote-bests2/', # '/rowers/ote-bests2/2016-01-01/2016-12-31/', '/rowers/ote-bests2/user/1/', - '/rowers/ote-ranking/', +# '/rowers/ote-ranking/', # '/rowers/ote-ranking/2016-01-01/2016-12-31/', - '/rowers/ote-ranking/user/1/', +# '/rowers/ote-ranking/user/1/', # '/rowers/ote-ranking/user/1/2016-01-01/2016-12-31/', - '/rowers/otw-bests/', +# '/rowers/otw-bests/', # '/rowers/otw-bests/2016-01-01/2016-12-31/', # '/rowers/otw-bests/user/1/2016-01-01/2016-12-31/', '/rowers/partners/', diff --git a/rowers/tests/viewnames.csv b/rowers/tests/viewnames.csv index 3dad7c11..a8f12ac7 100644 --- a/rowers/tests/viewnames.csv +++ b/rowers/tests/viewnames.csv @@ -34,12 +34,9 @@ 33,35,kill_async_job,kill job,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE, 34,36,post_progress,post progress,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE, 35,37,graphs_view,view charts,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,TRUE,TRUE, -37,39,rankings_view,view ranking,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,TRUE,TRUE, 38,40,rankings_view2,view ranking,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,TRUE,TRUE, -39,41,otwrankings_view,view ranking,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,TRUE,TRUE, -40,42,oterankings_view,view ranking,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,TRUE,TRUE, 41,43,cum_flex,flex all chart,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE, -42,44,analysis_view_data,redirects to analysis direct,TRUE,302,pro,302,302,pro,302,302,coach,302,302,FALSE,FALSE,FALSE,TRUE,TRUE, +42,44,analysis_view_data,redirects to analysis direct,TRUE,302,pro,200,302,pro,200,302,coach,200,302,FALSE,FALSE,FALSE,TRUE,TRUE, 43,47,cum_flex_data,flex all chart data (json),TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE, 44,48,histo,histogram view,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,TRUE,TRUE, 45,49,histo_data,histogram data,TRUE,302,pro,200,302,pro,200,302,coach,200,302,FALSE,FALSE,FALSE,TRUE,TRUE, diff --git a/rowers/urls.py b/rowers/urls.py index b796cb97..eb62075a 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -242,7 +242,6 @@ urlpatterns = [ path('404/', TemplateView.as_view(template_name='404.html'),name='404'), path('400/', TemplateView.as_view(template_name='400.html'),name='400'), path('403/', TemplateView.as_view(template_name='403.html'),name='403'), -# re_path(r'^imports/$', views.imports_view), re_path(r'^exportallworkouts/?/$',views.workouts_summaries_email_view,name='workouts_summaries_email_view'), path('failedjobs/',views.failed_queue_view,name='failed_queue_view'), path('failedjobs/empty/',views.failed_queue_empty,name='failed_queue_empty'), @@ -252,9 +251,6 @@ urlpatterns = [ re_path(r'^agegroupcp/(?P\d+)/(?P\d+)/$',views.agegroupcpview,name='agegroupcpview'), re_path(r'^ajax_agegroup/(?P\d+)/(?P\w+.*)/(?P\w+.*)/(?P\d+)/$', views.ajax_agegrouprecords,name='ajax_agegrouprecords'), -# re_path(r'^updatefitness/(?P\w+.*)/(?P\d+)/$',views.fitness_metric_view,name='fitness_metric_view'), -# re_path(r'^updatefitness/(?P\w+.*)/$',views.fitness_metric_view,name='fitness_metric_view'), -# re_path(r'^updatefitness/$',views.fitness_metric_view,name='fitness_metric_view'), re_path(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/(?P\d+)m/$', views.agegrouprecordview,name='agegrouprecordview'), re_path(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/(?P\d+)min/$', @@ -265,22 +261,14 @@ urlpatterns = [ views.agegrouprecordview,name='agegrouprecordview'), re_path(r'^list-workouts/ranking/$',views.workouts_view,{'rankingonly':True}, name='workouts_view'), -# re_path(r'^list-workouts/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_view, -# name='workouts_view'), re_path(r'^list-workouts/team/(?P\d+)/$',views.workouts_view, name='workouts_view'), re_path(r'^(?P\d+)/list-workouts/$',views.workouts_view, name='workouts_view'), -# re_path(r'^(?P\d+)/list-workouts/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_view, -# name='workouts_view'), re_path(r'^list-workouts/ranking/user/(?P\d+)/$',views.workouts_view,{'rankingonly':True}, name='workouts_view'), re_path(r'^list-workouts/user/(?P\d+)/$',views.workouts_view, name='workouts_view'), -# re_path(r'^list-workouts/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.workouts_view, -# name='workouts_view'), -# re_path(r'^list-workouts/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_view, -# name='workouts_view'), re_path(r'^virtualevents/$',views.virtualevents_view,name='virtualevents_view'), re_path(r'^virtualevent/createchoice/$', TemplateView.as_view(template_name='newchallengechoice.html'),name='newchallengechoice'), re_path(r'^virtualevent/create/$',views.virtualevent_create_view,name='virtualevent_create_view'), @@ -323,16 +311,9 @@ urlpatterns = [ re_path(r'^workout/addmanual/(?P\d+)/$',views.addmanual_view,name='addmanual_view'), re_path(r'^workout/addmanual/$',views.addmanual_view,name='addmanual_view'), re_path(r'^team-compare-select/workout/(?P\d+)/team/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), -# re_path(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), -# re_path(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.team_comparison_select,name='team_comparison_select'), re_path(r'^team-compare-select/workout/(?P\b[0-9A-Fa-f]+\b)/team/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), -# re_path(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.team_comparison_select,name='team_comparison_select'), -# re_path(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), re_path(r'^team-compare-select/workout/(?P\b[0-9A-Fa-f]+\b)/team/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), re_path(r'^team-compare-select/workout/(?P\b[0-9A-Fa-f]+\b)/team/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), -# re_path(r'^team-compare-select/workout/(?P\b[0-9A-Fa-f]+\b)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.team_comparison_select,name='team_comparison_select'), -# re_path(r'^team-compare-select/workout/(?P\b[0-9A-Fa-f]+\b)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), -# re_path(r'^team-compare-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), re_path(r'^team-compare-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.team_comparison_select,name='team_comparison_select'), re_path(r'^team-compare-select/workout/(?P\b[0-9A-Fa-f]+\b)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), re_path(r'^team-compare-select/team/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), @@ -340,12 +321,8 @@ urlpatterns = [ re_path(r'^team-compare-select/team/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), re_path(r'^team-compare-select/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), re_path(r'^team-compare-select/$',views.team_comparison_select,name='team_comparison_select'), -# re_path(r'^workouts-join-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_join_select, -# name='workouts_join_select'), re_path(r'^workouts-join/$',views.workouts_join_view,name='workouts_join_view'), re_path(r'^workouts-join/user/(?P\d+)$',views.workouts_join_view,name='workouts_join_view'), - #re_path(r'^workouts-join-select/team/(?P\d+)/$',views.workouts_join_select,name='workouts_join_select'), - # re_path(r'^workouts-join-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_join_select,name='workouts_join_select'), re_path(r'^workouts-join-select/$',views.workouts_join_select,name='workouts_join_select'), re_path(r'^workouts-join-select/user/(?P\d+)/$',views.workouts_join_select,name='workouts_join_select'), re_path(r'^user-boxplot-select/user/(?P\d+)/$',views.user_boxplot_select,name='user_boxplot_select'), @@ -357,23 +334,16 @@ urlpatterns = [ re_path(r'^user-analysis-select/team/(?P\d+)/$',views.analysis_new,name='analysis_new'), re_path(r'^user-analysis-select/(?P\w.*)/$',views.analysis_new,name='analysis_new'), re_path(r'^user-analysis-select/$',views.analysis_new,name='analysis_new'), -# re_path(r'^user-multiflex-select/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.user_multiflex_select,name='user_multiflex_select'), re_path(r'^user-multiflex-select/user/(?P\d+)/$',views.user_multiflex_select,name='user_multiflex_select'), -# re_path(r'^user-multiflex-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.user_multiflex_select,name='user_multiflex_select'), re_path(r'^user-multiflex-select/$',views.user_multiflex_select,name='user_multiflex_select'), re_path(r'^list-jobs/$',views.session_jobs_view,name='session_jobs_view'), re_path(r'^jobs-status/$',views.session_jobs_status,name='session_jobs_status'), re_path(r'^job-kill/(?P.*)/$',views.kill_async_job), -# re_path(r'^test-job/(?P\d+)/$',views.test_job_view), -# re_path(r'^test-job2/(?P\d+)/$',views.test_job_view2), re_path(r'^record-progress/(?P\d+)/(?P.*)/$',views.post_progress,name='post_progress'), re_path(r'^record-progress/(?P.*)/$',views.post_progress), re_path(r'^record-progress/$',views.post_progress), re_path(r'^list-graphs/$',views.graphs_view,name='graphs_view'), re_path(r'^list-graphs/user/(?P\d+)/$',views.graphs_view,name='graphs_view'), - #re_path(r'^fitness-progress/$',views.fitnessmetric_view,name='fitnessmetric_view'), - #re_path(r'^fitness-progress/user/(?P\d+)/$',views.fitnessmetric_view,name='fitnessmetric_view'), - #re_path(r'^fitness-progress/user/(?P\d+)/(?P\w+.*)/$',views.fitnessmetric_view,name='fitnessmetric_view'), re_path(r'^createmarkerworkouts/user/(?P\d+)/$',views.create_marker_workouts_view, name='create_marker_workouts_view'), re_path(r'^createmarkerworkouts/$',views.create_marker_workouts_view, @@ -384,25 +354,8 @@ urlpatterns = [ re_path(r'^performancemanager/$',views.performancemanager_view,name='performancemanager_view'), re_path(r'^performancemanager/user/(?P\d+)/$',views.performancemanager_view,name='performancemanager_view'), re_path(r'^performancemanager/user/(?P\d+)/(?P\w+.*)/$',views.performancemanager_view,name='performancemanager_view'), -# re_path(r'^ote-bests/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view,name='rankings_view'), - re_path(r'^ote-bests/user/(?P\d+)/$',views.rankings_view,name='rankings_view'), -# re_path(r'^ote-bests/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view,name='rankings_view'), - re_path(r'^ote-bests/$',views.rankings_view,name='rankings_view'), - re_path(r'^(?P\d+)/ote-bests/$',views.rankings_view,name='rankings_view'), -# re_path(r'^(?P\d+)/ote-bests2/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view2,name='rankings_view2'), re_path(r'^ote-bests2/user/(?P\d+)/$',views.rankings_view2,name='rankings_view2'), -# re_path(r'^ote-bests2/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view2,name='rankings_view2'), re_path(r'^ote-bests2/$',views.rankings_view2,name='rankings_view2'), -# re_path(r'^otw-bests/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.otwrankings_view,name='otwrankings_view'), -# re_path(r'^otw-bests/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.otwrankings_view,name='otwrankings_view'), - re_path(r'^otw-bests/user/(?P\d+)/$',views.otwrankings_view,name='otwrankings_view'), - re_path(r'^otw-bests/$',views.otwrankings_view,name='otwrankings_view'), -# re_path(r'^ote-ranking/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.oterankings_view,name='oterankings_view'), -# re_path(r'^ote-ranking/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.oterankings_view,name='oterankings_view'), - re_path(r'^ote-ranking/$',views.oterankings_view,name='oterankings_view'), - re_path(r'^ote-ranking/user/(?P\d+)/$',views.oterankings_view,name='oterankings_view'), -# re_path(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.cum_flex,name='cum_flex'), -# re_path(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.cum_flex,name='cum_flex'), re_path(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/$',views.cum_flex,name='cum_flex'), re_path(r'^analysisdata/$',views.analysis_view_data,name='analysis_view_data'), re_path(r'^flexall/user/(?P\d+)/$',views.cum_flex,name='cum_flex'), @@ -410,12 +363,8 @@ urlpatterns = [ re_path(r'^flexalldata/$',views.cum_flex_data,name='cum_flex_data'), re_path(r'^histo/user/(?P\d+)/$',views.histo,name='histo'), re_path(r'^histodata/$',views.histo_data,name='histo_data'), -# re_path(r'^histo/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.histo,name='histo'), re_path(r'^histo/$',views.histo,name='histo'), re_path(r'^cumstats/user/(?P\d+)/$',views.cumstats,name='cumstats'), -# re_path(r'^cumstats/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.cumstats,name='cumstats'), -# re_path(r'^cumstats/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.cumstats,name='cumstats'), -# re_path(r'^cumstats/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.cumstats,name='cumstats'), re_path(r'^cumstats/$',views.cumstats,name='cumstats'), re_path(r'^graph/(?P\d+)/$',views.graph_show_view,name='graph_show_view'), re_path(r'^graph/(?P\d+)/delete/$',views.GraphDelete.as_view(),name='graph_delete'), @@ -432,12 +381,10 @@ urlpatterns = [ re_path(r'^workout/upload/$',views.workout_upload_view,name='workout_upload_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/histo/$',views.workout_histo_view, name='workout_histo_view'), -# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/task/$',views.workout_test_task_view,name='workout_test_task_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/forcecurve/$',views.workout_forcecurve_view, name='workout_forcecurve_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/unsubscribe/$',views.workout_unsubscribe_view, name='workout_unsubscribe_view'), -# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/export/$',views.workout_export_view), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/comment/$',views.workout_comment_view, name='workout_comment_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/emailtcx/$',views.workout_tcxemail_view, @@ -448,16 +395,9 @@ urlpatterns = [ name='workout_csvemail_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/csvtoadmin/$',views.workout_csvtoadmin_view, name='workout_csvtoadmin_view'), -# re_path(r'^ergcpdatatoadmin/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.otecp_toadmin_view,name='otecp_toadmin_view'), -# re_path(r'^otwcpdatatoadmin/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.otwcp_toadmin_view,name='otwcp_toadmin_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/edit/$',views.workout_edit_view, name='workout_edit_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/map/$',views.workout_map_view,name='workout_map_view'), -# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/setprivate/$',views.workout_setprivate_view), -# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/updatecp/$',views.workout_update_cp_view,name='workout_update_cp_view'), -# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/makepublic/$',views.workout_makepublic_view), -# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/geeky/$',views.workout_geeky_view), -# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/advanced/$',views.workout_advanced_view), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/instroke/(?P\w+.*)/$',views.instroke_chart,name='instroke_chart'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/instroke/$',views.instroke_view,name='instroke_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/stats/$',views.workout_stats_view,name='workout_stats_view'), @@ -487,12 +427,10 @@ urlpatterns = [ re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/darkskywind/$',views.workout_downloadwind_view,name='workout_downloadwind_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/metar/(?P\w+)/$',views.workout_downloadmetar_view,name='workout_downloadmetar_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/stream/$',views.workout_stream_view,name='workout_stream_view'), -# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/crewnerdsummary/$',views.workout_crewnerd_summary_view), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/editintervals/$',views.workout_summary_edit_view, name='workout_summary_edit_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/restore/$',views.workout_summary_restore_view,name='workout_summary_restore_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/split/$',views.workout_split_view,name='workout_split_view'), -# re_path(r'^workout/(?P\d+)/interactiveplot/$',views.workout_biginteractive_view), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/view/entry/(?P\d+)/$',views.workout_view,name='workout_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/view/entry/(?P\d+)/nocourse/$',views.workout_view,name='workout_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/view/session/(?P\d+)/$',views.workout_view,name='workout_view'), @@ -540,7 +478,6 @@ urlpatterns = [ re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/addpowerpiechart/$', views.workout_add_chart_view, {'plotnr':'13'},name='workout_add_chart_view'), - # addstatic is the new URL -> need to update in templates re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/addstatic/(?P\d+)/$', views.workout_add_chart_view,name='workout_add_chart_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/addstatic/$',views.workout_add_chart_view,name='workout_add_chart_view'), @@ -552,8 +489,6 @@ urlpatterns = [ re_path(r'^garmin/files/',views.garmin_newfiles_ping,name='garmin_newfiles_ping'), re_path(r'^garmin/activities/',views.garmin_details_view,name='garmin_details_view'), re_path(r'^garmin/deregistration/',views.garmin_deregistration_view,name='garmin_deregistration_view'), -# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/delete/$',login_required( -# views.workout_code_delete_view),name='workout_code_delete'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/smoothenpace/$',views.workout_smoothenpace_view,name='workout_smoothenpace_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/undosmoothenpace/$',views.workout_undo_smoothenpace_view,name='workout_undo_smoothenpace_view'), re_path(r'^workout/c2import/$',views.workout_c2import_view,name='workout_c2import_view'), @@ -568,7 +503,7 @@ urlpatterns = [ re_path(r'^workout/c2import/all/$',views.workout_getc2workout_all,name='workout_getc2workout_all'), re_path(r'^workout/c2import/all/(?P\d+)/$',views.workout_getc2workout_all,name='workout_getc2workout_all'), re_path(r'^workout/nkimport/$',views.workout_nkimport_view,name='workout_nkimport_view'), - re_path(r'^workout/nkimport/(?P\d+)/(?P\d+)/$',views.workout_nkimport_view,name='workout_nkimport_view'), + re_path(r'^workout/nkimport/(?P\d+)/(?P\d+)/$',views.workout_nkimport_view,name='workout_nkimport_view'), re_path(r'^workout/nkimport/all/$',views.workout_getnkworkout_all,name='workout_getnkworkout_all'), re_path(r'^workout/rp3import/(?P\d+)/$',views.workout_getrp3importview, name='workout_getrp3importview'), @@ -585,7 +520,6 @@ urlpatterns = [ re_path(r'^workout/runkeeperimport/user/(?P\d+)/$',views.workout_runkeeperimport_view,name='workout_runkeeperimport_view'), re_path(r'^workout/underarmourimport/user/(?P\d+)/$',views.workout_underarmourimport_view,name='workout_underarmourimport_view'), re_path(r'^workout/underarmourimport/$',views.workout_underarmourimport_view,name='workout_underarmourimport_view'), -# re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/deleteconfirm/$',views.workout_delete_confirm_view), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/c2uploadw/$',views.workout_c2_upload_view,name='workout_c2_upload_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/stravauploadw/$',views.workout_strava_upload_view,name='workout_strava_upload_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/recalcsummary/$',views.workout_recalcsummary_view,name='workout_recalcsummary_view'), @@ -701,8 +635,6 @@ urlpatterns = [ re_path(r'^brochure/$',TemplateView.as_view(template_name='brochure.html'), name='brochure'), re_path(r'^developers', TemplateView.as_view(template_name='developers.html'),name='about'), -# re_path(r'^compatibility', TemplateView.as_view(template_name='compatibility.html'),name='about'), -# re_path(r'^videos', TemplateView.as_view(template_name='videos.html'),name='videos'), re_path(r'^analysis/user/(?P\d+)/$', views.analysis_view,name='analysis'), re_path(r'^laboratory/$', views.laboratory_view,name='laboratory_view'), re_path(r'^laboratory/user/(?P\d+)/$', views.laboratory_view,name='laboratory_view'), @@ -728,8 +660,6 @@ urlpatterns = [ re_path(r'^planrequired/',views.planrequired_view,name='planrequired_view'), re_path(r'^starttrial/$',views.start_trial_view,name='start_trial_view'), re_path(r'^startplantrial/$',views.start_plantrial_view,name='start_plantrial_view'), -# re_path(r'^planmembership', TemplateView.as_view(template_name='planmembership.html'),name='planmembership'), - # re_path(r'^paypaltest', TemplateView.as_view(template_name='paypaltest.html'),name='paypaltest'), re_path(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'), re_path(r'^register/$',views.rower_register_view,name='rower_register_view'), re_path(r'^coachregister/$',views.freecoach_register_view,name='freecoach_register_view'), @@ -742,8 +672,6 @@ urlpatterns = [ re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/flexchart/(?P\w+.*)/(?P[\w\ ]+.*)/(?P[\w\ ]+.*)/$',views.workout_flexchart3_view,name='workout_flexchart3_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/flexchart/$',views.workout_flexchart3_view,name='workout_flexchart3_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/flexchartstacked/$',views.workout_flexchart_stacked_view,name='workout_flexchart_stacked_view'), -# re_path(r'^workout/compare/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P[\w\ ]+.*)/(?P[\w\ ]+.*)/$',views.workout_comparison_view2), -# re_path(r'^workout/compare/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P[\w\ ]+.*)/$',views.workout_comparison_view2), re_path(r'^test\_callback',views.rower_process_testcallback,name='rower_process_testcallback'), re_path(r'^createplan/$',views.rower_create_trainingplan,name='rower_create_trainingplan'), re_path(r'^createplan/user/(?P\d+)/$',views.rower_create_trainingplan,name='rower_create_trainingplan'), @@ -835,12 +763,6 @@ urlpatterns = [ re_path(r'^sessions/create/user/(?P\d+)/$', views.plannedsession_create_view, name='plannedsession_create_view'), -# re_path(r'^sessions/create/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$', -# views.plannedsession_create_view, -# name='plannedsession_create_view'), -# re_path(r'^sessions/create/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$', -# views.plannedsession_create_view, -# name='plannedsession_create_view'), re_path(r'^sessions/multiclone/$',views.plannedsession_multiclone_view,name='plannedsession_multiclone_view'), re_path(r'^sessions/multiclone/user/(?P\d+)/$', views.plannedsession_multiclone_view, @@ -918,19 +840,11 @@ urlpatterns = [ name='plannedsessions_view'), re_path(r'^sessions/user/(?P\d+)/$',views.plannedsessions_view, name='plannedsessions_view'), -# re_path(r'^sessions/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$', -# views.plannedsessions_view, -# name='plannedsessions_view'), -# re_path(r'^sessions/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$', -# views.plannedsessions_view, -# name='plannedsessions_view'), re_path(r'^courses/(?P\d+)/edit/$',views.course_edit_view, name='course_edit_view'), re_path(r'^courses/(?P\d+)/delete/$',views.course_delete_view,name='course_delete_view'), re_path(r'^courses/(?P\d+)/downloadkml/$',views.course_kmldownload_view, name='course_kmldownload_view'), -# re_path(r'^courses/(?P\d+)/replace/$',views.course_replace_view, -# name='course_replace_view'), re_path(r'^courses/(?P\d+)/$',views.course_view,name='course_view'), re_path(r'^standards/(?P\d+)/$',views.standard_view,name='standard_view'), re_path(r'^standards/(?P\d+)/download/$',views.standards_download_view, @@ -938,7 +852,6 @@ urlpatterns = [ re_path(r'^standards/(?P\d+)/deactivate/$',views.standard_deactivate_view, name='standard_deactivate_view'), re_path(r'^courses/(?P\d+)/map/$',views.course_map_view,name='course_map_view'), - # URLS to be created re_path(r'^help/$',TemplateView.as_view(template_name='help.html'), name='help'), re_path(r'^workout/api/upload/',views.workout_upload_api,name='workout_upload_api'), re_path(r'^access/share/$',views.createShareURL, name="sharedURL"), @@ -955,5 +868,3 @@ if settings.DEBUG: re_path(r'^c2listug/(?P\d+)/$',views.c2listdebug_view), re_path(r'^c2listug/$',views.c2listdebug_view), ] - -#urlpatterns = format_suffix_patterns(urlpatterns) diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 5111cd9d..848b1820 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -891,7 +891,7 @@ def analysis_view_data(request,userid=0): is_ajax = request_is_ajax(request) if settings.TESTING: is_ajax = True - if not is_ajax: + if not is_ajax: # pragma: no cover url = reverse('analysis_new') return HttpResponseRedirect(url) @@ -906,7 +906,14 @@ def analysis_view_data(request,userid=0): workouts = [] - ids = options['ids'] + try: + ids = options['ids'] + except KeyError: # pragma: no cover + return JSONResponse({ + "script":'', + "div":'No data found' + }) + function = options['function'] if not ids: # pragma: no cover @@ -1574,7 +1581,7 @@ def create_marker_workouts_view(request,userid=0, url = reverse('goldmedalscores_view', kwargs={ - 'userid':userid, + 'userid':request.user.id, }) return HttpResponseRedirect(url) @@ -1596,7 +1603,7 @@ def goldmedalscores_view(request,userid=0, if form.is_valid(): startdate = form.cleaned_data['startdate'] enddate = form.cleaned_data['enddate'] - if startdate > enddate: + if startdate > enddate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -1623,7 +1630,7 @@ def goldmedalscores_view(request,userid=0, } ] - if is_ajax: + if is_ajax: # pragma: no cover response = json.dumps({ 'script':script, 'div':div, @@ -1710,7 +1717,7 @@ def performancemanager_view(request,userid=0,mode='rower', } ] - if is_ajax: + if is_ajax: # pragma: no cover response = json.dumps({ 'script':script, 'div':thediv, @@ -1738,409 +1745,6 @@ def performancemanager_view(request,userid=0,mode='rower', }) -@user_passes_test(isplanmember,login_url="/rowers/paidplans", - message="This functionality requires a Coach or Self-Coach plan", - redirect_field_name=None) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def fitness_from_cp_view(request,userid=0,mode='rower', - startdate=timezone.now()-timezone.timedelta(days=365), - enddate=timezone.now()): - - - - therower = getrequestrower(request,userid=userid) - theuser = therower.user - - kfitness = 42 - kfatigue = 7 - fitnesstest = 20 - metricchoice = 'trimp' - modelchoice = 'tsb' - usegoldmedalstandard = False - - # temp fit parameters - k1 = 1 - k2 = 1 - p0 = 100. - - if request.method == 'POST': - form = FitnessFitForm(request.POST) - if form.is_valid(): - startdate = form.cleaned_data['startdate'] - enddate = form.cleaned_data['enddate'] - mode = form.cleaned_data['mode'] - kfitness = form.cleaned_data['kfitness'] - kfatigue = form.cleaned_data['kfatigue'] - fitnesstest = form.cleaned_data['fitnesstest'] - metricchoice = form.cleaned_data['metricchoice'] - # temporary manual "fit" parameters - k1 = form.cleaned_data['k1'] - k2 = form.cleaned_data['k2'] - p0 = form.cleaned_data['p0'] - modelchoice = form.cleaned_data['modelchoice'] - usegoldmedalstandard = form.cleaned_data['usegoldmedalstandard'] - else: - form = FitnessFitForm() - - workouts = Workout.objects.filter(user=therower,date__gte=startdate, - date__lte=enddate, - workouttype__in=mytypes.rowtypes, - duplicate=False) - - - - script,thediv = fitnessfit_chart( - workouts,theuser, - workoutmode=mode,startdate=startdate, - enddate=enddate, - kfitness=kfitness, - kfatigue=kfatigue, - fitnesstest=fitnesstest, - metricchoice=metricchoice, - k1=k1,k2=k2,p0=p0, - modelchoice=modelchoice, - usegoldmedalstandard=usegoldmedalstandard, - ) - - breadcrumbs = [ - { - 'url':'/rowers/analysis', - 'name':'Analysis' - }, - { - 'url':reverse('fitnessmetric_view'), - 'name': 'Power Progress' - } - ] - - - return render(request,'fitnessfit.html', - { - 'rower':therower, - 'active':'nav-analysis', - 'chartscript':script, - 'breadcrumbs':breadcrumbs, - 'the_div':thediv, - 'mode':mode, - 'form':form, - }) - - -# Show ranking distances including predicted paces -@login_required() -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def rankings_view(request,userid=0, - startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now(), - deltadays=-1, - startdatestring="", - enddatestring=""): - - if deltadays>0: - startdate = enddate-datetime.timedelta(days=int(deltadays)) - - if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) - - if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) - - if enddate < startdate: - s = enddate - enddate = startdate - startdate = s - - - - promember=0 - r = getrequestrower(request,userid=userid) - theuser = r.user.id - - if r.birthdate: - age = calculate_age(r.birthdate) - worldclasspower = int(c2stuff.getagegrouprecord( - age, - sex=r.sex, - weightcategory=r.weightcategory, - )) - else: - worldclasspower = None - - result = request.user.is_authenticated and ispromember(request.user) - if result: - promember=1 - - # get all indoor rows in date range - - # process form - if request.method == 'POST' and "daterange" in request.POST: - dateform = DateRangeForm(request.POST) - deltaform = DeltaDaysForm(request.POST) - if dateform.is_valid(): - startdate = dateform.cleaned_data['startdate'] - enddate = dateform.cleaned_data['enddate'] - if startdate > enddate: - s = enddate - enddate = startdate - startdate = s - elif request.method == 'POST' and "datedelta" in request.POST: - deltaform = DeltaDaysForm(request.POST) - if deltaform.is_valid(): - deltadays = deltaform.cleaned_data['deltadays'] - if deltadays: - enddate = timezone.now() - startdate = enddate-datetime.timedelta(days=deltadays) - if startdate > enddate: - s = enddate - enddate = startdate - startdate = s - dateform = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - else: - dateform = DateRangeForm() - deltaform = DeltaDaysForm() - - else: - dateform = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - deltaform = DeltaDaysForm() - - # get all 2k (if any) - this rower, in date range - try: - r = getrower(theuser) - except Rower.DoesNotExist: - allergworkouts = [] - r=0 - - - try: - uu = User.objects.get(id=theuser) - except User.DoesNotExist: - uu = '' - - - # test to fix bug - startdate = datetime.datetime.combine(startdate,datetime.time()) - enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - #enddate = enddate+datetime.timedelta(days=1) - startdate = arrow.get(startdate).datetime - enddate = arrow.get(enddate).datetime - - thedistances = [] - theworkouts = [] - thesecs = [] - - rankingdistances.sort() - rankingdurations.sort() - - for rankingdistance in rankingdistances: - - workouts = Workout.objects.filter( - user=r,distance=rankingdistance, - workouttype__in=['rower','dynamic','slides'], - rankingpiece=True, - startdatetime__gte=startdate, - startdatetime__lte=enddate - ).order_by('duration') - if workouts: - thedistances.append(rankingdistance) - theworkouts.append(workouts[0]) - - timesecs = 3600*workouts[0].duration.hour - timesecs += 60*workouts[0].duration.minute - timesecs += workouts[0].duration.second - timesecs += 1.e-6*workouts[0].duration.microsecond - - thesecs.append(timesecs) - - for rankingduration in rankingdurations: - - workouts = Workout.objects.filter( - user=r,duration=rankingduration, - workouttype='rower', - rankingpiece=True, - startdatetime__gte=startdate, - startdatetime__lte=enddate - ).order_by('-distance') - if workouts: - thedistances.append(workouts[0].distance) - theworkouts.append(workouts[0]) - - timesecs = 3600*workouts[0].duration.hour - timesecs += 60*workouts[0].duration.minute - timesecs += workouts[0].duration.second - timesecs += 1.e-5*workouts[0].duration.microsecond - - thesecs.append(timesecs) - - thedistances = np.array(thedistances) - thesecs = np.array(thesecs) - - thevelos = thedistances/thesecs - theavpower = 2.8*(thevelos**3) - - - # create interactive plot - if len(thedistances) !=0 : - res = interactive_cpchart( - r,thedistances,thesecs,theavpower, - theworkouts,promember=promember - ) - script = res[0] - div = res[1] - paulslope = res[2] - paulintercept = res[3] - p1 = res[4] - message = res[5] - else: - script = '' - div = '

                No ranking pieces found.

                ' - paulslope = 1 - paulintercept = 1 - p1 = [1,1,1,1] - message = "" - - - if request.method == 'POST' and "piece" in request.POST: - form = PredictedPieceForm(request.POST) - if form.is_valid(): - value = form.cleaned_data['value'] - hourvalue,value = divmod(value,60) - if hourvalue >= 24: - hourvalue = 23 - pieceunit = form.cleaned_data['pieceunit'] - if pieceunit == 'd': - rankingdistances.append(value) - else: - rankingdurations.append(datetime.time(minute=int(value),hour=int(hourvalue))) - else: - form = PredictedPieceForm() - - rankingdistances.sort() - rankingdurations.sort() - - - predictions = [] - cpredictions = [] - - - for rankingdistance in rankingdistances: - # Paul's model - p = paulslope*np.log10(rankingdistance)+paulintercept - velo = 500./p - t = rankingdistance/velo - pwr = 2.8*(velo**3) - a = {'distance':rankingdistance, - 'duration':timedeltaconv(t), - 'pace':timedeltaconv(p), - 'power':int(pwr)} - predictions.append(a) - - # CP model - - pwr2 = p1[0]/(1+t/p1[2]) - pwr2 += p1[1]/(1+t/p1[3]) - - if pwr2 <= 0: - pwr2 = 50. - - velo2 = (pwr2/2.8)**(1./3.) - - if np.isnan(velo2) or velo2 <= 0: - velo2 = 1.0 - - t2 = rankingdistance/velo2 - - pwr3 = p1[0]/(1+t2/p1[2]) - pwr3 += p1[1]/(1+t2/p1[3]) - - if pwr3 <= 0: - pwr3 = 50. - - velo3 = (pwr3/2.8)**(1./3.) - if np.isnan(velo3) or velo3 <= 0: - velo3 = 1.0 - - t3 = rankingdistance/velo3 - p3 = 500./velo3 - - a = {'distance':rankingdistance, - 'duration':timedeltaconv(t3), - 'pace':timedeltaconv(p3), - 'power':int(pwr3)} - cpredictions.append(a) - - - - - for rankingduration in rankingdurations: - t = 3600.*rankingduration.hour - t += 60.*rankingduration.minute - t += rankingduration.second - t += rankingduration.microsecond/1.e6 - - # Paul's model - ratio = paulintercept/paulslope - - u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/paulslope - - d = 500*t*np.log(10.) - d = d/(paulslope*lambertw(u)) - d = d.real - - velo = d/t - p = 500./velo - pwr = 2.8*(velo**3) - a = {'distance':int(d), - 'duration':timedeltaconv(t), - 'pace':timedeltaconv(p), - 'power':int(pwr)} - predictions.append(a) - - # CP model - pwr = p1[0]/(1+t/p1[2]) - pwr += p1[1]/(1+t/p1[3]) - - if pwr <= 0: - pwr = 50. - - velo = (pwr/2.8)**(1./3.) - - if np.isnan(velo) or velo <=0: - velo = 1.0 - - d = t*velo - p = 500./velo - a = {'distance':int(d), - 'duration':timedeltaconv(t), - 'pace':timedeltaconv(p), - 'power':int(pwr)} - cpredictions.append(a) - - - messages.error(request,message) - return render(request, 'rankings.html', - {'rankingworkouts':theworkouts, - 'interactiveplot':script, - 'the_div':div, - 'predictions':predictions, - 'cpredictions':cpredictions, - 'nrdata':len(thedistances), - 'form':form, - 'rower':r, - 'active':'nav-analysis', - 'dateform':dateform, - 'deltaform':deltaform, - 'worldclasspower':worldclasspower, - 'id': theuser, - 'theuser':uu, - 'startdate':startdate, - 'enddate':enddate, - 'teams':get_my_teams(request.user), - }) @login_required() def ajax_agegrouprecords(request, @@ -2189,16 +1793,16 @@ def rankings_view2(request,userid=0, startdatestring="", enddatestring=""): - if deltadays>0: + if deltadays>0: # pragma: no cover startdate = enddate-datetime.timedelta(days=int(deltadays)) - if startdatestring != "": + if startdatestring != "": # pragma: no cover startdate = iso8601.parse_date(startdatestring) - if enddatestring != "": + if enddatestring != "": # pragma: no cover enddate = iso8601.parse_date(enddatestring) - if enddate < startdate: + if enddate < startdate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -2228,7 +1832,7 @@ def rankings_view2(request,userid=0, pass try: userid = options['userid'] - except KeyError: + except KeyError: # pragma: no cover userid = 0 else: options = {} @@ -2243,7 +1847,7 @@ def rankings_view2(request,userid=0, if str(userid) != str(theuser) or deltatime_seconds > 3600: recalc = True options['lastupdated'] = arrow.utcnow().isoformat() - else: + else: # pragma: no cover recalc = False options['userid'] = theuser.id @@ -2295,7 +1899,7 @@ def rankings_view2(request,userid=0, s = enddate enddate = startdate startdate = s - elif request.method == 'POST' and "datedelta" in request.POST: + elif request.method == 'POST' and "datedelta" in request.POST: # pragma: no cover deltaform = DeltaDaysForm(request.POST) if deltaform.is_valid(): deltadays = deltaform.cleaned_data['deltadays'] @@ -2420,7 +2024,7 @@ def rankings_view2(request,userid=0, message = "" - if request.method == 'POST' and "piece" in request.POST: + if request.method == 'POST' and "piece" in request.POST: # pragma: no cover form = PredictedPieceForm(request.POST) if form.is_valid(): value = form.cleaned_data['value'] @@ -2451,7 +2055,7 @@ def rankings_view2(request,userid=0, pwr = 2.8*(velo**3) try: pwr = int(pwr) - except (ValueError, AttributeError): + except (ValueError, AttributeError): # pragma: no cover pwr = 0 a = {'distance':rankingdistance, @@ -2464,12 +2068,12 @@ def rankings_view2(request,userid=0, pwr2 = p1[0]/(1+t/p1[2]) pwr2 += p1[1]/(1+t/p1[3]) - if pwr2 <= 0: + if pwr2 <= 0: # pragma: no cover pwr2 = 50. velo2 = (pwr2/2.8)**(1./3.) - if np.isnan(velo2) or velo2 <= 0: + if np.isnan(velo2) or velo2 <= 0: # pragma: no cover velo2 = 1.0 t2 = rankingdistance/velo2 @@ -2477,7 +2081,7 @@ def rankings_view2(request,userid=0, pwr3 = p1[0]/(1+t2/p1[2]) pwr3 += p1[1]/(1+t2/p1[3]) - if pwr3 <= 0: + if pwr3 <= 0: # pragma: no cover pwr3 = 50. velo3 = (pwr3/2.8)**(1./3.) @@ -2520,19 +2124,19 @@ def rankings_view2(request,userid=0, 'pace':timedeltaconv(p), 'power':int(pwr)} predictions.append(a) - except: + except: # pragma: no cover pass # CP model pwr = p1[0]/(1+t/p1[2]) pwr += p1[1]/(1+t/p1[3]) - if pwr <= 0: + if pwr <= 0: # pragma: no cover pwr = 50. velo = (pwr/2.8)**(1./3.) - if np.isnan(velo) or velo <=0: + if np.isnan(velo) or velo <=0: # pragma: no cover velo = 1.0 d = t*velo @@ -2595,253 +2199,6 @@ def rankings_view2(request,userid=0, }) -# Show ranking distances including predicted paces -@user_passes_test(ispromember,login_url="/rowers/paidplans", - message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality", - redirect_field_name=None) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def otwrankings_view(request,userid=0, - startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now(), - startdatestring="", - enddatestring=""): - - if startdatestring != "": - try: - startdate = iso8601.parse_date(startdatestring) - except ParseError: - pass - - if enddatestring != "": - try: - enddate = iso8601.parse_date(enddatestring) - except ParseError: - pass - - if enddate < startdate: - s = enddate - enddate = startdate - startdate = s - - r = getrequestrower(request,userid=userid) - promember = True - - theuser = r.user - - # get all OTW rows in date range - - # process form - if request.method == 'POST': - dateform = DateRangeForm(request.POST) - if dateform.is_valid(): - startdate = dateform.cleaned_data['startdate'] - enddate = dateform.cleaned_data['enddate'] - if startdate > enddate: - s = enddate - enddate = startdate - startdate = s - form = PredictedPieceFormNoDistance(request.POST) - if form.is_valid(): - value = form.cleaned_data['value'] - else: - value = None - trankingdurations = form.cleaned_data['trankingdurations'] - trankingdurations = [ - datetime.datetime.strptime(d,"%H:%M:%S").time() for d in trankingdurations - ] - if value: - hourvalue,tvalue = divmod(value,60) - hourvalue = int(hourvalue) - minutevalue = int(tvalue) - tvalue = int(60*(tvalue-minutevalue)) - if hourvalue >= 24: - hourvalue = 23 - trankingdurations.append(datetime.time( - minute=minutevalue, - hour=hourvalue, - second=tvalue - )) - - else: - form = PredictedPieceFormNoDistance() - dateform = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - workouttypes = ['rower','slides','dynamic'] - trankingdurations = rankingdurations - - # get all 2k (if any) - this rower, in date range - try: - r = Rower.objects.get(user=theuser) - request.session['rowerid'] = r.id - except Rower.DoesNotExist: - raise Http404("Rower doesn't exist") - - - - uu = theuser - - - # test to fix bug - startdate = datetime.datetime.combine(startdate,datetime.time()) - enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - #enddate = enddate+datetime.timedelta(days=1) - - startdate = arrow.get(startdate).datetime - enddate = arrow.get(enddate).datetime - - thedistances = [] - theworkouts = [] - thesecs = [] - - theworkouts = Workout.objects.filter( - user=r,rankingpiece=True, - workouttype__in=mytypes.otwtypes, - startdatetime__gte=startdate, - startdatetime__lte=enddate - ).order_by( - "-startdatetime" - ) - - delta,cpvalue,avgpower = dataprep.fetchcp(r,theworkouts) - - runningjob = 0 - - taskstatus = get_stored_tasks_status(request) - for task in taskstatus: - if task['func_name'] == 'updatecpwater': - if 'success' in task['status'].lower() or 'finished' in task['status'].lower(): - runningjob = 1 - messages.info(request,'CP chart data have been updated') - remove_asynctask(request,task['id']) - elif 'fail' in task['status'].lower(): - runningjob = 0 - try: - remove_asynctask(request,task[id]) - messages.error(request,'Oh, your task failed') - except KeyError: - pass - elif 'started' in task['status'].lower(): - messages.info(request,'Busy updating CP chart data') - runningjob = 1 - elif 'queued' in task['status'].lower() or 'pending' in task['status'].lower(): - messages.info(request,'Getting ready to update CP chart data') - runningjob = 1 - - - - if not runningjob: - job = dataprep.runcpupdate( - r,type='water', - startdate=startdate, - enddate=enddate - ) - request.session['job_id'] = job.id - try: - request.session['async_tasks'] += [(job.id,'updatecpwater')] - except KeyError: - request.session['async_tasks'] = [(job.id,'updatecpwater')] - messages.info(request,'New calculation queued. Page will reload automatically. You can check the status of your calculations here') - - powerdf = pd.DataFrame({ - 'Delta':delta, - 'CP':cpvalue, - 'workout':pd.Series(), - }) - - if powerdf.empty: - messages.info(request,'Your calculations are running in the background. Page will reload automatically. You can check the status of your calculations here') - - powerdf = powerdf[powerdf['CP']>0] - powerdf.dropna(axis=0,inplace=True) - powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True) - powerdf.drop_duplicates(subset='Delta',keep='first',inplace=True) - - - rowername = r.user.first_name+" "+r.user.last_name - # create interactive plot - if len(powerdf) !=0 : - res = interactive_otwcpchart(powerdf,promember=promember,rowername=rowername) - script = res[0] - div = res[1] - p1 = res[2] - ratio = res[3] - r.p0 = p1[0] - r.p1 = p1[1] - r.p2 = p1[2] - r.p3 = p1[3] - r.cpratio = ratio - r.save() - paulslope = 1 - paulintercept = 1 - message = res[4] - else: - script = '' - div = '

                No ranking pieces found.

                ' - paulslope = 1 - paulintercept = 1 - p1 = [1,1,1,1] - message = "" - - - - - cpredictions = [] - - for rankingduration in trankingdurations: - t = 3600.*rankingduration.hour - t += 60.*rankingduration.minute - t += rankingduration.second - t += rankingduration.microsecond/1.e6 - - - # CP model - pwr = p1[0]/(1+t/p1[2]) - pwr += p1[1]/(1+t/p1[3]) - - - if pwr <= 0: - pwr = 50. - - - if not np.isnan(pwr): - try: - pwr2 = pwr*ratio - except: - pwr2 = pwr - - a = { - 'duration':timedeltaconv(t), - 'power':int(pwr), - 'upper':int(pwr2)} - cpredictions.append(a) - - - - startdatestring = startdate.strftime('%Y-%m-%d') - enddatestring = enddate.strftime('%Y-%m-%d') - request.session['startdate'] = startdatestring - request.session['enddate'] = enddatestring - - messages.error(request,message) - return render(request, 'otwrankings.html', - {'rankingworkouts':theworkouts, - 'interactiveplot':script, - 'the_div':div, - 'cpredictions':cpredictions, - 'rower':r, - 'active':'nav-analysis', - 'avgpower':avgpower, - 'form':form, - 'dateform':dateform, - 'id': theuser, - 'theuser':uu, - 'startdate':startdate, - 'enddate':enddate, - 'teams':get_my_teams(request.user), - 'workouttype':'water', - }) @login_required() def otecp_toadmin_view(request,theuser=0, @@ -2987,343 +2344,6 @@ def otwcp_toadmin_view(request,theuser=0, return response -# Show ranking distances including predicted paces -@user_passes_test(ispromember,login_url="/rowers/paidplans", - message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality", - redirect_field_name=None) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def oterankings_view(request,userid=0, - startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now(), - startdatestring="", - enddatestring=""): - - if startdatestring != "": - try: - startdate = iso8601.parse_date(startdatestring) - except ParseError: - pass - - if enddatestring != "": - try: - enddate = iso8601.parse_date(enddatestring) - except ParseError: - pass - - if enddate < startdate: - s = enddate - enddate = startdate - startdate = s - - r = getrequestrower(request,userid=userid) - theuser = r.user - - - promember=0 - - # get all OTW rows in date range - - # process form - if request.method == 'POST': - dateform = DateRangeForm(request.POST) - if dateform.is_valid(): - startdate = dateform.cleaned_data['startdate'] - enddate = dateform.cleaned_data['enddate'] - if startdate > enddate: - s = enddate - enddate = startdate - startdate = s - workouttypeform = OteWorkoutTypeForm(request.POST) - if workouttypeform.is_valid(): - workouttypes = workouttypeform.cleaned_data['workouttypes'] - form = PredictedPieceForm(request.POST) - if form.is_valid(): - value = form.cleaned_data['value'] - pieceunit = form.cleaned_data['pieceunit'] - else: - value = None - - try: - trankingdistances = form.cleaned_data['trankingdistances'] - except KeyError: - trankingdistances = [] - - trankingdistances = [int(d) for d in trankingdistances] - - try: - trankingdurations = form.cleaned_data['trankingdurations'] - except KeyError: - trankingdurations = [] - - trankingdurations = [ - datetime.datetime.strptime(d,"%H:%M:%S").time() for d in trankingdurations - ] - if value: - hourvalue,tvalue = divmod(value,60) - hourvalue = int(hourvalue) - minutevalue = int(tvalue) - tvalue = int(60*(tvalue-minutevalue)) - if hourvalue >= 24: - hourvalue = 23 - if pieceunit == 'd': - trankingdistances.append(value) - else: - trankingdurations.append(datetime.time( - minute=minutevalue, - hour=hourvalue, - second=tvalue - )) - else: - form = PredictedPieceForm() - dateform = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - workouttypeform = OteWorkoutTypeForm() - workouttypes = ['rower','slides','dynamic'] - trankingdistances = rankingdistances - trankingdurations = rankingdurations - - # get all 2k (if any) - this rower, in date range - try: - r = Rower.objects.get(user=theuser) - request.session['rowerid'] = r.id - except Rower.DoesNotExist: - allergworkouts = [] - raise Http404("Rower doesn't exist") - - - uu = theuser - - - - # test to fix bug - startdate = datetime.datetime.combine(startdate,datetime.time()) - enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - - startdate = arrow.get(startdate).datetime - enddate = arrow.get(enddate).datetime - - thedistances = [] - theworkouts = [] - thesecs = [] - - theworkouts = Workout.objects.filter( - user=r,rankingpiece=True, - workouttype__in=workouttypes, - startdatetime__gte=startdate, - startdatetime__lte=enddate - ).order_by("-startdatetime") - - - delta,cpvalue,avgpower = dataprep.fetchcp( - r,theworkouts,table='cpergdata' - ) - - runningjob = 0 - - taskstatus = get_stored_tasks_status(request) - for task in taskstatus: - if task['func_name'] == 'updatecp': - if 'success' in task['status'].lower() or 'finished' in task['status'].lower(): - runningjob = 1 - messages.info(request,'CP chart data have been updated') - remove_asynctask(request,task['id']) - elif 'fail' in task['status'].lower(): - runningjob = 0 - try: - remove_asynctask(request,task[id]) - messages.error(request,'Oh, your task failed') - except KeyError: - pass - elif 'started' in task['status'].lower(): - messages.info(request,'Busy updating CP chart data') - runningjob = 1 - elif 'queued' in task['status'].lower(): - messages.info(request,'Getting ready to update CP chart data') - runningjob = 1 - - - if not runningjob: - job = dataprep.runcpupdate( - r,type='rower', - startdate=startdate, - enddate=enddate - ) - request.session['job_id'] = job.id - try: - request.session['async_tasks'] += [(job.id,'updatecp')] - except KeyError: - request.session['async_tasks'] = [(job.id,'updatecp')] - messages.info(request,'New calculation queued. Page will reload automatically. You can check the status of your calculations here') - - powerdf = pd.DataFrame({ - 'Delta':delta, - 'CP':cpvalue, - }) - - if powerdf.empty: - messages.info(request,'Your calculations are running in the background. Page will reload automatically. You can check the status of your calculations here') - - powerdf = powerdf[powerdf['CP']>0] - powerdf.dropna(axis=0,inplace=True) - powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True) - powerdf.drop_duplicates(subset='Delta',keep='first',inplace=True) - - rowername = r.user.first_name+" "+r.user.last_name - # create interactive plot - if len(powerdf) !=0 : - res = interactive_otwcpchart(powerdf,promember=promember,rowername=rowername) - script = res[0] - div = res[1] - p1 = res[2] - ratio = res[3] - r.ep0 = p1[0] - r.ep1 = p1[1] - r.ep2 = p1[2] - r.ep3 = p1[3] - r.ecpratio = ratio - r.save() - paulslope = 1 - paulintercept = 1 - message = res[4] - else: - ratio = 1 - script = '' - div = '

                No ranking pieces found.

                ' - paulslope = 1 - paulintercept = 1 - p1 = [1,1,1,1] - message = "" - - - - - - cpredictions = [] - - - - for rankingduration in trankingdurations: - t = 3600.*rankingduration.hour - t += 60.*rankingduration.minute - t += rankingduration.second - t += rankingduration.microsecond/1.e6 - - - # CP model - pwr = p1[0]/(1+t/p1[2]) - pwr += p1[1]/(1+t/p1[3]) - - velo = (pwr/2.8)**(1./3.) - p = 500./velo - d = t*velo - - if pwr <= 0: - pwr = 50. - - - if not np.isnan(pwr): - try: - pwr2 = pwr*ratio - except: - pwr2 = pwr - - a = collections.OrderedDict() - a['duration'] = timedeltaconv(t) - a['distance'] = int(d) - a['pace'] = timedeltaconv(p) - a['power'] = int(pwr) - a['upper'] = int(pwr2) - - cpredictions.append(a) - - - # initiation - get 10 min power, then use Paul's law - - t_10 = 600. - power_10 = p1[0]/(1+t_10/p1[2]) - power_10 += p1[1]/(1+t_10/p1[3]) - - velo_10 = (power_10/2.8)**(1./3.) - pace_10 = 500./velo_10 - distance_10 = t_10*velo_10 - - paulslope = 5. - - for rankingdistance in trankingdistances: - - delta = paulslope * np.log(rankingdistance/distance_10)/np.log(2) - - - p = pace_10+delta - velo = 500./p - t = rankingdistance/velo - - pwr2 = p1[0]/(1+t/p1[2]) - pwr2 += p1[1]/(1+t/p1[3]) - try: - pwr2 *= ratio - except UnboundLocalError: - pass - - if pwr2 <= 0: - pwr2 = 50. - - velo2 = (pwr2/2.8)**(1./3.) - - if np.isnan(velo2) or velo2 <= 0: - velo2 = 1.0 - - t2 = rankingdistance/velo2 - - pwr3 = p1[0]/(1+t2/p1[2]) - pwr3 += p1[1]/(1+t2/p1[3]) - pwr3 *= ratio - - - if pwr3 <= 0: - pwr3 = 50. - - velo3 = (pwr3/2.8)**(1./3.) - if np.isnan(velo3) or velo3 <= 0: - velo3 = 1.0 - - t3 = rankingdistance/velo3 - p3 = 500./velo3 - - a = { - 'distance':rankingdistance, - 'duration':timedeltaconv(t3), - 'power':'--', - 'upper':int(pwr3), - 'pace':timedeltaconv(p3)} - - cpredictions.append(a) - - # del form.fields["pieceunit"] - - - messages.error(request,message) - return render(request, 'oterankings.html', - {'rankingworkouts':theworkouts, - 'interactiveplot':script, - 'the_div':div, - 'rower':r, - 'active':'nav-analysis', - 'cpredictions':cpredictions, - 'avgpower':avgpower, - 'form':form, - 'dateform':dateform, - 'workouttypeform':workouttypeform, - 'id': theuser, - 'theuser':uu, - 'startdate':startdate, - 'enddate':enddate, - 'teams':get_my_teams(request.user), - 'workouttype':'rower', - }) - # Multi Flex Chart with Grouping diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index 5fc3c2b9..69a036a8 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -836,14 +836,14 @@ def workout_getnkworkout_all(request): @login_required() @permission_required('rower.is_coach',fn=get_user_by_userid, raise_exception=True) -def workout_nkimport_view(request,userid=0,startTime=0,endTime=0): +def workout_nkimport_view(request,userid=0,after=0,before=0): r = getrequestrower(request,userid=userid) try: thetoken = nk_open(request.user) except NoTokenError: return HttpResponseRedirect("/rowers/me/nkauthorize/") - res = nkstuff.get_nk_workout_list(request.user,startTime=startTime,endTime=endTime) + res = nkstuff.get_nk_workout_list(request.user,before=before,after=after) if (res.status_code != 200): if (res.status_code == 401):