Private
Public Access
1
0

Merge branch 'release/v9.20'

This commit is contained in:
Sander Roosendaal
2019-02-08 13:28:13 +01:00
43 changed files with 20544 additions and 406 deletions

View File

@@ -0,0 +1,574 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?><gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" creator="Oregon 400t" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd"><metadata><link href="http://www.garmin.com"><text>Garmin International</text></link><time>2016-05-20T15:41:26</time></metadata><trk><name>Export by rowingdata</name><trkseg> <trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:26+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:29.238150+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:32.148290+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:35.269000+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:38.152180+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:41.148270+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:44.148910+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:46.908250+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:49.819010+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:52.942510+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:55.639670+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:58.370000+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:01.188270+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:04.008300+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:06.888990+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:09.678900+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:12.469140+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:15.199010+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:17.963080+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:20.658340+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:23.538800+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:26.269790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:28.848350+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:31.729550+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:34.398400+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:37.038360+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:39.499250+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:42.349070+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:45.079070+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:47.752890+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:50.452350+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:53.182630+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:55.789410+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:58.671890+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:01.338860+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:04.068490+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:06.862620+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:09.618500+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:12.379160+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:15.229200+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:17.963150+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:20.692490+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:23.628520+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:26.329210+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:29.148960+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:31.668570+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:34.490920+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:37.369250+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:40.189230+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:42.798860+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:45.708750+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:48.318590+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:51.199500+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:53.869290+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:56.572490+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:59.212410+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:01.912890+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:04.459350+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:07.249360+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:09.949930+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:12.619870+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:15.378800+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:18.049420+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:20.719440+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:23.298970+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:26.178820+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:28.669980+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:31.429270+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:34.042790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:36.589070+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:39.412800+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:42.078870+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:44.783760+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:47.450710+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:50.149400+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:52.789720+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:55.429750+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:58.069700+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:00.742790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:03.442700+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:06.139610+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:08.689490+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:11.479530+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:14.119610+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:16.792860+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:19.368950+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:22.158960+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:24.889580+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:27.558940+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:30.469760+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:33.259860+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:36.079590+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:38.899560+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:41.689980+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:44.568940+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:47.329670+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:50.149560+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:52.969660+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:55.879910+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:58.789690+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:01.729660+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:04.669610+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:07.549730+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:10.458930+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:13.488980+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:16.429320+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:19.519650+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:22.459630+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:25.338880+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:28.459530+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:31.401590+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:34.339560+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:37.309450+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:40.098920+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:43.039950+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:46.039490+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:48.979630+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:51.949590+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:54.709590+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:57.589710+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:00.503120+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:03.408950+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:06.323410+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:09.229670+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:12.198960+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:15.079930+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:17.989660+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:20.959680+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:23.869730+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:26.782970+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:29.688910+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:32.539570+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:35.449720+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:38.329080+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:41.148960+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:44.088880+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:47.150600+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:50.029750+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:52.998850+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:55.880360+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:58.789400+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:01.639760+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:04.492770+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:07.429530+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:10.373270+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:13.309500+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:16.279570+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:19.160740+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:21.948820+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:25.039520+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:27.949340+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:30.890880+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:33.648790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:36.770050+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:39.499600+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:42.559140+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:45.439020+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:48.439810+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:51.379570+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:54.259600+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:57.139300+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:00.049550+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:02.838790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:05.839540+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:08.749400+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:11.689540+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:14.538900+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:17.389440+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:20.058880+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:23.059530+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:25.880610+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:28.608730+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:31.582600+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:34.278700+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:37.068660+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:40.039460+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:42.889790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:45.772580+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:48.708690+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:51.679450+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:54.499470+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:57.409440+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:00.439330+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:03.408680+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:06.378680+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:09.168860+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:12.229650+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:15.138650+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:18.049470+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:20.959460+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:23.242360+00:00</time>
</trkpt>
</trkseg></trk></gpx>

View File

@@ -1,3 +1,5 @@
from __future__ import absolute_import
from .tasks import app as celery_app

View File

@@ -118,11 +118,11 @@ def get_latlon(id):
rowdata = rdata(w.csvfilename)
try:
try:
latitude = rowdata.df.ix[:, ' latitude']
longitude = rowdata.df.ix[:, ' longitude']
latitude = rowdata.df.loc[:, ' latitude']
longitude = rowdata.df.loc[:, ' longitude']
except KeyError:
latitude = 0 * rowdata.df.ix[:, 'TimeStamp (sec)']
longitude = 0 * rowdata.df.ix[:, 'TimeStamp (sec)']
latitude = 0 * rowdata.df.loc[:, 'TimeStamp (sec)']
longitude = 0 * rowdata.df.loc[:, 'TimeStamp (sec)']
return [latitude, longitude]
except AttributeError:
return [pd.Series([]), pd.Series([])]
@@ -964,7 +964,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
totaltime = row.df['TimeStamp (sec)'].max(
) - row.df['TimeStamp (sec)'].min()
try:
totaltime = totaltime + row.df.ix[0, ' ElapsedTime (sec)']
totaltime = totaltime + row.df.loc[:, ' ElapsedTime (sec)'].iloc[0]
except KeyError:
pass
@@ -2077,37 +2077,37 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
return 0
rowdatadf.set_index([range(len(rowdatadf))], inplace=True)
t = rowdatadf.ix[:, 'TimeStamp (sec)']
t = pd.Series(t - rowdatadf.ix[0, 'TimeStamp (sec)'])
t = rowdatadf.loc[:, 'TimeStamp (sec)']
t = pd.Series(t - rowdatadf.loc[:, 'TimeStamp (sec)'].iloc[0])
row_index = rowdatadf.ix[:, ' Stroke500mPace (sec/500m)'] > 3000
row_index = rowdatadf.loc[:, ' Stroke500mPace (sec/500m)'] > 3000
rowdatadf.loc[row_index, ' Stroke500mPace (sec/500m)'] = 3000.
p = rowdatadf.ix[:, ' Stroke500mPace (sec/500m)']
p = rowdatadf.loc[:, ' Stroke500mPace (sec/500m)']
try:
velo = rowdatadf.ix[:,' AverageBoatSpeed (m/s)']
velo = rowdatadf.loc[:,' AverageBoatSpeed (m/s)']
except KeyError:
velo = 500./p
hr = rowdatadf.ix[:, ' HRCur (bpm)']
spm = rowdatadf.ix[:, ' Cadence (stokes/min)']
cumdist = rowdatadf.ix[:, 'cum_dist']
power = rowdatadf.ix[:, ' Power (watts)']
averageforce = rowdatadf.ix[:, ' AverageDriveForce (lbs)']
drivelength = rowdatadf.ix[:, ' DriveLength (meters)']
hr = rowdatadf.loc[:, ' HRCur (bpm)']
spm = rowdatadf.loc[:, ' Cadence (stokes/min)']
cumdist = rowdatadf.loc[:, 'cum_dist']
power = rowdatadf.loc[:, ' Power (watts)']
averageforce = rowdatadf.loc[:, ' AverageDriveForce (lbs)']
drivelength = rowdatadf.loc[:, ' DriveLength (meters)']
try:
workoutstate = rowdatadf.ix[:, ' WorkoutState']
workoutstate = rowdatadf.loc[:, ' WorkoutState']
except KeyError:
workoutstate = 0 * hr
peakforce = rowdatadf.ix[:, ' PeakDriveForce (lbs)']
peakforce = rowdatadf.loc[:, ' PeakDriveForce (lbs)']
forceratio = averageforce / peakforce
forceratio = forceratio.fillna(value=0)
try:
drivetime = rowdatadf.ix[:, ' DriveTime (ms)']
recoverytime = rowdatadf.ix[:, ' StrokeRecoveryTime (ms)']
drivetime = rowdatadf.loc[:, ' DriveTime (ms)']
recoverytime = rowdatadf.loc[:, ' StrokeRecoveryTime (ms)']
rhythm = 100. * drivetime / (recoverytime + drivetime)
rhythm = rhythm.fillna(value=0)
except:
@@ -2152,7 +2152,7 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
else:
drivenergy = drivelength * averageforce
distance = rowdatadf.ix[:, 'cum_dist']
distance = rowdatadf.loc[:, 'cum_dist']
velo = 500. / p
distanceperstroke = 60. * velo / spm
@@ -2184,26 +2184,26 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
if bands:
# HR bands
data['hr_ut2'] = rowdatadf.ix[:, 'hr_ut2']
data['hr_ut1'] = rowdatadf.ix[:, 'hr_ut1']
data['hr_at'] = rowdatadf.ix[:, 'hr_at']
data['hr_tr'] = rowdatadf.ix[:, 'hr_tr']
data['hr_an'] = rowdatadf.ix[:, 'hr_an']
data['hr_max'] = rowdatadf.ix[:, 'hr_max']
data['hr_ut2'] = rowdatadf.loc[:, 'hr_ut2']
data['hr_ut1'] = rowdatadf.loc[:, 'hr_ut1']
data['hr_at'] = rowdatadf.loc[:, 'hr_at']
data['hr_tr'] = rowdatadf.loc[:, 'hr_tr']
data['hr_an'] = rowdatadf.loc[:, 'hr_an']
data['hr_max'] = rowdatadf.loc[:, 'hr_max']
data['hr_bottom'] = 0.0 * data['hr']
try:
tel = rowdatadf.ix[:, ' ElapsedTime (sec)']
tel = rowdatadf.loc[:, ' ElapsedTime (sec)']
except KeyError:
rowdatadf[' ElapsedTime (sec)'] = rowdatadf['TimeStamp (sec)']
if barchart:
# time increments for bar chart
time_increments = rowdatadf.ix[:, ' ElapsedTime (sec)'].diff()
time_increments = rowdatadf.loc[:, ' ElapsedTime (sec)'].diff()
try:
time_increments.ix[0] = time_increments.ix[1]
time_increments.iloc[0] = time_increments.iloc[1]
except KeyError:
time_increments.ix[0] = 1.
time_increments.iloc[0] = 1.
time_increments = 0.5 * time_increments + 0.5 * np.abs(time_increments)
x_right = (t2 + time_increments.apply(lambda x: timedeltaconv(x)))
@@ -2212,28 +2212,28 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
if empower:
try:
wash = rowdatadf.ix[:, 'wash']
wash = rowdatadf.loc[:, 'wash']
except KeyError:
wash = 0 * power
try:
catch = rowdatadf.ix[:, 'catch']
catch = rowdatadf.loc[:, 'catch']
except KeyError:
catch = 0 * power
try:
finish = rowdatadf.ix[:, 'finish']
finish = rowdatadf.loc[:, 'finish']
except KeyError:
finish = 0 * power
try:
peakforceangle = rowdatadf.ix[:, 'peakforceangle']
peakforceangle = rowdatadf.loc[:, 'peakforceangle']
except KeyError:
peakforceangle = 0 * power
if data['driveenergy'].mean() == 0:
try:
driveenergy = rowdatadf.ix[:, 'driveenergy']
driveenergy = rowdatadf.loc[:, 'driveenergy']
except KeyError:
driveenergy = power * 60 / spm
else:
@@ -2246,7 +2246,7 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
drivelength = driveenergy / (averageforce * 4.44822)
try:
slip = rowdatadf.ix[:, 'slip']
slip = rowdatadf.loc[:, 'slip']
except KeyError:
slip = 0 * power
@@ -2319,11 +2319,11 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
if otwpower:
try:
nowindpace = rowdatadf.ix[:, 'nowindpace']
nowindpace = rowdatadf.loc[:, 'nowindpace']
except KeyError:
nowindpace = p
try:
equivergpower = rowdatadf.ix[:, 'equivergpower']
equivergpower = rowdatadf.loc[:, 'equivergpower']
except KeyError:
equivergpower = 0 * p + 50.

View File

@@ -103,7 +103,7 @@ def getsinglecp(df):
dfnew = pd.DataFrame({
'time':1000*(df['TimeStamp (sec)']-df.ix[0,'TimeStamp (sec)']),
'time':1000*(df['TimeStamp (sec)']-df.loc[:,'TimeStamp (sec)'].iloc[0]),
'power':df[' Power (watts)']
})
@@ -304,14 +304,16 @@ def getmaxwattinterval(tt,ww,i):
if len(w_roll):
# now goes with # data points - should be fixed seconds
indexmax = w_roll.idxmax(axis=1)
# indexmaxpos = indexmax.get_loc(indexmax)
indexmaxpos = indexmax
try:
t_0 = tt.ix[indexmax]
t_1 = tt.ix[indexmax-i]
deltas = tt.ix[indexmax-i:indexmax].diff().dropna()
t_0 = tt.ix[indexmaxpos]
t_1 = tt.ix[indexmaxpos-i]
deltas = tt.ix[indexmaxpos-i:indexmaxpos].diff().dropna()
testres = 1.0e-3*deltas.max() < 30.
if testres:
deltat = 1.0e-3*(t_0-t_1)
wmax = w_roll.ix[indexmax]
wmax = w_roll.ix[indexmaxpos]
#if wmax > 800 or wmax*5.0e-4*deltat > 800.0:
# wmax = 0
else:

View File

@@ -44,6 +44,7 @@ class BillingForm(forms.Form):
max_digits=8)
plan = forms.IntegerField(widget=forms.HiddenInput())
payment_method_nonce = forms.CharField(max_length=255,required=True)
tac= forms.BooleanField(required=True,initial=False)
# login form

View File

@@ -246,7 +246,7 @@ class PowerTimeFitnessMetric(models.Model):
('water','On the water')
)
date = models.DateField(default=timezone.now)
date = models.DateField(default=datetime.date.today)
last_workout = models.IntegerField(default=0)
user = models.ForeignKey(User)
PowerFourMin = models.FloatField(default=0)
@@ -334,7 +334,7 @@ class TeamForm(ModelForm):
class TeamInvite(models.Model):
team = models.ForeignKey(Team)
user = models.ForeignKey(User,null=True)
issuedate = models.DateField(default=timezone.now)
issuedate = models.DateField(default=datetime.date.today)
code = models.CharField(max_length=150,unique=True)
email = models.CharField(max_length=150,null=True,blank=True)
@@ -352,7 +352,7 @@ class TeamInviteForm(ModelForm):
class TeamRequest(models.Model):
team = models.ForeignKey(Team)
user = models.ForeignKey(User,null=True)
issuedate = models.DateField(default=timezone.now)
issuedate = models.DateField(default=datetime.date.today)
code = models.CharField(max_length=150,unique=True)
from utils import (
@@ -655,8 +655,8 @@ class Rower(models.Model):
paidplan = models.ForeignKey(PaidPlan,null=True,default=None)
planexpires = models.DateField(default=timezone.now)
teamplanexpires = models.DateField(default=timezone.now)
planexpires = models.DateField(default=datetime.date.today)
teamplanexpires = models.DateField(default=datetime.date.today)
clubsize = models.IntegerField(default=0)
protrialexpires = models.DateField(blank=True,null=True)
plantrialexpires = models.DateField(blank=True,null=True)
@@ -1022,10 +1022,10 @@ class GeoPoint(models.Model):
def half_year_from_now():
return timezone.now()+timezone.timedelta(days=182)
return (timezone.now()+timezone.timedelta(days=182)).date()
def a_week_from_now():
return timezone.now()+timezone.timedelta(days=7)
return (timezone.now()+timezone.timedelta(days=7)).date()
# models related to training planning - draft
# Do we need a separate class TestTarget?
@@ -1089,20 +1089,6 @@ class TrainingTargetForm(ModelForm):
# SportTracks has a TrainingGoal like this
#class TrainingGoal(models.Model):
# rower = models.ForeignKey(Rower)
# name = models.CharField(max_length=150,blank=True)
# startdate = models.DateField(default=timezone.now)
# enddate = models.DateField(
# default=timezone.now()+datetime.timedelta(days=28))
# goalmetric = models.CharField(max_length=150,default='rower',
# choices = modechoices)
# value = models.IntegerValue(default=1)
# I think we can use PlannedSession for that (in challenge mode)
# although such a TrainingGoal could have automatically calculated
# values without needing the user to assign
class TrainingPlan(models.Model):
@@ -1118,7 +1104,7 @@ class TrainingPlan(models.Model):
name = models.CharField(max_length=150,blank=True)
status = models.BooleanField(default=True,verbose_name='Active')
target = models.ForeignKey(TrainingTarget,blank=True,null=True)
startdate = models.DateField(default=timezone.now)
startdate = models.DateField(default=datetime.date.today)
enddate = models.DateField(
default=half_year_from_now)
@@ -1482,7 +1468,7 @@ def macrocyclecheckdates(plan):
class TrainingMacroCycle(models.Model):
plan = models.ForeignKey(TrainingPlan)
name = models.CharField(max_length=150,blank=True)
startdate = models.DateField(default=timezone.now)
startdate = models.DateField(default=datetime.date.today)
enddate = models.DateField(
default=half_year_from_now)
notes = models.TextField(max_length=300,blank=True)
@@ -1568,7 +1554,7 @@ class TrainingMacroCycleForm(ModelForm):
class TrainingMesoCycle(models.Model):
plan = models.ForeignKey(TrainingMacroCycle)
name = models.CharField(max_length=150,blank=True)
startdate = models.DateField(default=timezone.now)
startdate = models.DateField(default=datetime.date.today)
enddate = models.DateField(
default=half_year_from_now)
notes = models.TextField(max_length=300,blank=True)
@@ -1643,7 +1629,7 @@ class TrainingMesoCycle(models.Model):
class TrainingMicroCycle(models.Model):
plan = models.ForeignKey(TrainingMesoCycle)
name = models.CharField(max_length=150,blank=True)
startdate = models.DateField(default=timezone.now)
startdate = models.DateField(default=datetime.date.today)
enddate = models.DateField(
default=half_year_from_now)
notes = models.TextField(max_length=300,blank=True)
@@ -1790,7 +1776,7 @@ class PlannedSession(models.Model):
comment = models.TextField(max_length=500,blank=True,
)
startdate = models.DateField(default=timezone.now,
startdate = models.DateField(default=datetime.date.today,
verbose_name='On or After')
enddate = models.DateField(default=a_week_from_now,
@@ -3302,10 +3288,10 @@ class RowerForm(ModelForm):
# An announcement that goes to the right of the workouts list
# optionally sends a tweet to our twitter account
class SiteAnnouncement(models.Model):
created = models.DateField(default=timezone.now)
created = models.DateField(default=datetime.date.today)
announcement = models.TextField(max_length=280)
expires = models.DateField(default=timezone.now)
modified = models.DateField(default=timezone.now)
expires = models.DateField(default=datetime.date.today)
modified = models.DateField(default=datetime.date.today)
dotweet = models.BooleanField(default=False)
def save(self, *args, **kwargs):

View File

@@ -22,7 +22,8 @@
as a price per year. You can downgrade or cancel your
plan at any time, through the <a href="/rowers/me/edit/">settings page</a>.
Please refer to our <a href="/rowers/legal/">terms and conditions</a> for our
payments and refunds policy. Accepted payment methods are the payment methods offered
payments and <a href="/rowers/legal/#refunds">refunds policy</a>.
Accepted payment methods are the payment methods offered
by
<a href="https://www.braintreegateway.com/merchants/jytq7yxsm66qqdzb/verified">Braintree</a>
through us. If you have any questions about our payments and refunds policy, please contact

View File

@@ -72,6 +72,11 @@
<input type="hidden" id="nonce" name="payment_method_nonce" />
<input type="hidden" id="plan" name="plan" value="{{ plan.id }}">
<p>
<input id="tac" type="checkbox" name="tac" value="tac">I have taken note of the
<a href="/rowers/legal/#refunds" target="_blank">Refund and Cancellation</a>
Policy and agree with the <a href="/rowers/legal/" target="_blank">Terms of Service</a>.
</p>
{% csrf_token %}
<button type="submit" id="submit-button"><span>Downgrade to the &euro; {{ plan.price|currency }} plan</span></button>
</form>

View File

@@ -3,6 +3,52 @@
{% block title %}Legal{% endblock title %}
{% block main %}
<h1>Welcome to Rowsandall</h1>
<p>Welcome to Rowsandall. We want you to know and understand your rights and our rights relating
to the provision o fthe Services (as defined below). Please review them carefully.
Here are a few highlights:
</p>
<p>
<ul>
<li>
Your privacy is critically important to us. See how we collect and use your personal
information in our <a href="#privacy">Privacy Policy</a>
</li>
<li>
<a href="#deactivation">You can cancel your membership or delete your account at any time.</a>
</li>
<li>
<a href="#content">You own your content, but give us a right to use it</a>
</li>
<li>
<a href="#conduct">We expect our members to act with respect and we can cancel
your account if you act inappropriately</a>
</li>
<li>
<a href="#liability">Rowsandall is not liable for your activities and no warranties
are made by Rowsandall</a>
</li>
<li>
<a href="#termination">
We can cancel your account if you act inappropriately.
</a>
</li>
<li>
<a href="#refunds">
We offer paid plans with extended functionality. These are governed by
our refund policy.
</a>
</li>
<li>
<a href="#contact">
There are easy ways to reach us if you have questions or need help.
</a>
</li>
</ul>
</p>
<h1>Terms and Conditions</h1>
<h2>Credit</h2>
@@ -32,7 +78,12 @@
</p>
<h2>Acceptable use</h2>
<h2 id="conduct">Acceptable use</h2>
<p>You must not use this website to copy, store, host, transmit, sned, use, publish or
distribute any material which is illegal, obscene, defamatory, threatening, harassing, abusive,
or hateful or that advocates violence.
</p>
<p>You must not use this website in any way that causes, or may cause, damage to the website or impairment of the availability or accessibility of the website; or in any way which is unlawful, illegal, fraudulent or harmful, or in connection with any unlawful, illegal, fraudulent or harmful purpose or activity.</p>
@@ -51,7 +102,7 @@
<p>rowsandall.com may disable your user ID and password in rowsandall.com&rsquo;s sole discretion without notice or explanation.</p>
<h2>User content</h2>
<h2 id="content">User content</h2>
<p>In these terms and conditions, <q>your user content</q> means material (including without limitation text, images, audio material, video material and audio-visual material) that you submit to this website, for whatever purpose.</p>
@@ -78,7 +129,7 @@
<p>Nothing on this website constitutes, or is meant to constitute, advice of any kind. If you require advice in relation to any legal, financial or medica] matter you should consult an appropriate professional.</p>
<h2>Limitations of liability</h2>
<h2 id="liability">Limitations of liability</h2>
<p>rowsandall.com will not be liable to you (whether under the law of contact, the law of torts or otherwise) in relation to the contents of, or use of, or otherwise in connection with, this website:
@@ -136,6 +187,27 @@
<p>If a provision of these terms and conditions is determined by any court or other competent authority to be unlawful and/or unenforceable, the other provisions will continue in effect. If any unlawful and/or unenforceable provision would be lawful or enforceable if part of it were deleted, that part will be deemed to be deleted, and the rest of the provision will continue in effect. </p>
<h2 id="termination">Termination</h2>
<p>
You agree that Rowsandall may, under certain circumstances and without prior notice,
immediately terminate your accountand/or access to the site. Cause for such termination
shall include, but not be limited to, (a) breaches or violations of the Terms or
other incorporated agreements, policies, or guidelines, (b) requests by law enforcement
or other government agencies, (c) a request by you (self-initiated account deletions),
(d) discontinuance or material modification to the services (or any portion thereof), (e)
unexpected technical or security issues or problems, f) extended periods of inactivity,
and/or (g) nonpayment of any fees owed by you in connection with the Services.
Termination of your account may include (x) removal of access to all offerings within the
Services, (y) deletion of your information, files and Content associated with your account,
and (z) barring of further use of the Services. Further, you agree that all terminations
for cause shall be made in Rowsandalls sole discretion and that Strava shall not be liable
to you or any third party for any termination of your account or access to the Services.
The following Sections shall survive termination of your account
and/or the Terms: Member Content Submitted to the Services, Proprietary Rights,
Your Feedback, Disclaimer of Warranties and Liability, Indemnity, Applicable Laws and General.
</p>
<h2>Entire agreement</h2>
<p>These terms and conditions constitute the entire agreement between you and rowsandall.com in relation to your use of this website, and supersede all previous agreements in respect of your use of this website.</p>
@@ -145,7 +217,7 @@
<p>These terms and conditions will be governed by and construed in accordance with Czech Law and any disputes relating to these terms and conditions will be subject to the exclusive jurisdiction of the courts of The Czech Republic.</p>
<h2>rowsandall.com&rsquo;s details</h2>
<h2 id="contact">rowsandall.com&rsquo;s details</h2>
<p>The rowsandall.com site is owned by Rowsandall s.r.o., Nov&eacute; sady 988/2, Star&eacute; Brno, 602 00 Brno, Czech Republic (company identification number 070 48 572)</p>
@@ -156,7 +228,7 @@
{% include "refunds.html" %}
<h2>Privacy Policy</h2>
<h2 id="privacy">Privacy Policy</h2>
{% include "privacypolicy.html" %}

View File

@@ -302,7 +302,11 @@
<h2>Terms and Conditions, Contact Information</h2>
<p>Our paid plans follow the <a href="/rowers/legal/">Terms and Conditions</a>.</p>
<p>
Before purchasing any of our paid plans, you must
review and acknowledge our <a href="/rowers/legal/">Terms and Conditions</a>,
and <a href="/rowers/legal#refunds">Refunds and Returns Policy</a>
</p>
<p>Payments are made to "Rowsandall s.r.o.", with the following contact information:</p>
<p><strong>Rowsandall s.r.o.</strong><br />

View File

@@ -24,7 +24,8 @@
as a price per year. You can downgrade or cancel your
plan at any time, through the <a href="/rowers/me/edit/">settings page</a>.
Please refer to our <a href="/rowers/legal/">terms and conditions</a> for our
payments and refunds policy. Accepted payment methods are the payment methods offered
<a href="/rowers/legel/#refunds">payments and refunds policy</a>.
Accepted payment methods are the payment methods offered
by
<a href="https://www.braintreegateway.com/merchants/jytq7yxsm66qqdzb/verified">Braintree</a>
through us. If you have any questions about our payments and refunds policy, please contact

View File

@@ -20,7 +20,7 @@
</p>
<p>
Payments will be procesed by Braintree (A PayPal service):
Payments will be processed by Braintree (A PayPal service):
</p>
<p>
<a href="https://www.braintreegateway.com/merchants/{{ BRAINTREE_MERCHANT_ID }}/verified" target="_blank">
@@ -93,6 +93,11 @@
<input type="hidden" id="nonce" name="payment_method_nonce" />
<input type="hidden" id="plan" name="plan" value="{{ plan.id }}">
<p>
<input id="tac" type="checkbox" name="tac" value="tac">I have taken note of the
<a href="/rowers/legal/#refunds" target="_blank">Refund and Cancellation</a>
Policy and agree with the <a href="/rowers/legal/" target="_blank">Terms of Service</a>.
</p>
{% csrf_token %}
<button type="submit" id="submit-button"><span>Pay &euro; {{ plan.price|currency }}</span></button>
</form>
@@ -101,7 +106,6 @@
{% include 'braintreedropin.html' %}
{% endblock %}
{% block sidebar %}

View File

@@ -73,7 +73,7 @@
<a href="/rowers/sessions/multiclone/user/{{ rower.user.id }}/?when={{ timeperiod }}">
Clone multiple sessions
</a>
<button class="button green small" type="submit">Submit</button>
<button type="submit">Submit</button>
</form>
</li>
</ul>

View File

@@ -114,7 +114,7 @@
{{ dateshiftform.as_table }}
</table>
<p>
<input name='workoutselectform' class="button green" type="submit" value="Submit">
<input name='workoutselectform' type="submit" value="Submit">
</p>
<p>You can use the date and search forms above to search through all
sessions.</p>

View File

@@ -67,7 +67,7 @@
<a href="/rowers/sessions/{{ plannedsession.id }}/clone">Clone</a>
</p>
<p>
<input class="button green" type="submit" value="Save">
<input type="submit" value="Save">
</p>
<div id="id_guidance" class="padded">

View File

@@ -116,7 +116,7 @@
posts.
</p>
<h2>Data Deletion</h2>
<h2 id="deactivation">Membership Cancellation and Data Deletion</h2>
<p>If you have previously consented to allow rowsandall.com to store and process your personal
data in accordance with this privacy policy, and you wish to withdraw your conent,
@@ -237,7 +237,7 @@
edit your heart rate and power settings, as well as functional threshold information and the account information accessible on your
settings page under the header "Account Information". The team manager is not able to access or change your passwords, team memberships,
favorite charts, export settings, workflow layout, or secret tokens. Also, the team manager is not able to download all your data,
not can he deactivate or delete your account.
nor can he deactivate or delete your account.
</p>
<p>
@@ -274,6 +274,7 @@
has suitable GDPR compliant measures in place.
</p>
<h2>Inactive Users - accounts are deleted after 18 months</h2>
<p>

View File

@@ -1,5 +1,5 @@
<p>Thank you for shopping at Rowsandall.</p>
<p id="refunds">Thank you for shopping at Rowsandall.</p>
<h3>Digital products</h3>
@@ -9,19 +9,36 @@
of the plan, you can cancel the recurring payment. We do not issue refunds for payments
regarding the current plan period.</p>
<p>We do not issue refunds for digital products once the order is
confirmed and the product is sent.</p>
<p>If you are not 100% satisfied with your purchase, you can get a refund or
exhchange the product for another one.
</p>
<p>You can return a product for up to 30 days from the date you purchased it.
To be eligible for a refund, you need to contact us using the contact information
below. To improve our service, we ask you to explain how the product did not meet
your expectations. If your refund is approved, we will initiate a refund to your
credit card (or original method of payment). You will receive the credit within
a certain amount of days, depending on your card issuer's policies.
</p>
<p>We recommend contacting us for assistance if you experience any issues receiving
our products.</p>
<h3>Upgrades and Downgrades</h3>
<h3>Upgrades and Downgrades, Cancellations</h3>
Upgrades and downgrades between paid plans are effective immediately, but the billing cycle
is not changed. Upgrades are charged a pro-rated amount for the current billing cycle. Downgrades
will result in a credit on our accounts, leading to a lower charge at the beginning of the
subsequent billing cycle.
<p>
Upgrades and downgrades between paid plans are effective immediately, but the billing cycle
is not changed. Upgrades are charged a pro-rated amount for the current billing cycle. Downgrades
will result in a credit on our accounts, leading to a lower charge at the beginning of the
subsequent billing cycle.
</p>
<p>
With the exception of an approved refund within 30 days of purchase (see above), we do not
issue refunds upon cancellation of the plan. If you are eligible for a refund, contact
us within 30 days of your purchase.
</p>
<h3>Contact us</h3>

View File

@@ -20,7 +20,7 @@
</p>
<p>
Payments will be procesed by Braintree (A PayPal service):
Payments will be processed by Braintree (A PayPal service):
</p>
<p>
<a href="https://www.braintreegateway.com/merchants/{{ BRAINTREE_MERCHANT_ID }}/verified" target="_blank">
@@ -93,6 +93,11 @@
<input type="hidden" id="nonce" name="payment_method_nonce" />
<input type="hidden" id="plan" name="plan" value="{{ plan.id }}">
<p>
<input id="tac" type="checkbox" name="tac" value="tac">I have taken note of the
<a href="/rowers/legal/#refunds" target="_blank">Refund and Cancellation</a>
Policy and agree with the <a href="/rowers/legal/" target="_blank">Terms of Service</a>.
</p>
{% csrf_token %}
<button type="submit" id="submit-button"><span>Upgrade to the &euro; {{ plan.price|currency }} plan</span></button>
</form>

View File

@@ -61,7 +61,7 @@
{{ form.as_table }}
</table>
{% csrf_token %}
<input class="button green" type="submit" value="Save">
<input type="submit" value="Save">
</form>
</li>
{% for graph in graphs %}

View File

@@ -4,7 +4,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, RequestFactory, TransactionTestCase
from django.core.management import call_command
@@ -30,13 +30,15 @@ from rowers.tasks import handle_makeplot
from rowers.utils import serialize_list,deserialize_list
from rowers.utils import NoTokenError
from rowers.plannedsessions import get_dates_timeperiod
from shutil import copyfile
from shutil import copyfile, copy
from nose.tools import assert_true
from mock import Mock, patch
from minimocktest import MockTestCase
import pandas as pd
import rowers.c2stuff as c2stuff
from django.core.urlresolvers import reverse, reverse_lazy
import json
import numpy as np
@@ -107,7 +109,8 @@ def get_random_file(filename='rowers/tests/testdata/testdata.csv',name=''):
else:
newfilename = 'rowers/tests/testdata/temp/'+fromstring+uuid4().hex[:16]+'.'+extension
copyfile(filename,newfilename)
# copyfile(filename,newfilename)
copy(filename,newfilename)
thedict = {
'row':row,

View File

@@ -0,0 +1,52 @@
from statements import *
nu = datetime.datetime.now()
class WaterWorkoutViewTest(TestCase):
def setUp(self):
self.u = UserFactory()
self.r = Rower.objects.create(user=self.u,
birthdate=faker.profile()['birthdate'],
gdproptin=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()
result = get_random_file(filename='rowers/tests/testdata/onwater.csv')
self.wwater = WorkoutFactory(user=self.r,
csvfilename=result['filename'],
starttime=result['starttime'],
startdatetime=result['startdatetime'],
duration=result['duration'],
distance=result['totaldist']
)
def tearDown(self):
pass
@patch('rowers.dataprep.create_engine')
@patch('rowers.dataprep.getsmallrowdata_db')
def test_forcecurve(self, mocked_sqlalchemy, mocked_getsmallrowdata_db):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = reverse('workout_forcecurve_view',kwargs={'id':self.wwater.id})
response = self.c.get(url)
self.assertEqual(response.status_code,200)
form_data = {
'workstrokesonly': True
}
response = self.c.post(url,form_data)
self.assertEqual(response.status_code,200)

View File

@@ -366,6 +366,7 @@ class PaymentTest(TestCase):
'amount':'15.00',
'plan': plans[1].id,
'payment_method_nonce': 'aap',
'tac':'tac',
}
form = BillingForm(form_data)
@@ -410,6 +411,7 @@ class PaymentTest(TestCase):
'amount':'15.00',
'plan': plans[1].id,
'payment_method_nonce': 'aap',
'tac':'tac',
}
form = BillingForm(form_data)
@@ -453,6 +455,7 @@ class PaymentTest(TestCase):
'amount':'15.00',
'plan': plans[1].id,
'payment_method_nonce': 'aap',
'tac':'tac',
}
form = BillingForm(form_data)
@@ -470,3 +473,138 @@ class PaymentTest(TestCase):
expected_url = '/rowers/downgradecompleted/',
status_code=302,target_status_code=200)
@patch('rowers.views.braintreestuff.create_subscription', side_effect=mock_create_subscription)
def test_checkouts_view(self,mock_subscription):
u = UserFactory()
r = Rower.objects.create(user=u,
birthdate=faker.profile()['birthdate'],
gdproptin=True,
gdproptindate=timezone.now(),
rowerplan='coach',
paymentprocessor='braintree',
street_address = faker.street_address(),
city = faker.city(),
postal_code = faker.postalcode(),
country = faker.country(),
)
r.save()
u.set_password(self.password)
u.save()
plans = PaidPlan.objects.all().order_by('price')
plan = plans[1]
form_data = {
'amount':'15.00',
'plan': plans[1].id,
'payment_method_nonce': 'aap',
}
form = BillingForm(form_data)
self.assertTrue(not form.is_valid())
login = self.c.login(username=u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/checkouts/'
response = self.c.post(url, form_data,follow=True)
self.assertEqual(response.status_code,200)
self.assertRedirects(response,
expected_url = '/rowers/checkout/{planid}/'.format(
planid=plans[1].id),
status_code=302,target_status_code=200)
@patch('rowers.views.braintreestuff.update_subscription', side_effect=mock_update_subscription)
def test_upgrade_checkouts_view(self,mock_subscription):
u = UserFactory()
r = Rower.objects.create(user=u,
birthdate=faker.profile()['birthdate'],
gdproptin=True,
gdproptindate=timezone.now(),
rowerplan='coach',
paymentprocessor='braintree',
street_address = faker.street_address(),
city = faker.city(),
postal_code = faker.postalcode(),
country = faker.country(),
)
r.save()
u.set_password(self.password)
u.save()
plans = PaidPlan.objects.all().order_by('price')
plan = plans[1]
form_data = {
'amount':'15.00',
'plan': plans[1].id,
'payment_method_nonce': 'aap',
# 'tac':'tac',
}
form = BillingForm(form_data)
self.assertTrue(not form.is_valid())
login = self.c.login(username=u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/upgradecheckouts/'
response = self.c.post(url, form_data,follow=True)
self.assertEqual(response.status_code,200)
self.assertRedirects(response,
expected_url = '/rowers/upgradecheckout/{planid}/'.format(
planid=plans[1].id),
status_code=302,target_status_code=200)
@patch('rowers.views.braintreestuff.update_subscription', side_effect=mock_update_subscription)
def test_downgrade_checkouts_view(self,mock_subscription):
u = UserFactory()
r = Rower.objects.create(user=u,
birthdate=faker.profile()['birthdate'],
gdproptin=True,
gdproptindate=timezone.now(),
rowerplan='coach',
paymentprocessor='braintree',
street_address = faker.street_address(),
city = faker.city(),
postal_code = faker.postalcode(),
country = faker.country(),
)
r.save()
u.set_password(self.password)
u.save()
plans = PaidPlan.objects.all().order_by('price')
plan = plans[1]
form_data = {
'amount':'15.00',
'plan': plans[1].id,
'payment_method_nonce': 'aap',
# 'tac':'tac',
}
form = BillingForm(form_data)
self.assertTrue(not form.is_valid())
login = self.c.login(username=u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/downgradecheckouts/'
response = self.c.post(url, form_data,follow=True)
self.assertEqual(response.status_code,200)
self.assertRedirects(response,
expected_url = '/rowers/downgradecheckout/{planid}/'.format(
planid=plans[1].id),
status_code=302,target_status_code=200)

View File

@@ -1,6 +1,7 @@
#from __future__ import print_function
from statements import *
nu = datetime.datetime.now()
from rowers.utils import allmonths,allsundays
import rowers.plannedsessions as plannedsessions
@@ -124,7 +125,8 @@ class TrainingPlanTest(TestCase):
tested = True
# add test for creating new sessions
def sessions_create(self):
def test_sessions_create(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
@@ -150,8 +152,10 @@ class TrainingPlanTest(TestCase):
'name': faker.word(),
}
print 'posting to sessions/create'
form = PlannedSessionForm(post_data)
self.assertEqual(form.is_valid())
self.assertTrue(form.is_valid())
response = self.c.post(url,post_data)
self.assertEqual(response.status_code,200)
@@ -988,3 +992,542 @@ class MandatoryTestCompleteTest(TestCase):
response = self.c.get(url)
self.assertEqual(response.status_code,200)
class PlannedSessionsView(TestCase):
def setUp(self):
# user
self.u = UserFactory()
self.r = Rower.objects.create(user=self.u,
birthdate=faker.profile()['birthdate'],
gdproptin=True,
gdproptindate=timezone.now(),
rowerplan='coach')
self.r.save()
self.c = Client()
self.u2 = UserFactory(username='testbasicuser')
self.r2 = Rower.objects.create(user=self.u2,
birthdate=faker.profile()['birthdate'],
gdproptin=True,
gdproptindate=timezone.now(),
rowerplan='basic')
self.password2 = faker.word()
self.u2.set_password(self.password2)
self.u2.save()
self.team = Team.objects.create(
name = faker.word(),
notes = faker.text(),
manager = self.u,
)
self.r.team.add(self.team)
self.r2.team.add(self.team)
self.r.save()
self.r2.save()
# workouts
# workout 1 - 2019-01-13, rScore 69
result = get_random_file(filename='rowers/tests/testdata/2019-01-13_session.csv',name='sprintervals')
self.factory = RequestFactory()
self.password = faker.word()
self.u.set_password(self.password)
self.u.save()
self.w1 = Workout.objects.create(
name='sprintervals',
notes=faker.text(),
startdatetime = result['startdatetime'],
starttime = result['starttime'],
workouttype='rower',
date=result['date'],
duration=result['duration'],
distance=result['totaldist'],
csvfilename=result['filename'],
trimp = 77,
rscore = 69,
hrtss = 43,
normp = 236,
user=self.u.rower,
)
# plan
self.target = TrainingTarget.objects.create(
name = faker.word(),
manager = self.u.rower,
notes = faker.text()
)
self.target.rowers.add(self.u.rower)
self.target.save()
self.plan = TrainingPlan.objects.create(
manager = self.u.rower,
name = faker.word(),
status=True,
target = self.target,
startdate=timezone.now().date(),
enddate = self.target.date,
)
self.plan.rowers.add(self.u.rower)
self.plan.save()
# cycles
self.macro = TrainingMacroCycle.objects.create(
plan=self.plan,
name=faker.word(),
type='userdefined',
notes = faker.text(),
startdate = self.plan.startdate,
enddate = self.plan.enddate,
)
mesos = TrainingMesoCycle.objects.filter(plan=self.macro)
for m in mesos:
m.delete()
monthstarts = [d for d in allmonths(self.macro.startdate,self.macro.enddate)]
monthstarts.append(self.macro.enddate)
for i in range(len(monthstarts)-1):
firstday = monthstarts[i]
lastday = monthstarts[i+1]-datetime.timedelta(days=1)
if lastday < self.macro.enddate and i == len(monthstarts)-2:
lastday = self.macro.enddate
meso = TrainingMesoCycle(startdate=firstday,
enddate=lastday,
plan=self.macro,
name = '%s' % firstday.strftime("%B"),
type = 'userdefined')
meso.save()
mesos = TrainingMesoCycle.objects.filter(plan=self.macro)
for cycle in mesos:
micros = TrainingMicroCycle.objects.filter(plan=cycle)
for m in micros:
m.delete()
sundays = [s for s in allsundays(cycle.startdate,cycle.enddate)]
if sundays and sundays[-1] < cycle.enddate:
sundays = sundays+[cycle.enddate]
elif not sundays:
sundays = [cycle.enddate]
for i in range(len(sundays)):
if i==0:
monday = cycle.startdate
else:
monday = sundays[i]-datetime.timedelta(days=6)
if monday < cycle.startdate:
monday = cycle.startdate
nextsunday = sundays[i]
micro = TrainingMicroCycle(startdate=monday,
enddate=nextsunday,
plan=cycle,
name = 'Week %s' % monday.isocalendar()[1],
type='userdefined')
micro.save()
# sessions
startdatetime = self.w1.startdatetime
startdate = (startdatetime-datetime.timedelta(days=1)).date()
enddate = (startdatetime+datetime.timedelta(days=1)).date()
preferreddate = startdatetime.date()
self.startdate = startdate
self.enddate = enddate
self.ps_rscore = SessionFactory(
startdate=startdate,enddate=enddate,
sessiontype='test',
sessionmode = 'rScore',
criterium = 'none',
sessionvalue = 69,
sessionunit='None',
preferreddate=preferreddate,
manager=self.u,
)
self.ps_rscore.save()
added = plannedsessions.add_rower_session(self.u.rower,self.ps_rscore)
self.ps_dist = SessionFactory(
startdate=startdate,enddate=enddate,
sessiontype='test',
sessionmode = 'distance',
criterium = 'none',
sessionvalue = result['totaldist'],
sessionunit='m',
preferreddate=preferreddate,
manager=self.u,
)
self.ps_dist.save()
added = plannedsessions.add_rower_session(self.u.rower,self.ps_dist)
self.ps_time = SessionFactory(
startdate=startdate,enddate=enddate,
sessiontype='test',
sessionmode = 'time',
criterium = 'none',
sessionvalue = 38,
sessionunit='min',
preferreddate=preferreddate,
manager=self.u,
)
self.ps_time.save()
added = plannedsessions.add_rower_session(self.u.rower,self.ps_time)
self.ps_trimp = SessionFactory(
startdate=startdate,enddate=enddate,
sessiontype='test',
sessionmode = 'TRIMP',
criterium = 'none',
sessionvalue = 77,
sessionunit='none',
preferreddate=preferreddate,
manager=self.u,
)
self.ps_trimp.save()
added = plannedsessions.add_rower_session(self.u.rower,self.ps_trimp)
added = plannedsessions.add_team_session(self.team,self.ps_trimp)
def tearDown(self):
try:
os.remove(self.w1.csvfilename)
except (IOError, WindowsError):
pass
def test_clone_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/{id}/clone/'.format(id=self.ps_trimp.id)
today = datetime.date.today()
b = datetime.date.today()-timezone.timedelta(today.weekday())
e = b+timezone.timedelta(days=6)
expected_url = '/rowers/sessions/teamedit/5/'
response = self.c.get(url,follow=True)
self.assertEqual(response.status_code,200)
self.assertRedirects(response,
expected_url=expected_url,
status_code=302,target_status_code=200)
def test_multiclone_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/multiclone/'
response = self.c.get(url)
self.assertEqual(response.status_code,200)
formdata = {
'startdate':self.startdate,
'enddate':self.enddate,
}
form = DateRangeForm(formdata)
self.assertTrue(form.is_valid())
response = self.c.post(url,formdata)
self.assertEqual(response.status_code,200)
url = '/rowers/sessions/multiclone/?startdate={startdate}&enddate={enddate}'.format(
startdate = self.startdate,
enddate = self.enddate
)
formdata = {
'plannedsessions':[self.ps_time.id,self.ps_trimp.id],
'shiftstartdate':datetime.date.today()+timezone.timedelta(days=6)
}
form = PlannedSessionMultipleCloneForm(formdata)
self.assertTrue(form.is_valid())
form = SessionDateShiftForm(formdata)
self.assertTrue(form.is_valid())
response = self.c.post(url,formdata,follow=True)
self.assertEqual(response.status_code,200)
def test_multicreate_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
# get something
url = '/rowers/sessions/multicreate/user/1/extra/1/'
response = self.c.get(url)
self.assertEqual(response.status_code,200)
data = {}
data['csrf_token'] = response.context['csrf_token']
management_form = response.context['ps_formset'].management_form
for i in 'TOTAL_FORMS', 'INITIAL_FORMS', 'MIN_NUM_FORMS', 'MAX_NUM_FORMS':
data['%s-%s' % (management_form.prefix,i)] = management_form[i].value()
for i in range(response.context['ps_formset'].total_form_count()):
current_form = response.context['ps_formset'].forms[i]
for field_name in current_form.fields:
value = current_form[field_name].value()
data['%s-%s' % (current_form.prefix, field_name)] = value if value is not None else ''
# post data
response = self.c.post(url,data,follow=True)
self.assertEqual(response.status_code,200)
def test_teamcreate_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/teamcreate/'
response = self.c.get(url)
self.assertEqual(response.status_code,200)
form_data = {
'team':[self.team.id],
'startdate': self.w1.startdatetime.date(),
'enddate': (self.w1.startdatetime+datetime.timedelta(days=5)).date(),
'preferreddate': self.w1.startdatetime.date(),
'name': faker.word(),
'sessiontype': 'session',
'sessionmode': 'distance',
'criterium': 'none',
'sessionvalue': 13000,
'sessionunit': 'm',
'course': '',
'comment':faker.text()
}
plannedsessionform = PlannedSessionForm(form_data)
self.assertTrue(plannedsessionform.is_valid())
teamform = PlannedSessionTeamForm(self.u,form_data)
self.assertTrue(teamform.is_valid())
response = self.c.post(url,form_data,follow=True)
self.assertEqual(response.status_code,200)
def test_teamedit_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/teamedit/{id}/'.format(id=self.ps_trimp.id)
response = self.c.get(url)
self.assertEqual(response.status_code,200)
s = self.w1.startdatetime.date().strftime("%Y-%m-%d")
e = (self.w1.startdatetime+datetime.timedelta(days=5)).date().strftime("%Y-%m-%d")
p = self.w1.startdatetime.date().strftime("%Y-%m-%d")
form_data = {
'team':['1'],
'startdate': s,
'enddate': e,
'preferreddate': p,
'name': faker.word(),
'sessiontype': 'session',
'sessionmode': 'distance',
'criterium': 'none',
'sessionvalue': 13000,
'sessionunit': 'm',
'course': '',
'comment':faker.text(),
'members': ['{id1}'.format(id1=self.r.id)],
'initial-startdate':s,
'initial-enddate':e,
'initial-preferreddate':p
}
form = PlannedSessionForm(form_data,instance=self.ps_trimp)
if not form.is_valid():
print form.errors
self.assertTrue(form.is_valid())
form = PlannedSessionTeamForm(self.u,form_data)
if not form.is_valid():
print form.errors
self.assertTrue(form.is_valid())
form = PlannedSessionTeamMemberForm(self.ps_trimp,form_data)
if not form.is_valid():
print form.errors
self.assertTrue(form.is_valid())
response = self.c.post(url,follow=True)
self.assertEqual(response.status_code,200)
def test_coach_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
d1 = (self.ps_trimp.startdate-datetime.timedelta(days=1)).strftime(
"%Y-%m-%d")
d2 = (self.ps_trimp.enddate+datetime.timedelta(days=1)).strftime(
"%Y-%m-%d")
sps = plannedsessions.get_sessions_manager(self.u,teamid=0,
enddate=d2,startdate=d1)
self.assertTrue(len(sps)>0)
url = '/rowers/sessions/coach/?when={d1}/{d2}'.format(
d1=d1,
d2=d2,
)
response = self.c.get(url)
self.assertEqual(response.status_code,200)
def test_plannedsessions_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/?when={d1}/{d2}'.format(
d1=self.ps_trimp.startdate.strftime("%Y-%m%d"),
d2=self.ps_trimp.enddate.strftime("%Y-%m%d")
)
response = self.c.get(url)
self.assertEqual(response.status_code,200)
def test_plannedsessions_print_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/print/?when={d1}/{d2}'.format(
d1=self.ps_trimp.startdate.strftime("%Y-%m%d"),
d2=self.ps_trimp.enddate.strftime("%Y-%m%d")
)
response = self.c.get(url)
self.assertEqual(response.status_code,200)
def test_plannedsession_manage_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/manage/session/{id}/?when={d1}/{d2}'.format(
d1=self.ps_trimp.startdate.strftime("%Y-%m%d"),
d2=self.ps_trimp.enddate.strftime("%Y-%m%d"),
id=self.ps_trimp.id,
)
response = self.c.get(url)
self.assertEqual(response.status_code,200)
def test_plannedsession_edit_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/{id}/edit/'.format(
id=self.ps_time.id,
)
response = self.c.get(url)
self.assertEqual(response.status_code,200)
form_data = {
'startdate': self.w1.startdatetime.date().strftime("%Y-%m-%d"),
'enddate': (self.w1.startdatetime+datetime.timedelta(days=5)).date().strftime("%Y-%m-%d"),
'preferreddate': self.w1.startdatetime.date().strftime("%Y-%m-%d"),
'name': faker.word(),
'sessiontype': 'session',
'sessionmode': 'distance',
'criterium': 'none',
'sessionvalue': 13000,
'sessionunit': 'm',
'course': '',
'comment':faker.text(),
}
form = PlannedSessionForm(form_data,instance=self.ps_time)
if not form.is_valid():
print form.errors
self.assertTrue(form.is_valid())
response = self.c.post(url,follow=True)
self.assertEqual(response.status_code,200)
def test_plannedsession_detach_view(self):
self.ps_time.startdate = self.w1.date-datetime.timedelta(days=3)
self.ps_time.enddate = self.w1.date-datetime.timedelta(days=3)
self.ps_time.save()
self.w1.plannedsession = self.ps_time
self.w1.save()
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/{psid}/detach/{id}/'.format(
psid=self.ps_time.id,
id = self.w1.id,
)
response = self.c.get(url,follow=True)
self.assertEqual(response.status_code,200)
def test_plannedsession_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/{psid}/'.format(
psid = self.ps_time.id
)
response = self.c.get(url)
self.assertEqual(response.status_code,200)
def test_plannedsession_delete_view(self):
login = self.c.login(username=self.u.username, password=self.password)
self.assertTrue(login)
url = '/rowers/sessions/{psid}/delete/'.format(
psid = self.ps_time.id
)
response = self.c.get(url)
self.assertEqual(response.status_code,200)
response = self.c.post(url,follow=True)
self.assertEqual(response.status_code,200)

View File

@@ -1,4 +1,4 @@
#from __future__ import print_function
from __future__ import print_function
from statements import *
nu = datetime.datetime.now()
@@ -262,10 +262,11 @@ class URLTests(TestCase):
self.assertTrue(login)
response = self.c.get(url,follow=True)
if response.status_code != expected:
print url
print response.status_code
print(url )
print(response.status_code)
self.assertEqual(response.status_code,
expected)
expected)
html = BeautifulSoup(response.content,'html.parser')
urls = [a['href'] for a in html.find_all('a')]
@@ -274,10 +275,10 @@ class URLTests(TestCase):
if u not in tested and 'rowers' in u and 'http' not in u and 'authorize' not in u and 'import' not in u and 'logout' not in u:
response = self.c.get(u)
if response.status_code not in [200,302]:
print len(tested)
print url
print u
print response.status_code
print(len(tested))
print(url)
print(u)
print(response.status_code)
tested.append(u)
self.assertIn(response.status_code,
[200,302])

98
rowers/tests/testdata/onwater.csv vendored Normal file
View File

@@ -0,0 +1,98 @@
,index, lapIdx,TimeStamp (sec), Horizontal (meters),GPS Split,GPS Speed, Cadence (stokes/min), HRCur (bpm),Stroke Count,cum_dist, Stroke500mPace (sec/500m), ElapsedTime (sec), Power (watts), DriveLength (meters), StrokeDistance (meters), DriveTime (ms), DragFactor, StrokeRecoveryTime (ms), AverageDriveForce (lbs), AverageBoatSpeed (m/s), PeakDriveForce (lbs), AverageDriveForce (N), PeakDriveForce (N), WorkoutState, Stroke Number,originalvelo,hr_ut2,hr_ut1,hr_at,hr_tr,hr_an,hr_max,lim_ut2,lim_ut1,lim_at,lim_tr,lim_an,lim_max,pw_ut2,pw_ut1,pw_at,pw_tr,pw_an,pw_max,limpw_ut2,limpw_ut1,limpw_at,limpw_tr,limpw_an
0,0,0.0,1469705701.0,3.2,0.0,0.74,35.5,112,1,3.2,695.931477516,0.0,0,0,0,0,0,0,0,0.74,0,0.0,0.0,4,0,0.74,0.0,0.0,0.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
1,1,0.0,1469705702.6,8.6,0.0,2.07,38.5,113,2,8.6,228.8,1.59999990463,0,0,0,0,0,0,0,2.07,0,0.0,0.0,4,1,2.07,113.0,0.0,0.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
2,2,0.0,1469705704.5,15.1,0.0,3.36,38.5,115,3,15.1,153.336955279,3.5,0,0,0,0,0,0,0,3.36,0,0.0,0.0,4,3,3.35999999999,115.0,0.0,0.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
3,3,0.0,1469705705.6,21.4,0.0,4.09,39.0,115,4,21.4,124.977058407,4.59999990463,0,0,0,0,0,0,0,4.09,0,0.0,0.0,4,3,4.09,115.0,0.0,0.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
4,4,0.0,1469705707.5,28.8,0.0,4.43,38.5,118,5,28.8,112.083019815,6.5,0,0,0,0,0,0,0,4.43,0,0.0,0.0,4,5,4.42999999999,118.0,0.0,0.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
5,5,0.0,1469705708.8,36.2,0.0,4.64,37.5,125,6,36.2,106.442632632,7.79999995232,0,0,0,0,0,0,0,4.64,0,0.0,0.0,4,5,4.63999999999,125.0,0.0,0.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
6,6,0.0,1469705710.5,43.1,0.0,4.66,36.0,130,7,43.1,104.628021775,9.5,0,0,0,0,0,0,0,4.66,0,0.0,0.0,4,6,4.66,130.0,0.0,0.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
7,7,0.0,1469705712.2,52.0,0.0,4.76,34.0,135,8,52.0,106.01911804,11.2000000477,0,0,0,0,0,0,0,4.76,0,0.0,0.0,4,7,4.75999999999,135.0,0.0,0.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
8,8,0.0,1469705714.0,60.1,0.0,4.71,34.5,142,9,60.1,107.565165936,13.0,0,0,0,0,0,0,0,4.71,0,0.0,0.0,4,8,4.70999999998,142.0,0.0,0.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
9,9,0.0,1469705715.8,68.1,0.0,4.53,33.5,148,10,68.1,108.679681206,14.7999999523,0,0,0,0,0,0,0,4.53,0,0.0,0.0,4,9,4.53000000001,0.0,0.0,148.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
10,10,0.0,1469705717.6,76.3,0.0,4.44,32.5,154,11,76.3,109.466700689,16.5999999046,0,0,0,0,0,0,0,4.44,0,0.0,0.0,4,10,4.43999999998,0.0,0.0,154.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
11,11,0.0,1469705719.5,83.8,0.0,4.44,33.0,156,12,83.8,109.893487851,18.5,0,0,0,0,0,0,0,4.44,0,0.0,0.0,4,11,4.43999999998,0.0,0.0,156.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
12,12,0.0,1469705721.2,92.5,0.0,4.62,33.5,159,13,92.5,110.627456239,20.2000000477,0,0,0,0,0,0,0,4.62,0,0.0,0.0,4,12,4.62,0.0,0.0,159.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
13,13,0.0,1469705723.0,100.8,0.0,4.64,33.5,163,14,100.8,110.362782274,22.0,0,0,0,0,0,0,0,4.64,0,0.0,0.0,4,13,4.63999999999,0.0,0.0,0.0,163.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
14,14,0.0,1469705724.8,109.1,0.0,4.59,32.0,166,15,109.1,109.351182981,23.7999999523,0,0,0,0,0,0,0,4.59,0,0.0,0.0,4,14,4.58999999998,0.0,0.0,0.0,166.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
15,15,0.0,1469705726.8,118.1,0.0,4.52,32.5,168,16,118.1,108.636197885,25.7999999523,0,0,0,0,0,0,0,4.52,0,0.0,0.0,4,15,4.51999999998,0.0,0.0,0.0,0.0,168.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
16,16,0.0,1469705728.5,125.1,0.0,4.5,33.0,169,17,125.1,108.494979894,27.5,0,0,0,0,0,0,0,4.5,0,0.0,0.0,4,16,4.5,0.0,0.0,0.0,0.0,169.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
17,17,0.0,1469705730.4,134.7,0.0,4.66,33.5,171,18,134.7,109.232014911,29.4000000954,0,0,0,0,0,0,0,4.66,0,0.0,0.0,4,17,4.66,0.0,0.0,0.0,0.0,171.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
18,18,0.0,1469705732.2,143.0,0.0,4.66,32.5,172,19,143.0,109.4493854,31.2000000477,0,0,0,0,0,0,0,4.66,0,0.0,0.0,4,18,4.66,0.0,0.0,0.0,0.0,172.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
19,19,0.0,1469705734.0,151.2,0.0,4.58,33.0,172,20,151.2,109.222559423,33.0,0,0,0,0,0,0,0,4.58,0,0.0,0.0,4,19,4.57999999999,0.0,0.0,0.0,0.0,172.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
20,20,0.0,1469705735.8,159.4,0.0,4.52,33.0,173,21,159.4,109.097567302,34.7999999523,0,0,0,0,0,0,0,4.52,0,0.0,0.0,4,20,4.51999999998,0.0,0.0,0.0,0.0,173.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
21,21,0.0,1469705737.5,166.1,0.0,4.47,33.5,175,22,166.1,109.622785185,36.5,0,0,0,0,0,0,0,4.47,0,0.0,0.0,4,21,4.47000000001,0.0,0.0,0.0,0.0,175.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
22,22,0.0,1469705739.4,175.7,0.0,4.58,33.5,175,23,175.7,110.908884086,38.4000000954,0,0,0,0,0,0,0,4.58,0,0.0,0.0,4,22,4.57999999999,0.0,0.0,0.0,0.0,175.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
23,23,0.0,1469705741.2,183.8,0.0,4.57,32.5,175,24,183.8,111.571150665,40.2000000477,0,0,0,0,0,0,0,4.57,0,0.0,0.0,4,23,4.57,0.0,0.0,0.0,0.0,175.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
24,24,0.0,1469705743.0,191.8,0.0,4.47,33.0,175,25,191.8,111.781044645,42.0,0,0,0,0,0,0,0,4.47,0,0.0,0.0,4,24,4.47000000001,0.0,0.0,0.0,0.0,175.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
25,25,0.0,1469705744.8,199.8,0.0,4.39,32.0,176,26,199.8,111.973606594,43.7999999523,0,0,0,0,0,0,0,4.39,0,0.0,0.0,4,25,4.39,0.0,0.0,0.0,0.0,176.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
26,26,0.0,1469705746.7,207.8,0.0,4.39,32.5,176,27,207.8,112.082434148,45.7000000477,0,0,0,0,0,0,0,4.39,0,0.0,0.0,4,26,4.39,0.0,0.0,0.0,0.0,176.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
27,27,0.0,1469705748.6,216.7,0.0,4.49,33.0,174,28,216.7,112.462053887,47.5999999046,0,0,0,0,0,0,0,4.49,0,0.0,0.0,4,27,4.49000000001,0.0,0.0,0.0,0.0,174.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
28,28,0.0,1469705750.4,224.8,0.0,4.49,32.0,174,29,224.8,110.702820986,49.4000000954,0,0,0,0,0,0,0,4.49,0,0.0,0.0,4,28,4.49000000001,0.0,0.0,0.0,0.0,174.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
29,29,0.0,1469705752.5,232.9,0.0,4.47,33.0,174,30,232.9,111.287510895,51.5,0,0,0,0,0,0,0,4.47,0,0.0,0.0,4,30,4.47000000001,0.0,0.0,0.0,0.0,174.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
30,30,0.0,1469705754.0,240.9,0.0,4.48,32.0,175,31,240.9,113.880099386,53.0,0,0,0,0,0,0,0,4.48,0,0.0,0.0,4,30,4.48000000001,0.0,0.0,0.0,0.0,175.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
31,31,0.0,1469705755.8,248.9,0.0,4.43,32.0,175,32,248.9,117.397229535,54.7999999523,0,0,0,0,0,0,0,4.43,0,0.0,0.0,4,31,4.42999999999,0.0,0.0,0.0,0.0,175.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
32,32,0.0,1469705756.2,250.4,0.0,4.43,32.0,175,32,250.4,120.181532945,55.2000000477,0,0,0,0,0,0,0,4.43,0,0.0,0.0,4,32,4.42999999999,0.0,0.0,0.0,0.0,175.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
33,33,1.0,1469705757.6,5.7,0.0,3.62,30.5,160,1,256.1,121.464367621,56.5999999046,0,0,0,0,0,0,0,3.62,0,0.0,0.0,4,32,3.62000000001,0.0,0.0,160.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
34,34,1.0,1469705759.4,13.4,0.0,3.85,33.5,161,2,263.8,121.497391629,58.4000000954,0,0,0,0,0,0,0,3.85,0,0.0,0.0,4,33,3.85,0.0,0.0,0.0,161.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
35,35,1.0,1469705761.2,20.7,0.0,4.2,33.5,162,3,271.1,120.37982782,60.2000000477,0,0,0,0,0,0,0,4.2,0,0.0,0.0,4,34,4.19999999999,0.0,0.0,0.0,162.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
36,36,1.0,1469705763.0,29.2,0.0,4.47,33.5,162,4,279.6,118.387283716,62.0,0,0,0,0,0,0,0,4.47,0,0.0,0.0,4,35,4.47000000001,0.0,0.0,0.0,162.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
37,37,1.0,1469705764.8,37.3,0.0,4.47,33.0,164,5,287.7,115.233986774,63.7999999523,0,0,0,0,0,0,0,4.47,0,0.0,0.0,4,36,4.47000000001,0.0,0.0,0.0,164.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
38,38,1.0,1469705766.6,45.3,0.0,4.44,33.5,165,6,295.7,111.287510895,65.5999999046,0,0,0,0,0,0,0,4.44,0,0.0,0.0,4,37,4.43999999998,0.0,0.0,0.0,165.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
39,39,1.0,1469705768.5,53.5,0.0,4.42,33.5,165,7,303.9,111.718168135,67.5,0,0,0,0,0,0,0,4.42,0,0.0,0.0,4,38,4.41999999999,0.0,0.0,0.0,165.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
40,40,1.0,1469705770.2,60.7,0.0,4.38,32.0,167,8,311.1,113.471050335,69.2000000477,0,0,0,0,0,0,0,4.38,0,0.0,0.0,4,39,4.37999999998,0.0,0.0,0.0,167.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
41,41,1.0,1469705772.2,70.1,0.0,4.44,32.0,171,9,320.5,115.140584238,71.2000000477,0,0,0,0,0,0,0,4.44,0,0.0,0.0,4,40,4.43999999998,0.0,0.0,0.0,0.0,171.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
42,42,1.0,1469705774.1,77.8,0.0,4.3,32.0,172,10,328.2,116.273396972,73.0999999046,0,0,0,0,0,0,0,4.3,0,0.0,0.0,4,41,4.30000000002,0.0,0.0,0.0,0.0,172.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
43,43,1.0,1469705776.1,85.2,0.0,4.12,31.0,174,11,335.6,117.556791714,75.0999999046,0,0,0,0,0,0,0,4.12,0,0.0,0.0,4,42,4.12,0.0,0.0,0.0,0.0,174.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
44,44,1.0,1469705777.9,93.4,0.0,4.2,31.5,174,12,343.8,119.395508057,76.9000000954,0,0,0,0,0,0,0,4.2,0,0.0,0.0,4,43,4.19999999999,0.0,0.0,0.0,0.0,174.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
45,45,1.0,1469705779.9,101.5,0.0,4.21,32.0,176,13,351.9,121.165219651,78.9000000954,0,0,0,0,0,0,0,4.21,0,0.0,0.0,4,44,4.20999999999,0.0,0.0,0.0,0.0,176.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
46,46,1.0,1469705781.6,108.9,0.0,4.11,30.5,176,14,359.3,122.757318225,80.5999999046,0,0,0,0,0,0,0,4.11,0,0.0,0.0,4,45,4.10999999998,0.0,0.0,0.0,0.0,176.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
47,47,1.0,1469705783.6,116.9,0.0,4.02,32.0,175,15,367.3,123.722400388,82.5999999046,0,0,0,0,0,0,0,4.02,0,0.0,0.0,4,46,4.01999999999,0.0,0.0,0.0,0.0,175.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
48,48,1.0,1469705785.5,124.1,0.0,3.96,30.5,177,16,374.5,123.80237793,84.5,0,0,0,0,0,0,0,3.96,0,0.0,0.0,4,47,3.95999999999,0.0,0.0,0.0,0.0,177.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
49,49,1.0,1469705787.5,132.1,0.0,4.04,32.0,177,17,382.5,123.700282002,86.5,0,0,0,0,0,0,0,4.04,0,0.0,0.0,4,48,4.03999999999,0.0,0.0,0.0,0.0,177.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
50,50,1.0,1469705789.2,139.7,0.0,4.06,32.0,178,18,390.1,122.672370408,88.2000000477,0,0,0,0,0,0,0,4.06,0,0.0,0.0,4,49,4.05999999999,0.0,0.0,0.0,0.0,178.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
51,51,1.0,1469705791.1,146.7,0.0,4.09,33.0,178,19,397.1,121.011418513,90.0999999046,0,0,0,0,0,0,0,4.09,0,0.0,0.0,4,50,4.09,0.0,0.0,0.0,0.0,178.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
52,52,1.0,1469705793.1,155.4,0.0,4.27,31.0,177,20,405.8,119.62256154,92.0999999046,0,0,0,0,0,0,0,4.27,0,0.0,0.0,4,51,4.27000000001,0.0,0.0,0.0,0.0,177.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
53,53,1.0,1469705794.9,163.1,0.0,4.27,32.0,177,21,413.5,118.342215896,93.9000000954,0,0,0,0,0,0,0,4.27,0,0.0,0.0,4,52,4.27000000001,0.0,0.0,0.0,0.0,177.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
54,54,1.0,1469705797.1,171.6,0.0,4.24,31.5,178,22,422.0,117.740696015,96.0999999046,0,0,0,0,0,0,0,4.24,0,0.0,0.0,4,53,4.24,0.0,0.0,0.0,0.0,178.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
55,55,1.0,1469705798.6,179.3,0.0,4.22,32.0,179,23,429.7,117.599973684,97.5999999046,0,0,0,0,0,0,0,4.22,0,0.0,0.0,4,54,4.22000000001,0.0,0.0,0.0,0.0,179.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
56,56,1.0,1469705800.7,187.9,0.0,4.21,30.5,179,24,438.3,117.565167825,99.7000000477,0,0,0,0,0,0,0,4.21,0,0.0,0.0,4,55,4.20999999999,0.0,0.0,0.0,0.0,179.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
57,57,1.0,1469705802.5,195.8,0.0,4.28,30.5,180,25,446.2,117.967332124,101.5,0,0,0,0,0,0,0,4.28,0,0.0,0.0,4,56,4.27999999998,0.0,0.0,0.0,0.0,180.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
58,58,1.0,1469705804.5,204.3,0.0,4.22,30.5,180,26,454.7,118.489957355,103.5,0,0,0,0,0,0,0,4.22,0,0.0,0.0,4,57,4.22000000001,0.0,0.0,0.0,0.0,180.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
59,59,1.0,1469705806.4,212.2,0.0,4.2,30.5,180,27,462.6,118.763530461,105.400000095,0,0,0,0,0,0,0,4.2,0,0.0,0.0,4,58,4.19999999999,0.0,0.0,0.0,0.0,180.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
60,60,1.0,1469705808.5,221.4,0.0,4.26,29.5,180,28,471.8,117.583212735,107.5,0,0,0,0,0,0,0,4.26,0,0.0,0.0,4,59,4.25999999999,0.0,0.0,0.0,0.0,180.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
61,61,1.0,1469705810.4,229.8,0.0,4.17,30.5,180,29,480.2,119.140852815,109.400000095,0,0,0,0,0,0,0,4.17,0,0.0,0.0,4,60,4.16999999999,0.0,0.0,0.0,0.0,180.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
62,62,1.0,1469705812.3,236.6,0.0,4.11,33.5,181,30,487.0,121.480877381,111.299999952,0,0,0,0,0,0,0,4.11,0,0.0,0.0,4,61,4.10999999998,0.0,0.0,0.0,0.0,0.0,181.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
63,63,1.0,1469705814.0,244.8,0.0,4.24,33.5,181,31,495.2,122.38470448,113.0,0,0,0,0,0,0,0,4.24,0,0.0,0.0,4,62,4.24,0.0,0.0,0.0,0.0,0.0,181.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
64,64,1.0,1469705815.4,250.9,0.0,4.24,33.5,181,31,501.3,122.183234979,114.400000095,0,0,0,0,0,0,0,4.24,0,0.0,0.0,4,63,4.24,0.0,0.0,0.0,0.0,0.0,181.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
65,65,2.0,1469705816.3,0.9,0.0,3.66,28.0,158,1,502.2,121.2563172,115.299999952,0,0,0,0,0,0,0,3.66,0,0.0,0.0,4,63,3.66,0.0,0.0,158.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
66,66,2.0,1469705817.8,9.8,0.0,4.12,33.5,160,2,511.1,119.786227655,116.799999952,0,0,0,0,0,0,0,4.12,0,0.0,0.0,4,64,4.12,0.0,0.0,160.0,0.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
67,67,2.0,1469705819.6,18.0,0.0,4.44,32.5,162,3,519.3,117.678039467,118.599999905,0,0,0,0,0,0,0,4.44,0,0.0,0.0,4,65,4.43999999998,0.0,0.0,0.0,162.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
68,68,2.0,1469705821.5,26.1,0.0,4.47,33.0,161,4,527.4,115.319480659,120.5,0,0,0,0,0,0,0,4.47,0,0.0,0.0,4,66,4.47000000001,0.0,0.0,0.0,161.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
69,69,2.0,1469705823.4,35.0,0.0,4.43,32.0,164,5,536.3,112.531083761,122.400000095,0,0,0,0,0,0,0,4.43,0,0.0,0.0,4,67,4.42999999999,0.0,0.0,0.0,164.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
70,70,2.0,1469705825.1,41.9,0.0,4.43,33.0,165,6,543.2,109.693981917,124.099999905,0,0,0,0,0,0,0,4.43,0,0.0,0.0,4,68,4.42999999999,0.0,0.0,0.0,165.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
71,71,2.0,1469705827.1,51.5,0.0,4.6,33.5,166,7,552.8,110.111805834,126.099999905,0,0,0,0,0,0,0,4.6,0,0.0,0.0,4,69,4.6,0.0,0.0,0.0,166.0,0.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
72,72,2.0,1469705828.9,59.7,0.0,4.59,33.5,168,8,561.0,110.235734879,127.900000095,0,0,0,0,0,0,0,4.59,0,0.0,0.0,4,70,4.58999999998,0.0,0.0,0.0,0.0,168.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
73,73,2.0,1469705830.7,68.1,0.0,4.53,32.0,171,9,569.4,109.674351541,129.700000048,0,0,0,0,0,0,0,4.53,0,0.0,0.0,4,71,4.53000000001,0.0,0.0,0.0,0.0,171.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
74,74,2.0,1469705832.4,76.4,0.0,4.55,33.0,172,10,577.7,109.081478016,131.400000095,0,0,0,0,0,0,0,4.55,0,0.0,0.0,4,72,4.55,0.0,0.0,0.0,0.0,172.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
75,75,2.0,1469705834.3,84.0,0.0,4.54,32.5,173,11,585.3,108.95736186,133.299999952,0,0,0,0,0,0,0,4.54,0,0.0,0.0,4,73,4.54000000001,0.0,0.0,0.0,0.0,173.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
76,76,2.0,1469705836.0,92.9,0.0,4.63,33.0,174,12,594.2,109.581343074,135.0,0,0,0,0,0,0,0,4.63,0,0.0,0.0,4,74,4.63000000001,0.0,0.0,0.0,0.0,174.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
77,77,2.0,1469705837.9,101.3,0.0,4.61,33.5,176,13,602.6,109.437100452,136.900000095,0,0,0,0,0,0,0,4.61,0,0.0,0.0,4,75,4.61000000001,0.0,0.0,0.0,0.0,176.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
78,78,2.0,1469705839.7,109.6,0.0,4.58,33.5,177,14,610.9,108.898173861,138.700000048,0,0,0,0,0,0,0,4.58,0,0.0,0.0,4,76,4.57999999999,0.0,0.0,0.0,0.0,177.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
79,79,2.0,1469705841.5,118.0,0.0,4.54,33.5,178,15,619.3,108.514739286,140.5,0,0,0,0,0,0,0,4.54,0,0.0,0.0,4,77,4.54000000001,0.0,0.0,0.0,0.0,178.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
80,80,2.0,1469705843.1,125.0,0.0,4.54,34.0,178,16,626.3,108.408891045,142.099999905,0,0,0,0,0,0,0,4.54,0,0.0,0.0,4,78,4.54000000001,0.0,0.0,0.0,0.0,178.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
81,81,2.0,1469705845.1,134.8,0.0,4.69,34.5,179,17,636.1,108.970092917,144.099999905,0,0,0,0,0,0,0,4.69,0,0.0,0.0,4,79,4.69000000002,0.0,0.0,0.0,0.0,179.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
82,82,2.0,1469705846.7,142.2,0.0,4.67,34.0,180,18,643.5,108.943527129,145.700000048,0,0,0,0,0,0,0,4.67,0,0.0,0.0,4,80,4.67000000001,0.0,0.0,0.0,0.0,180.0,0.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
83,83,2.0,1469705848.5,150.6,0.0,4.59,34.5,181,19,651.9,108.491687362,147.5,0,0,0,0,0,0,0,4.59,0,0.0,0.0,4,81,4.58999999998,0.0,0.0,0.0,0.0,0.0,181.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
84,84,2.0,1469705850.3,158.8,0.0,4.52,33.5,181,20,660.1,108.195629805,149.299999952,0,0,0,0,0,0,0,4.52,0,0.0,0.0,4,82,4.51999999998,0.0,0.0,0.0,0.0,0.0,181.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
85,85,2.0,1469705852.1,166.4,0.0,4.52,33.5,181,21,667.7,108.474130564,151.099999905,0,0,0,0,0,0,0,4.52,0,0.0,0.0,4,83,4.51999999998,0.0,0.0,0.0,0.0,0.0,181.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
86,86,2.0,1469705853.9,175.2,0.0,4.68,33.5,182,22,676.5,109.550561798,152.900000095,0,0,0,0,0,0,0,4.68,0,0.0,0.0,4,84,4.67999999998,0.0,0.0,0.0,0.0,0.0,182.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
87,87,2.0,1469705855.7,183.2,0.0,4.65,32.0,182,23,684.5,110.12141592,154.700000048,0,0,0,0,0,0,0,4.65,0,0.0,0.0,4,85,4.65000000002,0.0,0.0,0.0,0.0,0.0,182.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
88,88,2.0,1469705857.5,191.2,0.0,4.51,33.0,182,24,692.5,110.388908617,156.5,0,0,0,0,0,0,0,4.51,0,0.0,0.0,4,86,4.51,0.0,0.0,0.0,0.0,0.0,182.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
89,89,2.0,1469705859.4,200.1,0.0,4.42,32.0,183,25,701.4,111.075438088,158.400000095,0,0,0,0,0,0,0,4.42,0,0.0,0.0,4,87,4.41999999999,0.0,0.0,0.0,0.0,0.0,183.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
90,90,2.0,1469705861.2,207.4,0.0,4.38,32.0,183,26,708.7,112.186192469,160.200000048,0,0,0,0,0,0,0,4.38,0,0.0,0.0,4,88,4.37999999998,0.0,0.0,0.0,0.0,0.0,183.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
91,91,2.0,1469705863.0,216.1,0.0,4.47,32.0,183,27,717.4,113.541324808,162.0,0,0,0,0,0,0,0,4.47,0,0.0,0.0,4,89,4.47000000001,0.0,0.0,0.0,0.0,0.0,183.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
92,92,2.0,1469705865.0,224.7,0.0,4.44,32.5,183,28,726.0,113.933934253,164.0,0,0,0,0,0,0,0,4.44,0,0.0,0.0,4,90,4.43999999998,0.0,0.0,0.0,0.0,0.0,183.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
93,93,2.0,1469705867.1,232.4,0.0,4.34,33.0,184,29,733.7,114.217860585,166.099999905,0,0,0,0,0,0,0,4.34,0,0.0,0.0,4,91,4.34,0.0,0.0,0.0,0.0,0.0,184.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
94,94,2.0,1469705868.6,240.6,0.0,4.35,32.0,184,30,741.9,114.508095643,167.599999905,0,0,0,0,0,0,0,4.35,0,0.0,0.0,4,92,4.34999999999,0.0,0.0,0.0,0.0,0.0,184.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
95,95,2.0,1469705870.7,249.0,0.0,4.34,30.5,184,31,750.3,114.922206507,169.700000048,0,0,0,0,0,0,0,4.34,0,0.0,0.0,4,93,4.34,0.0,0.0,0.0,0.0,0.0,184.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
96,96,2.0,1469705871.0,250.4,0.0,4.34,30.5,184,31,751.7,115.581707376,170.0,0,0,0,0,0,0,0,4.34,0,0.0,0.0,4,93,4.34,0.0,0.0,0.0,0.0,0.0,184.0,142,146,160,167,180,192,0.0,0.0,0.0,0.0,0.0,0.0,124.3,169.5,203.4,237.3,271.2
1 index lapIdx TimeStamp (sec) Horizontal (meters) GPS Split GPS Speed Cadence (stokes/min) HRCur (bpm) Stroke Count cum_dist Stroke500mPace (sec/500m) ElapsedTime (sec) Power (watts) DriveLength (meters) StrokeDistance (meters) DriveTime (ms) DragFactor StrokeRecoveryTime (ms) AverageDriveForce (lbs) AverageBoatSpeed (m/s) PeakDriveForce (lbs) AverageDriveForce (N) PeakDriveForce (N) WorkoutState Stroke Number originalvelo hr_ut2 hr_ut1 hr_at hr_tr hr_an hr_max lim_ut2 lim_ut1 lim_at lim_tr lim_an lim_max pw_ut2 pw_ut1 pw_at pw_tr pw_an pw_max limpw_ut2 limpw_ut1 limpw_at limpw_tr limpw_an
2 0 0 0.0 1469705701.0 3.2 0.0 0.74 35.5 112 1 3.2 695.931477516 0.0 0 0 0 0 0 0 0 0.74 0 0.0 0.0 4 0 0.74 0.0 0.0 0.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
3 1 1 0.0 1469705702.6 8.6 0.0 2.07 38.5 113 2 8.6 228.8 1.59999990463 0 0 0 0 0 0 0 2.07 0 0.0 0.0 4 1 2.07 113.0 0.0 0.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
4 2 2 0.0 1469705704.5 15.1 0.0 3.36 38.5 115 3 15.1 153.336955279 3.5 0 0 0 0 0 0 0 3.36 0 0.0 0.0 4 3 3.35999999999 115.0 0.0 0.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
5 3 3 0.0 1469705705.6 21.4 0.0 4.09 39.0 115 4 21.4 124.977058407 4.59999990463 0 0 0 0 0 0 0 4.09 0 0.0 0.0 4 3 4.09 115.0 0.0 0.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
6 4 4 0.0 1469705707.5 28.8 0.0 4.43 38.5 118 5 28.8 112.083019815 6.5 0 0 0 0 0 0 0 4.43 0 0.0 0.0 4 5 4.42999999999 118.0 0.0 0.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
7 5 5 0.0 1469705708.8 36.2 0.0 4.64 37.5 125 6 36.2 106.442632632 7.79999995232 0 0 0 0 0 0 0 4.64 0 0.0 0.0 4 5 4.63999999999 125.0 0.0 0.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
8 6 6 0.0 1469705710.5 43.1 0.0 4.66 36.0 130 7 43.1 104.628021775 9.5 0 0 0 0 0 0 0 4.66 0 0.0 0.0 4 6 4.66 130.0 0.0 0.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
9 7 7 0.0 1469705712.2 52.0 0.0 4.76 34.0 135 8 52.0 106.01911804 11.2000000477 0 0 0 0 0 0 0 4.76 0 0.0 0.0 4 7 4.75999999999 135.0 0.0 0.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
10 8 8 0.0 1469705714.0 60.1 0.0 4.71 34.5 142 9 60.1 107.565165936 13.0 0 0 0 0 0 0 0 4.71 0 0.0 0.0 4 8 4.70999999998 142.0 0.0 0.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
11 9 9 0.0 1469705715.8 68.1 0.0 4.53 33.5 148 10 68.1 108.679681206 14.7999999523 0 0 0 0 0 0 0 4.53 0 0.0 0.0 4 9 4.53000000001 0.0 0.0 148.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
12 10 10 0.0 1469705717.6 76.3 0.0 4.44 32.5 154 11 76.3 109.466700689 16.5999999046 0 0 0 0 0 0 0 4.44 0 0.0 0.0 4 10 4.43999999998 0.0 0.0 154.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
13 11 11 0.0 1469705719.5 83.8 0.0 4.44 33.0 156 12 83.8 109.893487851 18.5 0 0 0 0 0 0 0 4.44 0 0.0 0.0 4 11 4.43999999998 0.0 0.0 156.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
14 12 12 0.0 1469705721.2 92.5 0.0 4.62 33.5 159 13 92.5 110.627456239 20.2000000477 0 0 0 0 0 0 0 4.62 0 0.0 0.0 4 12 4.62 0.0 0.0 159.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
15 13 13 0.0 1469705723.0 100.8 0.0 4.64 33.5 163 14 100.8 110.362782274 22.0 0 0 0 0 0 0 0 4.64 0 0.0 0.0 4 13 4.63999999999 0.0 0.0 0.0 163.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
16 14 14 0.0 1469705724.8 109.1 0.0 4.59 32.0 166 15 109.1 109.351182981 23.7999999523 0 0 0 0 0 0 0 4.59 0 0.0 0.0 4 14 4.58999999998 0.0 0.0 0.0 166.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
17 15 15 0.0 1469705726.8 118.1 0.0 4.52 32.5 168 16 118.1 108.636197885 25.7999999523 0 0 0 0 0 0 0 4.52 0 0.0 0.0 4 15 4.51999999998 0.0 0.0 0.0 0.0 168.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
18 16 16 0.0 1469705728.5 125.1 0.0 4.5 33.0 169 17 125.1 108.494979894 27.5 0 0 0 0 0 0 0 4.5 0 0.0 0.0 4 16 4.5 0.0 0.0 0.0 0.0 169.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
19 17 17 0.0 1469705730.4 134.7 0.0 4.66 33.5 171 18 134.7 109.232014911 29.4000000954 0 0 0 0 0 0 0 4.66 0 0.0 0.0 4 17 4.66 0.0 0.0 0.0 0.0 171.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
20 18 18 0.0 1469705732.2 143.0 0.0 4.66 32.5 172 19 143.0 109.4493854 31.2000000477 0 0 0 0 0 0 0 4.66 0 0.0 0.0 4 18 4.66 0.0 0.0 0.0 0.0 172.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
21 19 19 0.0 1469705734.0 151.2 0.0 4.58 33.0 172 20 151.2 109.222559423 33.0 0 0 0 0 0 0 0 4.58 0 0.0 0.0 4 19 4.57999999999 0.0 0.0 0.0 0.0 172.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
22 20 20 0.0 1469705735.8 159.4 0.0 4.52 33.0 173 21 159.4 109.097567302 34.7999999523 0 0 0 0 0 0 0 4.52 0 0.0 0.0 4 20 4.51999999998 0.0 0.0 0.0 0.0 173.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
23 21 21 0.0 1469705737.5 166.1 0.0 4.47 33.5 175 22 166.1 109.622785185 36.5 0 0 0 0 0 0 0 4.47 0 0.0 0.0 4 21 4.47000000001 0.0 0.0 0.0 0.0 175.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
24 22 22 0.0 1469705739.4 175.7 0.0 4.58 33.5 175 23 175.7 110.908884086 38.4000000954 0 0 0 0 0 0 0 4.58 0 0.0 0.0 4 22 4.57999999999 0.0 0.0 0.0 0.0 175.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
25 23 23 0.0 1469705741.2 183.8 0.0 4.57 32.5 175 24 183.8 111.571150665 40.2000000477 0 0 0 0 0 0 0 4.57 0 0.0 0.0 4 23 4.57 0.0 0.0 0.0 0.0 175.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
26 24 24 0.0 1469705743.0 191.8 0.0 4.47 33.0 175 25 191.8 111.781044645 42.0 0 0 0 0 0 0 0 4.47 0 0.0 0.0 4 24 4.47000000001 0.0 0.0 0.0 0.0 175.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
27 25 25 0.0 1469705744.8 199.8 0.0 4.39 32.0 176 26 199.8 111.973606594 43.7999999523 0 0 0 0 0 0 0 4.39 0 0.0 0.0 4 25 4.39 0.0 0.0 0.0 0.0 176.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
28 26 26 0.0 1469705746.7 207.8 0.0 4.39 32.5 176 27 207.8 112.082434148 45.7000000477 0 0 0 0 0 0 0 4.39 0 0.0 0.0 4 26 4.39 0.0 0.0 0.0 0.0 176.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
29 27 27 0.0 1469705748.6 216.7 0.0 4.49 33.0 174 28 216.7 112.462053887 47.5999999046 0 0 0 0 0 0 0 4.49 0 0.0 0.0 4 27 4.49000000001 0.0 0.0 0.0 0.0 174.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
30 28 28 0.0 1469705750.4 224.8 0.0 4.49 32.0 174 29 224.8 110.702820986 49.4000000954 0 0 0 0 0 0 0 4.49 0 0.0 0.0 4 28 4.49000000001 0.0 0.0 0.0 0.0 174.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
31 29 29 0.0 1469705752.5 232.9 0.0 4.47 33.0 174 30 232.9 111.287510895 51.5 0 0 0 0 0 0 0 4.47 0 0.0 0.0 4 30 4.47000000001 0.0 0.0 0.0 0.0 174.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
32 30 30 0.0 1469705754.0 240.9 0.0 4.48 32.0 175 31 240.9 113.880099386 53.0 0 0 0 0 0 0 0 4.48 0 0.0 0.0 4 30 4.48000000001 0.0 0.0 0.0 0.0 175.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
33 31 31 0.0 1469705755.8 248.9 0.0 4.43 32.0 175 32 248.9 117.397229535 54.7999999523 0 0 0 0 0 0 0 4.43 0 0.0 0.0 4 31 4.42999999999 0.0 0.0 0.0 0.0 175.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
34 32 32 0.0 1469705756.2 250.4 0.0 4.43 32.0 175 32 250.4 120.181532945 55.2000000477 0 0 0 0 0 0 0 4.43 0 0.0 0.0 4 32 4.42999999999 0.0 0.0 0.0 0.0 175.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
35 33 33 1.0 1469705757.6 5.7 0.0 3.62 30.5 160 1 256.1 121.464367621 56.5999999046 0 0 0 0 0 0 0 3.62 0 0.0 0.0 4 32 3.62000000001 0.0 0.0 160.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
36 34 34 1.0 1469705759.4 13.4 0.0 3.85 33.5 161 2 263.8 121.497391629 58.4000000954 0 0 0 0 0 0 0 3.85 0 0.0 0.0 4 33 3.85 0.0 0.0 0.0 161.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
37 35 35 1.0 1469705761.2 20.7 0.0 4.2 33.5 162 3 271.1 120.37982782 60.2000000477 0 0 0 0 0 0 0 4.2 0 0.0 0.0 4 34 4.19999999999 0.0 0.0 0.0 162.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
38 36 36 1.0 1469705763.0 29.2 0.0 4.47 33.5 162 4 279.6 118.387283716 62.0 0 0 0 0 0 0 0 4.47 0 0.0 0.0 4 35 4.47000000001 0.0 0.0 0.0 162.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
39 37 37 1.0 1469705764.8 37.3 0.0 4.47 33.0 164 5 287.7 115.233986774 63.7999999523 0 0 0 0 0 0 0 4.47 0 0.0 0.0 4 36 4.47000000001 0.0 0.0 0.0 164.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
40 38 38 1.0 1469705766.6 45.3 0.0 4.44 33.5 165 6 295.7 111.287510895 65.5999999046 0 0 0 0 0 0 0 4.44 0 0.0 0.0 4 37 4.43999999998 0.0 0.0 0.0 165.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
41 39 39 1.0 1469705768.5 53.5 0.0 4.42 33.5 165 7 303.9 111.718168135 67.5 0 0 0 0 0 0 0 4.42 0 0.0 0.0 4 38 4.41999999999 0.0 0.0 0.0 165.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
42 40 40 1.0 1469705770.2 60.7 0.0 4.38 32.0 167 8 311.1 113.471050335 69.2000000477 0 0 0 0 0 0 0 4.38 0 0.0 0.0 4 39 4.37999999998 0.0 0.0 0.0 167.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
43 41 41 1.0 1469705772.2 70.1 0.0 4.44 32.0 171 9 320.5 115.140584238 71.2000000477 0 0 0 0 0 0 0 4.44 0 0.0 0.0 4 40 4.43999999998 0.0 0.0 0.0 0.0 171.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
44 42 42 1.0 1469705774.1 77.8 0.0 4.3 32.0 172 10 328.2 116.273396972 73.0999999046 0 0 0 0 0 0 0 4.3 0 0.0 0.0 4 41 4.30000000002 0.0 0.0 0.0 0.0 172.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
45 43 43 1.0 1469705776.1 85.2 0.0 4.12 31.0 174 11 335.6 117.556791714 75.0999999046 0 0 0 0 0 0 0 4.12 0 0.0 0.0 4 42 4.12 0.0 0.0 0.0 0.0 174.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
46 44 44 1.0 1469705777.9 93.4 0.0 4.2 31.5 174 12 343.8 119.395508057 76.9000000954 0 0 0 0 0 0 0 4.2 0 0.0 0.0 4 43 4.19999999999 0.0 0.0 0.0 0.0 174.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
47 45 45 1.0 1469705779.9 101.5 0.0 4.21 32.0 176 13 351.9 121.165219651 78.9000000954 0 0 0 0 0 0 0 4.21 0 0.0 0.0 4 44 4.20999999999 0.0 0.0 0.0 0.0 176.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
48 46 46 1.0 1469705781.6 108.9 0.0 4.11 30.5 176 14 359.3 122.757318225 80.5999999046 0 0 0 0 0 0 0 4.11 0 0.0 0.0 4 45 4.10999999998 0.0 0.0 0.0 0.0 176.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
49 47 47 1.0 1469705783.6 116.9 0.0 4.02 32.0 175 15 367.3 123.722400388 82.5999999046 0 0 0 0 0 0 0 4.02 0 0.0 0.0 4 46 4.01999999999 0.0 0.0 0.0 0.0 175.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
50 48 48 1.0 1469705785.5 124.1 0.0 3.96 30.5 177 16 374.5 123.80237793 84.5 0 0 0 0 0 0 0 3.96 0 0.0 0.0 4 47 3.95999999999 0.0 0.0 0.0 0.0 177.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
51 49 49 1.0 1469705787.5 132.1 0.0 4.04 32.0 177 17 382.5 123.700282002 86.5 0 0 0 0 0 0 0 4.04 0 0.0 0.0 4 48 4.03999999999 0.0 0.0 0.0 0.0 177.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
52 50 50 1.0 1469705789.2 139.7 0.0 4.06 32.0 178 18 390.1 122.672370408 88.2000000477 0 0 0 0 0 0 0 4.06 0 0.0 0.0 4 49 4.05999999999 0.0 0.0 0.0 0.0 178.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
53 51 51 1.0 1469705791.1 146.7 0.0 4.09 33.0 178 19 397.1 121.011418513 90.0999999046 0 0 0 0 0 0 0 4.09 0 0.0 0.0 4 50 4.09 0.0 0.0 0.0 0.0 178.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
54 52 52 1.0 1469705793.1 155.4 0.0 4.27 31.0 177 20 405.8 119.62256154 92.0999999046 0 0 0 0 0 0 0 4.27 0 0.0 0.0 4 51 4.27000000001 0.0 0.0 0.0 0.0 177.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
55 53 53 1.0 1469705794.9 163.1 0.0 4.27 32.0 177 21 413.5 118.342215896 93.9000000954 0 0 0 0 0 0 0 4.27 0 0.0 0.0 4 52 4.27000000001 0.0 0.0 0.0 0.0 177.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
56 54 54 1.0 1469705797.1 171.6 0.0 4.24 31.5 178 22 422.0 117.740696015 96.0999999046 0 0 0 0 0 0 0 4.24 0 0.0 0.0 4 53 4.24 0.0 0.0 0.0 0.0 178.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
57 55 55 1.0 1469705798.6 179.3 0.0 4.22 32.0 179 23 429.7 117.599973684 97.5999999046 0 0 0 0 0 0 0 4.22 0 0.0 0.0 4 54 4.22000000001 0.0 0.0 0.0 0.0 179.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
58 56 56 1.0 1469705800.7 187.9 0.0 4.21 30.5 179 24 438.3 117.565167825 99.7000000477 0 0 0 0 0 0 0 4.21 0 0.0 0.0 4 55 4.20999999999 0.0 0.0 0.0 0.0 179.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
59 57 57 1.0 1469705802.5 195.8 0.0 4.28 30.5 180 25 446.2 117.967332124 101.5 0 0 0 0 0 0 0 4.28 0 0.0 0.0 4 56 4.27999999998 0.0 0.0 0.0 0.0 180.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
60 58 58 1.0 1469705804.5 204.3 0.0 4.22 30.5 180 26 454.7 118.489957355 103.5 0 0 0 0 0 0 0 4.22 0 0.0 0.0 4 57 4.22000000001 0.0 0.0 0.0 0.0 180.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
61 59 59 1.0 1469705806.4 212.2 0.0 4.2 30.5 180 27 462.6 118.763530461 105.400000095 0 0 0 0 0 0 0 4.2 0 0.0 0.0 4 58 4.19999999999 0.0 0.0 0.0 0.0 180.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
62 60 60 1.0 1469705808.5 221.4 0.0 4.26 29.5 180 28 471.8 117.583212735 107.5 0 0 0 0 0 0 0 4.26 0 0.0 0.0 4 59 4.25999999999 0.0 0.0 0.0 0.0 180.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
63 61 61 1.0 1469705810.4 229.8 0.0 4.17 30.5 180 29 480.2 119.140852815 109.400000095 0 0 0 0 0 0 0 4.17 0 0.0 0.0 4 60 4.16999999999 0.0 0.0 0.0 0.0 180.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
64 62 62 1.0 1469705812.3 236.6 0.0 4.11 33.5 181 30 487.0 121.480877381 111.299999952 0 0 0 0 0 0 0 4.11 0 0.0 0.0 4 61 4.10999999998 0.0 0.0 0.0 0.0 0.0 181.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
65 63 63 1.0 1469705814.0 244.8 0.0 4.24 33.5 181 31 495.2 122.38470448 113.0 0 0 0 0 0 0 0 4.24 0 0.0 0.0 4 62 4.24 0.0 0.0 0.0 0.0 0.0 181.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
66 64 64 1.0 1469705815.4 250.9 0.0 4.24 33.5 181 31 501.3 122.183234979 114.400000095 0 0 0 0 0 0 0 4.24 0 0.0 0.0 4 63 4.24 0.0 0.0 0.0 0.0 0.0 181.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
67 65 65 2.0 1469705816.3 0.9 0.0 3.66 28.0 158 1 502.2 121.2563172 115.299999952 0 0 0 0 0 0 0 3.66 0 0.0 0.0 4 63 3.66 0.0 0.0 158.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
68 66 66 2.0 1469705817.8 9.8 0.0 4.12 33.5 160 2 511.1 119.786227655 116.799999952 0 0 0 0 0 0 0 4.12 0 0.0 0.0 4 64 4.12 0.0 0.0 160.0 0.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
69 67 67 2.0 1469705819.6 18.0 0.0 4.44 32.5 162 3 519.3 117.678039467 118.599999905 0 0 0 0 0 0 0 4.44 0 0.0 0.0 4 65 4.43999999998 0.0 0.0 0.0 162.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
70 68 68 2.0 1469705821.5 26.1 0.0 4.47 33.0 161 4 527.4 115.319480659 120.5 0 0 0 0 0 0 0 4.47 0 0.0 0.0 4 66 4.47000000001 0.0 0.0 0.0 161.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
71 69 69 2.0 1469705823.4 35.0 0.0 4.43 32.0 164 5 536.3 112.531083761 122.400000095 0 0 0 0 0 0 0 4.43 0 0.0 0.0 4 67 4.42999999999 0.0 0.0 0.0 164.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
72 70 70 2.0 1469705825.1 41.9 0.0 4.43 33.0 165 6 543.2 109.693981917 124.099999905 0 0 0 0 0 0 0 4.43 0 0.0 0.0 4 68 4.42999999999 0.0 0.0 0.0 165.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
73 71 71 2.0 1469705827.1 51.5 0.0 4.6 33.5 166 7 552.8 110.111805834 126.099999905 0 0 0 0 0 0 0 4.6 0 0.0 0.0 4 69 4.6 0.0 0.0 0.0 166.0 0.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
74 72 72 2.0 1469705828.9 59.7 0.0 4.59 33.5 168 8 561.0 110.235734879 127.900000095 0 0 0 0 0 0 0 4.59 0 0.0 0.0 4 70 4.58999999998 0.0 0.0 0.0 0.0 168.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
75 73 73 2.0 1469705830.7 68.1 0.0 4.53 32.0 171 9 569.4 109.674351541 129.700000048 0 0 0 0 0 0 0 4.53 0 0.0 0.0 4 71 4.53000000001 0.0 0.0 0.0 0.0 171.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
76 74 74 2.0 1469705832.4 76.4 0.0 4.55 33.0 172 10 577.7 109.081478016 131.400000095 0 0 0 0 0 0 0 4.55 0 0.0 0.0 4 72 4.55 0.0 0.0 0.0 0.0 172.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
77 75 75 2.0 1469705834.3 84.0 0.0 4.54 32.5 173 11 585.3 108.95736186 133.299999952 0 0 0 0 0 0 0 4.54 0 0.0 0.0 4 73 4.54000000001 0.0 0.0 0.0 0.0 173.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
78 76 76 2.0 1469705836.0 92.9 0.0 4.63 33.0 174 12 594.2 109.581343074 135.0 0 0 0 0 0 0 0 4.63 0 0.0 0.0 4 74 4.63000000001 0.0 0.0 0.0 0.0 174.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
79 77 77 2.0 1469705837.9 101.3 0.0 4.61 33.5 176 13 602.6 109.437100452 136.900000095 0 0 0 0 0 0 0 4.61 0 0.0 0.0 4 75 4.61000000001 0.0 0.0 0.0 0.0 176.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
80 78 78 2.0 1469705839.7 109.6 0.0 4.58 33.5 177 14 610.9 108.898173861 138.700000048 0 0 0 0 0 0 0 4.58 0 0.0 0.0 4 76 4.57999999999 0.0 0.0 0.0 0.0 177.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
81 79 79 2.0 1469705841.5 118.0 0.0 4.54 33.5 178 15 619.3 108.514739286 140.5 0 0 0 0 0 0 0 4.54 0 0.0 0.0 4 77 4.54000000001 0.0 0.0 0.0 0.0 178.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
82 80 80 2.0 1469705843.1 125.0 0.0 4.54 34.0 178 16 626.3 108.408891045 142.099999905 0 0 0 0 0 0 0 4.54 0 0.0 0.0 4 78 4.54000000001 0.0 0.0 0.0 0.0 178.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
83 81 81 2.0 1469705845.1 134.8 0.0 4.69 34.5 179 17 636.1 108.970092917 144.099999905 0 0 0 0 0 0 0 4.69 0 0.0 0.0 4 79 4.69000000002 0.0 0.0 0.0 0.0 179.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
84 82 82 2.0 1469705846.7 142.2 0.0 4.67 34.0 180 18 643.5 108.943527129 145.700000048 0 0 0 0 0 0 0 4.67 0 0.0 0.0 4 80 4.67000000001 0.0 0.0 0.0 0.0 180.0 0.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
85 83 83 2.0 1469705848.5 150.6 0.0 4.59 34.5 181 19 651.9 108.491687362 147.5 0 0 0 0 0 0 0 4.59 0 0.0 0.0 4 81 4.58999999998 0.0 0.0 0.0 0.0 0.0 181.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
86 84 84 2.0 1469705850.3 158.8 0.0 4.52 33.5 181 20 660.1 108.195629805 149.299999952 0 0 0 0 0 0 0 4.52 0 0.0 0.0 4 82 4.51999999998 0.0 0.0 0.0 0.0 0.0 181.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
87 85 85 2.0 1469705852.1 166.4 0.0 4.52 33.5 181 21 667.7 108.474130564 151.099999905 0 0 0 0 0 0 0 4.52 0 0.0 0.0 4 83 4.51999999998 0.0 0.0 0.0 0.0 0.0 181.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
88 86 86 2.0 1469705853.9 175.2 0.0 4.68 33.5 182 22 676.5 109.550561798 152.900000095 0 0 0 0 0 0 0 4.68 0 0.0 0.0 4 84 4.67999999998 0.0 0.0 0.0 0.0 0.0 182.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
89 87 87 2.0 1469705855.7 183.2 0.0 4.65 32.0 182 23 684.5 110.12141592 154.700000048 0 0 0 0 0 0 0 4.65 0 0.0 0.0 4 85 4.65000000002 0.0 0.0 0.0 0.0 0.0 182.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
90 88 88 2.0 1469705857.5 191.2 0.0 4.51 33.0 182 24 692.5 110.388908617 156.5 0 0 0 0 0 0 0 4.51 0 0.0 0.0 4 86 4.51 0.0 0.0 0.0 0.0 0.0 182.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
91 89 89 2.0 1469705859.4 200.1 0.0 4.42 32.0 183 25 701.4 111.075438088 158.400000095 0 0 0 0 0 0 0 4.42 0 0.0 0.0 4 87 4.41999999999 0.0 0.0 0.0 0.0 0.0 183.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
92 90 90 2.0 1469705861.2 207.4 0.0 4.38 32.0 183 26 708.7 112.186192469 160.200000048 0 0 0 0 0 0 0 4.38 0 0.0 0.0 4 88 4.37999999998 0.0 0.0 0.0 0.0 0.0 183.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
93 91 91 2.0 1469705863.0 216.1 0.0 4.47 32.0 183 27 717.4 113.541324808 162.0 0 0 0 0 0 0 0 4.47 0 0.0 0.0 4 89 4.47000000001 0.0 0.0 0.0 0.0 0.0 183.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
94 92 92 2.0 1469705865.0 224.7 0.0 4.44 32.5 183 28 726.0 113.933934253 164.0 0 0 0 0 0 0 0 4.44 0 0.0 0.0 4 90 4.43999999998 0.0 0.0 0.0 0.0 0.0 183.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
95 93 93 2.0 1469705867.1 232.4 0.0 4.34 33.0 184 29 733.7 114.217860585 166.099999905 0 0 0 0 0 0 0 4.34 0 0.0 0.0 4 91 4.34 0.0 0.0 0.0 0.0 0.0 184.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
96 94 94 2.0 1469705868.6 240.6 0.0 4.35 32.0 184 30 741.9 114.508095643 167.599999905 0 0 0 0 0 0 0 4.35 0 0.0 0.0 4 92 4.34999999999 0.0 0.0 0.0 0.0 0.0 184.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
97 95 95 2.0 1469705870.7 249.0 0.0 4.34 30.5 184 31 750.3 114.922206507 169.700000048 0 0 0 0 0 0 0 4.34 0 0.0 0.0 4 93 4.34 0.0 0.0 0.0 0.0 0.0 184.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2
98 96 96 2.0 1469705871.0 250.4 0.0 4.34 30.5 184 31 751.7 115.581707376 170.0 0 0 0 0 0 0 0 4.34 0 0.0 0.0 4 93 4.34 0.0 0.0 0.0 0.0 0.0 184.0 142 146 160 167 180 192 0.0 0.0 0.0 0.0 0.0 0.0 124.3 169.5 203.4 237.3 271.2

Binary file not shown.

View File

@@ -7,7 +7,7 @@ from models import Workout,Rower,StrokeData,FavoriteChart
from rest_framework import routers, serializers, viewsets,permissions
from rest_framework.urlpatterns import format_suffix_patterns
from rest_framework.permissions import *
from . import views
from rowers import views
from django.contrib.auth import views as auth_views
from django.views.generic.base import TemplateView
from django.conf.urls import (
@@ -108,198 +108,207 @@ urlpatterns = [
url(r'^o/authorize/$', base.AuthorizationView.as_view(), name="authorize"),
url(r'^o/token/$', base.TokenView.as_view(), name="token"),
url(r'^', include(router.urls)),
url(r'^api-docs/$', views.schema_view),
url(r'^api-docs/$', views.schema_view,name='schema_view'),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^api/workouts/(?P<id>\d+)/strokedata/$',views.strokedatajson),
url(r'^500v/$',views.error500_view),
url(r'^api/workouts/(?P<id>\d+)/strokedata/$',views.strokedatajson,name='strokedatajson'),
url(r'^500v/$',views.error500_view,name='error500_view'),
url(r'^502/$', TemplateView.as_view(template_name='502.html'),name='502'),
url(r'^500/$', TemplateView.as_view(template_name='500.html'),name='500'),
url(r'^404/$', TemplateView.as_view(template_name='404.html'),name='404'),
url(r'^400/$', TemplateView.as_view(template_name='400.html'),name='400'),
url(r'^403/$', TemplateView.as_view(template_name='403.html'),name='403'),
# url(r'^imports/$', views.imports_view),
url(r'^exportallworkouts/?/$',views.workouts_summaries_email_view),
url(r'^update_empower/$',views.rower_update_empower_view),
url(r'^agegroupcp/(?P<age>\d+)/$',views.agegroupcpview),
url(r'^agegroupcp/(?P<age>\d+)/(?P<normalize>\d+)/$',views.agegroupcpview),
url(r'^exportallworkouts/?/$',views.workouts_summaries_email_view,name='workouts_summaries_email_view'),
url(r'^update_empower/$',views.rower_update_empower_view,name='rower_update_empower_view'),
url(r'^agegroupcp/(?P<age>\d+)/$',views.agegroupcpview,name='agegroupcpview'),
url(r'^agegroupcp/(?P<age>\d+)/(?P<normalize>\d+)/$',views.agegroupcpview,name='agegroupcpview'),
url(r'^ajax_agegroup/(?P<age>\d+)/(?P<weightcategory>\w+.*)/(?P<sex>\w+.*)/(?P<userid>\d+)/$',
views.ajax_agegrouprecords),
url(r'^updatefitness/(?P<mode>\w+.*)/(?P<days>\d+)/$',views.fitness_metric_view),
url(r'^updatefitness/(?P<mode>\w+.*)/$',views.fitness_metric_view),
url(r'^updatefitness/$',views.fitness_metric_view),
views.ajax_agegrouprecords,name='ajax_agegrouprecords'),
url(r'^updatefitness/(?P<mode>\w+.*)/(?P<days>\d+)/$',views.fitness_metric_view,name='fitness_metric_view'),
url(r'^updatefitness/(?P<mode>\w+.*)/$',views.fitness_metric_view,name='fitness_metric_view'),
url(r'^updatefitness/$',views.fitness_metric_view,name='fitness_metric_view'),
url(r'^agegrouprecords/(?P<sex>\w+.*)/(?P<weightcategory>\w+.*)/(?P<distance>\d+)m/$',
views.agegrouprecordview),
views.agegrouprecordview,name='agegrouprecordview'),
url(r'^agegrouprecords/(?P<sex>\w+.*)/(?P<weightcategory>\w+.*)/(?P<duration>\d+)min/$',
views.agegrouprecordview),
views.agegrouprecordview,name='agegrouprecordview'),
url(r'^agegrouprecords/(?P<sex>\w+.*)/(?P<weightcategory>\w+.*)/$',
views.agegrouprecordview),
url(r'^list-workouts/ranking/$',views.workouts_view,{'rankingonly':True}),
url(r'^list-workouts/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workouts_view),
url(r'^list-workouts/team/(?P<teamid>\d+)/$',views.workouts_view),
url(r'^(?P<rowerid>\d+)/list-workouts/$',views.workouts_view),
url(r'^(?P<rowerid>\d+)/list-workouts/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workouts_view),
url(r'^list-workouts/user/(?P<userid>\d+)/$',views.workouts_view),
url(r'^list-workouts/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<userid>\d+)/$',views.workouts_view),
url(r'^list-workouts/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workouts_view),
url(r'^virtualevents/$',views.virtualevents_view),
url(r'^virtualevent/create/$',views.virtualevent_create_view),
url(r'^virtualevent/createindoor/$',views.indoorvirtualevent_create_view),
views.agegrouprecordview,name='agegrouprecordview'),
url(r'^list-workouts/ranking/$',views.workouts_view,{'rankingonly':True},
name='workouts_view'),
url(r'^list-workouts/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workouts_view,
name='workouts_view'),
url(r'^list-workouts/team/(?P<teamid>\d+)/$',views.workouts_view,
name='workouts_view'),
url(r'^(?P<rowerid>\d+)/list-workouts/$',views.workouts_view,
name='workouts_view'),
url(r'^(?P<rowerid>\d+)/list-workouts/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workouts_view,
name='workouts_view'),
url(r'^list-workouts/user/(?P<userid>\d+)/$',views.workouts_view,
name='workouts_view'),
url(r'^list-workouts/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<userid>\d+)/$',views.workouts_view,
name='workouts_view'),
url(r'^list-workouts/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workouts_view,
name='workouts_view'),
url(r'^virtualevents/$',views.virtualevents_view,name='virtualevents_view'),
url(r'^virtualevent/create/$',views.virtualevent_create_view,name='virtualevent_create_view'),
url(r'^virtualevent/createindoor/$',views.indoorvirtualevent_create_view,name='indoorvirtualevent_create_view'),
url(r'^raceregistration/togglenotification/(?P<id>\d+)/$',
views.virtualevent_toggle_email_view),
views.virtualevent_toggle_email_view,name='virtualevent_toggle_email_view'),
url(r'^indoorraceregistration/togglenotification/(?P<id>\d+)/$',
views.indoorvirtualevent_toggle_email_view),
url(r'^virtualevent/(?P<id>\d+)/$',views.virtualevent_view),
url(r'^virtualevent/(?P<id>\d+)/ranking$',views.virtualevent_ranking_view),
url(r'^virtualevent/(?P<id>\d+)/edit/$',views.virtualevent_edit_view),
url(r'^virtualevent/(?P<id>\d+)/editindoor/$',views.indoorvirtualevent_edit_view),
url(r'^virtualevent/(?P<id>\d+)/register/$',views.virtualevent_register_view),
url(r'^virtualevent/(?P<id>\d+)/registerindoor/$',views.indoorvirtualevent_register_view),
url(r'^virtualevent/(?P<id>\d+)/adddiscipline/$',views.virtualevent_addboat_view),
url(r'^virtualevent/(?P<id>\d+)/withdraw/(?P<recordid>\d+)/$',views.virtualevent_withdraw_view),
url(r'^virtualevent/(?P<id>\d+)/withdraw/$',views.virtualevent_withdraw_view),
views.indoorvirtualevent_toggle_email_view,name='indoorvirtualevent_toggle_email_view'),
url(r'^virtualevent/(?P<id>\d+)/$',views.virtualevent_view,name='virtualevent_view'),
url(r'^virtualevent/(?P<id>\d+)/ranking$',views.virtualevent_ranking_view,name='virtualevent_ranking_view'),
url(r'^virtualevent/(?P<id>\d+)/edit/$',views.virtualevent_edit_view,name='virtualevent_edit_view'),
url(r'^virtualevent/(?P<id>\d+)/editindoor/$',views.indoorvirtualevent_edit_view,name='indoorvirtualevent_edit_view'),
url(r'^virtualevent/(?P<id>\d+)/register/$',views.virtualevent_register_view,name='virtualevent_register_view'),
url(r'^virtualevent/(?P<id>\d+)/registerindoor/$',views.indoorvirtualevent_register_view,name='indoorvirtualevent_register_view'),
url(r'^virtualevent/(?P<id>\d+)/adddiscipline/$',views.virtualevent_addboat_view,name='virtualevent_addboat_view'),
url(r'^virtualevent/(?P<id>\d+)/withdraw/(?P<recordid>\d+)/$',views.virtualevent_withdraw_view,name='virtualevent_withdraw_view'),
url(r'^virtualevent/(?P<id>\d+)/withdraw/$',views.virtualevent_withdraw_view,name='virtualevent_withdraw_view'),
url(r'^virtualevent/(?P<id>\d+)/submit/$',
views.virtualevent_submit_result_view),
views.virtualevent_submit_result_view,name='virtualevent_submit_result_view'),
url(r'^virtualevent/(?P<id>\d+)/submit/(?P<workoutid>\d+)/$',
views.virtualevent_submit_result_view),
views.virtualevent_submit_result_view,name='virtualevent_submit_result_view'),
url(r'^virtualevent/(?P<raceid>\d+)/disqualify/(?P<recordid>\d+)/',
views.virtualevent_disqualify_view),
url(r'^list-workouts/$',views.workouts_view),
url(r'^list-courses/$',views.courses_view),
url(r'^courses/upload/$',views.course_upload_view),
url(r'^workout/addmanual/$',views.addmanual_view),
url(r'^team-compare-select/workout/(?P<id>\d+)/team/(?P<teamid>\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/team/(?P<teamid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/team/(?P<teamid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/team/(?P<teamid>\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/team/(?P<teamid>\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/team/(?P<teamid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/user/(?P<userid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/$',views.team_comparison_select),
url(r'^workouts-join-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workouts_join_select),
url(r'^workouts-join/$',views.workouts_join_view),
url(r'^workouts-join-select/team/(?P<teamid>\d+)/$',views.workouts_join_select),
url(r'^workouts-join-select/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workouts_join_select),
url(r'^workouts-join-select/$',views.workouts_join_select),
url(r'^user-boxplot-select/user/(?P<userid>\d+)/$',views.user_boxplot_select),
url(r'^user-boxplot-select/$',views.user_boxplot_select),
url(r'^user-multiflex-select/user/(?P<userid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.user_multiflex_select),
url(r'^user-multiflex-select/user/(?P<userid>\d+)/$',views.user_multiflex_select),
url(r'^user-multiflex-select/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.user_multiflex_select),
url(r'^user-multiflex-select/$',views.user_multiflex_select),
url(r'^list-jobs/$',views.session_jobs_view),
url(r'^jobs-status/$',views.session_jobs_status),
views.virtualevent_disqualify_view,name='virtualevent_submit_disqualify_view'),
url(r'^list-workouts/$',views.workouts_view,
name='workouts_view'),
url(r'^list-courses/$',views.courses_view,name='courses_view'),
url(r'^courses/upload/$',views.course_upload_view,name='course_upload_view'),
url(r'^workout/addmanual/$',views.addmanual_view,name='addmanual_view'),
url(r'^team-compare-select/workout/(?P<id>\d+)/team/(?P<teamid>\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/workout/(?P<id>\d+)/team/(?P<teamid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/workout/(?P<id>\d+)/team/(?P<teamid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/workout/(?P<id>\d+)/team/(?P<teamid>\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/workout/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/workout/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/workout/(?P<id>\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/team/(?P<teamid>\d+)/user/(?P<userid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/workout/(?P<id>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/team/(?P<teamid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/user/(?P<userid>\d+)/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^team-compare-select/$',views.team_comparison_select,name='team_comparison_select'),
url(r'^workouts-join-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workouts_join_select,name='workouts_join_select'),
url(r'^workouts-join/$',views.workouts_join_view,name='workouts_join_view'),
url(r'^workouts-join-select/team/(?P<teamid>\d+)/$',views.workouts_join_select,name='workouts_join_select'),
url(r'^workouts-join-select/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workouts_join_select,name='workouts_join_select'),
url(r'^workouts-join-select/$',views.workouts_join_select,name='workouts_join_select'),
url(r'^user-boxplot-select/user/(?P<userid>\d+)/$',views.user_boxplot_select,name='user_boxplot_select'),
url(r'^user-boxplot-select/$',views.user_boxplot_select,name='user_boxplot_select'),
url(r'^user-multiflex-select/user/(?P<userid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.user_multiflex_select,name='user_multiflex_select'),
url(r'^user-multiflex-select/user/(?P<userid>\d+)/$',views.user_multiflex_select,name='user_multiflex_select'),
url(r'^user-multiflex-select/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.user_multiflex_select,name='user_multiflex_select'),
url(r'^user-multiflex-select/$',views.user_multiflex_select,name='user_multiflex_select'),
url(r'^list-jobs/$',views.session_jobs_view,name='session_jobs_view'),
url(r'^jobs-status/$',views.session_jobs_status,name='session_jobs_status'),
url(r'^job-kill/(?P<id>.*)/$',views.kill_async_job),
url(r'^test-job/(?P<aantal>\d+)/$',views.test_job_view),
url(r'^test-job2/(?P<aantal>\d+)/$',views.test_job_view2),
url(r'^record-progress/(?P<value>\d+)/(?P<id>.*)/$',views.post_progress),
url(r'^record-progress/(?P<value>\d+)/(?P<id>.*)/$',views.post_progress,name='post_progress'),
url(r'^record-progress/(?P<id>.*)/$',views.post_progress),
url(r'^record-progress/$',views.post_progress),
url(r'^list-graphs/$',views.graphs_view),
url(r'^fitness-progress/$',views.fitnessmetric_view),
url(r'^fitness-progress/user/(?P<id>\d+)/$',views.fitnessmetric_view),
url(r'^fitness-progress/user/(?P<id>\d+)/(?P<mode>\w+.*)/$',views.fitnessmetric_view),
url(r'^ote-bests/user/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.rankings_view),
url(r'^ote-bests/user/(?P<theuser>\d+)/$',views.rankings_view),
url(r'^ote-bests/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.rankings_view),
url(r'^ote-bests/$',views.rankings_view),
url(r'^(?P<theuser>\d+)/ote-bests/$',views.rankings_view),
url(r'^(?P<theuser>\d+)/ote-bests2/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.rankings_view2),
url(r'^ote-bests2/user/(?P<theuser>\d+)/$',views.rankings_view2),
url(r'^ote-bests2/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.rankings_view2),
url(r'^ote-bests2/$',views.rankings_view2),
url(r'^otw-bests/user/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.otwrankings_view),
url(r'^otw-bests/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.otwrankings_view),
url(r'^otw-bests/user/(?P<theuser>\d+)/$',views.otwrankings_view),
url(r'^otw-bests/$',views.otwrankings_view),
url(r'^ote-ranking/user/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.oterankings_view),
url(r'^ote-ranking/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.oterankings_view),
url(r'^ote-ranking/$',views.oterankings_view),
url(r'^ote-ranking/user/(?P<theuser>\d+)/$',views.oterankings_view),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<theuser>\d+)/$',views.cum_flex),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.cum_flex),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/$',views.cum_flex),
url(r'^flexall/user/(?P<theuser>\d+)/$',views.cum_flex),
url(r'^flexall/$',views.cum_flex),
url(r'^flexalldata/$',views.cum_flex_data),
url(r'^histo/user/(?P<theuser>\d+)/$',views.histo),
url(r'^histodata/$',views.histo_data),
url(r'^histo/user/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.histo),
url(r'^histo/$',views.histo),
url(r'^cumstats/user/(?P<theuser>\d+)/$',views.cumstats),
url(r'^cumstats/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.cumstats),
url(r'^cumstats/user/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.cumstats),
url(r'^cumstats/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.cumstats),
url(r'^cumstats/$',views.cumstats),
url(r'^graph/(?P<id>\d+)/$',views.graph_show_view),
url(r'^list-graphs/$',views.graphs_view,name='graphs_view'),
url(r'^fitness-progress/$',views.fitnessmetric_view,name='fitnessmetric_view'),
url(r'^fitness-progress/user/(?P<id>\d+)/$',views.fitnessmetric_view,name='fitnessmetric_view'),
url(r'^fitness-progress/user/(?P<id>\d+)/(?P<mode>\w+.*)/$',views.fitnessmetric_view,name='fitnessmetric_view'),
url(r'^ote-bests/user/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.rankings_view,name='rankings_view'),
url(r'^ote-bests/user/(?P<theuser>\d+)/$',views.rankings_view,name='rankings_view'),
url(r'^ote-bests/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.rankings_view,name='rankings_view'),
url(r'^ote-bests/$',views.rankings_view,name='rankings_view'),
url(r'^(?P<theuser>\d+)/ote-bests/$',views.rankings_view,name='rankings_view'),
url(r'^(?P<theuser>\d+)/ote-bests2/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.rankings_view2,name='rankings_view2'),
url(r'^ote-bests2/user/(?P<theuser>\d+)/$',views.rankings_view2,name='rankings_view2'),
url(r'^ote-bests2/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.rankings_view2,name='rankings_view2'),
url(r'^ote-bests2/$',views.rankings_view2,name='rankings_view2'),
url(r'^otw-bests/user/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.otwrankings_view,name='otwrankings_view'),
url(r'^otw-bests/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.otwrankings_view,name='otwrankings_view'),
url(r'^otw-bests/user/(?P<theuser>\d+)/$',views.otwrankings_view,name='otwrankings_view'),
url(r'^otw-bests/$',views.otwrankings_view,name='otwrankings_view'),
url(r'^ote-ranking/user/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.oterankings_view,name='oterankings_view'),
url(r'^ote-ranking/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.oterankings_view,name='oterankings_view'),
url(r'^ote-ranking/$',views.oterankings_view,name='oterankings_view'),
url(r'^ote-ranking/user/(?P<theuser>\d+)/$',views.oterankings_view,name='oterankings_view'),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/user/(?P<theuser>\d+)/$',views.cum_flex,name='cum_flex'),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.cum_flex,name='cum_flex'),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/$',views.cum_flex,name='cum_flex'),
url(r'^flexall/user/(?P<theuser>\d+)/$',views.cum_flex,name='cum_flex'),
url(r'^flexall/$',views.cum_flex,name='cum_flex'),
url(r'^flexalldata/$',views.cum_flex_data,name='cum_flex_data'),
url(r'^histo/user/(?P<theuser>\d+)/$',views.histo,name='histo'),
url(r'^histodata/$',views.histo_data,name='histo_data'),
url(r'^histo/user/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.histo,name='histo'),
url(r'^histo/$',views.histo,name='histo'),
url(r'^cumstats/user/(?P<theuser>\d+)/$',views.cumstats,name='cumstats'),
url(r'^cumstats/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.cumstats,name='cumstats'),
url(r'^cumstats/user/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.cumstats,name='cumstats'),
url(r'^cumstats/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.cumstats,name='cumstats'),
url(r'^cumstats/$',views.cumstats,name='cumstats'),
url(r'^graph/(?P<id>\d+)/$',views.graph_show_view,name='graph_show_view'),
url(r'^graph/(?P<pk>\d+)/delete/$',views.GraphDelete.as_view(),name='graph_delete'),
url(r'^workout/(?P<id>\d+)/get-thumbnails/$',views.get_thumbnails),
url(r'^workout/(?P<id>\d+)/toggle-ranking/$',views.workout_toggle_ranking),
url(r'^workout/(?P<id>\d+)/get-thumbnails/$',views.get_thumbnails,name='get_thumbnails'),
url(r'^workout/(?P<id>\d+)/toggle-ranking/$',views.workout_toggle_ranking,name='workout_toggle_ranking'),
url(r'^workout/(?P<id>\d+)/get-testscript/$',views.get_testscript),
url(r'^workout/upload/team/$',views.team_workout_upload_view),
url(r'^workout/upload/team/$',views.team_workout_upload_view,name='team_workout_upload_view'),
url(r'^workout/upload/$',views.workout_upload_view,name='workout_upload_view'),
url(r'^workout/(?P<id>\d+)/histo/$',views.workout_histo_view),
url(r'^workout/(?P<id>\d+)/histo/$',views.workout_histo_view,name='workout_histo_view'),
url(r'^workout/(?P<id>\d+)/task/$',views.workout_test_task_view),
url(r'^workout/(?P<id>\d+)/forcecurve/$',views.workout_forcecurve_view),
url(r'^workout/(?P<id>\d+)/unsubscribe/$',views.workout_unsubscribe_view),
url(r'^workout/(?P<id>\d+)/forcecurve/$',views.workout_forcecurve_view,name='workout_forcecurve_view'),
url(r'^workout/(?P<id>\d+)/unsubscribe/$',views.workout_unsubscribe_view,name='workout_unsubscribe_view'),
# url(r'^workout/(?P<id>\d+)/export/$',views.workout_export_view),
url(r'^workout/(?P<id>\d+)/comment/$',views.workout_comment_view),
url(r'^workout/(?P<id>\d+)/emailtcx/$',views.workout_tcxemail_view),
url(r'^workout/(?P<id>\d+)/emailgpx/$',views.workout_gpxemail_view),
url(r'^workout/(?P<id>\d+)/emailcsv/$',views.workout_csvemail_view),
url(r'^workout/(?P<id>\d+)/csvtoadmin/$',views.workout_csvtoadmin_view),
url(r'^ergcpdatatoadmin/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.otecp_toadmin_view),
url(r'^otwcpdatatoadmin/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.otwcp_toadmin_view),
url(r'^workout/(?P<id>\d+)/comment/$',views.workout_comment_view,name='workout_comment_view'),
url(r'^workout/(?P<id>\d+)/emailtcx/$',views.workout_tcxemail_view,name='workout_tcxemail_view'),
url(r'^workout/(?P<id>\d+)/emailgpx/$',views.workout_gpxemail_view,name='workout_gpxemail_view'),
url(r'^workout/(?P<id>\d+)/emailcsv/$',views.workout_csvemail_view,name='workout_csvemail_view'),
url(r'^workout/(?P<id>\d+)/csvtoadmin/$',views.workout_csvtoadmin_view,name='workout_csvtoadmin_view'),
url(r'^ergcpdatatoadmin/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.otecp_toadmin_view,name='otecp_toadmin_view'),
url(r'^otwcpdatatoadmin/(?P<theuser>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.otwcp_toadmin_view,name='otwcp_toadmin_view'),
# url(r'^workout/compare/(?P<id>\d+)/$',views.workout_comparison_list),
# url(r'^workout/compare2/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/$',views.workout_comparison_view),
# url(r'^workout/compare/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workout_comparison_list),
url(r'^workout/(?P<id>\d+)/edit/$',views.workout_edit_view,
name='workout_edit_view'),
url(r'^workout/(?P<id>\d+)/map/$',views.workout_map_view),
url(r'^workout/(?P<id>\d+)/map/$',views.workout_map_view,name='workout_map_view'),
# url(r'^workout/(?P<id>\d+)/setprivate/$',views.workout_setprivate_view),
url(r'^workout/(?P<id>\d+)/updatecp/$',views.workout_update_cp_view),
url(r'^workout/(?P<id>\d+)/updatecp/$',views.workout_update_cp_view,name='workout_update_cp_view'),
# url(r'^workout/(?P<id>\d+)/makepublic/$',views.workout_makepublic_view),
# url(r'^workout/(?P<id>\d+)/geeky/$',views.workout_geeky_view),
# url(r'^workout/(?P<id>\d+)/advanced/$',views.workout_advanced_view),
url(r'^workout/(?P<id>\d+)/instroke/(?P<metric>\w+.*)/$',views.instroke_chart),
url(r'^workout/(?P<id>\d+)/instroke/$',views.instroke_view),
url(r'^workout/(?P<id>\d+)/instroke/(?P<metric>\w+.*)/$',views.instroke_chart,name='instroke_chart'),
url(r'^workout/(?P<id>\d+)/instroke/$',views.instroke_view,name='instroke_view'),
url(r'^workout/(?P<id>\d+)/stats/$',views.workout_stats_view,name='workout_stats_view'),
url(r'^workout/(?P<id>\d+)/data/$',views.workout_data_view,
name='workout_data_view'),
url(r'^workout/(?P<id>\d+)/otwsetpower/$',views.workout_otwsetpower_view),
url(r'^workout/(?P<id>\d+)/interactiveotwplot/$',views.workout_otwpowerplot_view),
url(r'^workout/(?P<id>\d+)/wind/$',views.workout_wind_view),
url(r'^workout/(?P<id>\d+)/image/$',views.workout_uploadimage_view),
url(r'^virtualevent/(?P<id>\d+)/compare/$',views.virtualevent_compare_view),
url(r'^workout/(?P<id>\d+)/otwsetpower/$',views.workout_otwsetpower_view,name='workout_otwsetpower_view'),
url(r'^workout/(?P<id>\d+)/interactiveotwplot/$',views.workout_otwpowerplot_view,name='workout_otwpowerplot_view'),
url(r'^workout/(?P<id>\d+)/wind/$',views.workout_wind_view,name='workout_wind_view'),
url(r'^workout/(?P<id>\d+)/image/$',views.workout_uploadimage_view,name='workout_uploadimage_view'),
url(r'^virtualevent/(?P<id>\d+)/compare/$',views.virtualevent_compare_view,name='virtualevent_compare_view'),
url(r'^virtualevent/(?P<id>\d+)/image/$',
views.virtualevent_uploadimage_view),
views.virtualevent_uploadimage_view,name='virtualevent_uploadimage_view'),
url(r'^virtualevent/(?P<id>\d+)/setimage/(?P<logoid>\d+)/$',
views.virtualevent_setlogo_view),
views.virtualevent_setlogo_view,name='virtualevent_setlog_view'),
url(r'^logo/(?P<id>\d+)/delete/$',
views.logo_delete_view),
url(r'^workout/(?P<id>\d+)/darkskywind/$',views.workout_downloadwind_view),
url(r'^workout/(?P<id>\d+)/metar/(?P<airportcode>\w+)/$',views.workout_downloadmetar_view),
url(r'^workout/(?P<id>\d+)/stream/$',views.workout_stream_view),
views.logo_delete_view,name='logo_delete_view'),
url(r'^workout/(?P<id>\d+)/darkskywind/$',views.workout_downloadwind_view,name='workout_downloadwind_view'),
url(r'^workout/(?P<id>\d+)/metar/(?P<airportcode>\w+)/$',views.workout_downloadmetar_view,name='workout_downloadmetar_view'),
url(r'^workout/(?P<id>\d+)/stream/$',views.workout_stream_view,name='workout_stream_view'),
# url(r'^workout/(?P<id>\d+)/crewnerdsummary/$',views.workout_crewnerd_summary_view),
url(r'^workout/(?P<id>\d+)/editintervals/$',views.workout_summary_edit_view,
name='workout_summary_edit_view'),
url(r'^workout/(?P<id>\d+)/restore/$',views.workout_summary_restore_view),
url(r'^workout/(?P<id>\d+)/split/$',views.workout_split_view),
url(r'^workout/(?P<id>\d+)/restore/$',views.workout_summary_restore_view,name='workout_summary_restore_view'),
url(r'^workout/(?P<id>\d+)/split/$',views.workout_split_view,name='workout_split_view'),
# url(r'^workout/(?P<id>\d+)/interactiveplot/$',views.workout_biginteractive_view),
url(r'^workout/(?P<id>\d+)/view/$',views.workout_view),
url(r'^workout/(?P<id>\d+)/$',views.workout_view),
url(r'^workout/fusion/(?P<id1>\d+)/(?P<id2>\d+)/$',views.workout_fusion_view),
url(r'^workout/fusion/(?P<id>\d+)/$',views.workout_fusion_list),
url(r'^workout/fusion/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workout_fusion_list),
url(r'^workout/(?P<id>\d+)/view/$',views.workout_view,name='workout_view'),
url(r'^workout/(?P<id>\d+)/$',views.workout_view,name='workout_view'),
url(r'^workout/fusion/(?P<id1>\d+)/(?P<id2>\d+)/$',views.workout_fusion_view,name='workout_fusion_view'),
url(r'^workout/fusion/(?P<id>\d+)/$',views.workout_fusion_list,name='workout_fusion_list'),
url(r'^workout/fusion/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)/$',views.workout_fusion_list,name='workout_fusion_list'),
url(r'^help/$',TemplateView.as_view(
template_name='help.html'),name='help'
),
@@ -308,125 +317,126 @@ urlpatterns = [
# keeping the old URLs for retrofit
url(r'^workout/(?P<id>\d+)/addtimeplot/$',
views.workout_add_chart_view,
{'plotnr':'1'}),
{'plotnr':'1'},name='workout_add_chart_view'),
url(r'^workout/(?P<id>\d+)/adddistanceplot/$',
views.workout_add_chart_view,
{'plotnr':'2'}),
{'plotnr':'2'},name='workout_add_chart_view'),
url(r'^workout/(?P<id>\d+)/addpiechart/$',
views.workout_add_chart_view,
{'plotnr':'3'}),
{'plotnr':'3'},name='workout_add_chart_view'),
url(r'^workout/(?P<id>\d+)/adddistanceplot2/$',
views.workout_add_chart_view,
{'plotnr':'7'}),
{'plotnr':'7'},name='workout_add_chart_view'),
url(r'^workout/(?P<id>\d+)/addtimeplot2/$',
views.workout_add_chart_view,
{'plotnr':'8'}),
{'plotnr':'8'},name='workout_add_chart_view'),
url(r'^workout/(?P<id>\d+)/addotwpowerplot/$',
views.workout_add_chart_view,
{'plotnr':'9'}),
{'plotnr':'9'},name='workout_add_chart_view'),
url(r'^workout/(?P<id>\d+)/addpowerpiechart/$',
views.workout_add_chart_view,
{'plotnr':'13'}),
{'plotnr':'13'},name='workout_add_chart_view'),
# addstatic is the new URL -> need to update in templates
url(r'^workout/(?P<id>\d+)/addstatic/(?P<plotnr>\d+)/$',
views.workout_add_chart_view),
url(r'^workout/(?P<id>\d+)/addstatic/$',views.workout_add_chart_view),
views.workout_add_chart_view,name='workout_add_chart_view'),
url(r'^workout/(?P<id>\d+)/addstatic/$',views.workout_add_chart_view,name='workout_add_chart_view'),
url(r'^workout/(?P<pk>\d+)/delete/$',login_required(
views.WorkoutDelete.as_view()),
name='workout_delete'),
url(r'^workout/(?P<id>\d+)/smoothenpace/$',views.workout_smoothenpace_view),
url(r'^workout/(?P<id>\d+)/undosmoothenpace/$',views.workout_undo_smoothenpace_view),
url(r'^workout/c2import/$',views.workout_c2import_view),
url(r'^workout/c2list/$',views.workout_c2import_view),
url(r'^workout/c2list/(?P<page>\d+)/$',views.workout_c2import_view),
url(r'^workout/c2list/user/(?P<userid>\d+)/$',views.workout_c2import_view),
url(r'^workout/c2list/(?P<page>\d+)/user/(?P<userid>\d+)/$',views.workout_c2import_view),
url(r'^workout/stravaimport/$',views.workout_stravaimport_view),
url(r'^workout/stravaimport/user/(?P<userid>\d+)/$',views.workout_stravaimport_view),
url(r'^workout/c2import/all/$',views.workout_getc2workout_all),
url(r'^workout/c2import/all/(?P<page>\d+)/$',views.workout_getc2workout_all),
url(r'^workout/(?P<source>\w+.*)import/(?P<externalid>\d+)/$',views.workout_getimportview),
url(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all),
url(r'^workout/stravaimport/next/$',views.workout_getstravaworkout_next),
url(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view),
url(r'^workout/sporttracksimport/user/(?P<userid>\d+)/$',views.workout_sporttracksimport_view),
url(r'^workout/sporttracksimport/all/$',views.workout_getsporttracksworkout_all),
url(r'^workout/polarimport/$',views.workout_polarimport_view),
url(r'^workout/polarimport/user/(?P<userid>\d+)/',views.workout_polarimport_view),
url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view),
url(r'^workout/runkeeperimport/user/(?P<userid>\d+)/$',views.workout_runkeeperimport_view),
url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view),
url(r'^workout/(?P<id>\d+)/smoothenpace/$',views.workout_smoothenpace_view,name='workout_smoothenpace_view'),
url(r'^workout/(?P<id>\d+)/undosmoothenpace/$',views.workout_undo_smoothenpace_view,name='workout_undo_smoothenpace_view'),
url(r'^workout/c2import/$',views.workout_c2import_view,name='workout_c2import_view'),
url(r'^workout/c2list/$',views.workout_c2import_view,name='workout_c2import_view'),
url(r'^workout/c2list/(?P<page>\d+)/$',views.workout_c2import_view,name='workout_c2import_view'),
url(r'^workout/c2list/user/(?P<userid>\d+)/$',views.workout_c2import_view,name='workout_c2import_view'),
url(r'^workout/c2list/(?P<page>\d+)/user/(?P<userid>\d+)/$',views.workout_c2import_view,name='workout_c2import_view'),
url(r'^workout/stravaimport/$',views.workout_stravaimport_view,name='workout_stravaimport_view'),
url(r'^workout/stravaimport/user/(?P<userid>\d+)/$',views.workout_stravaimport_view,name='workout_stravaimport_view'),
url(r'^workout/c2import/all/$',views.workout_getc2workout_all,name='workout_getc2workout_all'),
url(r'^workout/c2import/all/(?P<page>\d+)/$',views.workout_getc2workout_all,name='workout_getc2workout_all'),
url(r'^workout/(?P<source>\w+.*)import/(?P<externalid>\d+)/$',views.workout_getimportview,name='workout_getimportview'),
url(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all,name='workout_getstravaworkout_all'),
url(r'^workout/stravaimport/next/$',views.workout_getstravaworkout_next,name='workout_getstravaworkout_next'),
url(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view,name='workout_sporttracksimport_view'),
url(r'^workout/sporttracksimport/user/(?P<userid>\d+)/$',views.workout_sporttracksimport_view,name='workout_sporttracksimport_view'),
url(r'^workout/sporttracksimport/all/$',views.workout_getsporttracksworkout_all,name='workout_getsporttracksworkout_all'),
url(r'^workout/polarimport/$',views.workout_polarimport_view,name='workout_polarimport_view'),
url(r'^workout/polarimport/user/(?P<userid>\d+)/',views.workout_polarimport_view,name='workout_polarimport_view'),
url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view,name='workout_runkeeperimport_view'),
url(r'^workout/runkeeperimport/user/(?P<userid>\d+)/$',views.workout_runkeeperimport_view,name='workout_runkeeperimport_view'),
url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view,name='workout_underarmourimport_view'),
# url(r'^workout/(?P<id>\d+)/deleteconfirm/$',views.workout_delete_confirm_view),
url(r'^workout/(?P<id>\d+)/c2uploadw/$',views.workout_c2_upload_view),
url(r'^workout/(?P<id>\d+)/stravauploadw/$',views.workout_strava_upload_view),
url(r'^workout/(?P<id>\d+)/recalcsummary/$',views.workout_recalcsummary_view),
url(r'^workout/(?P<id>\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view),
url(r'^workout/(?P<id>\d+)/runkeeperuploadw/$',views.workout_runkeeper_upload_view),
url(r'^workout/(?P<id>\d+)/underarmouruploadw/$',views.workout_underarmour_upload_view),
url(r'^workout/(?P<id>\d+)/tpuploadw/$',views.workout_tp_upload_view),
url(r'^multi-compare/workout/(?P<id>\d+)/user/(?P<userid>\d+)/$',views.multi_compare_view),
url(r'^multi-compare/workout/(?P<id>\d+)/$',views.multi_compare_view),
url(r'^multi-compare/$',views.multi_compare_view),
url(r'^user-boxplot/user/(?P<userid>\d+)/$',views.boxplot_view),
url(r'^user-boxplot/$',views.boxplot_view),
url(r'^user-boxplot-data/$',views.boxplot_view_data),
url(r'^user-multiflex/user/(?P<userid>\d+)/$',views.multiflex_view),
url(r'^user-multiflex/$',views.multiflex_view),
url(r'^user-multiflex-data/$',views.multiflex_data),
url(r'^me/deactivate/$',views.deactivate_user),
url(r'^me/delete/$',views.remove_user),
url(r'^me/gdpr-optin-confirm/?/$',views.user_gdpr_confirm),
url(r'^me/gdpr-optin-confirm/$',views.user_gdpr_confirm),
url(r'^me/gdpr-optin/?/$',views.user_gdpr_optin),
url(r'^me/gdpr-optin/$',views.user_gdpr_optin),
url(r'^me/teams/$',views.rower_teams_view),
url(r'^me/calcdps/$',views.rower_calcdps_view),
url(r'^me/exportsettings/$',views.rower_exportsettings_view),
url(r'^me/exportsettings/user/(?P<userid>\d+)/$',views.rower_exportsettings_view),
url(r'^team/(?P<id>\d+)/$',views.team_view),
url(r'^team/(?P<id>\d+)/memberstats/$',views.team_members_stats_view),
url(r'^team/(?P<id>\d+)/edit/$',views.team_edit_view),
url(r'^team/(?P<id>\d+)/leaveconfirm/$',views.team_leaveconfirm_view),
url(r'^team/(?P<id>\d+)/leave/$',views.team_leave_view),
url(r'^team/(?P<id>\d+)/deleteconfirm/$',views.team_deleteconfirm_view),
url(r'^team/(?P<teamid>\d+)/requestmembership/(?P<userid>\d+)/$',views.team_requestmembership_view),
url(r'^team/(?P<id>\d+)/delete/$',views.team_delete_view),
url(r'^team/create/$',views.team_create_view),
url(r'^me/team/(?P<teamid>\d+)/drop/(?P<userid>\d+)/$',views.manager_member_drop_view),
url(r'^me/invitation/(?P<id>\d+)/reject/$',views.invitation_reject_view),
url(r'^me/invitation/(?P<id>\d+)/revoke/$',views.invitation_revoke_view),
url(r'^me/invitation/$',views.rower_invitations_view),
url(r'^me/raise500/$',views.raise_500),
url(r'^me/invitation/(\w+.*)/$',views.rower_invitations_view),
url(r'^me/request/(?P<id>\d+)/revoke/$',views.request_revoke_view),
url(r'^me/request/(?P<id>\d+)/reject/$',views.request_reject_view),
url(r'^me/request/(\w+.*)/$',views.manager_requests_view),
url(r'^me/request/$',views.manager_requests_view),
url(r'^me/edit/$',views.rower_edit_view),
url(r'^me/edit/user/(?P<userid>\d+)/$',views.rower_edit_view),
url(r'^me/preferences/$',views.rower_prefs_view),
url(r'^me/transactions/$',views.transactions_view),
url(r'^me/preferences/user/(?P<userid>\d+)/$',views.rower_prefs_view),
url(r'^me/edit/(.+.*)/$',views.rower_edit_view),
url(r'^me/c2authorize/$',views.rower_c2_authorize),
url(r'^me/polarauthorize/$',views.rower_polar_authorize),
url(r'^me/revokeapp/(?P<id>\d+)/$',views.rower_revokeapp_view),
url(r'^me/stravaauthorize/$',views.rower_strava_authorize),
url(r'^me/sporttracksauthorize/$',views.rower_sporttracks_authorize),
url(r'^me/underarmourauthorize/$',views.rower_underarmour_authorize),
url(r'^me/tpauthorize/$',views.rower_tp_authorize),
url(r'^me/runkeeperauthorize/$',views.rower_runkeeper_authorize),
url(r'^me/sporttracksrefresh/$',views.rower_sporttracks_token_refresh),
url(r'^me/underarmourrefresh/$',views.rower_underarmour_token_refresh),
url(r'^me/tprefresh/$',views.rower_tp_token_refresh),
url(r'^me/c2refresh/$',views.rower_c2_token_refresh),
url(r'^me/favoritecharts/$',views.rower_favoritecharts_view),
url(r'^me/favoritecharts/user/(?P<userid>\d+)/$',views.rower_favoritecharts_view),
url(r'^workout/(?P<id>\d+)/c2uploadw/$',views.workout_c2_upload_view,name='workout_c2_upload_view'),
url(r'^workout/(?P<id>\d+)/stravauploadw/$',views.workout_strava_upload_view,name='workout_strava_upload_view'),
url(r'^workout/(?P<id>\d+)/recalcsummary/$',views.workout_recalcsummary_view,name='workout_recalcsummary_view'),
url(r'^workout/(?P<id>\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view,name='workout_sporttracks_upload_view'),
url(r'^workout/(?P<id>\d+)/runkeeperuploadw/$',views.workout_runkeeper_upload_view,name='workout_runkeeper_upload_view'),
url(r'^workout/(?P<id>\d+)/underarmouruploadw/$',views.workout_underarmour_upload_view,name='workout_underarmour_upload_view'),
url(r'^workout/(?P<id>\d+)/tpuploadw/$',views.workout_tp_upload_view,name='workout_tp_upload_view'),
url(r'^multi-compare/workout/(?P<id>\d+)/user/(?P<userid>\d+)/$',views.multi_compare_view,
name='multi_compare_view'),
url(r'^multi-compare/workout/(?P<id>\d+)/$',views.multi_compare_view,name='multi_compare_view'),
url(r'^multi-compare/$',views.multi_compare_view,name='multi_compare_view'),
url(r'^user-boxplot/user/(?P<userid>\d+)/$',views.boxplot_view,name='boxplot_view'),
url(r'^user-boxplot/$',views.boxplot_view,name='boxplot_view'),
url(r'^user-boxplot-data/$',views.boxplot_view_data,name='boxplot_view_data'),
url(r'^user-multiflex/user/(?P<userid>\d+)/$',views.multiflex_view,name='multiflex_view'),
url(r'^user-multiflex/$',views.multiflex_view,name='multiflex_view'),
url(r'^user-multiflex-data/$',views.multiflex_data,name='multiflex_data'),
url(r'^me/deactivate/$',views.deactivate_user,name='deactivate_user'),
url(r'^me/delete/$',views.remove_user,name='remove_user'),
url(r'^me/gdpr-optin-confirm/?/$',views.user_gdpr_confirm,name='user_gdpr_confirm'),
url(r'^me/gdpr-optin-confirm/$',views.user_gdpr_confirm,name='user_gdpr_confirm'),
url(r'^me/gdpr-optin/?/$',views.user_gdpr_optin,name='user_gdpr_optin'),
url(r'^me/gdpr-optin/$',views.user_gdpr_optin,name='user_gdpr_optin'),
url(r'^me/teams/$',views.rower_teams_view,name='rower_teams_view'),
url(r'^me/calcdps/$',views.rower_calcdps_view,name='rower_calcdps_view'),
url(r'^me/exportsettings/$',views.rower_exportsettings_view,name='rower_exportsettings_view'),
url(r'^me/exportsettings/user/(?P<userid>\d+)/$',views.rower_exportsettings_view,name='rower_exportsettings_view'),
url(r'^team/(?P<id>\d+)/$',views.team_view,name='team_view'),
url(r'^team/(?P<id>\d+)/memberstats/$',views.team_members_stats_view,name='team_members_stats_view'),
url(r'^team/(?P<id>\d+)/edit/$',views.team_edit_view,name='team_edit_view'),
url(r'^team/(?P<id>\d+)/leaveconfirm/$',views.team_leaveconfirm_view,name='team_leaveconfirm_view'),
url(r'^team/(?P<id>\d+)/leave/$',views.team_leave_view,name='team_leave_view'),
url(r'^team/(?P<id>\d+)/deleteconfirm/$',views.team_deleteconfirm_view,name='team_deleteconfirm_view'),
url(r'^team/(?P<teamid>\d+)/requestmembership/(?P<userid>\d+)/$',views.team_requestmembership_view,name='team_requestmembership_view'),
url(r'^team/(?P<id>\d+)/delete/$',views.team_delete_view,name='team_delete_view'),
url(r'^team/create/$',views.team_create_view,name='team_create_view'),
url(r'^me/team/(?P<teamid>\d+)/drop/(?P<userid>\d+)/$',views.manager_member_drop_view,name='manager_member_drop_view'),
url(r'^me/invitation/(?P<id>\d+)/reject/$',views.invitation_reject_view,name='invitation_reject_view'),
url(r'^me/invitation/(?P<id>\d+)/revoke/$',views.invitation_revoke_view,name='invitation_revoke_view'),
url(r'^me/invitation/$',views.rower_invitations_view,name='rower_invitations_view'),
url(r'^me/raise500/$',views.raise_500,name='raise_500'),
url(r'^me/invitation/(\w+.*)/$',views.rower_invitations_view,name='rower_invitations_view'),
url(r'^me/request/(?P<id>\d+)/revoke/$',views.request_revoke_view,name='request_revoke_view'),
url(r'^me/request/(?P<id>\d+)/reject/$',views.request_reject_view,name='request_reject_view'),
url(r'^me/request/(\w+.*)/$',views.manager_requests_view,name='manager_requests_view'),
url(r'^me/request/$',views.manager_requests_view,name='manager_requests_view'),
url(r'^me/edit/$',views.rower_edit_view,name='rower_edit_view'),
url(r'^me/edit/user/(?P<userid>\d+)/$',views.rower_edit_view,name='rower_edit_view'),
url(r'^me/preferences/$',views.rower_prefs_view,name='rower_prefs_view'),
url(r'^me/transactions/$',views.transactions_view,name='transactions_view'),
url(r'^me/preferences/user/(?P<userid>\d+)/$',views.rower_prefs_view,name='rower_prefs_view'),
url(r'^me/edit/(.+.*)/$',views.rower_edit_view,name='rower_edit_view'),
url(r'^me/c2authorize/$',views.rower_c2_authorize,name='rower_c2_authorize'),
url(r'^me/polarauthorize/$',views.rower_polar_authorize,name='rower_polar_authorize'),
url(r'^me/revokeapp/(?P<id>\d+)/$',views.rower_revokeapp_view,name='rower_revokeapp_view'),
url(r'^me/stravaauthorize/$',views.rower_strava_authorize,name='rower_strava_authorize'),
url(r'^me/sporttracksauthorize/$',views.rower_sporttracks_authorize,name='rower_sporttracks_authorize'),
url(r'^me/underarmourauthorize/$',views.rower_underarmour_authorize,name='rower_underarmour_authorize'),
url(r'^me/tpauthorize/$',views.rower_tp_authorize,name='rower_tp_authorize'),
url(r'^me/runkeeperauthorize/$',views.rower_runkeeper_authorize,name='rower_runkeeper_authorize'),
url(r'^me/sporttracksrefresh/$',views.rower_sporttracks_token_refresh,name='rower_sporttracks_token_refresh'),
url(r'^me/underarmourrefresh/$',views.rower_underarmour_token_refresh,name='rower_underarmoud_token_refresh'),
url(r'^me/tprefresh/$',views.rower_tp_token_refresh,name='rower_tp_token_refresh'),
url(r'^me/c2refresh/$',views.rower_c2_token_refresh,name='rower_c2_token_refresh'),
url(r'^me/favoritecharts/$',views.rower_favoritecharts_view,name='rower_favoritecharts_view'),
url(r'^me/favoritecharts/user/(?P<userid>\d+)/$',views.rower_favoritecharts_view,name='rower_favoritecharts_view'),
# url(r'^me/workflowconfig/$',views.workout_workflow_config_view),
url(r'^me/workflowconfig2/$',views.workout_workflow_config2_view),
url(r'^me/workflowconfig2/user/(?P<userid>\d+)/$',views.workout_workflow_config2_view),
url(r'^me/workflowdefault/$',views.workflow_default_view),
url(r'^email/send/$', views.sendmail),
url(r'^me/workflowconfig2/$',views.workout_workflow_config2_view,name='workout_workflow_config2_view'),
url(r'^me/workflowconfig2/user/(?P<userid>\d+)/$',views.workout_workflow_config2_view,name='workout_workflow_config2_view'),
url(r'^me/workflowdefault/$',views.workflow_default_view,name='workflow_default_view'),
url(r'^email/send/$', views.sendmail,name='sendmail'),
url(r'^email/thankyou/$', TemplateView.as_view(template_name='thankyou.html'), name='thankyou'),
url(r'^email/$', TemplateView.as_view(template_name='email.html'), name='email'),
url(r'^about', TemplateView.as_view(template_name='about_us.html'),name='about'),
@@ -440,39 +450,39 @@ urlpatterns = [
url(r'^analysis/$', views.analysis_view,name='analysis'),
url(r'^laboratory/$', views.laboratory_view,name='laboratory'),
url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'),
url(r'^checkout/(?P<planid>\d+)/$',views.payment_confirm_view),
url(r'^upgradecheckout/(?P<planid>\d+)/$',views.upgrade_confirm_view),
url(r'^downgradecheckout/(?P<planid>\d+)/$',views.downgrade_confirm_view),
url(r'^checkout/(?P<planid>\d+)/$',views.payment_confirm_view,name='payment_confirm_view'),
url(r'^upgradecheckout/(?P<planid>\d+)/$',views.upgrade_confirm_view,name='upgrade_confirm_view'),
url(r'^downgradecheckout/(?P<planid>\d+)/$',views.downgrade_confirm_view,name='downgrade_confirm_view'),
url(r'^billing/$',views.billing_view,name='billing'),
url(r'^upgrade/$',views.upgrade_view,name='upgrade'),
url(r'^downgrade/$',views.downgrade_view,name='downgrade'),
url(r'^paymentcompleted/$',views.payment_completed_view),
url(r'^downgradecompleted/$',views.downgrade_completed_view),
url(r'^paymentcompleted/$',views.payment_completed_view,name='payment_completed_view'),
url(r'^downgradecompleted/$',views.downgrade_completed_view,name='downgrade_completed_view'),
url(r'^paidplans/$',views.paidplans_view,name='paidplans'),
url(r'^me/cancelsubscriptions/$',views.plan_stop_view),
url(r'^me/cancelsubscription/(?P<id>[\w\ ]+.*)/$',views.plan_tobasic_view),
url(r'^me/cancelsubscriptions/$',views.plan_stop_view,name='plan_stop_view'),
url(r'^me/cancelsubscription/(?P<id>[\w\ ]+.*)/$',views.plan_tobasic_view,name='plan_tobasic_view'),
url(r'^checkouts/$',views.checkouts_view,name='checkouts'),
url(r'^upgradecheckouts/$',views.upgrade_checkouts_view,name='upgrade_checkouts'),
url(r'^downgradecheckouts/$',views.downgrade_checkouts_view,name='downgrade_checkouts'),
url(r'^planrequired/',views.planrequired_view),
url(r'^starttrial/$',views.start_trial_view),
url(r'^startplantrial/$',views.start_plantrial_view),
url(r'^planrequired/',views.planrequired_view,name='planrequired_view'),
url(r'^starttrial/$',views.start_trial_view,name='start_trial_view'),
url(r'^startplantrial/$',views.start_plantrial_view,name='start_plantrial_view'),
# url(r'^planmembership', TemplateView.as_view(template_name='planmembership.html'),name='planmembership'),
# url(r'^paypaltest', TemplateView.as_view(template_name='paypaltest.html'),name='paypaltest'),
url(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'),
url(r'^register/$',views.rower_register_view),
url(r'^register/$',views.rower_register_view,name='rower_register_view'),
url(r'^register/thankyou/$', TemplateView.as_view(template_name='registerthankyou.html'), name='registerthankyou'),
url(r'^workout/(?P<id>\d+)/workflow/$',views.workout_workflow_view,
name='workout_workflow_view'),
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>[\w\ ]+.*)/(?P<yparam1>[\w\ ]+.*)/(?P<yparam2>[\w\ ]+.*)/(?P<plottype>\w+)/$',views.workout_flexchart3_view),
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>[\w\ ]+.*)/(?P<yparam2>[\w\ ]+.*)/(?P<plottype>\w+.*)/$',views.workout_flexchart3_view),
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>[\w\ ]+.*)/(?P<yparam2>[\w\ ]+.*)/$',views.workout_flexchart3_view),
url(r'^workout/(?P<id>\d+)/flexchart/$',views.workout_flexchart3_view),
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>[\w\ ]+.*)/(?P<yparam1>[\w\ ]+.*)/(?P<yparam2>[\w\ ]+.*)/(?P<plottype>\w+)/$',views.workout_flexchart3_view,name='workout_flexchart3_view'),
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>[\w\ ]+.*)/(?P<yparam2>[\w\ ]+.*)/(?P<plottype>\w+.*)/$',views.workout_flexchart3_view,name='workout_flexchart3_view'),
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>[\w\ ]+.*)/(?P<yparam2>[\w\ ]+.*)/$',views.workout_flexchart3_view,name='workout_flexchart3_view'),
url(r'^workout/(?P<id>\d+)/flexchart/$',views.workout_flexchart3_view,name='workout_flexchart3_view'),
# url(r'^workout/compare/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>[\w\ ]+.*)/(?P<plottype>[\w\ ]+.*)/$',views.workout_comparison_view2),
# url(r'^workout/compare/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>[\w\ ]+.*)/$',views.workout_comparison_view2),
url(r'^test\_callback',views.rower_process_testcallback),
url(r'^createplan/$',views.rower_create_trainingplan),
url(r'^createplan/user/(?P<userid>\d+)/$',views.rower_create_trainingplan),
url(r'^test\_callback',views.rower_process_testcallback,name='rower_process_testcallback'),
url(r'^createplan/$',views.rower_create_trainingplan,name='rower_create_trainingplan'),
url(r'^createplan/user/(?P<userid>\d+)/$',views.rower_create_trainingplan,name='rower_create_trainingplan'),
url(r'^deleteplan/(?P<pk>\d+)/$',login_required(
views.TrainingPlanDelete.as_view())),
url(r'^deletemicrocycle/(?P<pk>\d+)/$',login_required(

View File

@@ -468,3 +468,17 @@ def get_strava_stream(r,metric,stravaid,series_type='time',fetchresolution='high
s = requests.get(url,headers=headers)
return s
def allmonths(startdate,enddate):
d = startdate
while d<enddate:
yield d
d = datetime.date(d.year+(d.month / 12),((d.month % 12) + 1),1)
def allsundays(startdate,enddate):
d = startdate
d += datetime.timedelta(days = 6 - d.weekday()) # first Sunday
while d<=enddate:
yield d
d += datetime.timedelta(days=7)

12
rowers/views/__init__.py Normal file
View File

@@ -0,0 +1,12 @@
from .analysisviews import *
from .apiviews import *
from .errorviews import *
from .exportviews import *
from .importviews import *
from .otherviews import *
from .paymentviews import *
from .planviews import *
from .racesviews import *
from .teamviews import *
from .userviews import *
from .workoutviews import *

File diff suppressed because it is too large Load Diff

182
rowers/views/apiviews.py Normal file
View File

@@ -0,0 +1,182 @@
from statements import *
# Stroke data form to test API upload
@login_required()
def strokedataform(request,id=0):
try:
id=int(id)
except ValueError:
id = 0
try:
w = Workout.objects.get(id=id)
except Workout.DoesNotExist:
raise Http404("Workout doesn't exist")
if request.method == 'GET':
form = StrokeDataForm()
return render(request, 'strokedata_form.html',
{
'form':form,
'teams':get_my_teams(request.user),
'id':id,
'workout':w,
})
elif request.method == 'POST':
form = StrokeDataForm()
return render(request, 'strokedata_form.html',
{
'form':form,
'teams':get_my_teams(request.user),
'id':id,
'workout':w,
})
# Process the POSTed stroke data according to the API definition
# Return the GET stroke data according to the API definition
from rest_framework_swagger.renderers import OpenAPIRenderer, SwaggerUIRenderer
@csrf_exempt
@login_required()
@api_view(['GET','POST'])
def strokedatajson(request,id):
"""
POST: Add Stroke data to workout
GET: Get stroke data of workout
"""
row = get_workout_permitted(request.user,id)
try:
id = int(id)
except ValueError:
return HttpResponse("Not a valid workout number",status=400)
if request.method == 'GET':
# currently only returns a subset.
columns = ['spm','time','hr','pace','power','distance']
datadf = dataprep.getsmallrowdata_db(columns,ids=[id])
with open('media/apilog.log','a') as logfile:
logfile.write(str(timezone.now())+": ")
logfile.write(request.user.username+"(GET) \n")
return JSONResponse(datadf)
if request.method == 'POST':
checkdata,r = dataprep.getrowdata_db(id=row.id)
if not checkdata.empty:
return HttpResponse("Duplicate Error",409)
# strokedata = request.POST['strokedata']
# checking/validating and cleaning
try:
strokedata = json.loads(request.POST['strokedata'])
except:
return HttpResponse("No JSON object could be decoded",400)
df = pd.DataFrame(strokedata)
df.index = df.index.astype(int)
df.sort_index(inplace=True)
# time, hr, pace, spm, power, drivelength, distance, drivespeed, dragfactor, strokerecoverytime, averagedriveforce, peakdriveforce, lapidx
try:
time = df['time']/1.e3
except KeyError:
return HttpResponse("There must be time values",status=400)
aantal = len(time)
pace = df['pace']/1.e3
if len(pace) != aantal:
return HttpResponse("Pace array has incorrect length",status=400)
distance = df['distance']
if len(distance) != aantal:
return HttpResponse("Distance array has incorrect length",status=400)
spm = df['spm']
if len(spm) != aantal:
return HttpResponse("SPM array has incorrect length",status=400)
res = dataprep.testdata(time,distance,pace,spm)
if not res:
return HttpResponse("Data are not numerical",status=400)
power = trydf(df,aantal,'power')
drivelength = trydf(df,aantal,'drivelength')
drivespeed = trydf(df,aantal,'drivespeed')
dragfactor = trydf(df,aantal,'dragfactor')
drivetime = trydf(df,aantal,'drivetime')
strokerecoverytime = trydf(df,aantal,'strokerecoverytime')
averagedriveforce = trydf(df,aantal,'averagedriveforce')
peakdriveforce = trydf(df,aantal,'peakdriveforce')
wash = trydf(df,aantal,'wash')
catch = trydf(df,aantal,'catch')
finish = trydf(df,aantal,'finish')
peakforceangle = trydf(df,aantal,'peakforceangle')
driveenergy = trydf(df,aantal,'driveenergy')
slip = trydf(df,aantal,'slip')
lapidx = trydf(df,aantal,'lapidx')
hr = trydf(df,aantal,'hr')
starttime = totimestamp(row.startdatetime)+time[0]
unixtime = starttime+time
with open('media/apilog.log','a') as logfile:
logfile.write(str(starttime)+": ")
logfile.write(request.user.username+"(POST) \r\n")
data = pd.DataFrame({'TimeStamp (sec)':unixtime,
' Horizontal (meters)': distance,
' Cadence (stokes/min)':spm,
' HRCur (bpm)':hr,
' DragFactor':dragfactor,
' Stroke500mPace (sec/500m)':pace,
' Power (watts)':power,
' DriveLength (meters)':drivelength,
' DriveTime (ms)':drivetime,
' StrokeRecoveryTime (ms)':strokerecoverytime,
' AverageDriveForce (lbs)':averagedriveforce,
' PeakDriveForce (lbs)':peakdriveforce,
' lapIdx':lapidx,
' ElapsedTime (sec)':time,
'catch':catch,
'slip':slip,
'finish':finish,
'wash':wash,
'driveenergy':driveenergy,
'peakforceangle':peakforceangle,
})
# Following part should be replaced with dataprep.new_workout_from_df
r = getrower(request.user)
timestr = row.startdatetime.strftime("%Y%m%d-%H%M%S")
csvfilename ='media/Import_'+timestr+'.csv'
res = data.to_csv(csvfilename+'.gz',index_label='index',
compression='gzip')
row.csvfilename = csvfilename
row.save()
powerperc = 100*np.array([r.pw_ut2,
r.pw_ut1,
r.pw_at,
r.pw_tr,r.pw_an])/r.ftp
ftp = float(r.ftp)
if row.workouttype in mytypes.otwtypes:
ftp = ftp*(100.-r.otwslack)/100.
rr = rrower(hrmax=r.max,hrut2=r.ut2,
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
datadf = dataprep.dataprep(rowdata,id=row.id,bands=True,barchart=True,otwpower=True,empower=True)
# mangling
#
return HttpResponse(row.id,status=201)
#Method not supported
return HttpResponseNotAllowed("Method not supported")

View File

@@ -0,0 +1,30 @@
from statements import *
# Custom error pages with Rowsandall headers
def error500_view(request):
response = render_to_response('500.html', {},
context_instance = RequestContext(request))
response.status_code = 500
return response
def error404_view(request):
response = render_to_response('404.html', {},
context_instance = RequestContext(request))
response.status_code = 404
return response
def error400_view(request):
response = render_to_response('400.html', {},
context_instance = RequestContext(request))
response.status_code = 400
return response
def error403_view(request):
response = render_to_response('403.html', {},
context_instance = RequestContext(request))
response.status_code = 403
return response

220
rowers/views/exportviews.py Normal file
View File

@@ -0,0 +1,220 @@
from statements import *
# Export workout to TCX and send to user's email address
@login_required()
def workout_tcxemail_view(request,id=0):
r = getrower(request.user)
w = get_workout(id)
if not checkworkoutuser(request.user,w):
raise PermissionDenied("Access denied")
row = rdata(w.csvfilename)
code = str(uuid4())
tcxfilename = code+'.tcx'
row.exporttotcx(tcxfilename)
with open(tcxfilename,'r') as f:
response = HttpResponse(f)
response['Content-Disposition'] = 'attachment; filename="%s"' % tcxfilename
response['Content-Type'] = 'application/octet-stream'
os.remove(tcxfilename)
return response
@login_required()
def plannedsessions_icsemail_view(request,userid=0):
r = getrequestrower(request,userid=userid)
startdate,enddate = get_dates_timeperiod(request)
sps = get_sessions(r,startdate=startdate,enddate=enddate)
cal = Calendar()
cal.add('prodid','rowsandall')
cal.add('version','1.0')
for ps in sps:
event = Event()
comment = '{d} {u} {c}'.format(
d=ps.sessionvalue,
u = ps.sessionunit,
c = ps.criterium)
event.add('summary',ps.name)
event.add('dtstart',ps.preferreddate)
event.add('dtend',ps.preferreddate)
event['uid'] = 'plannedsession_'+str(ps.id)
event.add('description',ps.comment)
event.add('comment',comment)
cal.add_component(event)
response = HttpResponse(cal.to_ical())
response['Content-Disposition'] = 'attachment; filename="training_plan_{u}_{d1}_{d2}.ics"'.format(
u = request.user.username,
d1 = startdate.strftime("%Y%m%d"),
d2 = enddate.strftime("%Y%m%d"),
)
response['Content-Type'] = 'application/octet-stream'
return response
@login_required()
def course_kmldownload_view(request,id=0):
r = getrower(request.user)
if r.emailbounced:
message = "Please check your email address first. Email to this address bounced."
messages.error(request,message)
return HttpResponseRedirect(
reverse(course_view,
kwargs = {
'id':str(id),
})
)
course = GeoCourse.objects.get(id=id)
kmlstring = courses.coursetokml(course)
kmlfilename = 'course_{id}.kml'.format(id=id)
response = HttpResponse(kmlstring)
response['Content-Disposition'] = 'attachment; filename="{filename}"'.format(filename=kmlfilename)
response['Content-Type'] = 'application/octet-stream'
return response
# Export workout to GPX and send to user's email address
@login_required()
def workout_gpxemail_view(request,id=0):
r = getrower(request.user)
w = get_workout(id)
if not checkworkoutuser(request.user,w):
raise PermissionDenied("Access denied")
row = rdata(w.csvfilename)
code = str(uuid4())
gpxfilename = code+'.gpx'
row.exporttogpx(gpxfilename)
with open(gpxfilename,'r') as f:
response = HttpResponse(f)
response['Content-Disposition'] = 'attachment; filename="%s"' % gpxfilename
response['Content-Type'] = 'application/octet-stream'
os.remove(gpxfilename)
return response
# Get Workout summary CSV file
@login_required()
def workouts_summaries_email_view(request):
r = getrower(request.user)
if r.emailbounced:
message = "Please check your email address first. Email to this address bounced."
messages.error(request, message)
return HttpResponseRedirect(
reverse(r.defaultlandingpage,
kwargs = {
'id':str(w.id),
})
)
if request.method == 'POST':
form = DateRangeForm(request.POST)
if form.is_valid():
startdate = form.cleaned_data['startdate']
enddate = form.cleaned_data['enddate']
filename = 'rowsandall_workouts_{first}_{last}.csv'.format(
first=startdate,
last=enddate
)
df = dataprep.workout_summary_to_df(r,startdate=startdate,enddate=enddate)
df.to_csv(filename,encoding='utf-8')
res = myqueue(queuehigh,handle_sendemailsummary,
r.user.first_name,
r.user.last_name,
r.user.email,
filename,
emailbounced = r.emailbounced
)
messages.info(request,'The summary CSV file was sent to you per email')
else:
form = DateRangeForm()
return render(request,"export_workouts.html",
{
'form':form
})
# Get Workout CSV file and send it to user's email address
@login_required()
def workout_csvemail_view(request,id=0):
r = getrower(request.user)
w = get_workout(id)
if not checkworkoutuser(request.user,w):
raise PermissionDenied("Access denied")
rowdata = rdata(w.csvfilename)
code = str(uuid4())
filename = code+'.csv'
rowdate = rowdata.rowdatetime
starttimeunix = arrow.get(rowdate).timestamp
df = rowdata.df
df[' ElapsedTime (sec)'] = df['TimeStamp (sec)']
df['TimeStamp (sec)'] = df['TimeStamp (sec)'] + starttimeunix
response = HttpResponse(df.to_csv())
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
response['Content-Type'] = 'application/octet-stream'
return response
# Get Workout CSV file and send it to user's email address
@login_required()
def workout_csvtoadmin_view(request,id=0):
message = ""
r = getrower(request.user)
w = get_workout(id)
csvfile = w.csvfilename
res = myqueue(queuehigh,
handle_sendemailcsv,
'Sander',
'Roosendaal',
'roosendaalsander@gmail.com',
csvfile)
successmessage = "The CSV file was sent to the site admin per email"
messages.info(request,successmessage)
url = reverse(workout_view,
kwargs = {
'id':str(w.id),
})
response = HttpResponseRedirect(url)
return response

1604
rowers/views/importviews.py Normal file

File diff suppressed because it is too large Load Diff

142
rowers/views/otherviews.py Normal file
View File

@@ -0,0 +1,142 @@
from statements import *
@login_required()
def deactivate_user(request):
pk = request.user.id
user = User.objects.get(pk=pk)
user_form = DeactivateUserForm(instance=user)
if request.user.is_authenticated() and request.user.id == user.id:
if request.method == "POST":
user_form = DeactivateUserForm(request.POST, instance=user)
if user_form.is_valid():
if not user_form.cleaned_data['is_active']:
r = Rower.objects.get(user=user)
if r.paidplan is not None and r.paidplan.paymentprocessor == 'braintree':
try:
subscriptions = braintreestuff.find_subscriptions(r)
for subscription in subscriptions:
success, themessages,errormessages = braintreestuff.cancel_subscription(r,id)
for message in themessages:
messages.info(request,message)
except ProcessorCustomerError:
pass
r.paidplan = None
r.teamplanexpires = timezone.now()
r.planexpires = timezone.now()
r.clubsize = 0
r.rowerplan = 'basic'
r.save()
deactivate_user = user_form.save(commit=False)
user.is_active = False
user.save()
deactivate_user.save()
# url = reverse(auth_views.logout_then_login)
url = '/logout/?next=/login'
return HttpResponseRedirect(url)
return render(request, "userprofile_deactivate.html", {
"user_form": user_form,
})
else:
raise PermissionDenied
@login_required()
def user_gdpr_optin(request):
r = getrower(request.user)
r.gdproptin = False
r.gdproptindate = None
r.save()
nexturl = request.GET.get('next','/rowers/list-workouts/')
if r.gdproptin:
return HttpResponseRedirect(nexturl)
return render(request,'gdpr_optin.html',{
"next": nexturl
})
@login_required()
def user_gdpr_confirm(request):
r = getrower(request.user)
r.gdproptin = True
r.gdproptindate = timezone.now()
r.save()
nexturl = request.GET.get('next','/rowers/list-workouts/')
return HttpResponseRedirect(nexturl)
@login_required()
def remove_user(request):
pk = request.user.id
user = User.objects.get(pk=pk)
user_form = DeleteUserForm(instance=user)
if request.user.is_authenticated() and request.user.id == user.id:
if request.method == "POST":
user_form = DeleteUserForm(request.POST,instance=user)
if user_form.is_valid():
cd = user_form.cleaned_data
name = user.first_name+' '+user.last_name
email = user.email
r = Rower.objects.get(user=user)
if r.paidplan is not None and r.paidplan.paymentprocessor == 'braintree':
try:
subscriptions = braintreestuff.find_subscriptions(r)
for subscription in subscriptions:
success, themessages,errormessages = braintreestuff.cancel_subscription(r,id)
for message in themessages:
messages.info(request,message)
except ProcessorCustomerError:
pass
if cd['delete_user']:
user.delete()
res = myqueue(queuehigh,
handle_sendemail_userdeleted,
name, email)
url = '/logout/?next=/login'
# url = reverse(auth_views.logout_then_login)
return HttpResponseRedirect(url)
return render(request, "userprofile_delete.html", {
"user_form": user_form,
})
else:
raise PermissionDenied
# Shows analysis page
@login_required()
def analysis_view(request,userid=0):
r = getrequestrower(request,userid=userid)
return render(request,
"analysis.html",
{
'active':'nav-analysis',
'rower':r,
}
)
# Shows laboratory page
@login_required()
def laboratory_view(request,userid=0):
r = getrequestrower(request,userid=userid)
return render(request,
"laboratory.html",
{
'active':'nav-analysis',
'rower':r,
}
)

View File

@@ -0,0 +1,590 @@
from statements import *
def paidplans_view(request):
if not request.user.is_anonymous():
r = getrequestrower(request)
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
messages.error(request,'Automated payment processing is currently only available through BrainTree (by PayPal). You are currently on a recurring payment plan with PayPal. Contact the site administrator at support@rowsandall.com before you proceed')
else:
r = None
return render(request,
'paidplans.html',
{'rower':r})
@login_required()
def billing_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
r = getrequestrower(request)
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
messages.error(request,'Automated payment processing is currently only available through BrainTree (by PayPal). You are currently on a recurring payment plan with PayPal. Contact the site administrator at support@rowsandall.com before you proceed')
if payments.is_existing_customer(r):
url = reverse(upgrade_view)
return HttpResponseRedirect(url)
if request.method == 'POST':
billingaddressform = RowerBillingAddressForm(request.POST)
planselectform = PlanSelectForm(request.POST,paymentprocessor='braintree')
if billingaddressform.is_valid():
cd = billingaddressform.cleaned_data
for attr, value in cd.items():
setattr(r, attr, value)
r.save()
if billingaddressform.is_valid():
if planselectform.is_valid():
plan = planselectform.cleaned_data['plan']
try:
customer_id = braintreestuff.create_customer(r)
except ProcessorCustomerError:
messages.error(request,"Something went wrong registering you as a customer.")
url = reverse(billing_view)
return HttpResponseRedirect(url)
url = reverse(payment_confirm_view,
kwargs={
'planid':plan.id
})
return HttpResponseRedirect(url)
else:
billingaddressform = RowerBillingAddressForm(instance=r)
planselectform = PlanSelectForm(paymentprocessor='braintree')
return render(request,
'billing.html',
{'rower':r,
'billingaddressform':billingaddressform,
'planselectform':planselectform,
})
@login_required()
def upgrade_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
r = getrequestrower(request)
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
messages.error(request,'Automated payment processing is currently only available through BrainTree (by PayPal). You are currently on a recurring payment plan with PayPal. Contact the site administrator at support@rowsandall.com before you proceed')
if r.subscription_id is None or r.subscription_id == '':
url = reverse(billing_view)
return HttpResponseRedirect(url)
if request.method == 'POST':
billingaddressform = RowerBillingAddressForm(request.POST)
planselectform = PlanSelectForm(request.POST,paymentprocessor='braintree')
if billingaddressform.is_valid():
cd = billingaddressform.cleaned_data
for attr, value in cd.items():
setattr(r, attr, value)
r.save()
if planselectform.is_valid():
plan = planselectform.cleaned_data['plan']
if billingaddressform.is_valid():
url = reverse(upgrade_confirm_view,
kwargs={
'planid':plan.id
})
return HttpResponseRedirect(url)
else:
billingaddressform = RowerBillingAddressForm(instance=r)
planselectform = PlanSelectForm(paymentprocessor='braintree',
rower=r)
return render(request,
'upgrade.html',
{'rower':r,
'billingaddressform':billingaddressform,
'planselectform':planselectform,
})
@login_required()
def downgrade_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
r = getrequestrower(request)
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
messages.error(request,'Automated payment processing is currently only available through BrainTree (by PayPal). You are currently on a recurring payment plan with PayPal. Contact the site administrator at support@rowsandall.com before you proceed')
if r.subscription_id is None or r.subscription_id == '':
url = reverse(billing_view)
return HttpResponseRedirect(url)
if request.method == 'POST':
billingaddressform = RowerBillingAddressForm(request.POST)
planselectform = PlanSelectForm(request.POST,paymentprocessor='braintree')
if billingaddressform.is_valid():
cd = billingaddressform.cleaned_data
for attr, value in cd.items():
setattr(r, attr, value)
r.save()
if planselectform.is_valid():
plan = planselectform.cleaned_data['plan']
if plan.price > r.paidplan.price:
nextview = upgrade_confirm_view
elif plan.price == r.paidplan.price:
messages.info(request,'You did not select a new plan')
url = reverse(downgrade_view)
return HttpResponseRedirect(url)
else:
nextview = downgrade_confirm_view
if billingaddressform.is_valid():
url = reverse(nextview,
kwargs={
'planid':plan.id
})
return HttpResponseRedirect(url)
else:
billingaddressform = RowerBillingAddressForm(instance=r)
planselectform = PlanSelectForm(paymentprocessor='braintree',
rower=r,includeall=True, initial={'plan':r.paidplan})
return render(request,
'downgrade.html',
{'rower':r,
'billingaddressform':billingaddressform,
'planselectform':planselectform,
})
@login_required()
def plan_stop_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
r = getrequestrower(request)
subscriptions = []
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
messages.error(request,'Automated payment processing is currently only available through BrainTree (by PayPal). You are currently on a recurring payment plan with PayPal. Contact the site administrator at support@rowsandall.com before you proceed')
if r.paidplan is not None and r.paidplan.paymentprocessor == 'braintree':
try:
subscriptions = braintreestuff.find_subscriptions(r)
except ProcessorCustomerError:
r.paymentprocessor = None
r.save()
return render(request,
'subscriptions_cancel.html',
{'rower':r,
'subscriptions':subscriptions
})
@login_required()
def plan_tobasic_view(request,id=0):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
r = getrequestrower(request)
if r.paidplan.paymentprocessor == 'braintree':
success, themessages,errormessages = braintreestuff.cancel_subscription(r,id)
for message in themessages:
messages.info(request,message)
for message in errormessages:
messages.error(request,message)
url = reverse(plan_stop_view)
return HttpResponseRedirect(url)
@login_required()
def upgrade_confirm_view(request,planid = 0):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
try:
plan = PaidPlan.objects.get(id=planid)
except PaidPlan.DoesNotExist:
messages.error(request,"Something went wrong. Please try again.")
url = reverse(billing_view)
return HttpResponseRedirect(url)
r = getrequestrower(request)
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
messages.error(request,'Automated payment processing is currently only available through BrainTree (by PayPal). You are currently on a recurring payment plan with PayPal. Contact the site administrator at support@rowsandall.com before you proceed')
client_token = braintreestuff.get_client_token(r)
return render(request,
"upgradeconfirm.html",
{
'plan':plan,
'client_token':client_token,
'rower':r,
})
@login_required()
def downgrade_confirm_view(request,planid = 0):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
try:
plan = PaidPlan.objects.get(id=planid)
except PaidPlan.DoesNotExist:
messages.error(request,"Something went wrong. Please try again.")
url = reverse(billing_view)
return HttpResponseRedirect(url)
r = getrequestrower(request)
client_token = braintreestuff.get_client_token(r)
return render(request,
"downgradeconfirm.html",
{
'plan':plan,
'client_token':client_token,
'rower':r,
})
@login_required()
def payment_confirm_view(request,planid = 0):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
try:
plan = PaidPlan.objects.get(id=planid)
except PaidPlan.DoesNotExist:
messages.error(request,"Something went wrong. Please try again.")
url = reverse(billing_view)
return HttpResponseRedirect(url)
r = getrequestrower(request)
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
messages.error(request,'Automated payment processing is currently only available through BrainTree (by PayPal). You are currently on a recurring payment plan with PayPal. Contact the site administrator at support@rowsandall.com before you proceed')
client_token = braintreestuff.get_client_token(r)
return render(request,
"paymentconfirm.html",
{
'plan':plan,
'client_token':client_token,
'rower':r,
})
@login_required()
def checkouts_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
r = getrequestrower(request)
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
messages.error(request,'Automated payment processing is currently only available through BrainTree (by PayPal). You are currently on a recurring payment plan with PayPal. Contact the site administrator at support@rowsandall.com before you proceed')
if request.method != 'POST':
url = reverse(paidplans_view)
return HttpResponseRedirect(url)
form = BillingForm(request.POST)
if form.is_valid():
data = form.cleaned_data
success,amount = braintreestuff.create_subscription(r,data)
if success:
messages.info(request,"Your payment has succeeded and your plan has been updated")
url = "{baseurl}?amount={amount:.2f}".format(
baseurl = reverse(payment_completed_view),
amount = amount)
return HttpResponseRedirect(url)
else:
messages.error(request,"There was a problem with your payment")
url = reverse(billing_view)
return HttpResponseRedirect(url)
elif 'tac' not in request.POST:
try:
planid = int(request.POST['plan'])
url = reverse('payment_confirm_view',kwargs={'planid':planid})
messages.error(request,"You must review and acknowledge the terms and conditions")
return HttpResponseRedirect(url)
except IndexError:
messages.error(request,"There was an error in the payment form")
url = reverse('billing_view')
return HttpResponseRedirect(url)
else:
messages.error(request,"There was an error in the payment form")
url = reverse(billing_view)
return HttpResponseRedirect(url)
url = reverse(paidplans_view)
return HttpResponseRedirect(url)
@login_required()
def upgrade_checkouts_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
r = getrequestrower(request)
if request.method != 'POST':
url = reverse(paidplans_view)
return HttpResponseRedirect(url)
form = BillingForm(request.POST)
if form.is_valid():
data = form.cleaned_data
success,amount = braintreestuff.update_subscription(r,data)
if success:
messages.info(request,"Your payment has succeeded and your plan has been updated")
url = "{baseurl}?amount={amount:.2f}".format(
baseurl = reverse(payment_completed_view),
amount = amount)
return HttpResponseRedirect(url)
else:
messages.error(request,"There was a problem with your payment")
url = reverse(upgrade_view)
return HttpResponseRedirect(url)
elif 'tac' not in request.POST:
try:
planid = int(request.POST['plan'])
url = reverse('upgrade_confirm_view',kwargs={'planid':planid})
messages.error(request,"You must review and acknowledge the terms and conditions")
return HttpResponseRedirect(url)
except IndexError:
messages.error(request,"There was an error in the payment form")
url = reverse('billing_view')
return HttpResponseRedirect(url)
else:
messages.error(request,"There was an error in the payment form")
url = reverse(upgrade_view)
return HttpResponseRedirect(url)
url = reverse(paidplans_view)
return HttpResponseRedirect(url)
@login_required()
def downgrade_checkouts_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
r = getrequestrower(request)
if request.method != 'POST':
url = reverse(paidplans_view)
return HttpResponseRedirect(url)
form = BillingForm(request.POST)
if form.is_valid():
data = form.cleaned_data
success = braintreestuff.update_subscription(r,data,method='down')
if success:
messages.info(request,"Your plan has been updated")
url = reverse(downgrade_completed_view)
return HttpResponseRedirect(url)
else:
messages.error(request,"There was a problem with your transaction")
url = reverse(upgrade_view)
return HttpResponseRedirect(url)
elif 'tac' not in request.POST:
try:
planid = int(request.POST['plan'])
url = reverse('downgrade_confirm_view',kwargs={'planid':planid})
messages.error(request,"You must review and acknowledge the terms and conditions")
return HttpResponseRedirect(url)
except IndexError:
messages.error(request,"There was an error in the payment form")
url = reverse('billing_view')
return HttpResponseRedirect(url)
else:
messages.error(request,"There was an error in the payment form")
url = reverse(upgrade_view)
return HttpResponseRedirect(url)
url = reverse(paidplans_view)
return HttpResponseRedirect(url)
@login_required()
def payment_completed_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
amount = request.GET.get('amount',0)
r = getrequestrower(request)
return render(request,
"payment_completed.html",
{
'rower':r,
'amount':amount,
})
@login_required()
def downgrade_completed_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
r = getrequestrower(request)
return render(request,
"downgrade_completed.html",
{
'rower':r
})
# User registration
def rower_register_view(request):
nextpage = request.GET.get('next','/rowers/list-workouts/')
if nextpage == '':
nextpage = '/rowers/list-workouts/'
if request.method == 'POST':
#form = RegistrationFormUniqueEmail(request.POST)
form = RegistrationFormSex(request.POST)
if form.is_valid():
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
password = form.cleaned_data['password1']
username = form.cleaned_data['username']
sex = form.cleaned_data['sex']
birthdate = form.cleaned_data['birthdate']
weightcategory = form.cleaned_data['weightcategory']
adaptiveclass = form.cleaned_data['adaptiveclass']
nextpage = request.POST['next']
theuser = User.objects.create_user(username,password=password)
theuser.first_name = first_name
theuser.last_name = last_name
theuser.email = email
theuser.save()
birthdate = birthdate.replace(tzinfo=None)
therower = Rower(user=theuser,sex=sex,birthdate=birthdate,
weightcategory=weightcategory,
adaptiveclass=adaptiveclass)
therower.save()
# create default favorite charts
add_defaultfavorites(therower)
# Create Sample workout
f = 'media/testdata.csv.gz'
timestr = strftime("%Y%m%d-%H%M%S")
f2 = f[:-7]+timestr+'.csv.gz'
copyfile(f,f2)
response = dataprep.new_workout_from_file(therower,f2,
title='New User Sample Data',
notes='This is an example workout to get you started')
newworkoutid = response[0]
w = Workout.objects.get(id=newworkoutid)
w.startdatetime = timezone.now()
w.save()
# Create and send email
fullemail = first_name + " " + last_name + " " + "<" + email + ">"
subject = "Thank you for registering on rowsandall.com"
from_address = 'Sander Roosendaal <info@rowsandall.com>'
d = {'first_name':theuser.first_name}
send_template_email(from_address,[fullemail],
subject,'registeremail.html',d)
subject2 = "New User"
message2 = "New user registered.\n"
message2 += fullemail + "\n"
message2 += "User name: "+username
send_mail(subject2, message2,
'Rowsandall Server <info@rowsandall.com>',
['roosendaalsander@gmail.com'])
theuser = authenticate(username=username,password=password)
login(request,theuser)
return HttpResponseRedirect(nextpage)
# '/rowers/register/thankyou/')
else:
return render(request,
"registration_form.html",
{'form':form,
'next':nextpage,})
else:
form = RegistrationFormSex()
return render(request,
"registration_form.html",
{'form':form,
'next':nextpage,})
@login_required()
def transactions_view(request):
if not request.user.is_staff:
raise PermissionDenied("Not Allowed")
if request.method == 'POST':
dateform = DateRangeForm(request.POST)
if dateform.is_valid():
startdate = dateform.cleaned_data['startdate']
enddate = dateform.cleaned_data['enddate']
df = braintreestuff.get_transactions(startdate,enddate)
filename="transactions_{s}_{e}.csv".format(s = startdate, e = enddate)
response = HttpResponse(df.to_csv())
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
response['Content-Type'] = 'application/octet-stream'
return response
else:
dateform = DateRangeForm()
return render(request,
'transactions.html',
{
'dateform':dateform
})

2577
rowers/views/planviews.py Normal file

File diff suppressed because it is too large Load Diff

2305
rowers/views/racesviews.py Normal file

File diff suppressed because it is too large Load Diff

1184
rowers/views/statements.py Normal file

File diff suppressed because it is too large Load Diff

536
rowers/views/teamviews.py Normal file
View File

@@ -0,0 +1,536 @@
from statements import *
@login_required()
def team_view(request,id=0,userid=0):
ismember = 0
hasrequested = 0
r = getrequestrower(request,userid=userid)
myteams, memberteams, otherteams = get_teams(request)
teams.remove_expired_invites()
try:
t = Team.objects.get(id=id)
except Team.DoesNotExist:
raise Http404("Team doesn't exist")
if request.method == 'POST' and request.user == t.manager:
inviteform = TeamInviteForm(request.POST)
inviteform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct().exclude(rower__team__name=t.name)
if inviteform.is_valid():
cd = inviteform.cleaned_data
newmember = cd['user']
email = cd['email']
inviteid,text = teams.create_invite(t,t.manager,
user=newmember,
email=email)
if inviteid:
teams.send_invite_email(inviteid)
successmessage = text
messages.info(request,successmessage)
else:
message = text
messages.error(request,message)
elif request.user == t.manager:
inviteform = TeamInviteForm()
inviteform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct().exclude(rower__team__name=t.name)
else:
inviteform = ''
members = Rower.objects.filter(team=t).order_by('user__last_name','user__first_name')
thisteammyrequests = TeamRequest.objects.filter(team=t,user=request.user)
if len(thisteammyrequests):
hasrequested = 1
if r in members:
ismember = 1
breadcrumbs = [
{
'url':reverse(rower_teams_view),
'name': 'Teams'
},
{
'url':reverse(team_view,kwargs={'id':id}),
'name': t.name
}
]
return render(request, 'team.html',
{
'team':t,
'teams':get_my_teams(request.user),
'myteams':myteams,
'memberteams':memberteams,
'members':members,
'breadcrumbs':breadcrumbs,
'active':'nav-teams',
'inviteform':inviteform,
'ismember':ismember,
'hasrequested':hasrequested,
})
@login_required()
def team_leaveconfirm_view(request,id=0):
try:
t = Team.objects.get(id=id)
except Team.DoesNotExist:
raise Http404("Team doesn't exist")
myteams, memberteams, otherteams = get_teams(request)
breadcrumbs = [
{
'url':reverse(rower_teams_view),
'name': 'Teams'
},
{
'url':reverse(team_view,kwargs={'id':id}),
'name': t.name
},
{
'url':reverse(team_leaveconfirm_view,kwargs={'id':id}),
'name': 'Leave'
}
]
return render(request,'teamleaveconfirm.html',
{
'team':t,
'teams':get_my_teams(request.user),
'myteams':myteams,
'memberteams':memberteams,
'otherteams':otherteams,
'active':'nav-teams',
'breadcrumbs':breadcrumbs,
})
@login_required()
def rower_calcdps_view(request):
r = getrower(request.user)
ws = [(w.id,w.csvfilename) for w in Workout.objects.filter(user=r)]
res = myqueue(queue,handle_updatedps,r.user.email,ws,debug=False,
emailbounced=r.emailbounced)
messages.info(request,"Your workouts are being updated in the background. You will receive email when this is done.")
url = reverse('workouts_view')
return HttpResponseRedirect(url)
@login_required()
def team_leave_view(request,id=0):
r = getrower(request.user)
teams.remove_member(id,r)
url = reverse(rower_teams_view)
response = HttpResponseRedirect(url)
return response
from rowers.forms import TeamInviteCodeForm
def get_teams(request):
r = Rower.objects.get(user=request.user)
myteams = Team.objects.filter(
manager=request.user).order_by('name')
memberteams = Team.objects.filter(
rower=r).exclude(manager=request.user).order_by('name')
otherteams = Team.objects.filter(
private='open').exclude(
rower=r).exclude(manager=request.user).order_by('name')
return myteams, memberteams, otherteams
@login_required()
def rower_teams_view(request,message='',successmessage=''):
if request.method == 'POST':
form = TeamInviteCodeForm(request.POST)
if form.is_valid():
code = form.cleaned_data['code']
res,text = teams.process_invite_code(request.user,code)
if res:
successmessage = text
else:
message = text
else:
form = TeamInviteCodeForm()
r = getrower(request.user)
ts = Team.objects.filter(rower=r)
myteams, memberteams, otherteams = get_teams(request)
teams.remove_expired_invites()
invites = TeamInvite.objects.filter(user=request.user)
requests = TeamRequest.objects.filter(user=request.user)
myrequests = TeamRequest.objects.filter(team__in=myteams)
myinvites = TeamInvite.objects.filter(team__in=myteams)
clubsize = teams.count_invites(request.user)+teams.count_club_members(request.user)
max_clubsize = r.clubsize
messages.info(request,successmessage)
messages.error(request,message)
breadcrumbs = [
{
'url':reverse(rower_teams_view),
'name': 'Teams'
}
]
return render(request, 'teams.html',
{
'teams':ts,
'active':'nav-teams',
'breadcrumbs':breadcrumbs,
'clubsize':clubsize,
'max_clubsize':max_clubsize,
'myteams':myteams,
'memberteams':memberteams,
'invites':invites,
'otherteams':otherteams,
'requests':requests,
'myrequests':myrequests,
'form':form,
'myinvites':myinvites,
})
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
def invitation_revoke_view(request,id):
res,text = teams.revoke_invite(request.user,id)
if res:
messages.info(request,text)
successmessage = text
else:
message = text
messages.error(request,text)
url = reverse(rower_teams_view)
return HttpResponseRedirect(url)
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
def manager_member_drop_view(request,teamid,userid,
message='',successmessage=''):
rower = Rower.objects.get(user__id=userid)
res, text = teams.mgr_remove_member(teamid,request.user,rower)
if res:
messages.info(request,text)
else:
messages.error(request,text)
url = reverse(rower_teams_view)
return HttpResponseRedirect(url)
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
def manager_requests_view(request,code=None,message='',successmessage=''):
if code:
res,text = teams.process_request_code(request.user,code)
if res:
successmessage = text
message = ''
else:
message = text
successmessage = ''
messages.info(request,successmessage)
messages.error(request,message)
url = reverse(rower_teams_view,kwargs={
})
return HttpResponseRedirect(url)
@login_required()
def team_requestmembership_view(request,teamid,userid):
try:
t = Team.objects.get(id=teamid)
except Team.DoesNotExist:
raise Http404("Team doesn't exist")
res,text = teams.create_request(t,userid)
if res:
messages.info(request,text)
else:
messages.error(request,text)
url = reverse(team_view,kwargs={
'id':int(teamid),
})
return HttpResponseRedirect(url)
@login_required()
def request_revoke_view(request,id=0):
res,text = teams.revoke_request(request.user,id)
if res:
messages.info(request,text)
else:
messages.error(request,text)
url = reverse(rower_teams_view)
return HttpResponseRedirect(url)
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
def request_reject_view(request,id=0):
res,text = teams.reject_request(request.user,id)
if res:
messages.info(request,text)
else:
messages.error(request,text)
url = reverse(rower_teams_view)
return HttpResponseRedirect(url)
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
def invitation_reject_view(request,id=0):
res,text = teams.reject_invitation(request.user,id)
if res:
messages.info(request,text)
else:
messages.error(request,text)
url = reverse(rower_teams_view)
return HttpResponseRedirect(url)
@login_required()
def rower_invitations_view(request,code=None,message='',successmessage=''):
if code:
teams.remove_expired_invites()
res,text = teams.process_invite_code(request.user,code)
if res:
messages.info(request,text)
teamid=res
url = reverse(team_view,kwargs={
'id':teamid,
})
else:
messages.error(request,text)
url = reverse(rower_teams_view)
return HttpResponseRedirect(url)
url = reverse(rower_teams_view,kwargs={
})
return HttpResponseRedirect(url)
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
def team_edit_view(request,id=0):
try:
t = Team.objects.get(id=id)
except Team.DoesNotExist:
raise Http404("Team does not exist")
if request.method == 'POST':
teamcreateform = TeamForm(request.POST,instance=t)
if teamcreateform.is_valid():
cd = teamcreateform.cleaned_data
name = cd['name']
notes = cd['notes']
manager = request.user
private = cd['private']
viewing = cd['viewing']
res,message=teams.update_team(t,name,manager,private,notes,
viewing)
if res:
messages.info(request,message)
else:
messages.error(request,message)
url = reverse(team_view,
kwargs={
'id':int(id),
}
)
response = HttpResponseRedirect(url)
return response
else:
teamcreateform = TeamForm(instance=t)
myteams, memberteams, otherteams = get_teams(request)
breadcrumbs = [
{
'url':reverse(rower_teams_view),
'name': 'Teams'
},
{
'url':reverse(team_view,kwargs={'id':id}),
'name': t.name
},
{
'url':reverse(team_edit_view,kwargs={'id':id}),
'name': 'Edit'
}
]
return render(request,'teamedit.html',
{
'form':teamcreateform,
'teams':get_my_teams(request.user),
'myteams':myteams,
'memberteams':memberteams,
'otherteams':otherteams,
'active':'nav-teams',
'breadcrumbs':breadcrumbs,
'team':t,
})
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
def team_create_view(request):
if request.method == 'POST':
teamcreateform = TeamForm(request.POST)
if teamcreateform.is_valid():
cd = teamcreateform.cleaned_data
name = cd['name']
notes = cd['notes']
manager = request.user
private = cd['private']
viewing = cd['viewing']
res,message=teams.create_team(name,manager,private,notes,
viewing)
url = reverse(rower_teams_view)
response = HttpResponseRedirect(url)
return response
else:
teamcreateform = TeamForm()
myteams, memberteams, otherteams = get_teams(request)
breadcrumbs = [
{
'url':reverse(rower_teams_view),
'name': 'Teams'
},
{
'url':reverse(team_create_view),
'name': "New Team"
},
]
return render(request,'teamcreate.html',
{
'teams':get_my_teams(request.user),
'form':teamcreateform,
'myteams':myteams,
'memberteams':memberteams,
'otherteams':otherteams,
'active':'nav-teams',
'breadcrumbs':breadcrumbs,
})
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
def team_deleteconfirm_view(request,id):
r = getrower(request.user)
try:
t = Team.objects.get(id=id)
except Team.DoesNotExist:
raise Http404("This team doesn't exist")
if t.manager != request.user:
raise PermissionDenied("You are not allowed to delete this team")
myteams, memberteams, otherteams = get_teams(request)
breadcrumbs = [
{
'url':reverse(rower_teams_view),
'name': 'Teams'
},
{
'url':reverse(team_view,kwargs={'id':id}),
'name': t.name
},
{
'url':reverse(team_deleteconfirm_view,kwargs={'id':id}),
'name': 'Leave'
}
]
return render(request,'teamdeleteconfirm.html',
{
'teams':get_my_teams(request.user),
'team':t,
'myteams':myteams,
'memberteams':memberteams,
'otherteams':otherteams,
'active':'nav-teams',
})
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
def team_delete_view(request,id):
r = getrower(request.user)
try:
t = Team.objects.get(id=id)
except Team.DoesNotExist:
raise Http404("This team doesn't exist")
if t.manager != request.user:
raise PermissionDenied("You are not allowed to delete this team")
teams.remove_team(t.id)
url = reverse(rower_teams_view)
response = HttpResponseRedirect(url)
return response
@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
def team_members_stats_view(request,id):
r = getrower(request.user)
try:
t = Team.objects.get(id=id)
except Team.DoesNotExist:
raise Http404("This team doesn't exist")
if t.manager != request.user:
raise PermissionDenied("You are not allowed to see this page")
members = Rower.objects.filter(team=t).order_by("user__last_name","user__first_name")
theusers = [member.user for member in members]
myteams, memberteams, otherteams = get_teams(request)
breadcrumbs = [
{
'url':reverse(rower_teams_view),
'name': 'Teams'
},
{
'url':reverse(team_view,kwargs={'id':id}),
'name': t.name
},
{
'url':reverse(team_members_stats_view,kwargs={'id':id}),
'name': 'Members Stats'
}
]
response = render(request,'teamstats.html',
{
'teams':get_my_teams(request.user),
'myteams':myteams,
'memberteams':memberteams,
'otherteams':otherteams,
'active':'nav-teams',
'breadcrumbs':breadcrumbs,
'team':t,
'theusers':theusers,
})
return response

485
rowers/views/userviews.py Normal file
View File

@@ -0,0 +1,485 @@
from statements import *
@login_required()
def start_trial_view(request):
r = getrower(request.user)
if r.protrialexpires is not None:
messages.error(request,'You do not qualify for a trial')
url = '/rowers/paidplans'
return HttpResponseRedirect(url)
r.protrialexpires = datetime.date.today()+datetime.timedelta(13)
r.save()
url = reverse(workouts_view)
messages.info(request,'We have started your 14 day trial period')
subject2 = "User started Pro Trial"
message2 = "User Started Pro Trial.\n"
message2 += request.user.email + "\n"
message2 += "User name: "+request.user.username
send_mail(subject2, message2,
'Rowsandall Server <info@rowsandall.com>',
['roosendaalsander@gmail.com'])
return HttpResponseRedirect(url)
@login_required()
def start_plantrial_view(request):
r = getrower(request.user)
if r.plantrialexpires is not None:
messages.error(request,'You do not qualify for a trial')
url = '/rowers/paidplans'
return HttpResponseRedirect(url)
r.plantrialexpires = datetime.date.today()+datetime.timedelta(13)
r.protrialexpires = datetime.date.today()+datetime.timedelta(13)
r.save()
url = reverse(workouts_view)
messages.info(request,'We have started your 14 day trial period')
subject2 = "User started Plan Trial"
message2 = "User Started Plan Trial.\n"
message2 += request.user.email + "\n"
message2 += "User name: "+request.user.username
send_mail(subject2, message2,
'Rowsandall Server <info@rowsandall.com>',
['roosendaalsander@gmail.com'])
return HttpResponseRedirect(url)
# Page where user can manage his favorite charts
@login_required()
def rower_favoritecharts_view(request,userid=0):
message = ''
successmessage = ''
r = getrequestrower(request,userid=userid,notpermanent=True)
favorites = FavoriteChart.objects.filter(user=r).order_by('id')
aantal = len(favorites)
favorites_data = [{'yparam1':f.yparam1,
'yparam2':f.yparam2,
'xparam':f.xparam,
'plottype':f.plottype,
'workouttype':f.workouttype,
'reststrokes':f.reststrokes,
'notes':f.notes,}
for f in favorites]
FavoriteChartFormSet = formset_factory(FavoriteForm,formset=BaseFavoriteFormSet,extra=0)
if aantal==0:
FavoriteChartFormSet = formset_factory(FavoriteForm,formset=BaseFavoriteFormSet,extra=1)
if request.method == 'POST':
favorites_formset = FavoriteChartFormSet(request.POST)
if favorites_formset.is_valid():
new_instances = []
for favorites_form in favorites_formset:
yparam1 = favorites_form.cleaned_data.get('yparam1')
yparam2 = favorites_form.cleaned_data.get('yparam2')
xparam = favorites_form.cleaned_data.get('xparam')
plottype = favorites_form.cleaned_data.get('plottype')
workouttype = favorites_form.cleaned_data.get('workouttype')
reststrokes = favorites_form.cleaned_data.get('reststrokes')
notes = favorites_form.cleaned_data.get('notes')
new_instances.append(FavoriteChart(user=r,
yparam1=yparam1,
yparam2=yparam2,
xparam=xparam,
plottype=plottype,
notes=notes,
workouttype=workouttype,
reststrokes=reststrokes))
try:
with transaction.atomic():
FavoriteChart.objects.filter(user=r).delete()
FavoriteChart.objects.bulk_create(new_instances)
successmessage = "You have updated your favorites"
messages.info(request,message)
if len(new_instances)==0:
FavoriteChartFormSet=formset_factory(FavoriteForm,formset=BaseFavoriteFormSet,extra=1)
favorites_formset = FavoriteChartFormSet()
except IntegrityError:
message = "something went wrong"
messages.error(request,message)
else:
favorites_formset = FavoriteChartFormSet(initial=favorites_data)
context = {
'favorites_formset':favorites_formset,
'teams':get_my_teams(request.user),
'rower':r,
}
return render(request,'favoritecharts.html',context)
# page where user sets his export settings
@login_required()
def rower_exportsettings_view(request,userid=0):
r = getrequestrower(request,userid=userid)
if request.method == 'POST':
form = RowerExportForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
for attr, value in cd.items():
setattr(r, attr, value)
r.save()
messages.info(request,'Settings saved')
else:
form = RowerExportForm(instance=r)
breadcrumbs = [
{
'url':'/rowers/me/edit/',
'name': 'Profile'
},
{
'url': reverse(rower_exportsettings_view),
'name': 'Export Settings'
}
]
return render(request, 'rower_exportsettings.html',
{'form':form,
'rower':r,
'breadcrumbs': breadcrumbs,
})
# Page where user can set his details
# Add email address to form so user can change his email address
@login_required()
def rower_edit_view(request,rowerid=0,userid=0,message=""):
r = getrequestrower(request,rowerid=rowerid,userid=userid,notpermanent=True)
rowerid = r.id
breadcrumbs = [
{
'url':'/rowers/me/edit/',
'name': 'Profile'
},
{
'url': reverse(rower_edit_view),
'name': 'Account Settings'
}
]
if request.method == 'POST':
accountform = AccountRowerForm(request.POST)
userform = UserForm(request.POST,instance=r.user)
if accountform.is_valid() and userform.is_valid():
# process
cd = accountform.cleaned_data
ucd = userform.cleaned_data
first_name = ucd['first_name']
last_name = ucd['last_name']
email = ucd['email']
sex = cd['sex']
adaptiveclass = cd['adaptiveclass']
defaultlandingpage = cd['defaultlandingpage']
weightcategory = cd['weightcategory']
birthdate = cd['birthdate']
showfavoritechartnotes = cd['showfavoritechartnotes']
getemailnotifications = cd['getemailnotifications']
getimportantemails = cd['getimportantemails']
defaulttimezone=cd['defaulttimezone']
u = r.user
if u.email != email and len(email):
resetbounce = True
else:
resetbounce = False
if len(first_name):
u.first_name = first_name
u.last_name = last_name
if len(email): ## and check_email_freeforuse(u,email):
u.email = email
resetbounce = True
u.save()
r.defaulttimezone=defaulttimezone
r.weightcategory = weightcategory
r.adaptiveclass = adaptiveclass
r.getemailnotifications = getemailnotifications
r.getimportantemails = getimportantemails
r.defaultlandingpage = defaultlandingpage
r.showfavoritechartnotes = showfavoritechartnotes
r.sex = sex
r.birthdate = birthdate
if resetbounce and r.emailbounced:
r.emailbounced = False
r.save()
accountform = AccountRowerForm(instance=r)
userform = UserForm(instance=u)
successmessage = 'Account Information changed'
messages.info(request,successmessage)
else:
accountform = AccountRowerForm(instance=r)
userform = UserForm(instance=r.user)
grants = AccessToken.objects.filter(user=request.user)
return render(request, 'rower_form.html',
{
'teams':get_my_teams(request.user),
'breadcrumbs':breadcrumbs,
'grants':grants,
'userform':userform,
'accountform':accountform,
'rower':r,
})
# Page where user can set his details
# Add email address to form so user can change his email address
@login_required()
def rower_prefs_view(request,userid=0,message=""):
r = getrequestrower(request,userid=userid,notpermanent=True)
rowerid = r.id
breadcrumbs = [
{
'url':'/rowers/me/edit/',
'name': 'Profile'
},
{
'url': reverse(rower_prefs_view),
'name': 'Zones'
}
]
form = RowerForm(instance=r)
powerform = RowerPowerForm(instance=r)
powerzonesform = RowerPowerZonesForm(instance=r)
if request.method == 'POST' and "ut2" in request.POST:
form = RowerForm(request.POST)
if form.is_valid():
# something
cd = form.cleaned_data
hrmax = cd['max']
ut2 = cd['ut2']
ut1 = cd['ut1']
at = cd['at']
tr = cd['tr']
an = cd['an']
rest = cd['rest']
r.max = max(min(hrmax,250),10)
r.ut2 = max(min(ut2,250),10)
r.ut1 = max(min(ut1,250),10)
r.at = max(min(at,250),10)
r.tr = max(min(tr,250),10)
r.an = max(min(an,250),10)
r.rest = max(min(rest,250),10)
r.save()
successmessage = "Your Heart Rate data were changed"
messages.info(request,successmessage)
elif request.method == 'POST' and "ftp" in request.POST:
powerform = RowerPowerForm(request.POST)
if powerform.is_valid():
cd = powerform.cleaned_data
hrftp = cd['hrftp']
if hrftp == 0:
hrftp = int((r.an+r.tr)/2.)
ftp = cd['ftp']
otwslack = cd['otwslack']
powerfrac = 100*np.array([r.pw_ut2,
r.pw_ut1,
r.pw_at,
r.pw_tr,r.pw_an])/r.ftp
r.ftp = max(min(ftp,650),50)
r.otwslack = max(min(otwslack,50),0)
ut2,ut1,at,tr,an = (r.ftp*powerfrac/100.).astype(int)
r.pw_ut2 = ut2
r.pw_ut1 = ut1
r.pw_at = at
r.pw_tr = tr
r.pw_an = an
r.hrftp = hrftp
r.save()
message = "FTP and/or OTW slack values changed."
messages.info(request,message)
elif request.method == 'POST' and "ut3name" in request.POST:
powerzonesform = RowerPowerZonesForm(request.POST)
if powerzonesform.is_valid():
cd = powerzonesform.cleaned_data
pw_ut2 = cd['pw_ut2']
pw_ut1 = cd['pw_ut1']
pw_at = cd['pw_at']
pw_tr = cd['pw_tr']
pw_an = cd['pw_an']
ut3name = cd['ut3name']
ut2name = cd['ut2name']
ut1name = cd['ut1name']
atname = cd['atname']
trname = cd['trname']
anname = cd['anname']
powerzones = [ut3name,ut2name,ut1name,atname,trname,anname]
r.pw_ut2 = pw_ut2
r.pw_ut1 = pw_ut1
r.pw_at = pw_at
r.pw_tr = pw_tr
r.pw_an = pw_an
r.powerzones = powerzones
r.save()
successmessage = "Your Power Zone data were changed"
messages.info(request,successmessage)
return render(request, 'rower_preferences.html',
{
'form':form,
'teams':get_my_teams(request.user),
'powerform':powerform,
'powerzonesform':powerzonesform,
'breadcrumbs':breadcrumbs,
'rower':r,
})
# Revoke an app that you granted access through the API.
# this views is called when you press a button on the User edit page
# the button is only there when you have granted access to an app
@login_required()
def rower_revokeapp_view(request,id=0):
try:
tokens = AccessToken.objects.filter(user=request.user,application=id)
refreshtokens = AccessToken.objects.filter(user=request.user,application=id)
for token in tokens:
token.revoke()
for token in refreshtokens:
token.revoke()
r = getrower(request.user)
form = RowerForm(instance=r)
powerform = RowerPowerForm(instance=r)
grants = AccessToken.objects.filter(user=request.user)
url = reverse(rower_edit_view)
return HttpResponseRedirect(url)
except AccessToken.DoesNotExist:
raise Http404("Access token doesn't exist")
@login_required()
def rower_update_empower_view(
request,
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now()
):
try:
r = getrower(request.user)
except Rower.DoesNotExist:
raise Http404("Rower doesn't exist")
if request.method == 'POST' and 'daterange' in request.POST:
dateform = DateRangeForm(request.POST)
if dateform.is_valid():
startdate = dateform.cleaned_data['startdate']
enddate = dateform.cleaned_data['enddate']
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
request.session['startdate'] = startdatestring
request.session['enddate'] = enddatestring
else:
dateform = DateRangeForm(initial={
'startdate':startdate,
'enddate':enddate,
})
if request.method == 'POST' and 'workouts' in request.POST:
form = WorkoutMultipleCompareForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
workouts = cd['workouts']
workoutdicts = []
for w in workouts:
if w.user != r:
message = "You can only alter your own workouts"
messages.error(request,message)
if 'x' in w.boattype and w.oarlength is not None and w.oarlength > 3.30:
message = "Oarlength and boat type mismatch for workout "+str(w.id)+". Skipping workout"
messages.error(request,message)
elif 'x' not in w.boattype and w.oarlength is not None and w.oarlength <= 3.30:
message = "Oarlength and boat type mismatch for workout "+str(w.id)+". Skipping workout"
messages.error(request,message)
elif w.oarlength is None:
message = "Incorrect oarlength in workout "+str(w.id)+". Skipping workout"
messages.error(request,message)
else:
workoutdict = {
'id':w.id,
'boattype':w.boattype,
'filename':w.csvfilename,
'inboard':w.inboard,
'oarlength':w.oarlength
}
workoutdicts.append(workoutdict)
w.workoutsource = 'speedcoach2corrected'
w.save()
job = myqueue(queuelow,handle_update_empower,
request.user.email,workoutdicts,
debug=False,
emailbounced=r.emailbounced)
try:
request.session['async_tasks'] += [(job.id,'update_empower')]
except KeyError:
request.session['async_tasks'] = [(job.id,'update_empower')]
successmessage = 'Your workouts are being updated in the background. You will receive email when this is done. You can check the status of your calculations <a href="/rowers/jobs-status" target="_blank">here</a>'
messages.info(request,successmessage)
url = reverse(workouts_view)
return HttpResponseRedirect(url)
else:
workouts = Workout.objects.filter(
startdatetime__gte=startdate,
startdatetime__lte=enddate,
workoutsource='speedcoach2',
user=r,
).order_by("-date","-starttime")
form = WorkoutMultipleCompareForm()
form.fields["workouts"].queryset = workouts
# GET request = prepare form
return render(request, 'empower_fix.html',
{'workouts':workouts,
'active': 'nav-workouts',
'dateform':dateform,
'form':form,
'rower':r
})

5202
rowers/views/workoutviews.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1757,35 +1757,35 @@ def add_workout_from_strokedata(user,importid,data,strokedata,
unixtime = cum_time+starttimeunix
# unixtime[0] = starttimeunix
seconds = 0.1*strokedata.ix[:,'t']
seconds = 0.1*strokedata.loc[:,'t']
nr_rows = len(unixtime)
try:
latcoord = strokedata.ix[:,'lat']
loncoord = strokedata.ix[:,'lon']
latcoord = strokedata.loc[:,'lat']
loncoord = strokedata.loc[:,'lon']
except:
latcoord = np.zeros(nr_rows)
loncoord = np.zeros(nr_rows)
try:
strokelength = strokedata.ix[:,'strokelength']
strokelength = strokedata.loc[:,'strokelength']
except:
strokelength = np.zeros(nr_rows)
dist2 = 0.1*strokedata.ix[:,'d']
dist2 = 0.1*strokedata.loc[:,'d']
try:
spm = strokedata.ix[:,'spm']
spm = strokedata.loc[:,'spm']
except KeyError:
spm = 0*dist2
try:
hr = strokedata.ix[:,'hr']
hr = strokedata.loc[:,'hr']
except KeyError:
hr = 0*spm
pace = strokedata.ix[:,'p']/10.
pace = strokedata.loc[:,'p']/10.
pace = np.clip(pace,0,1e4)
pace = pace.replace(0,300)
@@ -7967,7 +7967,7 @@ def workout_downloadwind_view(request,id=0,
return HttpResponse("Error: CSV Data File Not Found")
try:
bearing = rowdata.df.ix[:,'bearing'].values
bearing = rowdata.df.loc[:,'bearing'].values
except KeyError:
rowdata.add_bearing()
rowdata.write_csv(f1,gzip=True)
@@ -7976,7 +7976,7 @@ def workout_downloadwind_view(request,id=0,
try:
avglat = rowdata.df[' latitude'].mean()
avglon = rowdata.df[' longitude'].mean()
avgtime = int(rowdata.df['TimeStamp (sec)'].mean()-rowdata.df.ix[0,'TimeStamp (sec)'])
avgtime = int(rowdata.df['TimeStamp (sec)'].mean()-rowdata.df.loc[:,'TimeStamp (sec)'].iloc[0])
startdatetime = dateutil.parser.parse("{}, {}".format(row.date,
row.starttime))
@@ -8033,7 +8033,7 @@ def workout_downloadmetar_view(request,id=0,
return HttpResponse("Error: CSV Data File Not Found")
try:
bearing = rowdata.df.ix[:,'bearing'].values
bearing = rowdata.df.loc[:,'bearing'].values
except KeyError:
rowdata.add_bearing()
rowdata.write_csv(f1,gzip=True)
@@ -8043,7 +8043,7 @@ def workout_downloadmetar_view(request,id=0,
avglat = rowdata.df[' latitude'].mean()
avglon = rowdata.df[' longitude'].mean()
airportcode = get_airport_code(avglat,avglon)[0]
avgtime = int(rowdata.df['TimeStamp (sec)'].mean()-rowdata.df.ix[0,'TimeStamp (sec)'])
avgtime = int(rowdata.df['TimeStamp (sec)'].mean()-rowdata.df.loc[:,'TimeStamp (sec)'].iloc[0])
startdatetime = dateutil.parser.parse("{}, {}".format(row.date,
row.starttime))
@@ -8121,7 +8121,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""):
hascoordinates = 1
try:
latitude = rowdata.df.ix[:,' latitude']
latitude = rowdata.df.loc[:,' latitude']
except KeyError:
hascoordinates = 0
@@ -8129,7 +8129,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""):
hascoordinates = 0
try:
bearing = rowdata.df.ix[:,'bearing'].values
bearing = rowdata.df.loc[:,'bearing'].values
except KeyError:
rowdata.add_bearing()
rowdata.write_csv(f1,gzip=True)
@@ -8811,7 +8811,7 @@ def cumstats(request,theuser=0,
thedict = {}
for field2,verbosename in fielddict.iteritems():
try:
thedict[field2] = cor.ix[field1,field2]
thedict[field2] = cor.loc[field1,field2]
except KeyError:
thedict[field2] = 0
@@ -9030,7 +9030,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
thedict = {}
for field2,verbosename in fielddict.iteritems():
try:
thedict[field2] = cor.ix[field1,field2]
thedict[field2] = cor.loc[field1,field2]
except KeyError:
thedict[field2] = 0
@@ -14167,6 +14167,7 @@ def plannedsession_create_view(request,
enddatestring=enddatestring)
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(request.POST)
if sessioncreateform.is_valid():
@@ -14439,7 +14440,8 @@ def plannedsession_teamcreate_view(request,
sessioncreateform = PlannedSessionForm(request.POST)
sessionteamselectform = PlannedSessionTeamForm(
request.user,request.POST
)
)
if sessioncreateform.is_valid() and sessionteamselectform.is_valid():
cd = sessioncreateform.cleaned_data
startdate = cd['startdate']
@@ -18412,12 +18414,7 @@ class TrainingTargetUpdate(UpdateView):
return obj
def allsundays(startdate,enddate):
d = startdate
d += timedelta(days = 6 - d.weekday()) # first Sunday
while d<=enddate:
yield d
d += timedelta(days=7)
from rowers.utils import allsundays
@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans",
message="This functionality requires a Coach or Self-Coach plan",
@@ -18472,12 +18469,7 @@ def planmesocyclebyweek(request,id=0,userid=0):
return HttpResponseRedirect(url)
def allmonths(startdate,enddate):
d = startdate
while d<enddate:
yield d
d = datetime.date(d.year+(d.month / 12),((d.month % 12) + 1),1)
from rowers.utils import allmonths
@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans",
message="This functionality requires a Coach or Self-Coach plan",