Private
Public Access
1
0

half way through cleaning up and commenting the code

This commit is contained in:
Sander Roosendaal
2017-01-13 14:36:05 +01:00
parent 24364dcfb1
commit 220bc531dd
38 changed files with 140 additions and 2682 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,110 +0,0 @@
TimeStamp (sec), activityIdx, lapIdx, pointIdx, ElapsedTime (sec), Horizontal (meters), Stroke500mPace (sec/500m), Cadence (stokes/min), HRCur (bpm), Power (watts), Calories (kCal), Speed (m/sec), StrokeCount, StrokeDistance (meters), DriveLength (meters), DriveTime (ms), StrokeRecoveryTime (ms), WorkPerStroke (joules), AverageDriveForce (lbs), PeakDriveForce (lbs), DragFactor
1461004356.11047, 0, 0, 0, 1.34, 5.8, 124.45, 0, 112, 184, 0, 4.033, 1, 2.67, 1.18, 660, 430, 0, 148.4, 228.3, 0
1461004357.37363, 0, 0, 1, 2.64, 11.9, 107.86, 52, 114, 283, 0, 4.657, 2, 5.4, 1.18, 530, 570, 0, 134.4, 209.7, 110
1461004358.86966, 0, 0, 2, 4.11, 19.5, 102.66, 46, 118, 328, 1, 4.894, 3, 6.36, 1.33, 520, 730, 0, 137.8, 226.2, 110
1461004360.40359, 0, 0, 3, 5.69, 28, 95.64, 40, 120, 406, 1, 5.254, 4, 7.8, 1.45, 540, 830, 0, 139, 219.9, 111
1461004361.99023, 0, 0, 4, 7.26, 36.7, 92.38, 38, 125, 451, 2, 5.441, 5, 8.59, 1.48, 530, 820, 0, 141, 223.7, 110
1461004363.64047, 0, 0, 5, 8.89, 45.7, 90.84, 38, 132, 475, 3, 5.534, 6, 8.66, 1.48, 540, 890, 0, 132.9, 245.3, 110
1461004365.29068, 0, 0, 6, 10.55, 54.7, 91.31, 37, 135, 467, 4, 5.505, 7, 8.86, 1.42, 510, 930, 0, 138.6, 222.8, 110
1461004367.00093, 0, 0, 7, 12.24, 64, 92.1, 36, 141, 455, 5, 5.458, 8, 9.21, 1.48, 540, 930, 0, 134.8, 226.9, 110
1461004368.65075, 0, 0, 8, 13.93, 73.1, 92.54, 36, 144, 455, 5, 5.432, 9, 9.14, 1.48, 550, 930, 0, 131.2, 234.4, 110
1461004370.51044, 0, 0, 9, 15.79, 82.9, 93.32, 36, 152, 438, 6, 5.386, 10, 9.07, 1.45, 550, 1110, 0, 124.9, 211.2, 110
1461004372.4003, 0, 0, 10, 17.68, 92.6, 95.87, 32, 156, 403, 7, 5.242, 11, 9.79, 1.42, 550, 1150, 0, 123.9, 209.1, 110
1461004374.35136, 0, 0, 11, 19.63, 102.5, 98.2, 31, 160, 375, 8, 5.117, 12, 9.86, 1.45, 570, 1160, 0, 121.1, 210.9, 110
1461004376.27099, 0, 0, 12, 21.55, 112.1, 99.61, 31, 164, 359, 9, 5.044, 13, 9.79, 1.45, 590, 1150, 0, 118.8, 219.1, 110
1461004378.07035, 0, 0, 13, 23.34, 121.2, 100.17, 31, 166, 353, 10, 5.016, 14, 9.79, 1.48, 590, 1150, 0, 122.6, 208.4, 110
1461004380.05067, 0, 0, 14, 25.32, 131.2, 99.45, 32, 168, 361, 10, 5.052, 15, 9.51, 1.45, 580, 1090, 0, 126.1, 218, 110
1461004382.00372, 0, 0, 15, 27.24, 140.9, 98.98, 32, 169, 366, 11, 5.076, 16, 9.51, 1.45, 580, 1130, 0, 119.5, 204.9, 110
1461004383.89027, 0, 0, 16, 29.16, 150.5, 99.84, 31, 171, 357, 12, 5.032, 17, 9.58, 1.42, 570, 1140, 0, 120.1, 213.3, 110
1461004385.68965, 0, 0, 17, 30.96, 159.6, 100.5, 31, 172, 350, 13, 4.999, 18, 9.79, 1.51, 610, 1140, 0, 117.3, 210.8, 110
1461004387.79028, 0, 0, 18, 33.05, 169.9, 100.34, 32, 173, 352, 14, 5.007, 19, 9.44, 1.45, 580, 1190, 0, 119.7, 198.6, 110
1461004389.74033, 0, 0, 19, 35.02, 179.8, 100.57, 30, 174, 349, 15, 4.996, 20, 9.87, 1.45, 580, 1180, 0, 126.1, 212.6, 110
1461004391.6934, 0, 0, 20, 36.97, 189.6, 100.2, 30, 174, 353, 15, 5.014, 21, 9.86, 1.45, 580, 1160, 0, 124.7, 204.5, 110
1461004393.70408, 0, 0, 21, 38.96, 199.5, 100.1, 31, 175, 354, 16, 5.019, 22, 9.78, 1.45, 580, 1190, 0, 120.2, 202.3, 110
1461004395.67953, 0, 0, 22, 40.9, 209.2, 100.99, 30, 175, 345, 17, 4.975, 23, 9.85, 1.45, 590, 1160, 0, 119.7, 197.6, 110
1461004397.41974, 0, 1, 0, 42.69, 218.2, 101.05, 31, 176, 344, 18, 4.972, 24, 9.71, 1.45, 600, 1160, 0, 121.1, 202.9, 110
1461004399.46009, 0, 1, 1, 44.72, 228.3, 100.13, 32, 176, 354, 19, 5.018, 25, 9.51, 1.45, 580, 1130, 0, 121.8, 207.3, 110
1461004401.3506, 0, 1, 2, 46.62, 237.8, 100.06, 31, 176, 355, 19, 5.021, 26, 9.64, 1.45, 580, 1110, 0, 116.5, 207.4, 110
1461004403.29953, 0, 1, 3, 48.42, 246.9, 100.65, 31, 176, 348, 20, 4.992, 27, 9.57, 1.48, 600, 1110, 0, 123, 211.5, 110
1461004405.22022, 0, 1, 4, 50.47, 257.2, 99.69, 32, 177, 359, 21, 5.04, 28, 9.58, 1.45, 580, 1130, 0, 124.3, 208.8, 110
1461004407.19972, 0, 1, 5, 52.39, 266.9, 99.47, 31, 177, 361, 22, 5.051, 29, 9.65, 1.45, 580, 1150, 0, 120.4, 207.4, 110
1461004408.9101, 0, 1, 6, 54.17, 276, 99.87, 31, 177, 357, 23, 5.031, 30, 9.72, 1.45, 580, 1150, 0, 126.3, 210.5, 110
1461004411.00986, 0, 1, 7, 56.23, 286.3, 99.22, 32, 177, 364, 23, 5.064, 31, 9.51, 1.42, 560, 1170, 0, 125.6, 215.2, 110
1461004412.77946, 0, 1, 8, 58.04, 295.5, 99.56, 31, 177, 360, 24, 5.047, 32, 9.86, 1.45, 580, 1170, 0, 121.8, 214.4, 110
1461004414.82028, 0, 1, 9, 60.1, 305.8, 99.94, 31, 178, 356, 25, 5.027, 33, 9.71, 1.45, 600, 1160, 0, 120.6, 210.2, 110
1461004416.8312, 0, 1, 10, 62.04, 315.5, 99.94, 31, 178, 356, 26, 5.028, 34, 9.78, 1.45, 580, 1160, 0, 124, 222.3, 110
1461004418.72014, 0, 1, 11, 63.99, 325.3, 99.87, 31, 178, 357, 27, 5.031, 35, 9.78, 1.45, 580, 1140, 0, 123.7, 208.6, 110
1461004420.67038, 0, 1, 12, 65.93, 335.1, 99.71, 31, 178, 358, 28, 5.039, 36, 9.79, 1.48, 590, 1140, 0, 121.8, 218.6, 109
1461004422.49949, 0, 1, 13, 67.76, 344.4, 99.81, 31, 179, 357, 28, 5.034, 37, 9.71, 1.45, 590, 1140, 0, 121.9, 212.9, 110
1461004424.56946, 0, 1, 14, 69.81, 354.6, 99.91, 31, 179, 356, 29, 5.029, 38, 9.79, 1.42, 570, 1170, 0, 122.3, 208.7, 110
1461004426.45946, 0, 1, 15, 71.72, 364.2, 100.48, 31, 179, 350, 30, 5, 39, 9.78, 1.45, 580, 1120, 0, 122.7, 209, 110
1461004428.22943, 0, 1, 16, 73.51, 373.3, 99.94, 32, 179, 356, 31, 5.028, 40, 9.57, 1.45, 580, 1120, 0, 123.5, 229.9, 110
1461004430.30156, 0, 1, 17, 75.51, 383.3, 99.42, 32, 179, 362, 32, 5.054, 41, 9.5, 1.42, 560, 1120, 0, 124.8, 208.4, 109
1461004432.16011, 0, 1, 18, 77.41, 393, 99.26, 32, 179, 363, 32, 5.062, 42, 9.63, 1.45, 580, 1130, 0, 122.9, 226.6, 110
1461004434.10936, 0, 1, 19, 79.34, 402.7, 99.5, 32, 179, 361, 33, 5.05, 43, 9.56, 1.42, 560, 1150, 0, 124.9, 218.3, 110
1461004436.0894, 0, 2, 0, 81.3, 412.5, 99.64, 31, 179, 359, 34, 5.043, 44, 9.71, 1.42, 570, 1180, 0, 122.6, 212.9, 109
1461004437.86025, 0, 2, 1, 83.1, 421.6, 100.31, 31, 180, 352, 35, 5.009, 45, 9.84, 1.45, 600, 1180, 0, 120.4, 215.3, 110
1461004439.89998, 0, 2, 2, 85.14, 431.8, 100.11, 31, 180, 354, 36, 5.019, 46, 9.78, 1.48, 590, 1110, 0, 123.2, 213.3, 110
1461004441.81943, 0, 2, 3, 87.07, 441.6, 99.56, 32, 180, 360, 37, 5.047, 47, 9.51, 1.42, 570, 1160, 0, 123.4, 209.6, 110
1461004443.77011, 0, 2, 4, 89.02, 451.3, 99.72, 31, 180, 358, 37, 5.038, 48, 9.79, 1.45, 590, 1160, 0, 121.4, 212.2, 110
1461004445.59931, 0, 2, 5, 90.83, 460.6, 100.05, 31, 180, 355, 38, 5.022, 49, 9.71, 1.42, 570, 1160, 0, 126.1, 214.7, 110
1461004447.6099, 0, 2, 6, 92.85, 470.7, 99.57, 31, 180, 360, 39, 5.046, 50, 9.78, 1.45, 580, 1120, 0, 126, 216.2, 110
1461004449.55928, 0, 2, 7, 94.78, 480.5, 99.2, 32, 181, 364, 40, 5.065, 51, 9.63, 1.45, 590, 1150, 0, 122, 229.7, 109
1461004451.4801, 0, 2, 8, 96.72, 490.3, 99.47, 31, 181, 361, 41, 5.051, 52, 9.7, 1.42, 560, 1170, 0, 124.9, 221.2, 110
1461004453.33954, 0, 2, 9, 98.57, 499.5, 100.01, 31, 181, 355, 42, 5.024, 53, 9.85, 1.45, 580, 1170, 0, 119.2, 209, 109
1461004455.4099, 0, 2, 10, 100.66, 509.9, 100.76, 31, 181, 347, 42, 4.986, 54, 9.77, 1.45, 590, 1180, 0, 121.6, 224.3, 110
1461004457.36002, 0, 2, 11, 102.6, 519.6, 100.59, 31, 181, 349, 43, 4.995, 55, 9.78, 1.42, 580, 1160, 0, 123.1, 212.1, 109
1461004459.31064, 0, 2, 12, 104.58, 529.5, 100.3, 31, 181, 352, 44, 5.009, 56, 9.77, 1.45, 580, 1190, 0, 122.6, 216.3, 109
1461004461.16922, 0, 2, 13, 106.42, 538.7, 100.5, 30, 181, 350, 45, 4.999, 57, 9.92, 1.45, 580, 1190, 0, 120.4, 213.9, 110
1461004463.26918, 0, 2, 14, 108.49, 549, 100.79, 31, 181, 347, 46, 4.985, 58, 9.71, 1.45, 580, 1150, 0, 121.7, 216.6, 110
1461004465.10101, 0, 2, 15, 110.36, 558.4, 100.66, 31, 181, 348, 46, 4.991, 59, 9.63, 1.42, 570, 1110, 0, 120.4, 218.1, 109
1461004467.01999, 0, 2, 16, 112.26, 567.8, 100.59, 32, 181, 349, 47, 4.995, 60, 9.41, 1.42, 570, 1120, 0, 121.8, 227.8, 109
1461004468.90954, 0, 2, 17, 114.14, 577.3, 100.48, 31, 181, 350, 48, 5, 61, 9.55, 1.45, 600, 1090, 0, 117.8, 218, 109
1461004470.80092, 0, 2, 18, 116.06, 586.9, 100.11, 32, 181, 354, 49, 5.019, 62, 9.49, 1.48, 610, 1110, 0, 115, 209.3, 110
1461004472.72009, 0, 2, 19, 117.97, 596.5, 100.44, 32, 181, 351, 50, 5.002, 63, 9.49, 1.45, 580, 1130, 0, 120.6, 209.1, 110
1461004474.60979, 0, 2, 20, 119.87, 606, 100.28, 31, 182, 352, 50, 5.01, 64, 9.57, 1.42, 570, 1120, 0, 120, 217.9, 109
1461004476.4385, 0, 3, 0, 121.65, 614.9, 100.89, 32, 181, 346, 51, 4.98, 65, 9.41, 1.39, 570, 1120, 0, 118.6, 211.9, 110
1461004478.47986, 0, 3, 1, 123.73, 625.1, 101.01, 31, 182, 345, 52, 4.974, 66, 9.71, 1.48, 600, 1130, 0, 115.3, 219.1, 110
1461004480.27929, 0, 3, 2, 125.52, 634.1, 101.24, 31, 182, 342, 53, 4.962, 67, 9.57, 1.45, 590, 1130, 0, 121.4, 219, 110
1461004482.37966, 0, 3, 3, 127.6, 644.4, 100.67, 32, 181, 348, 54, 4.991, 68, 9.42, 1.42, 570, 1190, 0, 118.7, 218.1, 109
1461004484.29991, 0, 3, 4, 129.56, 654.1, 101.34, 30, 181, 341, 54, 4.958, 69, 9.85, 1.45, 590, 1140, 0, 121.6, 220.8, 110
1461004486.16014, 0, 3, 5, 131.41, 663.4, 100.79, 31, 181, 347, 55, 4.985, 70, 9.57, 1.42, 570, 1090, 0, 122.9, 210.4, 110
1461004488.07993, 0, 3, 6, 133.33, 673, 100.32, 32, 181, 352, 56, 5.008, 71, 9.35, 1.42, 570, 1140, 0, 118.5, 206.8, 109
1461004490.03001, 0, 3, 7, 135.27, 682.6, 100.98, 31, 181, 345, 57, 4.975, 72, 9.56, 1.42, 580, 1150, 0, 116.9, 218.1, 109
1461004491.97913, 0, 3, 8, 137.22, 692.3, 101.5, 31, 181, 340, 58, 4.95, 73, 9.63, 1.45, 590, 1150, 0, 118.7, 221.9, 110
1461004493.77931, 0, 3, 9, 138.99, 701.1, 101.41, 31, 181, 341, 58, 4.954, 74, 9.57, 1.42, 580, 1150, 0, 119, 205.9, 110
1461004495.78987, 0, 3, 10, 141.04, 711.2, 101.29, 31, 181, 342, 59, 4.96, 75, 9.64, 1.48, 600, 1100, 0, 116.2, 222.9, 110
1461004497.64987, 0, 3, 11, 142.92, 720.6, 101.08, 32, 181, 344, 60, 4.971, 76, 9.36, 1.42, 590, 1090, 0, 120.4, 210.2, 110
1461004499.56987, 0, 3, 12, 144.81, 730, 100.32, 32, 182, 352, 61, 5.008, 77, 9.35, 1.42, 570, 1130, 0, 119.2, 218.4, 109
1461004501.45977, 0, 3, 13, 146.71, 739.5, 100.77, 32, 181, 347, 61, 4.986, 78, 9.49, 1.42, 570, 1110, 0, 119.5, 210.1, 109
1461004503.31974, 0, 3, 14, 148.59, 748.9, 100.91, 32, 182, 346, 62, 4.979, 79, 9.41, 1.42, 590, 1100, 0, 117.6, 217.4, 109
1461004505.20973, 0, 3, 15, 150.44, 758.1, 100.85, 32, 181, 346, 63, 4.982, 80, 9.34, 1.42, 590, 1090, 0, 114.9, 212.3, 109
1461004507.04, 0, 3, 16, 152.26, 767.2, 100.96, 32, 181, 345, 64, 4.976, 81, 9.27, 1.42, 580, 1030, 0, 118.6, 222, 109
1461004508.78319, 0, 3, 17, 154, 775.9, 100.29, 33, 182, 352, 65, 5.01, 82, 9.06, 1.42, 570, 1030, 0, 116.3, 208.4, 109
1461004510.72907, 0, 3, 18, 155.96, 785.7, 100.51, 32, 182, 350, 65, 4.999, 83, 9.42, 1.48, 610, 1050, 0, 114.2, 220.8, 110
1461004512.58978, 0, 3, 19, 157.79, 794.9, 100.32, 33, 182, 352, 66, 5.008, 84, 9.07, 1.39, 560, 1070, 0, 116.1, 211.2, 109
1461004514.42009, 0, 3, 20, 159.65, 804, 101.03, 32, 182, 344, 67, 4.973, 85, 9.27, 1.45, 590, 1040, 0, 112.5, 199.5, 109
1461004516.18978, 0, 4, 0, 161.46, 813, 101.62, 33, 182, 338, 68, 4.944, 86, 8.98, 1.39, 580, 1050, 0, 111.6, 200.2, 109
1461004518.07996, 0, 4, 1, 163.33, 822.2, 101.73, 33, 181, 337, 68, 4.938, 87, 8.99, 1.39, 560, 1100, 0, 114.6, 206.4, 109
1461004519.90999, 0, 4, 2, 165.15, 831.2, 102.27, 32, 181, 332, 69, 4.912, 88, 9.2, 1.39, 570, 1050, 0, 115.6, 204.9, 110
1461004521.74184, 0, 4, 3, 166.98, 840.2, 101.9, 32, 182, 336, 70, 4.93, 89, 9.14, 1.45, 590, 1010, 0, 110, 200, 110
1461004523.59979, 0, 4, 4, 168.81, 849.2, 101.98, 34, 182, 335, 71, 4.926, 90, 8.71, 1.36, 550, 1070, 0, 114.6, 206, 110
1461004525.36992, 0, 4, 5, 170.62, 858, 102.27, 32, 181, 332, 71, 4.912, 91, 9.07, 1.39, 570, 1040, 0, 111.7, 185.3, 109
1461004527.19977, 0, 4, 6, 172.43, 866.9, 102.47, 33, 181, 330, 72, 4.902, 92, 8.92, 1.39, 570, 1040, 0, 114, 195, 109
1461004529.06276, 0, 4, 7, 174.32, 876.2, 102.31, 33, 181, 332, 73, 4.91, 93, 8.99, 1.42, 580, 1080, 0, 110.1, 199.7, 110
1461004530.82905, 0, 4, 8, 176.02, 884.6, 102.69, 32, 181, 328, 74, 4.892, 94, 9.14, 1.42, 580, 1080, 0, 113.9, 216.3, 110
1461004532.75083, 0, 4, 9, 177.99, 894.1, 102.44, 33, 181, 330, 74, 4.904, 95, 8.99, 1.42, 580, 1060, 0, 108.7, 196, 109
1461004534.39983, 0, 4, 10, 179.66, 902.4, 102.85, 32, 181, 326, 75, 4.884, 96, 9.05, 1.42, 580, 1060, 0, 114.9, 199.6, 109
1461004536.32286, 0, 4, 11, 181.59, 911.9, 101.55, 34, 182, 339, 76, 4.947, 97, 8.85, 1.45, 590, 1000, 0, 110.6, 199, 110
1461004538.06289, 0, 4, 12, 183.32, 920.5, 101.39, 34, 181, 341, 76, 4.955, 98, 8.78, 1.39, 580, 970, 0, 109.7, 195.2, 110
1461004539.89296, 0, 4, 13, 185.11, 929.4, 101.35, 34, 181, 341, 77, 4.957, 99, 8.71, 1.42, 570, 1010, 0, 112.5, 207.2, 109
1461004541.6899, 0, 4, 14, 186.8, 937.8, 101.24, 33, 181, 342, 78, 4.962, 100, 8.92, 1.42, 570, 1010, 0, 112.9, 206.9, 109
1461004543.39974, 0, 4, 15, 188.64, 946.9, 101.37, 34, 181, 341, 79, 4.956, 101, 8.85, 1.39, 560, 940, 0, 112.1, 200.7, 110
1461004545.11348, 0, 4, 16, 190.34, 955.4, 101, 35, 181, 345, 79, 4.975, 102, 8.42, 1.36, 560, 970, 0, 113.8, 187.5, 110
1461004546.85166, 0, 4, 17, 192.1, 964.1, 100.78, 35, 180, 347, 80, 4.985, 103, 8.57, 1.36, 550, 1010, 0, 109.9, 194.7, 110
1461004548.65002, 0, 4, 18, 193.91, 973, 101.83, 34, 181, 336, 81, 4.934, 104, 8.78, 1.39, 580, 1010, 0, 107.6, 188.8, 110
1461004550.35928, 0, 4, 19, 195.6, 981.3, 102.6, 34, 181, 329, 81, 4.896, 105, 8.71, 1.36, 560, 1010, 0, 108.9, 183.6, 110
1461004552.30971, 0, 4, 20, 197.53, 990.5, 103.54, 33, 181, 320, 82, 4.852, 106, 8.86, 1.36, 560, 1040, 0, 102.4, 187.2, 110
1461004554.19972, 0, 4, 21, 199.44, 999.5, 105.35, 33, 180, 304, 83, 4.768, 107, 8.7, 1.33, 590, 1110, 0, 100, 181.7, 109
1461004554.35294, 0, 4, 22, 199.56, 1000, 105.35, 33, 180, 304, 83, 4.768, 107, 8.7, 1.33, 590, 1110, 0, 100, 181.7, 109
1461004556.03066, 0, 6, 0, 199.57, 1000, 105.35, 33, 180, 304, 83, 4.768, 107, 8.7, 1.33, 590, 1110, 0, 100, 181.7, 109
1 TimeStamp (sec) activityIdx lapIdx pointIdx ElapsedTime (sec) Horizontal (meters) Stroke500mPace (sec/500m) Cadence (stokes/min) HRCur (bpm) Power (watts) Calories (kCal) Speed (m/sec) StrokeCount StrokeDistance (meters) DriveLength (meters) DriveTime (ms) StrokeRecoveryTime (ms) WorkPerStroke (joules) AverageDriveForce (lbs) PeakDriveForce (lbs) DragFactor
2 1461004356.11047 0 0 0 1.34 5.8 124.45 0 112 184 0 4.033 1 2.67 1.18 660 430 0 148.4 228.3 0
3 1461004357.37363 0 0 1 2.64 11.9 107.86 52 114 283 0 4.657 2 5.4 1.18 530 570 0 134.4 209.7 110
4 1461004358.86966 0 0 2 4.11 19.5 102.66 46 118 328 1 4.894 3 6.36 1.33 520 730 0 137.8 226.2 110
5 1461004360.40359 0 0 3 5.69 28 95.64 40 120 406 1 5.254 4 7.8 1.45 540 830 0 139 219.9 111
6 1461004361.99023 0 0 4 7.26 36.7 92.38 38 125 451 2 5.441 5 8.59 1.48 530 820 0 141 223.7 110
7 1461004363.64047 0 0 5 8.89 45.7 90.84 38 132 475 3 5.534 6 8.66 1.48 540 890 0 132.9 245.3 110
8 1461004365.29068 0 0 6 10.55 54.7 91.31 37 135 467 4 5.505 7 8.86 1.42 510 930 0 138.6 222.8 110
9 1461004367.00093 0 0 7 12.24 64 92.1 36 141 455 5 5.458 8 9.21 1.48 540 930 0 134.8 226.9 110
10 1461004368.65075 0 0 8 13.93 73.1 92.54 36 144 455 5 5.432 9 9.14 1.48 550 930 0 131.2 234.4 110
11 1461004370.51044 0 0 9 15.79 82.9 93.32 36 152 438 6 5.386 10 9.07 1.45 550 1110 0 124.9 211.2 110
12 1461004372.4003 0 0 10 17.68 92.6 95.87 32 156 403 7 5.242 11 9.79 1.42 550 1150 0 123.9 209.1 110
13 1461004374.35136 0 0 11 19.63 102.5 98.2 31 160 375 8 5.117 12 9.86 1.45 570 1160 0 121.1 210.9 110
14 1461004376.27099 0 0 12 21.55 112.1 99.61 31 164 359 9 5.044 13 9.79 1.45 590 1150 0 118.8 219.1 110
15 1461004378.07035 0 0 13 23.34 121.2 100.17 31 166 353 10 5.016 14 9.79 1.48 590 1150 0 122.6 208.4 110
16 1461004380.05067 0 0 14 25.32 131.2 99.45 32 168 361 10 5.052 15 9.51 1.45 580 1090 0 126.1 218 110
17 1461004382.00372 0 0 15 27.24 140.9 98.98 32 169 366 11 5.076 16 9.51 1.45 580 1130 0 119.5 204.9 110
18 1461004383.89027 0 0 16 29.16 150.5 99.84 31 171 357 12 5.032 17 9.58 1.42 570 1140 0 120.1 213.3 110
19 1461004385.68965 0 0 17 30.96 159.6 100.5 31 172 350 13 4.999 18 9.79 1.51 610 1140 0 117.3 210.8 110
20 1461004387.79028 0 0 18 33.05 169.9 100.34 32 173 352 14 5.007 19 9.44 1.45 580 1190 0 119.7 198.6 110
21 1461004389.74033 0 0 19 35.02 179.8 100.57 30 174 349 15 4.996 20 9.87 1.45 580 1180 0 126.1 212.6 110
22 1461004391.6934 0 0 20 36.97 189.6 100.2 30 174 353 15 5.014 21 9.86 1.45 580 1160 0 124.7 204.5 110
23 1461004393.70408 0 0 21 38.96 199.5 100.1 31 175 354 16 5.019 22 9.78 1.45 580 1190 0 120.2 202.3 110
24 1461004395.67953 0 0 22 40.9 209.2 100.99 30 175 345 17 4.975 23 9.85 1.45 590 1160 0 119.7 197.6 110
25 1461004397.41974 0 1 0 42.69 218.2 101.05 31 176 344 18 4.972 24 9.71 1.45 600 1160 0 121.1 202.9 110
26 1461004399.46009 0 1 1 44.72 228.3 100.13 32 176 354 19 5.018 25 9.51 1.45 580 1130 0 121.8 207.3 110
27 1461004401.3506 0 1 2 46.62 237.8 100.06 31 176 355 19 5.021 26 9.64 1.45 580 1110 0 116.5 207.4 110
28 1461004403.29953 0 1 3 48.42 246.9 100.65 31 176 348 20 4.992 27 9.57 1.48 600 1110 0 123 211.5 110
29 1461004405.22022 0 1 4 50.47 257.2 99.69 32 177 359 21 5.04 28 9.58 1.45 580 1130 0 124.3 208.8 110
30 1461004407.19972 0 1 5 52.39 266.9 99.47 31 177 361 22 5.051 29 9.65 1.45 580 1150 0 120.4 207.4 110
31 1461004408.9101 0 1 6 54.17 276 99.87 31 177 357 23 5.031 30 9.72 1.45 580 1150 0 126.3 210.5 110
32 1461004411.00986 0 1 7 56.23 286.3 99.22 32 177 364 23 5.064 31 9.51 1.42 560 1170 0 125.6 215.2 110
33 1461004412.77946 0 1 8 58.04 295.5 99.56 31 177 360 24 5.047 32 9.86 1.45 580 1170 0 121.8 214.4 110
34 1461004414.82028 0 1 9 60.1 305.8 99.94 31 178 356 25 5.027 33 9.71 1.45 600 1160 0 120.6 210.2 110
35 1461004416.8312 0 1 10 62.04 315.5 99.94 31 178 356 26 5.028 34 9.78 1.45 580 1160 0 124 222.3 110
36 1461004418.72014 0 1 11 63.99 325.3 99.87 31 178 357 27 5.031 35 9.78 1.45 580 1140 0 123.7 208.6 110
37 1461004420.67038 0 1 12 65.93 335.1 99.71 31 178 358 28 5.039 36 9.79 1.48 590 1140 0 121.8 218.6 109
38 1461004422.49949 0 1 13 67.76 344.4 99.81 31 179 357 28 5.034 37 9.71 1.45 590 1140 0 121.9 212.9 110
39 1461004424.56946 0 1 14 69.81 354.6 99.91 31 179 356 29 5.029 38 9.79 1.42 570 1170 0 122.3 208.7 110
40 1461004426.45946 0 1 15 71.72 364.2 100.48 31 179 350 30 5 39 9.78 1.45 580 1120 0 122.7 209 110
41 1461004428.22943 0 1 16 73.51 373.3 99.94 32 179 356 31 5.028 40 9.57 1.45 580 1120 0 123.5 229.9 110
42 1461004430.30156 0 1 17 75.51 383.3 99.42 32 179 362 32 5.054 41 9.5 1.42 560 1120 0 124.8 208.4 109
43 1461004432.16011 0 1 18 77.41 393 99.26 32 179 363 32 5.062 42 9.63 1.45 580 1130 0 122.9 226.6 110
44 1461004434.10936 0 1 19 79.34 402.7 99.5 32 179 361 33 5.05 43 9.56 1.42 560 1150 0 124.9 218.3 110
45 1461004436.0894 0 2 0 81.3 412.5 99.64 31 179 359 34 5.043 44 9.71 1.42 570 1180 0 122.6 212.9 109
46 1461004437.86025 0 2 1 83.1 421.6 100.31 31 180 352 35 5.009 45 9.84 1.45 600 1180 0 120.4 215.3 110
47 1461004439.89998 0 2 2 85.14 431.8 100.11 31 180 354 36 5.019 46 9.78 1.48 590 1110 0 123.2 213.3 110
48 1461004441.81943 0 2 3 87.07 441.6 99.56 32 180 360 37 5.047 47 9.51 1.42 570 1160 0 123.4 209.6 110
49 1461004443.77011 0 2 4 89.02 451.3 99.72 31 180 358 37 5.038 48 9.79 1.45 590 1160 0 121.4 212.2 110
50 1461004445.59931 0 2 5 90.83 460.6 100.05 31 180 355 38 5.022 49 9.71 1.42 570 1160 0 126.1 214.7 110
51 1461004447.6099 0 2 6 92.85 470.7 99.57 31 180 360 39 5.046 50 9.78 1.45 580 1120 0 126 216.2 110
52 1461004449.55928 0 2 7 94.78 480.5 99.2 32 181 364 40 5.065 51 9.63 1.45 590 1150 0 122 229.7 109
53 1461004451.4801 0 2 8 96.72 490.3 99.47 31 181 361 41 5.051 52 9.7 1.42 560 1170 0 124.9 221.2 110
54 1461004453.33954 0 2 9 98.57 499.5 100.01 31 181 355 42 5.024 53 9.85 1.45 580 1170 0 119.2 209 109
55 1461004455.4099 0 2 10 100.66 509.9 100.76 31 181 347 42 4.986 54 9.77 1.45 590 1180 0 121.6 224.3 110
56 1461004457.36002 0 2 11 102.6 519.6 100.59 31 181 349 43 4.995 55 9.78 1.42 580 1160 0 123.1 212.1 109
57 1461004459.31064 0 2 12 104.58 529.5 100.3 31 181 352 44 5.009 56 9.77 1.45 580 1190 0 122.6 216.3 109
58 1461004461.16922 0 2 13 106.42 538.7 100.5 30 181 350 45 4.999 57 9.92 1.45 580 1190 0 120.4 213.9 110
59 1461004463.26918 0 2 14 108.49 549 100.79 31 181 347 46 4.985 58 9.71 1.45 580 1150 0 121.7 216.6 110
60 1461004465.10101 0 2 15 110.36 558.4 100.66 31 181 348 46 4.991 59 9.63 1.42 570 1110 0 120.4 218.1 109
61 1461004467.01999 0 2 16 112.26 567.8 100.59 32 181 349 47 4.995 60 9.41 1.42 570 1120 0 121.8 227.8 109
62 1461004468.90954 0 2 17 114.14 577.3 100.48 31 181 350 48 5 61 9.55 1.45 600 1090 0 117.8 218 109
63 1461004470.80092 0 2 18 116.06 586.9 100.11 32 181 354 49 5.019 62 9.49 1.48 610 1110 0 115 209.3 110
64 1461004472.72009 0 2 19 117.97 596.5 100.44 32 181 351 50 5.002 63 9.49 1.45 580 1130 0 120.6 209.1 110
65 1461004474.60979 0 2 20 119.87 606 100.28 31 182 352 50 5.01 64 9.57 1.42 570 1120 0 120 217.9 109
66 1461004476.4385 0 3 0 121.65 614.9 100.89 32 181 346 51 4.98 65 9.41 1.39 570 1120 0 118.6 211.9 110
67 1461004478.47986 0 3 1 123.73 625.1 101.01 31 182 345 52 4.974 66 9.71 1.48 600 1130 0 115.3 219.1 110
68 1461004480.27929 0 3 2 125.52 634.1 101.24 31 182 342 53 4.962 67 9.57 1.45 590 1130 0 121.4 219 110
69 1461004482.37966 0 3 3 127.6 644.4 100.67 32 181 348 54 4.991 68 9.42 1.42 570 1190 0 118.7 218.1 109
70 1461004484.29991 0 3 4 129.56 654.1 101.34 30 181 341 54 4.958 69 9.85 1.45 590 1140 0 121.6 220.8 110
71 1461004486.16014 0 3 5 131.41 663.4 100.79 31 181 347 55 4.985 70 9.57 1.42 570 1090 0 122.9 210.4 110
72 1461004488.07993 0 3 6 133.33 673 100.32 32 181 352 56 5.008 71 9.35 1.42 570 1140 0 118.5 206.8 109
73 1461004490.03001 0 3 7 135.27 682.6 100.98 31 181 345 57 4.975 72 9.56 1.42 580 1150 0 116.9 218.1 109
74 1461004491.97913 0 3 8 137.22 692.3 101.5 31 181 340 58 4.95 73 9.63 1.45 590 1150 0 118.7 221.9 110
75 1461004493.77931 0 3 9 138.99 701.1 101.41 31 181 341 58 4.954 74 9.57 1.42 580 1150 0 119 205.9 110
76 1461004495.78987 0 3 10 141.04 711.2 101.29 31 181 342 59 4.96 75 9.64 1.48 600 1100 0 116.2 222.9 110
77 1461004497.64987 0 3 11 142.92 720.6 101.08 32 181 344 60 4.971 76 9.36 1.42 590 1090 0 120.4 210.2 110
78 1461004499.56987 0 3 12 144.81 730 100.32 32 182 352 61 5.008 77 9.35 1.42 570 1130 0 119.2 218.4 109
79 1461004501.45977 0 3 13 146.71 739.5 100.77 32 181 347 61 4.986 78 9.49 1.42 570 1110 0 119.5 210.1 109
80 1461004503.31974 0 3 14 148.59 748.9 100.91 32 182 346 62 4.979 79 9.41 1.42 590 1100 0 117.6 217.4 109
81 1461004505.20973 0 3 15 150.44 758.1 100.85 32 181 346 63 4.982 80 9.34 1.42 590 1090 0 114.9 212.3 109
82 1461004507.04 0 3 16 152.26 767.2 100.96 32 181 345 64 4.976 81 9.27 1.42 580 1030 0 118.6 222 109
83 1461004508.78319 0 3 17 154 775.9 100.29 33 182 352 65 5.01 82 9.06 1.42 570 1030 0 116.3 208.4 109
84 1461004510.72907 0 3 18 155.96 785.7 100.51 32 182 350 65 4.999 83 9.42 1.48 610 1050 0 114.2 220.8 110
85 1461004512.58978 0 3 19 157.79 794.9 100.32 33 182 352 66 5.008 84 9.07 1.39 560 1070 0 116.1 211.2 109
86 1461004514.42009 0 3 20 159.65 804 101.03 32 182 344 67 4.973 85 9.27 1.45 590 1040 0 112.5 199.5 109
87 1461004516.18978 0 4 0 161.46 813 101.62 33 182 338 68 4.944 86 8.98 1.39 580 1050 0 111.6 200.2 109
88 1461004518.07996 0 4 1 163.33 822.2 101.73 33 181 337 68 4.938 87 8.99 1.39 560 1100 0 114.6 206.4 109
89 1461004519.90999 0 4 2 165.15 831.2 102.27 32 181 332 69 4.912 88 9.2 1.39 570 1050 0 115.6 204.9 110
90 1461004521.74184 0 4 3 166.98 840.2 101.9 32 182 336 70 4.93 89 9.14 1.45 590 1010 0 110 200 110
91 1461004523.59979 0 4 4 168.81 849.2 101.98 34 182 335 71 4.926 90 8.71 1.36 550 1070 0 114.6 206 110
92 1461004525.36992 0 4 5 170.62 858 102.27 32 181 332 71 4.912 91 9.07 1.39 570 1040 0 111.7 185.3 109
93 1461004527.19977 0 4 6 172.43 866.9 102.47 33 181 330 72 4.902 92 8.92 1.39 570 1040 0 114 195 109
94 1461004529.06276 0 4 7 174.32 876.2 102.31 33 181 332 73 4.91 93 8.99 1.42 580 1080 0 110.1 199.7 110
95 1461004530.82905 0 4 8 176.02 884.6 102.69 32 181 328 74 4.892 94 9.14 1.42 580 1080 0 113.9 216.3 110
96 1461004532.75083 0 4 9 177.99 894.1 102.44 33 181 330 74 4.904 95 8.99 1.42 580 1060 0 108.7 196 109
97 1461004534.39983 0 4 10 179.66 902.4 102.85 32 181 326 75 4.884 96 9.05 1.42 580 1060 0 114.9 199.6 109
98 1461004536.32286 0 4 11 181.59 911.9 101.55 34 182 339 76 4.947 97 8.85 1.45 590 1000 0 110.6 199 110
99 1461004538.06289 0 4 12 183.32 920.5 101.39 34 181 341 76 4.955 98 8.78 1.39 580 970 0 109.7 195.2 110
100 1461004539.89296 0 4 13 185.11 929.4 101.35 34 181 341 77 4.957 99 8.71 1.42 570 1010 0 112.5 207.2 109
101 1461004541.6899 0 4 14 186.8 937.8 101.24 33 181 342 78 4.962 100 8.92 1.42 570 1010 0 112.9 206.9 109
102 1461004543.39974 0 4 15 188.64 946.9 101.37 34 181 341 79 4.956 101 8.85 1.39 560 940 0 112.1 200.7 110
103 1461004545.11348 0 4 16 190.34 955.4 101 35 181 345 79 4.975 102 8.42 1.36 560 970 0 113.8 187.5 110
104 1461004546.85166 0 4 17 192.1 964.1 100.78 35 180 347 80 4.985 103 8.57 1.36 550 1010 0 109.9 194.7 110
105 1461004548.65002 0 4 18 193.91 973 101.83 34 181 336 81 4.934 104 8.78 1.39 580 1010 0 107.6 188.8 110
106 1461004550.35928 0 4 19 195.6 981.3 102.6 34 181 329 81 4.896 105 8.71 1.36 560 1010 0 108.9 183.6 110
107 1461004552.30971 0 4 20 197.53 990.5 103.54 33 181 320 82 4.852 106 8.86 1.36 560 1040 0 102.4 187.2 110
108 1461004554.19972 0 4 21 199.44 999.5 105.35 33 180 304 83 4.768 107 8.7 1.33 590 1110 0 100 181.7 109
109 1461004554.35294 0 4 22 199.56 1000 105.35 33 180 304 83 4.768 107 8.7 1.33 590 1110 0 100 181.7 109
110 1461004556.03066 0 6 0 199.57 1000 105.35 33 180 304 83 4.768 107 8.7 1.33 590 1110 0 100 181.7 109

View File

@@ -1,58 +0,0 @@
index, AverageDriveForce (lbs), Cadence (stokes/min), DriveLength (meters), DriveTime (ms), ElapsedTime (sec), HRCur (bpm), Horizontal (meters), PeakDriveForce (lbs), Power (watts), Stroke500mPace (sec/500m), StrokeDistance (meters), StrokeRecoveryTime (ms), lapIdx,TimeStamp (sec)
0,0.0,54,0.0,0.0,2.6,106,11.8,0.0,0.0,130.7,0.0,0.0,0.0,1461602536.6
1,0.0,54,0.0,0.0,2.6,108,11.8,0.0,0.0,108.7,0.0,0.0,0.0,1461602536.6
2,0.0,43,0.0,0.0,4.1,110,19.7,0.0,0.0,101.3,0.0,0.0,0.0,1461602538.1
3,0.0,40,0.0,0.0,5.7,116,28.7,0.0,0.0,93.3,0.0,0.0,0.0,1461602539.7
4,0.0,37,0.0,0.0,7.4,122,38.0,0.0,0.0,90.6,0.0,0.0,0.0,1461602541.4
5,0.0,36,0.0,0.0,9.0,126,47.1,0.0,0.0,90.0,0.0,0.0,0.0,1461602543.0
6,0.0,37,0.0,0.0,10.7,132,56.4,0.0,0.0,90.2,0.0,0.0,0.0,1461602544.7
7,0.0,36,0.0,0.0,12.4,138,65.7,0.0,0.0,90.6,0.0,0.0,0.0,1461602546.4
8,0.0,35,0.0,0.0,14.1,142,75.0,0.0,0.0,91.2,0.0,0.0,0.0,1461602548.1
9,0.0,37,0.0,0.0,15.5,148,83.2,0.0,0.0,90.6,0.0,0.0,0.0,1461602549.5
10,0.0,38,0.0,0.0,17.3,151,92.8,0.0,0.0,90.2,0.0,0.0,0.0,1461602551.3
11,0.0,37,0.0,0.0,18.9,155,101.9,0.0,0.0,90.4,0.0,0.0,0.0,1461602552.9
12,0.0,36,0.0,0.0,20.5,159,110.5,0.0,0.0,90.9,0.0,0.0,0.0,1461602554.5
13,0.0,36,0.0,0.0,22.2,161,120.3,0.0,0.0,90.8,0.0,0.0,0.0,1461602556.2
14,0.0,36,0.0,0.0,23.9,164,129.5,0.0,0.0,90.8,0.0,0.0,0.0,1461602557.9
15,0.0,36,0.0,0.0,25.6,166,138.7,0.0,0.0,91.3,0.0,0.0,0.0,1461602559.6
16,0.0,36,0.0,0.0,27.2,166,147.7,0.0,0.0,91.9,0.0,0.0,0.0,1461602561.2
17,0.0,36,0.0,0.0,28.9,168,156.9,0.0,0.0,92.0,0.0,0.0,0.0,1461602562.9
18,0.0,36,0.0,0.0,30.5,169,165.7,0.0,0.0,92.0,0.0,0.0,0.0,1461602564.5
19,0.0,37,0.0,0.0,32.2,170,174.7,0.0,0.0,91.4,0.0,0.0,0.0,1461602566.2
20,0.0,37,0.0,0.0,33.8,171,183.6,0.0,0.0,91.4,0.0,0.0,0.0,1461602567.8
21,0.0,37,0.0,0.0,35.4,171,192.6,0.0,0.0,91.4,0.0,0.0,0.0,1461602569.4
22,0.0,36,0.0,0.0,37.0,172,201.2,0.0,0.0,92.0,0.0,0.0,0.0,1461602571.0
23,0.0,36,0.0,0.0,38.7,173,210.6,0.0,0.0,92.4,0.0,0.0,0.0,1461602572.7
24,0.0,37,0.0,0.0,40.4,173,219.5,0.0,0.0,91.9,0.0,0.0,0.0,1461602574.4
25,0.0,37,0.0,0.0,42.0,174,228.2,0.0,0.0,92.4,0.0,0.0,0.0,1461602576.0
26,0.0,37,0.0,0.0,43.6,174,237.1,0.0,0.0,92.5,0.0,0.0,0.0,1461602577.6
27,0.0,36,0.0,0.0,45.2,174,245.9,0.0,0.0,93.0,0.0,0.0,0.0,1461602579.2
28,0.0,37,0.0,0.0,46.9,175,254.9,0.0,0.0,93.4,0.0,0.0,0.0,1461602580.9
29,0.0,36,0.0,0.0,48.5,175,263.8,0.0,0.0,92.9,0.0,0.0,0.0,1461602582.5
30,0.0,37,0.0,0.0,50.1,175,272.4,0.0,0.0,92.3,0.0,0.0,0.0,1461602584.1
31,0.0,38,0.0,0.0,51.6,176,280.6,0.0,0.0,92.5,0.0,0.0,0.0,1461602585.6
32,0.0,36,0.0,0.0,53.4,176,290.1,0.0,0.0,92.8,0.0,0.0,0.0,1461602587.4
33,0.0,36,0.0,0.0,55.1,176,299.1,0.0,0.0,93.5,0.0,0.0,0.0,1461602589.1
34,0.0,36,0.0,0.0,56.7,177,308.0,0.0,0.0,93.7,0.0,0.0,0.0,1461602590.7
35,0.0,36,0.0,0.0,58.4,177,316.9,0.0,0.0,94.1,0.0,0.0,0.0,1461602592.4
36,0.0,36,0.0,0.0,60.0,177,325.5,0.0,0.0,94.3,0.0,0.0,0.0,1461602594.0
37,0.0,37,0.0,0.0,61.7,177,334.4,0.0,0.0,94.9,0.0,0.0,0.0,1461602595.7
38,0.0,36,0.0,0.0,63.4,178,343.3,0.0,0.0,95.2,0.0,0.0,0.0,1461602597.4
39,0.0,35,0.0,0.0,65.1,178,352.3,0.0,0.0,95.5,0.0,0.0,0.0,1461602599.1
40,0.0,35,0.0,0.0,66.7,178,360.8,0.0,0.0,96.1,0.0,0.0,0.0,1461602600.7
41,0.0,35,0.0,0.0,68.6,178,370.3,0.0,0.0,96.3,0.0,0.0,0.0,1461602602.6
42,0.0,35,0.0,0.0,70.3,178,379.4,0.0,0.0,95.8,0.0,0.0,0.0,1461602604.3
43,0.0,35,0.0,0.0,72.0,178,388.5,0.0,0.0,95.8,0.0,0.0,0.0,1461602606.0
44,0.0,35,0.0,0.0,73.7,178,397.2,0.0,0.0,96.5,0.0,0.0,0.0,1461602607.7
45,0.0,35,0.0,0.0,75.5,178,406.1,0.0,0.0,97.1,0.0,0.0,0.0,1461602609.5
46,0.0,35,0.0,0.0,77.1,179,414.3,0.0,0.0,97.8,0.0,0.0,0.0,1461602611.1
47,0.0,34,0.0,0.0,78.8,179,423.3,0.0,0.0,98.4,0.0,0.0,0.0,1461602612.8
48,0.0,34,0.0,0.0,80.7,179,432.8,0.0,0.0,98.0,0.0,0.0,0.0,1461602614.7
49,0.0,34,0.0,0.0,82.5,178,442.1,0.0,0.0,96.8,0.0,0.0,0.0,1461602616.5
50,0.0,34,0.0,0.0,84.3,179,451.4,0.0,0.0,96.9,0.0,0.0,0.0,1461602618.3
51,0.0,34,0.0,0.0,86.0,178,460.7,0.0,0.0,97.1,0.0,0.0,0.0,1461602620.0
52,0.0,33,0.0,0.0,87.9,179,469.9,0.0,0.0,97.3,0.0,0.0,0.0,1461602621.9
53,0.0,34,0.0,0.0,89.6,178,479.1,0.0,0.0,97.8,0.0,0.0,0.0,1461602623.6
54,0.0,33,0.0,0.0,91.4,179,488.2,0.0,0.0,98.6,0.0,0.0,0.0,1461602625.4
55,0.0,33,0.0,0.0,93.3,179,497.5,0.0,0.0,99.3,0.0,0.0,0.0,1461602627.3
56,0.0,33,0.0,0.0,93.8,178,500.0,0.0,0.0,99.3,0.0,0.0,0.0,1461602627.8
1 index AverageDriveForce (lbs) Cadence (stokes/min) DriveLength (meters) DriveTime (ms) ElapsedTime (sec) HRCur (bpm) Horizontal (meters) PeakDriveForce (lbs) Power (watts) Stroke500mPace (sec/500m) StrokeDistance (meters) StrokeRecoveryTime (ms) lapIdx TimeStamp (sec)
2 0 0.0 54 0.0 0.0 2.6 106 11.8 0.0 0.0 130.7 0.0 0.0 0.0 1461602536.6
3 1 0.0 54 0.0 0.0 2.6 108 11.8 0.0 0.0 108.7 0.0 0.0 0.0 1461602536.6
4 2 0.0 43 0.0 0.0 4.1 110 19.7 0.0 0.0 101.3 0.0 0.0 0.0 1461602538.1
5 3 0.0 40 0.0 0.0 5.7 116 28.7 0.0 0.0 93.3 0.0 0.0 0.0 1461602539.7
6 4 0.0 37 0.0 0.0 7.4 122 38.0 0.0 0.0 90.6 0.0 0.0 0.0 1461602541.4
7 5 0.0 36 0.0 0.0 9.0 126 47.1 0.0 0.0 90.0 0.0 0.0 0.0 1461602543.0
8 6 0.0 37 0.0 0.0 10.7 132 56.4 0.0 0.0 90.2 0.0 0.0 0.0 1461602544.7
9 7 0.0 36 0.0 0.0 12.4 138 65.7 0.0 0.0 90.6 0.0 0.0 0.0 1461602546.4
10 8 0.0 35 0.0 0.0 14.1 142 75.0 0.0 0.0 91.2 0.0 0.0 0.0 1461602548.1
11 9 0.0 37 0.0 0.0 15.5 148 83.2 0.0 0.0 90.6 0.0 0.0 0.0 1461602549.5
12 10 0.0 38 0.0 0.0 17.3 151 92.8 0.0 0.0 90.2 0.0 0.0 0.0 1461602551.3
13 11 0.0 37 0.0 0.0 18.9 155 101.9 0.0 0.0 90.4 0.0 0.0 0.0 1461602552.9
14 12 0.0 36 0.0 0.0 20.5 159 110.5 0.0 0.0 90.9 0.0 0.0 0.0 1461602554.5
15 13 0.0 36 0.0 0.0 22.2 161 120.3 0.0 0.0 90.8 0.0 0.0 0.0 1461602556.2
16 14 0.0 36 0.0 0.0 23.9 164 129.5 0.0 0.0 90.8 0.0 0.0 0.0 1461602557.9
17 15 0.0 36 0.0 0.0 25.6 166 138.7 0.0 0.0 91.3 0.0 0.0 0.0 1461602559.6
18 16 0.0 36 0.0 0.0 27.2 166 147.7 0.0 0.0 91.9 0.0 0.0 0.0 1461602561.2
19 17 0.0 36 0.0 0.0 28.9 168 156.9 0.0 0.0 92.0 0.0 0.0 0.0 1461602562.9
20 18 0.0 36 0.0 0.0 30.5 169 165.7 0.0 0.0 92.0 0.0 0.0 0.0 1461602564.5
21 19 0.0 37 0.0 0.0 32.2 170 174.7 0.0 0.0 91.4 0.0 0.0 0.0 1461602566.2
22 20 0.0 37 0.0 0.0 33.8 171 183.6 0.0 0.0 91.4 0.0 0.0 0.0 1461602567.8
23 21 0.0 37 0.0 0.0 35.4 171 192.6 0.0 0.0 91.4 0.0 0.0 0.0 1461602569.4
24 22 0.0 36 0.0 0.0 37.0 172 201.2 0.0 0.0 92.0 0.0 0.0 0.0 1461602571.0
25 23 0.0 36 0.0 0.0 38.7 173 210.6 0.0 0.0 92.4 0.0 0.0 0.0 1461602572.7
26 24 0.0 37 0.0 0.0 40.4 173 219.5 0.0 0.0 91.9 0.0 0.0 0.0 1461602574.4
27 25 0.0 37 0.0 0.0 42.0 174 228.2 0.0 0.0 92.4 0.0 0.0 0.0 1461602576.0
28 26 0.0 37 0.0 0.0 43.6 174 237.1 0.0 0.0 92.5 0.0 0.0 0.0 1461602577.6
29 27 0.0 36 0.0 0.0 45.2 174 245.9 0.0 0.0 93.0 0.0 0.0 0.0 1461602579.2
30 28 0.0 37 0.0 0.0 46.9 175 254.9 0.0 0.0 93.4 0.0 0.0 0.0 1461602580.9
31 29 0.0 36 0.0 0.0 48.5 175 263.8 0.0 0.0 92.9 0.0 0.0 0.0 1461602582.5
32 30 0.0 37 0.0 0.0 50.1 175 272.4 0.0 0.0 92.3 0.0 0.0 0.0 1461602584.1
33 31 0.0 38 0.0 0.0 51.6 176 280.6 0.0 0.0 92.5 0.0 0.0 0.0 1461602585.6
34 32 0.0 36 0.0 0.0 53.4 176 290.1 0.0 0.0 92.8 0.0 0.0 0.0 1461602587.4
35 33 0.0 36 0.0 0.0 55.1 176 299.1 0.0 0.0 93.5 0.0 0.0 0.0 1461602589.1
36 34 0.0 36 0.0 0.0 56.7 177 308.0 0.0 0.0 93.7 0.0 0.0 0.0 1461602590.7
37 35 0.0 36 0.0 0.0 58.4 177 316.9 0.0 0.0 94.1 0.0 0.0 0.0 1461602592.4
38 36 0.0 36 0.0 0.0 60.0 177 325.5 0.0 0.0 94.3 0.0 0.0 0.0 1461602594.0
39 37 0.0 37 0.0 0.0 61.7 177 334.4 0.0 0.0 94.9 0.0 0.0 0.0 1461602595.7
40 38 0.0 36 0.0 0.0 63.4 178 343.3 0.0 0.0 95.2 0.0 0.0 0.0 1461602597.4
41 39 0.0 35 0.0 0.0 65.1 178 352.3 0.0 0.0 95.5 0.0 0.0 0.0 1461602599.1
42 40 0.0 35 0.0 0.0 66.7 178 360.8 0.0 0.0 96.1 0.0 0.0 0.0 1461602600.7
43 41 0.0 35 0.0 0.0 68.6 178 370.3 0.0 0.0 96.3 0.0 0.0 0.0 1461602602.6
44 42 0.0 35 0.0 0.0 70.3 178 379.4 0.0 0.0 95.8 0.0 0.0 0.0 1461602604.3
45 43 0.0 35 0.0 0.0 72.0 178 388.5 0.0 0.0 95.8 0.0 0.0 0.0 1461602606.0
46 44 0.0 35 0.0 0.0 73.7 178 397.2 0.0 0.0 96.5 0.0 0.0 0.0 1461602607.7
47 45 0.0 35 0.0 0.0 75.5 178 406.1 0.0 0.0 97.1 0.0 0.0 0.0 1461602609.5
48 46 0.0 35 0.0 0.0 77.1 179 414.3 0.0 0.0 97.8 0.0 0.0 0.0 1461602611.1
49 47 0.0 34 0.0 0.0 78.8 179 423.3 0.0 0.0 98.4 0.0 0.0 0.0 1461602612.8
50 48 0.0 34 0.0 0.0 80.7 179 432.8 0.0 0.0 98.0 0.0 0.0 0.0 1461602614.7
51 49 0.0 34 0.0 0.0 82.5 178 442.1 0.0 0.0 96.8 0.0 0.0 0.0 1461602616.5
52 50 0.0 34 0.0 0.0 84.3 179 451.4 0.0 0.0 96.9 0.0 0.0 0.0 1461602618.3
53 51 0.0 34 0.0 0.0 86.0 178 460.7 0.0 0.0 97.1 0.0 0.0 0.0 1461602620.0
54 52 0.0 33 0.0 0.0 87.9 179 469.9 0.0 0.0 97.3 0.0 0.0 0.0 1461602621.9
55 53 0.0 34 0.0 0.0 89.6 178 479.1 0.0 0.0 97.8 0.0 0.0 0.0 1461602623.6
56 54 0.0 33 0.0 0.0 91.4 179 488.2 0.0 0.0 98.6 0.0 0.0 0.0 1461602625.4
57 55 0.0 33 0.0 0.0 93.3 179 497.5 0.0 0.0 99.3 0.0 0.0 0.0 1461602627.3
58 56 0.0 33 0.0 0.0 93.8 178 500.0 0.0 0.0 99.3 0.0 0.0 0.0 1461602627.8

View File

@@ -1,372 +0,0 @@
<map version="1.0.1">
<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->
<node CREATED="1461605460487" ID="ID_889197617" MODIFIED="1461606620316" TEXT="Rowsandall.com">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node CREATED="1461605502608" ID="ID_1180462618" MODIFIED="1464031892658" POSITION="left" TEXT="Views">
<node CREATED="1461605473619" FOLDED="true" ID="ID_758526503" MODIFIED="1465560183674" TEXT="User">
<node CREATED="1461605477168" ID="ID_1749649289" MODIFIED="1461605479404" TEXT="Standard">
<node CREATED="1461605480370" ID="ID_738158750" MODIFIED="1462199805310" TEXT="login">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605482538" ID="ID_1405710591" MODIFIED="1462199807598" TEXT="logout">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605484671" ID="ID_1442326086" MODIFIED="1461605487813" TEXT="change password"/>
<node CREATED="1461605488216" ID="ID_1649042094" MODIFIED="1461605492132" TEXT="forgotten password"/>
</node>
<node CREATED="1461605833468" ID="ID_1862101264" MODIFIED="1461605836329" TEXT="Profile">
<node CREATED="1461605838740" ID="ID_1834978335" MODIFIED="1462199827098" TEXT="Profile Edit">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node CREATED="1461605852258" FOLDED="true" ID="ID_1710060901" MODIFIED="1465560182848" TEXT="Workouts">
<node CREATED="1461607050049" ID="ID_480866837" MODIFIED="1462372232456" TEXT="Add Workout">
<icon BUILTIN="button_ok"/>
<node CREATED="1461607067010" ID="ID_661274255" MODIFIED="1462372158825" TEXT="Import from C2">
<arrowlink DESTINATION="ID_640810634" ENDARROW="Default" ENDINCLINATION="115;0;" ID="Arrow_ID_41303595" STARTARROW="None" STARTINCLINATION="115;0;"/>
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461607694156" ID="ID_1130452500" MODIFIED="1462199832919" TEXT="File Upload">
<arrowlink DESTINATION="ID_640810634" ENDARROW="Default" ENDINCLINATION="293;0;" ID="Arrow_ID_758678018" STARTARROW="None" STARTINCLINATION="293;0;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1461605874513" ID="ID_1782808892" MODIFIED="1461607669961" TEXT="Workouts (list of workouts with check boxes and buttons)">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node CREATED="1461605893808" ID="ID_518138659" MODIFIED="1462372195888" TEXT="Upload to C2 (can be bulk, grayed out if already)">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605938181" ID="ID_640810634" MODIFIED="1462372165831" TEXT="Edit Workout">
<linktarget COLOR="#b0b0b0" DESTINATION="ID_640810634" ENDARROW="Default" ENDINCLINATION="115;0;" ID="Arrow_ID_41303595" SOURCE="ID_661274255" STARTARROW="None" STARTINCLINATION="115;0;"/>
<linktarget COLOR="#b0b0b0" DESTINATION="ID_640810634" ENDARROW="Default" ENDINCLINATION="293;0;" ID="Arrow_ID_758678018" SOURCE="ID_1130452500" STARTARROW="None" STARTINCLINATION="293;0;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1461605945605" ID="ID_1416204687" MODIFIED="1461605948881" TEXT="Re-upload"/>
<node CREATED="1461606059232" ID="ID_1181900408" MODIFIED="1462372171747" TEXT="Delete">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605951301" ID="ID_1968531900" MODIFIED="1461605954953" TEXT="Add wind"/>
<node CREATED="1461605965845" ID="ID_1834624609" MODIFIED="1462372174420" TEXT="Notes field">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461606989942" ID="ID_827883014" MODIFIED="1462372177224" TEXT="Type">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461607007953" ID="ID_1419094175" MODIFIED="1461607017030" TEXT="Workout Date"/>
<node CREATED="1461607011010" ID="ID_609096815" MODIFIED="1461607021325" TEXT="Workout Time"/>
<node CREATED="1462372184965" ID="ID_373832954" MODIFIED="1462372188425" TEXT="Add summary data"/>
<node CREATED="1461606385679" ID="ID_630481471" MODIFIED="1461606394314" TEXT="Create new image"/>
</node>
<node CREATED="1461606355535" ID="ID_1087026303" MODIFIED="1461607115821" TEXT="Images">
<node CREATED="1461606373437" ID="ID_103313544" MODIFIED="1462372204106" TEXT="Thumbnails of all images related to this workout">
<icon BUILTIN="button_ok"/>
<node CREATED="1461607873806" ID="ID_274993696" MODIFIED="1462372206775" TEXT="Image">
<icon BUILTIN="button_ok"/>
<node CREATED="1461607878860" ID="ID_1920400420" MODIFIED="1462372494580" TEXT="Download link "/>
<node CREATED="1462372495159" ID="ID_95260866" MODIFIED="1462372498010" TEXT="Copy link"/>
<node CREATED="1461607881802" ID="ID_98661252" MODIFIED="1461607883115" TEXT="Delete"/>
</node>
</node>
</node>
</node>
<node CREATED="1461607842284" ID="ID_1056962364" MODIFIED="1462372225114" TEXT="Dashboard (recent workouts and images)">
<icon BUILTIN="button_ok"/>
<node CREATED="1462477981731" ID="ID_1584782313" MODIFIED="1462477992939" TEXT="Click on workout and get all related graphs"/>
</node>
</node>
<node CREATED="1461606171232" FOLDED="true" ID="ID_622814831" MODIFIED="1465560179352" TEXT="Static Pages">
<node CREATED="1461606207102" ID="ID_578601651" MODIFIED="1465560156611" TEXT="Donate">
<icon BUILTIN="button_ok"/>
<node CREATED="1461606226184" ID="ID_1214482888" MODIFIED="1461606232099" TEXT="Help cover hosting costs!"/>
</node>
<node CREATED="1461606209720" ID="ID_915618144" MODIFIED="1465560159175" TEXT="About">
<icon BUILTIN="button_ok"/>
<node CREATED="1461606219407" ID="ID_1994937123" MODIFIED="1461606224396" TEXT="Bla bla bla about"/>
</node>
<node CREATED="1461606211560" ID="ID_1050734643" MODIFIED="1465560162149" TEXT="Contact">
<icon BUILTIN="button_ok"/>
<node CREATED="1461606214176" ID="ID_929787220" MODIFIED="1461606217618" TEXT="Email contact form"/>
</node>
</node>
<node CREATED="1461606535579" ID="ID_1450476512" MODIFIED="1461606537849" TEXT="Admin">
<node CREATED="1461606539053" ID="ID_283722711" MODIFIED="1465560176760" TEXT="Delete old workouts"/>
<node CREATED="1461606693893" ID="ID_1225613996" MODIFIED="1461606698106" TEXT="Remove user"/>
</node>
</node>
<node CREATED="1461605512814" FOLDED="true" ID="ID_367361758" MODIFIED="1464105541217" POSITION="right" TEXT="Data">
<node CREATED="1461605518069" ID="ID_931509269" MODIFIED="1461859560704" TEXT="Users">
<linktarget COLOR="#b0b0b0" DESTINATION="ID_931509269" ENDARROW="Default" ENDINCLINATION="200;0;" ID="Arrow_ID_793154745" SOURCE="ID_942353046" STARTARROW="None" STARTINCLINATION="200;0;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1461605521065" ID="ID_1638831444" MODIFIED="1461859556854" TEXT="Standard">
<linktarget COLOR="#b0b0b0" DESTINATION="ID_1638831444" ENDARROW="Default" ENDINCLINATION="191;0;" ID="Arrow_ID_304251916" SOURCE="ID_1797909649" STARTARROW="None" STARTINCLINATION="191;0;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1461605527357" ID="ID_64076292" MODIFIED="1461675033560" TEXT="username">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605531205" ID="ID_1160148822" MODIFIED="1461675039348" TEXT="password">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605534005" ID="ID_468992723" MODIFIED="1461675044250" TEXT="email address">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605537685" ID="ID_658719592" MODIFIED="1461675047673" TEXT="First name">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605541815" ID="ID_780111581" MODIFIED="1461675049604" TEXT="Last Name">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node CREATED="1461651836946" ID="ID_1797909649" MODIFIED="1461859566661" TEXT="Rower">
<arrowlink DESTINATION="ID_1638831444" ENDARROW="Default" ENDINCLINATION="191;0;" ID="Arrow_ID_304251916" STARTARROW="None" STARTINCLINATION="191;0;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1461605578428" ID="ID_1864317482" MODIFIED="1461675054304" TEXT="HR Bands (with default settings)">
<icon BUILTIN="button_ok"/>
<node CREATED="1461605582890" ID="ID_1036263090" MODIFIED="1461652489462" TEXT="max">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605584970" ID="ID_349101423" MODIFIED="1461674288201" TEXT="an">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605606354" ID="ID_658122284" MODIFIED="1461674293973" TEXT="tr">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605609690" ID="ID_64081034" MODIFIED="1461674300195" TEXT="at">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605612128" ID="ID_1685146538" MODIFIED="1461674305654" TEXT="ut1">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605614208" ID="ID_1935848031" MODIFIED="1461674312392" TEXT="ut2">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605618128" ID="ID_425502762" MODIFIED="1461674318162" TEXT="rest">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1461605640561" ID="ID_1222231283" MODIFIED="1461674599803" TEXT="Default weight class">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605559179" ID="ID_707728856" MODIFIED="1461605560984" TEXT="Hidden">
<node CREATED="1461605561891" ID="ID_1160097125" MODIFIED="1461674977236" TEXT="C2 log access token">
<icon BUILTIN="button_ok"/>
<node CREATED="1461605710787" ID="ID_1360155429" MODIFIED="1461605730720" TEXT="obtained when user grants permission through his C2 identity"/>
</node>
<node CREATED="1461605570034" ID="ID_1771848783" MODIFIED="1461674983016" TEXT="Access token expiration date">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node CREATED="1461605740385" ID="ID_39541443" MODIFIED="1461605747853" TEXT="Workouts">
<node CREATED="1461605749553" ID="ID_942353046" MODIFIED="1461652737920" TEXT="User">
<arrowlink DESTINATION="ID_931509269" ENDARROW="Default" ENDINCLINATION="200;0;" ID="Arrow_ID_793154745" STARTARROW="None" STARTINCLINATION="200;0;"/>
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461606406059" ID="ID_454812442" MODIFIED="1461652703049" TEXT="Workout_name">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461606414638" ID="ID_928281830" MODIFIED="1461660580936" TEXT="Workout_date">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461606429486" ID="ID_484521014" MODIFIED="1461866244072" TEXT="Workout_starttime">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461606866528" ID="ID_1872216450" MODIFIED="1461866319482" TEXT="Workout_distance">
<icon BUILTIN="button_ok"/>
<node CREATED="1461866323170" ID="ID_936304102" MODIFIED="1461866324983" TEXT="meters"/>
</node>
<node CREATED="1461606878962" ID="ID_1128895938" MODIFIED="1461866381363" TEXT="Workout_duration">
<icon BUILTIN="button_ok"/>
<node CREATED="1461866327528" ID="ID_901906294" MODIFIED="1461866329945" TEXT="seconds"/>
</node>
<node CREATED="1461606908475" ID="ID_900580299" MODIFIED="1461866411448" TEXT="Workout_weight_class">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461606914708" FOLDED="true" ID="ID_931316189" MODIFIED="1461675065400" TEXT="Workout_type">
<icon BUILTIN="button_ok"/>
<node CREATED="1461606925676" ID="ID_1969400042" MODIFIED="1461606933440" TEXT="On-water"/>
<node CREATED="1461606927748" ID="ID_1209065588" MODIFIED="1461606941465" TEXT="Indoor Rower"/>
<node CREATED="1461606944797" ID="ID_610597647" MODIFIED="1461606949114" TEXT="Indoor Rower with Slides"/>
<node CREATED="1461606952525" ID="ID_1889795917" MODIFIED="1461606956547" TEXT="Dynamic Indoor Rower"/>
<node CREATED="1461606960376" ID="ID_294896523" MODIFIED="1461606962612" TEXT="Ski Erg"/>
<node CREATED="1461606963397" ID="ID_490247020" MODIFIED="1461606967058" TEXT="Paddle Adapter"/>
<node CREATED="1461606970534" ID="ID_1089182854" MODIFIED="1461606973571" TEXT="On-snow"/>
</node>
<node CREATED="1461605767159" ID="ID_156406" MODIFIED="1461866434741" TEXT="Filename (csv file)">
<icon BUILTIN="button_ok"/>
<node CREATED="1461606269644" ID="ID_196687111" MODIFIED="1461606286903" TEXT="I presume the data will be in painsled style csv files- not in the database"/>
</node>
<node CREATED="1461606317938" ID="ID_1830610935" MODIFIED="1463015586401" TEXT="Images">
<linktarget COLOR="#b0b0b0" DESTINATION="ID_1830610935" ENDARROW="Default" ENDINCLINATION="115;0;" ID="Arrow_ID_576769313" SOURCE="ID_1806450802" STARTARROW="None" STARTINCLINATION="115;0;"/>
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605787942" ID="ID_6975390" MODIFIED="1461866507607" TEXT="Uploaded to c2 yes/no">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461605980412" ID="ID_739576489" MODIFIED="1461866856190" TEXT="Notes">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1461823229485" ID="ID_1676270847" MODIFIED="1461836884659" TEXT="Image">
<node CREATED="1461823234420" ID="ID_100561287" MODIFIED="1461866881645" TEXT="File name">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461823237869" ID="ID_366884875" MODIFIED="1461866884487" TEXT="Creation Date">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461823241228" ID="ID_1806450802" MODIFIED="1461866887134" TEXT="Workout">
<arrowlink DESTINATION="ID_1830610935" ENDARROW="Default" ENDINCLINATION="115;0;" ID="Arrow_ID_576769313" STARTARROW="None" STARTINCLINATION="115;0;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node CREATED="1461606622088" FOLDED="true" ID="ID_1185569412" MODIFIED="1464024669570" POSITION="right" TEXT="Design">
<node CREATED="1461606626928" ID="ID_500274274" MODIFIED="1461606634684" TEXT="Header">
<node CREATED="1461607250605" ID="ID_277736788" MODIFIED="1461607542769" TEXT="Logo">
<node CREATED="1461831818073" ID="ID_1883988129" MODIFIED="1461831820242" TEXT="Top Left"/>
</node>
<node CREATED="1461831845737" ID="ID_1769289061" MODIFIED="1461831849446" TEXT="Navigation Bar"/>
<node CREATED="1461832234311" ID="ID_890051640" MODIFIED="1461832238780" TEXT="Value Prop on Home Page"/>
<node CREATED="1461607537352" ID="ID_9873263" MODIFIED="1461607540890" TEXT="Dashboard"/>
<node CREATED="1461607651139" ID="ID_1816736051" MODIFIED="1461607653176" TEXT="Workouts"/>
<node CREATED="1461607681100" ID="ID_963617159" MODIFIED="1461607683905" TEXT="Add Workout"/>
<node CREATED="1461832024698" ID="ID_704022131" MODIFIED="1461835713046" TEXT="Contact ">
<node CREATED="1461832031127" ID="ID_1522003911" MODIFIED="1461832033220" TEXT="top right"/>
</node>
<node CREATED="1461606804240" ID="ID_1832303281" MODIFIED="1461607544061" TEXT="User"/>
</node>
<node CREATED="1461606635252" ID="ID_1658688353" MODIFIED="1461606636679" TEXT="Footer">
<node CREATED="1461607518944" ID="ID_1140796060" MODIFIED="1461607526372" TEXT="Links to static pages"/>
</node>
<node CREATED="1461606637239" ID="ID_371706656" MODIFIED="1461606641893" TEXT="Side menu?"/>
</node>
<node CREATED="1461823376524" ID="ID_1672286072" MODIFIED="1461823378932" POSITION="left" TEXT="Testing"/>
<node CREATED="1461825250754" FOLDED="true" ID="ID_478462481" MODIFIED="1468564897482" POSITION="left" TEXT="Functionality">
<node CREATED="1461859283282" ID="ID_671390350" MODIFIED="1461859648988" TEXT="Workouts take user data for making plot">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461859444717" ID="ID_231247258" MODIFIED="1461873064421" TEXT="File upload creates workout">
<icon BUILTIN="button_ok"/>
<node CREATED="1461859462821" ID="ID_614435280" MODIFIED="1461873050715" TEXT="check for duplicate start times">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461861313345" ID="ID_1214320980" MODIFIED="1461868259008" TEXT="add workout starttime, workout distance, workout duration">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1461876950835" ID="ID_1233516192" MODIFIED="1461939989747" TEXT="add DurationField instead of TimeField to Workout">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461939997214" ID="ID_623587817" MODIFIED="1461940003606" TEXT="Delete workouts">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461859314613" ID="ID_1989736428" MODIFIED="1461956084613" TEXT="Plot info stored in Image class - linked to Workout - linked to user">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461859340521" ID="ID_1835485102" MODIFIED="1461956098273" TEXT="Workout summary data added to workout on import">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461859363717" ID="ID_1063073204" MODIFIED="1461956100660" TEXT="Import TCX files">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1462037395055" ID="ID_426454632" MODIFIED="1462089744303" TEXT="restrict file import to csv and tcx">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461868236440" ID="ID_998738107" MODIFIED="1462092856141" TEXT="add tenths in rowingdata.py line 455">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1462090268399" ID="ID_1789786780" MODIFIED="1463013907767" TEXT="add proper error handling">
<icon BUILTIN="button_ok"/>
<node CREATED="1462095525267" ID="ID_1485370247" MODIFIED="1462095529439" TEXT="Internal error handling"/>
<node CREATED="1462095529783" ID="ID_1494810517" MODIFIED="1462095534480" TEXT="Error handling related to C2"/>
</node>
<node CREATED="1462385130662" ID="ID_1736622825" MODIFIED="1468564862058" TEXT="create C2 authorization/renewal functionality">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461859380482" ID="ID_286348211" MODIFIED="1462095448230" TEXT="Connect to C2 and store token">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461859292062" ID="ID_891978726" MODIFIED="1462114645928" TEXT="Upload simple workout to C2">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1462114661522" ID="ID_108970697" MODIFIED="1462126485430" TEXT="Store C2 workout ID in database for checking duplicates">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1462114646664" ID="ID_1219356268" MODIFIED="1462258165015" TEXT="Upload stroke data to C2">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1462201886153" ID="ID_235589940" MODIFIED="1468564866385" TEXT="Add average and max HR to Workout model">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1462220317016" ID="ID_247996816" MODIFIED="1462259473708" TEXT="Graph choices">
<icon BUILTIN="button_ok"/>
<node CREATED="1462220324724" ID="ID_1722947819" MODIFIED="1462259470955" TEXT="Add pie chart">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1461859296985" ID="ID_697148148" MODIFIED="1462279669306" TEXT="Import workouts from C2">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1462279678160" ID="ID_748439178" MODIFIED="1462372114571" TEXT="Upload TCX data to C2">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1461859495116" ID="ID_1813236024" MODIFIED="1461859511687" TEXT="Add HR bands to &quot;open&quot; rowingdata view (for anonymous users)">
<node CREATED="1464099527327" ID="ID_1377500887" MODIFIED="1464099533644" TEXT="made it easier to sign up"/>
</node>
<node CREATED="1461859515623" ID="ID_871304706" MODIFIED="1464024676014" TEXT="get sendmail working on rowsandall.com">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1462451790489" ID="ID_1246677164" MODIFIED="1463146936088" TEXT="make password change integral part of the site">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1463013921749" ID="ID_891957290" MODIFIED="1464773708543" TEXT="Make interactive plots possible">
<icon BUILTIN="button_ok"/>
<node CREATED="1463013931611" ID="ID_1645855977" MODIFIED="1463013936147" TEXT="use mpld3"/>
<node CREATED="1463146923529" ID="ID_111815361" MODIFIED="1463146928361" TEXT="change plotting to bokeh"/>
</node>
<node CREATED="1464033158984" ID="ID_1019464919" MODIFIED="1468564874119" TEXT="add label under graph thumbnails">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1463056343673" ID="ID_1704885677" MODIFIED="1464773723535" TEXT="Make duration field prettier in C2 Import view">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1463898326795" ID="ID_304310926" MODIFIED="1468564877186" TEXT="compare 2 workouts">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1465541522068" ID="ID_24723428" MODIFIED="1465541524989" TEXT="add Teams"/>
</node>
<node CREATED="1462372120147" FOLDED="true" ID="ID_1790010779" MODIFIED="1468564903194" POSITION="left" TEXT="Bugs">
<node CREATED="1462372122865" ID="ID_791488808" MODIFIED="1463926727764" TEXT="Export to C2 - reimport - 2 hours difference ">
<icon BUILTIN="button_ok"/>
<node CREATED="1462372134058" ID="ID_1541966541" MODIFIED="1462372139127" TEXT="Check time zone information"/>
</node>
<node CREATED="1462392509362" ID="ID_1974493580" MODIFIED="1464773734760" TEXT="Total time not correct">
<icon BUILTIN="button_ok"/>
<node CREATED="1462393932924" ID="ID_1584420283" MODIFIED="1462393949048" TEXT="Could take max(&apos;Elapsed Time&apos;) but this doesn&apos;t work for intervals sessions"/>
<node CREATED="1462393949569" ID="ID_601203201" MODIFIED="1462393955852" TEXT="Perhaps detect if intervals or not"/>
<node CREATED="1462394984031" ID="ID_772280168" MODIFIED="1462395007935" TEXT="Interestingly, the old painsledtoc2 upload from cmd line gives a shorter duration"/>
</node>
<node CREATED="1462392520077" ID="ID_1005078711" MODIFIED="1462395039415" TEXT="Interval workout time not rendered correctly on C2">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1462393593313" ID="ID_1412686474" MODIFIED="1462393610112" TEXT="If user is not registered to C2 and wants to upload data, responses are not working well"/>
<node CREATED="1462433524171" ID="ID_207392923" MODIFIED="1464773757964" TEXT="Workout duration from RowPro seems to be wrong">
<icon BUILTIN="button_ok"/>
<node CREATED="1462433646218" ID="ID_1865445212" MODIFIED="1462433655083" TEXT="Elapsed Time resets at intervals"/>
<node CREATED="1462434136715" ID="ID_862653660" MODIFIED="1462434152061" TEXT="There is no time stamp - need to solve this in rowingdata.py"/>
</node>
<node CREATED="1462986270815" ID="ID_355099188" MODIFIED="1468564882289" TEXT="TCX files without HR data">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1463056227952" ID="ID_1543943630" MODIFIED="1463056234311" TEXT="TCX files from Painsled">
<node CREATED="1463056996127" ID="ID_1741508714" MODIFIED="1463057048432" TEXT="No lat/lon values present"/>
<node CREATED="1464027094358" ID="ID_109801653" MODIFIED="1464027099523" TEXT="can import through strava?"/>
</node>
</node>
<node CREATED="1462383105838" FOLDED="true" ID="ID_1770973494" MODIFIED="1464773783299" POSITION="right" TEXT="Other">
<node CREATED="1462383109198" ID="ID_1666350492" MODIFIED="1463015612121" TEXT="Migrate from Celery to RQ">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</map>

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}Here's your result{% endblock %}
{% block content %}
Waiting for task with result {{ task }}
{% endblock %}

View File

@@ -1,25 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
{% block meta %} {% endblock %}
</head>
<body>
<h1>My helpful rowing site</h1>
{% if user.is_authenticated %}
<p>Welcome, {{ user.first_name }}.</p>
<p><a href="/logout/">logout</a></p>
{% else %}
<p><a href="/login/">login</a> </p>
{% endif %}
<hr>
{% block content %}{% endblock %}
{% block footer %}
<hr>
<p>{{ versionstring }}</p>
<p>Thanks for visiting my site.</p>
{% endblock %}
</body>
</html>

View File

@@ -1,22 +0,0 @@
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Submit">
</form>
</body>
</html>

View File

@@ -1,7 +0,0 @@
{% extends "base.html" %}
{% block title %}Current time{% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}

View File

@@ -1,21 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}File loading{% endblock %}
{% block content %}
<h1>File Upload</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Submit">
{% endblock %}

View File

@@ -1,7 +0,0 @@
{% extends "base.html" %}
{% block title %}Future time{% endblock %}
{% block content %}
<p>In {{ offset }} hours, it will be {{ future_time }}.</p>
{% endblock %}

View File

@@ -1,10 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}Here's your plot{% endblock %}
{% block content %}
<h1> Here's your plot</h1>
<p><image src="{% static imagename %}"/></p>
{% endblock %}

View File

@@ -1,37 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Workouts{% endblock %}
{% block content %}
<h1>My Workouts</h1>
{% if workouts %}
<table width="70%">
<tr>
<td> <strong>Date</strong> </td>
<td> <strong>Time </strong></td>
<td> <strong>Name </strong></td>
<td> <strong>Type </strong></td>
<td> <strong>Distance</strong> </td>
<td> <strong>Duration</strong> </td>
<td> <strong>Edit</strong></td>
</tr>
{% for workout in workouts %}
<tr>
<td> {{ workout.date }} </td>
<td> {{ workout.starttime }} </td>
<td> {{ workout.name }} </td>
<td> {{ workout.workouttype }} </td>
<td> {{ workout.distance }}m</td>
<td> {{ workout.duration |durationprint:"%H:%M:%S" }} </td>
<td> <a href="/rowers/workout/{{ workout.id }}/edit">E</td>
</tr>
{% endfor %}
</table>
{% else %}
<p> No workouts found </p>
{% endif %}
{% endblock %}

View File

@@ -1,23 +0,0 @@
<html>
<head>
<title>Login Form</title>
</head>
<body>
<h1>Login</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
<input type="submit" value="Submit">
</form>
</body>
</html>

View File

@@ -1,26 +0,0 @@
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
{% endblock %}

View File

@@ -1,21 +0,0 @@
{% extends "base.html" %}
{% block title %}Change Rower {% endblock %}
{% block content %}
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>Edit your Parameters</h1>
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Save">
{% endblock %}

View File

@@ -1,7 +0,0 @@
{% extends "base.html" %}
{% block title %}Rowingdata Version{% endblock %}
{% block content %}
<p>{{ versionstring }}.</p>
{% endblock %}

View File

@@ -1,11 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}Waiting{% endblock %}
{% block meta %}<meta http-equiv="refresh" content="30">{% endblock %}
{% block content %}
<h1>Waiting for your image to be processed</h1>
<p> {{ message }} </p>
<p>Please do not close this page. Page should refresh automatically (or you can hit reload)</p>
{% endblock %}

View File

@@ -1,21 +0,0 @@
{% extends "base.html" %}
{% block title %}Change Workout {% endblock %}
{% block content %}
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>Edit Workout Data</h1>
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Save">
{% endblock %}

View File

@@ -27,7 +27,7 @@ from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SEC
from rowsandall_app.settings import SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI, SPORTTRACKS_CLIENT_SECRET
import requests
import json
from rowsandall_app.rows import handle_uploaded_file
from rowers.rows import handle_uploaded_file
from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx
from scipy.signal import savgol_filter
@@ -60,6 +60,7 @@ import plots
from io import BytesIO
from scipy.special import lambertw
# used in shell to send a newsletter to all Rowers
def emailall(emailfile,subject):
rowers = Rower.objects.all()
for rower in rowers:

View File

@@ -1,6 +1,6 @@
from django import forms
from rowers.models import Workout
from rowsandall_app.rows import validate_file_extension,must_be_csv
from rowers.rows import validate_file_extension,must_be_csv
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.contrib.admin.widgets import AdminDateWidget
@@ -9,10 +9,12 @@ from django.utils import timezone,translation
import datetime
# login form
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput())
# simple form for Contact page. Sends email to info@rowsandall.com
class EmailForm(forms.Form):
firstname = forms.CharField(max_length=255)
lastname = forms.CharField(max_length=255)
@@ -21,16 +23,21 @@ class EmailForm(forms.Form):
botcheck = forms.CharField(max_length=5)
message = forms.CharField()
# Upload the CrewNerd Summary CSV
class CNsummaryForm(forms.Form):
file = forms.FileField(required=True,validators=[must_be_csv])
# The little window to type '4x2000m/500m' to update the workout summary
class SummaryStringForm(forms.Form):
intervalstring = forms.CharField(max_length=255,label='Workout Description')
# Used for testing the POST API for StrokeData
class StrokeDataForm(forms.Form):
strokedata = forms.CharField(label='payload',
widget=forms.Textarea)
# The form used for uploading files
class DocumentsForm(forms.Form):
filetypechoices = (
('csv' , 'Painsled iOS CSV'),
@@ -50,9 +57,6 @@ class DocumentsForm(forms.Form):
workouttype = forms.ChoiceField(required=True,
choices=Workout.workouttypes,
initial='rower')
# fileformat = forms.ChoiceField(required=True,
# choices=filetypechoices,
# initial='csv')
notes = forms.CharField(required=False,
widget=forms.Textarea)
@@ -60,7 +64,8 @@ class DocumentsForm(forms.Form):
fields = ['title','file','workouttype','fileformat']
# The form to indicate additional actions to be performed immediately
# after a successful upload
class UploadOptionsForm(forms.Form):
plotchoices = (
('timeplot','Time Plot'),
@@ -76,6 +81,8 @@ class UploadOptionsForm(forms.Form):
class Meta:
fields = ['make_plot','plottype','upload_toc2']
# This form is used on the Analysis page to add a custom distance/time
# trial and predict the pace
class PredictedPieceForm(forms.Form):
unitchoices = (
('t','minutes'),
@@ -88,6 +95,7 @@ class PredictedPieceForm(forms.Form):
class Meta:
fields = ['value','pieceunit']
# On the Geeky side, to update stream information for river dwellers
class UpdateStreamForm(forms.Form):
unitchoices = (
('m','m/s'),
@@ -107,6 +115,7 @@ class UpdateStreamForm(forms.Form):
class Meta:
fields = ['dist1','dist2','stream1', 'stream2','streamunit']
# add wind information to your workout
class UpdateWindForm(forms.Form):
unitchoices = (
('m','m/s'),
@@ -134,8 +143,7 @@ class UpdateWindForm(forms.Form):
'windunit',
'winddirection1','winddirection2']
# Form to select a data range to show workouts from a certain time period
class DateRangeForm(forms.Form):
startdate = forms.DateField(initial=timezone.now()-datetime.timedelta(days=365),
widget=SelectDateWidget(years=range(1990,2050)),
@@ -147,6 +155,7 @@ class DateRangeForm(forms.Form):
class Meta:
fields = ['startdate','enddate']
# Form used to select workouts for the past N days
class DeltaDaysForm(forms.Form):
deltadays = forms.IntegerField(initial=0,required=False,label='')
@@ -191,13 +200,14 @@ class RegistrationFormUniqueEmail(RegistrationFormTermsOfService):
raise forms.ValidationError("This email address is already in use. Please supply a different email address.")
return self.cleaned_data['email']
# Time field supporting microseconds. Not used, I believe.
class MyTimeField(forms.TimeField):
def __init__(self, *args, **kwargs):
super(MyTimeField, self).__init__(*args, **kwargs)
supports_microseconds = True
# Form used to update interval stats
class IntervalUpdateForm(forms.Form):
def __init__(self, *args, **kwargs):

View File

@@ -18,6 +18,8 @@ from sqlite3 import OperationalError
from django.utils import timezone
import datetime
from rowers.rows import validate_file_extension
from rowsandall_app.settings import (
TWEET_ACCESS_TOKEN_KEY,
TWEET_ACCESS_TOKEN_SECRET,
@@ -47,12 +49,12 @@ database_url = 'mysql://{user}:{password}@{host}:{port}/{database_name}'.format(
if settings.DEBUG or user=='':
database_url = 'sqlite:///db.sqlite3'
# Create your models here.
# For future Team functionality
class Team(models.Model):
name = models.CharField(max_length=150)
notes = models.CharField(blank=True,max_length=200)
# Extension of User with rowing specific data
class Rower(models.Model):
weightcategories = (
('hwt','heavy-weight'),
@@ -95,6 +97,7 @@ class Rower(models.Model):
def __str__(self):
return self.user.username
# Saving a chart as a favorite chart
class FavoriteChart(models.Model):
y1params = (
('hr','Heart Rate'),
@@ -181,6 +184,7 @@ class FavoriteForm(ModelForm):
fields = ['xparam','yparam1','yparam2',
'plottype','workouttype','reststrokes']
# To generate favorite chart forms on the fly
class BaseFavoriteFormSet(BaseFormSet):
def clean(self):
if any(self.errors):
@@ -209,6 +213,7 @@ class BaseFavoriteFormSet(BaseFormSet):
if not yparam2:
yparam2 = 'None'
# Workout
class Workout(models.Model):
workouttypes = (
('water','On-water'),
@@ -273,7 +278,7 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
if os.path.isfile(instance.csvfilename+'.gz'):
os.remove(instance.csvfilename+'.gz')
# Delete stroke data from the database when a workout is deleted
@receiver(models.signals.post_delete,sender=Workout)
def auto_delete_strokedata_on_delete(sender, instance, **kwargs):
if instance.id:
@@ -289,6 +294,11 @@ def auto_delete_strokedata_on_delete(sender, instance, **kwargs):
conn.close()
engine.dispose()
# Model of StrokeData table
# the definition here is used only to enable easy Django migration
# when the StrokeData are expanded.
# No Django Instances of this model are managed. Strokedata table is
# accesssed directly with SQL commands
class StrokeData(models.Model):
class Meta:
db_table = 'strokedata'
@@ -330,6 +340,7 @@ class StrokeData(models.Model):
wash = models.FloatField(default=0,null=True)
peakforceangle = models.FloatField(default=0,null=True)
# A wrapper around the png files
class GraphImage(models.Model):
filename = models.CharField(default='',max_length=150,blank=True,null=True)
creationdatetime = models.DateTimeField()
@@ -338,7 +349,7 @@ class GraphImage(models.Model):
def __str__(self):
return self.filename
# delete related file object
# delete related file object when image is deleted
@receiver(models.signals.post_delete,sender=GraphImage)
def auto_delete_image_on_delete(sender,instance, **kwargs):
if instance.filename:
@@ -347,11 +358,11 @@ def auto_delete_image_on_delete(sender,instance, **kwargs):
else:
print "couldn't find the file "+instance.filename
# Date input utility
class DateInput(forms.DateInput):
input_type = 'date'
# Form to update Workout data
class WorkoutForm(ModelForm):
duration = forms.TimeInput(format='%H:%M:%S.%f')
class Meta:
@@ -368,16 +379,20 @@ class WorkoutForm(ModelForm):
if self.instance.workouttype != 'water':
del self.fields['boattype']
# Used for the rowing physics calculations
class AdvancedWorkoutForm(ModelForm):
class Meta:
model = Workout
fields = ['boattype','weightvalue']
# Simple form to set rower's Functional Threshold Power
class RowerPowerForm(ModelForm):
class Meta:
model = Rower
fields = ['ftp']
# Form to set rower's Heart Rate zones, including test routines
# to enable consistency
class RowerForm(ModelForm):
class Meta:
model = Rower
@@ -519,6 +534,8 @@ class RowerForm(ModelForm):
if an>=max:
raise forms.ValidationError("AN should be lower than Max")
# 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)
announcement = models.TextField(max_length=140)

View File

@@ -71,13 +71,3 @@ def handle_uploaded_file(f):
return fname,fname2
# this might work on windows
#import magic
#def validate_mime_type(value):
# supported_types=['text/csv','application/vnd.garmin.tcx+xml']
# with magic.Magic(flags=magic.MAGIC_MIME_TYPE) as m:
# mime_type=m.id_buffer(value.file.read())
# value.file.seek(0)
# if mime_type not in supported_types:
# raise ValidationError(u'Unsupported file type.')

View File

@@ -1,3 +1,7 @@
# This is just a scratch pad to temporarily park code, just in case I need
# it later. Hardly used since i have proper versioning
@login_required()
def workout_edit_view(request,id=0):
if request.method == 'POST':

View File

@@ -8,7 +8,7 @@ import rowers.interactiveplots as iplots
import datetime
from rowingdata import rowingdata as rdata
from rowingdata import rower as rrower
from rowsandall_app.rows import handle_uploaded_file
from rowers.rows import handle_uploaded_file
from django.core.files.uploadedfile import SimpleUploadedFile
from time import strftime,strptime,mktime,time,daylight
import os

View File

@@ -100,7 +100,6 @@ urlpatterns = [
url(r'^api-docs$', views.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'^testbokeh$',views.testbokeh),
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'),
@@ -113,10 +112,6 @@ urlpatterns = [
url(r'^list-workouts/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.workouts_view),
url(r'^list-workouts/$',views.workouts_view),
url(r'^list-graphs/$',views.graphs_view),
url(r'^dashboard/c/(?P<message>\w+.*)/$',views.dashboard_view),
url(r'^dashboard/s/(?P<successmessage>\w+.*)/$',views.dashboard_view),
url(r'^dashboard/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.dashboard_view),
url(r'^dashboard/$',views.dashboard_view),
url(r'^(?P<theuser>\d+)/ote-bests/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.rankings_view),
url(r'^(?P<theuser>\d+)/ote-bests/(?P<deltadays>\d+)$',views.rankings_view),
url(r'^ote-bests/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.rankings_view),
@@ -194,7 +189,6 @@ urlpatterns = [
url(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view),
url(r'^workout/sporttracksimport/(\d+)/$',views.workout_getsporttracksworkout_view),
url(r'^workout/(\d+)/deleteconfirm$',views.workout_delete_confirm_view),
url(r'^workout/(\d+)/c2upload/$',views.list_c2_upload_view),
url(r'^workout/(\d+)/c2uploadw/$',views.workout_c2_upload_view),
url(r'^workout/(\d+)/stravauploadw/$',views.workout_strava_upload_view),
url(r'^workout/(\d+)/recalcsummary/$',views.workout_recalcsummary_view),

View File

@@ -1,6 +1,7 @@
import time
import zipfile
import operator
import warnings
from django.views.generic.base import TemplateView
from django.db.models import Q
from django.db import IntegrityError, transaction
@@ -46,7 +47,7 @@ import requests
import json
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from rowsandall_app.rows import handle_uploaded_file
from rowers.rows import handle_uploaded_file
from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv
from rowers.tasks import handle_sendemail_unrecognized
from scipy.signal import savgol_filter
@@ -105,8 +106,10 @@ USER_LANGUAGE = 'en-US'
from interactiveplots import *
# Define the API documentation
schema_view = get_swagger_view(title='Rowsandall API (Unstable)')
# Custom error pages with Rowsandall headers
def error500_view(request):
response = render_to_response('500.html', {},
context_instance = RequestContext(request))
@@ -135,6 +138,8 @@ def error403_view(request):
response.status_code = 403
return response
# Wrapper around the rowingdata call to catch some exceptions
# Checks for CSV file, then for gzipped CSV file, and if all fails, returns 0
def rdata(file,rower=rrower()):
try:
res = rrdata(file,rower=rower)
@@ -146,6 +151,7 @@ def rdata(file,rower=rrower()):
return res
# Used for the interval editor - translates seconds to a time object
def get_time(second):
if (second<=0) or (second>1e9):
hours = 0
@@ -166,10 +172,13 @@ def get_time(second):
return datetime.time(hours,minutes,sec,microsecond)
# get the workout ID from the SportTracks URI
def getidfromsturi(uri):
return uri[len(uri)-8:]
# Splits SportTracks data which is one long sequence of
# [t,[lat,lon],t2,[lat2,lon2] ...]
# to [t,t2,t3, ...], [[lat,long],[lat2,long2],...
def splitstdata(lijst):
t = []
latlong = []
@@ -188,10 +197,13 @@ def geo_distance(lat1,lon1,lat2,lon2):
We're never moving more than 10 meters between trackpoints
Bearing calculation fails if one of the points is a pole.
(Hey, from the North pole you can walk South, East, North and end up
on the same spot!)
"""
# radius of earth in km
# radius of our earth in km --> should be moved to settings if
# rowing takes off on other planets
R = 6373.0
# pi
@@ -219,11 +231,13 @@ def geo_distance(lat1,lon1,lat2,lon2):
return [distance,bearing]
# Check if a user is a Pro member
def promember(user):
r = Rower.objects.get(user=user)
result = user.is_authenticated() and (r.rowerplan=='pro' or r.rowerplan=='coach')
return result
# User registration
def rower_register_view(request):
if request.method == 'POST':
form = RegistrationFormUniqueEmail(request.POST)
@@ -290,6 +304,7 @@ def rower_register_view(request):
"registration_form.html",
{'form':form,})
# Shows email form and sends it if submitted
def sendmail(request):
if request.method == 'POST':
form = EmailForm(request.POST)
@@ -312,6 +327,7 @@ def sendmail(request):
else:
return HttpResponseRedirect('/rowers/email/')
# Check if workout belongs to this user
def checkworkoutuser(user,workout):
try:
r = Rower.objects.get(user=user)
@@ -319,6 +335,8 @@ def checkworkoutuser(user,workout):
except Rower.DoesNotExist:
return(False)
# Create workout data from Strava or Concept2
# data and create the associated Workout object and save it
def add_workout_from_strokedata(user,importid,data,strokedata,
source='c2',splitdata=None):
workouttype = data['type']
@@ -393,10 +411,8 @@ def add_workout_from_strokedata(user,importid,data,strokedata,
pace = strokedata.ix[:,'p']/10.
velo = 500./pace
# if (source=='c2' or source=='strava'):
power = 2.8*velo**3
# else:
# power = 0.0*velo
# save csv
# Create data frame with all necessary data to write to csv
@@ -419,7 +435,7 @@ def add_workout_from_strokedata(user,importid,data,strokedata,
' ElapsedTime (sec)':seconds
})
# data.sort(['TimeStamp (sec)'],ascending=True)
df.sort_values(by='TimeStamp (sec)',ascending=True)
timestr = strftime("%Y%m%d-%H%M%S")
@@ -451,19 +467,21 @@ def add_workout_from_strokedata(user,importid,data,strokedata,
# end autosmoothing
# Create CSV file name and save data to CSV file
csvfilename ='media/Import_'+str(importid)+'.csv'
res = df.to_csv(csvfilename+'.gz',index_label='index',
compression='gzip')
averagehr = df[' HRCur (bpm)'].mean()
maxhr = df[' HRCur (bpm)'].max()
# make workout
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an,ftp=r.ftp)
row = rdata(csvfilename,rower=rr)
averagehr = row.df[' HRCur (bpm)'].mean()
maxhr = row.df[' HRCur (bpm)'].max()
totaldist = row.df['cum_dist'].max()
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
@@ -488,8 +506,9 @@ def add_workout_from_strokedata(user,importid,data,strokedata,
ws = Workout.objects.filter(starttime=workoutstarttime,
user=r)
if (len(ws) != 0):
print "Warning: This workout probably already exists in the database"
warnings.warn("Probably a duplicate workout",UserWarning)
# Create the Workout object
w = Workout(user=r,name=title,
date=workoutdate,workouttype=workouttype,
duration=duration,distance=totaldist,
@@ -503,6 +522,8 @@ def add_workout_from_strokedata(user,importid,data,strokedata,
return w.id
# Create workout from SportTracks Data, which are slightly different
# than Strava or Concept2 data
def add_workout_from_stdata(user,importid,data):
workouttype = data['type']
if workouttype not in [x[0] for x in Workout.workouttypes]:
@@ -512,7 +533,6 @@ def add_workout_from_stdata(user,importid,data):
except:
comments = ''
# comments = "Imported data \n"+str(comments)
try:
thetimezone = tz(data['timezone'])
except:
@@ -653,8 +673,6 @@ def add_workout_from_stdata(user,importid,data):
df = df.fillna(0)
# data.sort(['TimeStamp (sec)'],ascending=True)
df.sort_values(by='TimeStamp (sec)',ascending=True)
timestr = strftime("%Y%m%d-%H%M%S")
@@ -689,14 +707,15 @@ def add_workout_from_stdata(user,importid,data):
res = df.to_csv(csvfilename+'.gz',index_label='index',
compression='gzip')
averagehr = df[' HRCur (bpm)'].mean()
maxhr = df[' HRCur (bpm)'].max()
# make workout
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an,ftp=r.ftp)
row = rdata(csvfilename,rower=rr)
averagehr = row.df[' HRCur (bpm)'].mean()
maxhr = row.df[' HRCur (bpm)'].max()
totaldist = row.df['cum_dist'].max()
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
@@ -736,12 +755,13 @@ def add_workout_from_stdata(user,importid,data):
return w.id
# Checks if user has Concept2 tokens, resets tokens if they are
# expired.
def c2_open(user):
r = Rower.objects.get(user=user)
if (r.c2token == '') or (r.c2token is None):
s = "Token doesn't exist. Need to authorize"
raise C2NoTokenError("User has no token")
# return HttpResponseRedirect("/rowers/me/c2authorize/")
else:
if (timezone.now()>r.tokenexpirydate):
res = c2stuff.rower_c2_token_refresh(user)
@@ -754,7 +774,7 @@ def c2_open(user):
return thetoken
# Checks if user has SportTracks token, renews them if they are expired
def sporttracks_open(user):
r = Rower.objects.get(user=user)
if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
@@ -768,60 +788,7 @@ def sporttracks_open(user):
return thetoken
# Create your views here.
@login_required()
def list_c2_upload_view(request,id=0):
message = ""
try:
thetoken = c2_open(request.user)
except C2NoTokenError:
return HttpResponseRedirect("/rowers/me/c2authorize/")
# ready to upload. Hurray
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)):
c2userid = c2stuff.get_userid(thetoken)
data = c2stuff.createc2workoutdata(w)
authorizationstring = str('Bearer ' + thetoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
import urllib
url = "https://log.concept2.com/api/users/%s/results" % (c2userid)
response = requests.post(url,headers=headers,data=json.dumps(data))
# check for duplicate error first
if (response.status_code == 409 ):
message = "Duplicate error"
w.uploadedtoc2 = -1
w.save()
elif (response.status_code == 201 or response.status_code == 200):
try:
s= json.loads(response.text)
c2id = s['data']['id']
w.uploadedtoc2 = c2id
w.save()
url = reverse(workouts_view)
return HttpResponseRedirect(url)
except:
message = "Something went wrong in list_c2_upload_view. Response 200/201 but Upload to C2 failed: "+response.text
else:
s = response
message = "Something went wrong in list_c2_upload_view. Upload to C2 failed."
else:
message = "You are not authorized to upload this workout"
url = reverse(workouts_view,
kwargs = {
'message':str(message),
})
return HttpResponseRedirect(url)
# Export workout to TCX and send to user's email address
@login_required()
def workout_tcxemail_view(request,id=0):
message = ""
@@ -874,6 +841,7 @@ def workout_tcxemail_view(request,id=0):
return response
# Get Workout CSV file and send it to user's email address
@login_required()
def workout_csvemail_view(request,id=0):
message = ""
@@ -910,6 +878,8 @@ def workout_csvemail_view(request,id=0):
return response
# Send workout to Strava
# abundance of error logging here because there were/are some bugs
@login_required()
def workout_strava_upload_view(request,id=0):
message = ""
@@ -991,6 +961,7 @@ def workout_strava_upload_view(request,id=0):
return response
# Upload workout to Concept2 logbook
@login_required()
def workout_c2_upload_view(request,id=0):
message = ""
@@ -1059,6 +1030,7 @@ def workout_c2_upload_view(request,id=0):
return HttpResponseRedirect(url)
# Upload workout to SportTracks
@login_required()
def workout_sporttracks_upload_view(request,id=0):
message = ""
@@ -1116,7 +1088,7 @@ def workout_sporttracks_upload_view(request,id=0):
return HttpResponseRedirect(url)
# Concept2 authorization
@login_required()
def rower_c2_authorize(request):
# Generate a random string for the state parameter
@@ -1132,6 +1104,7 @@ def rower_c2_authorize(request):
url += "&scope="+scope
return HttpResponseRedirect(url)
# Strava Authorization
@login_required()
def rower_strava_authorize(request):
# Generate a random string for the state parameter
@@ -1149,6 +1122,7 @@ def rower_strava_authorize(request):
return HttpResponseRedirect(url)
# SportTracks Authorization
@login_required()
def rower_sporttracks_authorize(request):
# Generate a random string for the state parameter
@@ -1167,6 +1141,7 @@ def rower_sporttracks_authorize(request):
return HttpResponseRedirect(url)
# Concept2 token refresh. URL for manual refresh. Not visible to users
@login_required()
def rower_c2_token_refresh(request):
r = Rower.objects.get(user=request.user)
@@ -1191,6 +1166,7 @@ def rower_c2_token_refresh(request):
return imports_view(request,successmessage=successmessage,message=message)
# SportTracks token refresh. URL for manual refresh. Not visible to users
@login_required()
def rower_sporttracks_token_refresh(request):
r = Rower.objects.get(user=request.user)
@@ -1211,6 +1187,7 @@ def rower_sporttracks_token_refresh(request):
return imports_view(request,successmessage=successmessage)
# Concept2 Callback
@login_required()
def rower_process_callback(request):
try:
@@ -1235,6 +1212,7 @@ def rower_process_callback(request):
successmessage = "Tokens stored. Good to go"
return imports_view(request,successmessage=successmessage)
# The imports page
@login_required()
def imports_view(request,successmessage="",message=""):
return render(request,"imports.html",
@@ -1242,16 +1220,19 @@ def imports_view(request,successmessage="",message=""):
'message': message,
})
# Just for testing purposes
@login_required()
def test_reverse_view(request):
successmessage = "Tokens stored. Good to go"
return imports_view(request,successmessage=successmessage)
# dummy
@login_required()
def rower_process_twittercallback(request):
return "dummy"
# Process Strava Callback
@login_required()
def rower_process_stravacallback(request):
code = request.GET['code']
@@ -1268,7 +1249,7 @@ def rower_process_stravacallback(request):
return imports_view(request,successmessage=successmessage)
# Process SportTracks callback
@login_required()
def rower_process_sporttrackscallback(request):
code = request.GET['code']
@@ -1290,6 +1271,7 @@ def rower_process_sporttrackscallback(request):
successmessage = "Tokens stored. Good to go"
return imports_view(request,successmessage=successmessage)
# Process Own API callback - for API testing purposes
@login_required()
def rower_process_testcallback(request):
code = request.GET['code']
@@ -1309,7 +1291,7 @@ def rower_process_testcallback(request):
return HttpResponse(text)
# View around the Histogram of all strokes. Not implemented in UI
@login_required()
def histo_all(request,theuser=0):
promember=0
@@ -1356,6 +1338,7 @@ def histo_all(request,theuser=0):
'theuser':u,
})
# The Flex plot for a large selection of workouts
@login_required()
def cum_flex(request,theuser=0,
xparam='spm',
@@ -1478,6 +1461,7 @@ def cum_flex(request,theuser=0,
'promember':promember,
})
# Show the EMpower Oarlock generated Stroke Profile
@user_passes_test(promember,login_url="/",redirect_field_name=None)
def workout_forcecurve_view(request,id=0,workstrokesonly=False):
row = Workout.objects.get(id=id)
@@ -1516,6 +1500,7 @@ def workout_forcecurve_view(request,id=0,workstrokesonly=False):
'workstrokesonly': not workstrokesonly,
})
# Show Stroke power histogram for a workout
@login_required()
def workout_histo_view(request,id=0):
row = Workout.objects.get(id=id)
@@ -1544,6 +1529,7 @@ def workout_histo_view(request,id=0):
'mayedit':mayedit,
})
# Histogram for a date/time range
@login_required()
def histo(request,theuser=0,
startdate=timezone.now()-datetime.timedelta(days=365),
@@ -1651,6 +1637,7 @@ def histo(request,theuser=0,
'deltaform':deltaform,
})
# Show ranking distances including predicted paces
@login_required()
def rankings_view(request,theuser=0,
startdate=timezone.now()-datetime.timedelta(days=365),
@@ -1683,7 +1670,7 @@ def rankings_view(request,theuser=0,
if result:
promember=1
# get all indoor rows of in date range
# get all indoor rows in date range
# process form
if request.method == 'POST' and "daterange" in request.POST:
@@ -1945,6 +1932,7 @@ def rankings_view(request,theuser=0,
'enddate':enddate,
})
# Reload the workout and calculate the summary from the stroke data (lapIDx)
@login_required()
def workout_recalcsummary_view(request,id=0):
row = Workout.objects.get(id=id)
@@ -1967,7 +1955,7 @@ def workout_recalcsummary_view(request,id=0):
return HttpResponseRedirect(url)
# List Workouts
@login_required()
def workouts_view(request,message='',successmessage='',
startdatestring="",enddatestring="",
@@ -1975,9 +1963,6 @@ def workouts_view(request,message='',successmessage='',
enddate=timezone.now()+datetime.timedelta(days=1)):
try:
r = Rower.objects.get(user=request.user)
# res = mailprocessing.safeprocessattachments()
#if len(res)>0 and np.cumsum(np.array(res)).max()>0:
# successmessage = 'New Workouts have been created from email'
if request.method == 'POST':
dateform = DateRangeForm(request.POST)
@@ -2049,6 +2034,7 @@ def workouts_view(request,message='',successmessage='',
except Rower.DoesNotExist:
return HttpResponse("User has no rower instance")
# List of workouts to compare a selected workout to
@user_passes_test(promember,login_url="/",redirect_field_name=None)
def workout_comparison_list(request,id=0,message='',successmessage='',
startdatestring="",enddatestring="",
@@ -2124,6 +2110,7 @@ def workout_comparison_list(request,id=0,message='',successmessage='',
except Rower.DoesNotExist:
return HttpResponse("User has no rower instance")
# Basic 'EDIT' view of workout
def workout_view(request,id=0):
try:
# check if valid ID exists (workout exists)
@@ -2162,7 +2149,7 @@ def workout_view(request,id=0):
except Workout.DoesNotExist:
return HttpResponseNotFound("Workout doesn't exist")
# Resets stroke data to raw data (pace)
@user_passes_test(promember,login_url="/",redirect_field_name=None)
def workout_undo_smoothenpace_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
@@ -2189,7 +2176,7 @@ def workout_undo_smoothenpace_view(request,id=0,message="",successmessage=""):
return HttpResponseRedirect(url)
# Data smoothing of pace data
@user_passes_test(promember,login_url="/",redirect_field_name=None)
def workout_smoothenpace_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
@@ -2225,6 +2212,7 @@ def workout_smoothenpace_view(request,id=0,message="",successmessage=""):
return HttpResponseRedirect(url)
# Process CrewNerd Summary CSV and update summary
@user_passes_test(promember,login_url="/",redirect_field_name=None)
def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
@@ -2269,6 +2257,7 @@ def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""):
{'form':form,
'id':row.id})
# Get weather for given location and date/time
@user_passes_test(promember,login_url="/",redirect_field_name=None)
def workout_downloadwind_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
@@ -2325,7 +2314,7 @@ def workout_downloadwind_view(request,id=0,message="",successmessage=""):
return response
# Show form to update wind data
@user_passes_test(promember,login_url="/",redirect_field_name=None)
def workout_wind_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
@@ -2425,6 +2414,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""):
'gmapdiv':gmdiv})
# Show form to update River stream data (for river dwellers)
@user_passes_test(promember,login_url="/",redirect_field_name=None)
def workout_stream_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
@@ -2486,7 +2476,7 @@ def workout_stream_view(request,id=0,message="",successmessage=""):
'form':form,
'the_div':div})
# Form to set average crew weight and boat type, then run power calcs
@user_passes_test(promember, login_url="/",redirect_field_name=None)
def workout_otwsetpower_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
@@ -2572,7 +2562,7 @@ def workout_otwsetpower_view(request,id=0,message="",successmessage=""):
'form':form,
})
# A special Edit page with all the Geeky functionality for the workout
@login_required()
def workout_geeky_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
@@ -2617,7 +2607,7 @@ def workout_geeky_view(request,id=0,message="",successmessage=""):
'interactiveplot':script,
'the_div':div})
#@user_passes_test(promember,login_url="/",redirect_field_name=None)
# The Advanced edit page
@login_required()
def workout_advanced_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
@@ -2662,6 +2652,7 @@ def workout_advanced_view(request,id=0,message="",successmessage=""):
'interactiveplot':script,
'the_div':div})
# The interactive plot comparing two workouts (obsolete version)
def workout_comparison_view(request,id1=0,id2=0,xparam='distance',yparam='spm'):
promember=0
if not request.user.is_anonymous():
@@ -2687,6 +2678,7 @@ def workout_comparison_view(request,id1=0,id2=0,xparam='distance',yparam='spm'):
'yparam':yparam,
})
# Updated version of comparison pliot
def workout_comparison_view2(request,id1=0,id2=0,xparam='distance',
yparam='spm',plottype='line'):
promember=0
@@ -2715,7 +2707,7 @@ def workout_comparison_view2(request,id1=0,id2=0,xparam='distance',
})
# The famous flex chart
def workout_flexchart3_view(request,*args,**kwargs):
try:
@@ -2879,98 +2871,8 @@ def workout_flexchart3_view(request,*args,**kwargs):
'maxfav':maxfav,
})
def testbokeh(request):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
x = np.array(range(51))/10.
y = x**2.
z = (2*(x-2.5))**2
data = dict(
x = x,
y = y,
z = z,
)
df = pd.DataFrame(data)
filtered_df = df
source = ColumnDataSource(
df
)
source2 = ColumnDataSource(
filtered_df
)
plot = Figure(tools=TOOLS)
plot.circle('x','y',source=source2)
plot.xaxis.axis_label = "X"
plot.yaxis.axis_label = "Y"
plot.x_range = Range1d(-1,6)
plot.y_range = Range1d(-5,30)
callback = CustomJS(args = dict(source=source,source2=source2), code="""
var data = source.data
var data2 = source2.data
var x1 = data['x']
var y1 = data['y']
var z1 = data['z']
var mina = mina.value
var maxa = maxa.value
var minz = minz.value
var maxz = maxz.value
data2['x'] = []
data2['y'] = []
data2['z'] = []
for (i=0; i<x1.length; i++) {
if (x1[i]>=mina && x1[i]<=maxa && z1[i]<=maxz && z1[i]>=minz) {
data2['x'].push(x1[i])
data2['y'].push(y1[i])
data2['z'].push(z1[i])
}
}
source2.trigger('change');
""")
s1 = Slider(start=0.0, end=5,value=0.0, step=.1,title="Min X Value",callback=callback)
callback.args["mina"] = s1
s2 = Slider(start=0.0, end=5,value=5.0, step=.1,title="Max X Value",callback=callback)
callback.args["maxa"] = s2
s3 = Slider(start=0.0, end=25,value=0.0, step=.1,title="Min Z Value",callback=callback)
callback.args["minz"] = s3
s4 = Slider(start=0.0, end=25,value=25.0, step=.1,title="Max Z Value",callback=callback)
callback.args["maxz"] = s4
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('X value','@x'),
('Y value','@y'),
('Z value','@z'),
])
hover.mode = 'mouse'
layout = layoutrow([layoutcolumn([s1,s2,s3,s4]),plot])
# widgetbox(s)
script, div = components(layout)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
return render(request,
'test.html',
{'the_script': script,
'the_div': div,
'js_res': js_resources,
'css_res':css_resources,
})
#@user_passes_test(promember,login_url="/",redirect_field_name=None)
# The interactive plot with the colored Heart rate zones
def workout_biginteractive_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
# check if user is owner of this workout
@@ -3007,6 +2909,7 @@ def workout_biginteractive_view(request,id=0,message="",successmessage=""):
'promember':promember,
'mayedit':mayedit})
# The interactive plot with wind corrected pace for OTW outings
def workout_otwpowerplot_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
# check if user is owner of this workout
@@ -4414,31 +4317,6 @@ def graph_delete_view(request,id=0):
return HttpResponse("Graph Image doesn't exist")
@login_required()
def dashboard_view(request,message="",successmessage=""):
try:
request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
r = Rower.objects.get(user=request.user)
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime")
if (len(g)<=3):
return render(request,'dashboard.html',
{'workouts':workouts,
'graphs1':g[0:3],
'message':message,
'successmessage':successmessage})
else:
return render(request,'dashboard.html',
{'workouts':workouts,
'graphs1':g[0:3],
'graphs2':g[3:6],
'message':message,
'successmessage':successmessage})
except Rower.DoesNotExist:
return HttpResponse("User has no rower instance")
@login_required()
def graphs_view(request):

View File

@@ -1,33 +1,5 @@
from django import forms
from rowers.models import Workout
from rows import validate_file_extension
class ContactForm(forms.Form):
subject = forms.CharField()
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
class DocumentsForm(forms.Form):
filetypechoices = (
('tcx' , 'TCX'),
('csv' , 'Painsled CSV')
)
title = forms.CharField(required=False)
file = forms.FileField(required=True,
validators=[validate_file_extension])
workouttype = forms.ChoiceField(required=True,
choices=Workout.workouttypes,
initial='rower')
fileformat = forms.ChoiceField(required=True,
choices=filetypechoices,
initial='csv')
notes = forms.CharField(required=False,
widget=forms.Textarea)
class Meta:
fields = ['title','file','workouttype','fileformat']

View File

@@ -1,7 +1,3 @@
# -*- coding: utf-8 -*-
from django.db import models
from rows import validate_file_extension
class Document(models.Model):
docfile = models.FileField(upload_to='documents/%Y/%m/%d',
validators=[validate_file_extension])

View File

@@ -1,3 +0,0 @@
def addrc(x,y,z):
return int(x)+int(y)

View File

@@ -1,121 +0,0 @@
"""
Django settings for rowsandall_app project.
Generated by 'django-admin startproject' using Django 1.9.5.
For more information on this file, see
https://docs.djangoproject.com/en/1.9/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.9/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '&cg#y8h-8s#00ayk#gu)+l43j1j9^9r&qf$3!$x#ov@1houiph'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'rowsandall_app.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'rowsandall_app.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.9/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Europe/Prague'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
STATIC_URL = '/static/'

View File

@@ -1,3 +0,0 @@
graph = {{ my_data|safe }};
mpld3.draw_figure("fig01", graph);

View File

@@ -17,9 +17,7 @@ from django.conf.urls import url,include
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from rowsandall_app.views import rootview,version,rowingdata,showStaticImage,\
add,wait,nrowingdata,waitforplot,showplot,interactiveplot
from rowsandall_app.views import uploadfile
from rowsandall_app.views import rootview
from django.contrib.auth import views as auth_views
from rowers import views as rowersviews
@@ -28,8 +26,6 @@ urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^$',rootview),
url(r'^version/$',version),
url(r'^addresult/(.+.*)/$',wait),
url(r'^login/',auth_views.login, name='login'),
url(r'^logout/',auth_views.logout_then_login,name='logout'),
url(r'^password_change_done/$',auth_views.password_change_done,name='password_change_done'),
@@ -42,12 +38,10 @@ urlpatterns = [
url(r'^password_reset_complete/$',auth_views.password_reset_complete,name='password_reset_complete'),
url(r'^rowers/',include('rowers.urls')),
url(r'^cvkbrno/',include('cvkbrno.urls')),
url(r'^add/(\d+)/(\d+)/$',add),
url(r'^call\_back',rowersviews.rower_process_callback),
url(r'^stravacall\_back',rowersviews.rower_process_stravacallback),
url(r'^sporttracks\_callback',rowersviews.rower_process_sporttrackscallback),
url(r'^twitter\_callback',rowersviews.rower_process_twittercallback),
url(r'^interactiveplot',interactiveplot),
url(r'^i18n/', include('django.conf.urls.i18n')),
]

View File

@@ -1,258 +1,11 @@
from django.http import HttpResponse,Http404,HttpResponseRedirect
from django.template import Template, Context
from django.template.loader import get_template
from django.shortcuts import render, redirect, render_to_response
from django.conf import settings
from rowsandall_app.forms import ContactForm,DocumentsForm
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from matplotlib.pyplot import figure, axes, pie, title
from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.ticker import MultipleLocator,FuncFormatter,NullFormatter
import matplotlib.pyplot as plt
from rowingdata import rower as rrower
from rowingdata import main as rmain
from rowingdata import rowingdata as rdata
from rowingdata import TCXParser
import StringIO
from django.contrib.auth.decorators import login_required
import django_rq
queue = django_rq.get_queue('default')
import datetime
import pandas as pd
import os
import numpy as np
import json
import mpld3
from rctasks import addrc
from rows import *
from rowers.tasks import add as addtask
from rowers.tasks import handle_makeplot
from celery.result import AsyncResult
from celery.exceptions import TimeoutError
from rowers.models import Rower,User,Workout,GraphImage
def showStaticImage(request,imagename):
return render(request, 'image_page.html', {'imagename': imagename})
def rootview(request):
magicsentence = rmain()
return render(request, 'frontpage.html', {'versionstring': magicsentence})
def version(request):
magicsentence = rmain()
return render(request, 'base.html', {'versionstring': magicsentence})
def rowingdata(request,formloc):
if request.method == 'POST':
form = DocumentsForm(request.POST,request.FILES)
if form.is_valid():
f = request.FILES['file']
t = request.POST['title']
res = handle_uploaded_file(f)
f1 = res[0]
f2 = res[1]
row = rdata(f2)
fig1 = row.get_timeplot_erg(t)
canvas = FigureCanvasAgg(fig1)
# response = HttpResponse(content_type='image/png')
# canvas.print_png(response)
imagename = f1+'.png'
plt.savefig('static/plots/'+imagename,format='png')
plt.close(fig1)
response = render(request,'image_page.html',{'imagename':'plots/'+imagename})
else:
response = HttpResponse("invalid form")
return response
else:
form = DocumentsForm()
return render(request, 'document_form.html',
{'form':form, 'formloc': formloc})
@login_required()
def nrowingdata(request,formloc):
if request.method == 'POST':
form = DocumentsForm(request.POST,request.FILES)
if form.is_valid():
f = request.FILES['file']
res = handle_uploaded_file(f)
t = request.POST['title']
fileformat = request.POST['fileformat']
workouttype = request.POST['workouttype']
notes = request.POST['notes']
f1 = res[0] # file name
f2 = res[1] # file name incl media directory
# handle TCX
if (fileformat == 'tcx'):
row = TCXParser(f2)
f_to_be_deleted = f2
# should delete file
f2 = f2+'.csv'
row.write_csv(f2)
os.remove(f_to_be_deleted)
imagename = f1+'.png'
fullpathimagename = 'static/plots/'+imagename
u = request.user
r = Rower.objects.get(user=request.user)
hrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
}
# make plot - asynchronous task
res = handle_makeplot.delay(f1,f2,t,hrdata)
# make workout and put in database
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
row = rdata(f2,rower=rr)
totaldist = row.df['cum_dist'].max()
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
hours = int(totaltime/3600.)
minutes = int((totaltime - 3600.*hours)/60.)
seconds = int(totaltime - 3600.*hours - 60.*minutes)
duration = "%s:%s:%s" % (hours,minutes,seconds)
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
# check for duplicate start times
r = Rower.objects.get(user=request.user)
ws = Workout.objects.filter(starttime=workoutstarttime,
user=r)
if (len(ws) != 0):
print "Warning: This workout probably already exists in the database"
w = Workout(user=r,name=t,date=workoutdate,workouttype=workouttype,
duration=duration,distance=totaldist,
weightcategory=r.weightcategory,
starttime=workoutstarttime,
csvfilename=f2,notes=notes)
w.save()
i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(),
filename=fullpathimagename)
i.save()
url = reverse(waitforplot,args=[str(res.id)])
return HttpResponseRedirect(url)
else:
response = HttpResponse("invalid form")
return response
else:
form = DocumentsForm()
return render(request, 'document_form.html',
{'form':form, 'formloc': formloc})
def uploadfile(request,formloc):
if request.method == 'POST':
form = DocumentsForm(request.POST, request.FILES)
if form.is_valid():
result = handle_uploaded_file(request.FILES['file'])
return HttpResponse("succes! "+result)
else:
return HttpResponse("Invalid Form")
else:
form = DocumentsForm()
return render(request, 'document_form.html',
{'form': form, 'formloc':formloc})
@login_required()
def add(request,x,y):
if settings.DEBUG:
task = addtask.apply_async((int(x),int(y)),countdown=10)
task_id = AsyncResult(task)
print task.id
else:
task = queue.enqueue(addrc,x,y,0)
task_id = task.id
url = reverse(wait,args=[str(task_id)])
return HttpResponseRedirect(url)
def wait(request,task_id=""):
if settings.DEBUG:
res = AsyncResult(task_id)
else:
res = queue.fetch_job(task_id)
if (res.status == 'SUCCESS') or (res.status == 'finished'):
return HttpResponse("Task complete. Result: "+str(res.result))
else:
m = "Task status: "+str(res.status)
return render(request,'waiting_page.html',{'message':m})
return HttpResponse("Task status: "+str(res.status)+". <p>Hit reload to check again")
def waitforplot(request,task_id=""):
res = AsyncResult(task_id)
if (res.status == 'SUCCESS'):
url = reverse(showplot,args=[str(res.result)])
return HttpResponseRedirect(url)
else:
m = "Task status: "+str(res.status)
return render(request,'waiting_page.html',{'message':m})
def showplot(request,imagename=""):
return render(request,'image_page.html',{'imagename':'plots/'+imagename})
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email', 'noreply@example.com'),
['siteowner@example.com'],
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm()
return render(request, 'contact_form.html', {'form': form})
def interactiveplot(request):
x = np.linspace(-10,10,num=1200)
y = x**2-5*x+4
fig = plt.figure(figsize=(6,5))
graph = plt.plot(x,y)
g = mpld3.fig_to_html(fig)
# js_data = json.dumps(mpld3.fig_to_dict(fig))
plt.close()
# return render(request,'interactiveplot.html',{"my_data":js_data})
return HttpResponse(g)