Merge branch 'develop' into feature/stravadevice
BIN
logos/uasquare.xcf
Normal file
@@ -4,6 +4,7 @@ from rowers.models import Workout, User, Rower,StrokeData
|
||||
from rowingdata import rowingdata as rrdata
|
||||
|
||||
from rowers.tasks import handle_sendemail_unrecognized
|
||||
from rowers.tasks import handle_zip_file
|
||||
|
||||
from rowingdata import rower as rrower
|
||||
from rowingdata import main as rmain
|
||||
@@ -44,7 +45,7 @@ import sys
|
||||
import django_rq
|
||||
queue = django_rq.get_queue('default')
|
||||
queuelow = django_rq.get_queue('low')
|
||||
queuehigh = django_rq.get_queue('low')
|
||||
queuehigh = django_rq.get_queue('default')
|
||||
|
||||
|
||||
user = settings.DATABASES['default']['USER']
|
||||
@@ -362,7 +363,10 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
velo = 500./pace
|
||||
|
||||
f = row.df['TimeStamp (sec)'].diff().mean()
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
if f !=0:
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
else:
|
||||
windowsize = 1
|
||||
if not 'originalvelo' in row.df:
|
||||
row.df['originalvelo'] = velo
|
||||
|
||||
@@ -569,12 +573,21 @@ def new_workout_from_file(r,f2,
|
||||
inboard = 0.88
|
||||
if len(fileformat)==3 and fileformat[0]=='zip':
|
||||
f_to_be_deleted = f2
|
||||
with zipfile.ZipFile(f2) as z:
|
||||
# for now, we're getting only the first file
|
||||
# from the NK zip file (issue #69 on bitbucket)
|
||||
f2 = z.extract(z.namelist()[0],path='media/')
|
||||
fileformat = fileformat[2]
|
||||
os.remove(f_to_be_deleted)
|
||||
title = os.path.basename(f2)
|
||||
if settings.DEBUG:
|
||||
res = handle_zip_file.delay(
|
||||
r.user.email,title,f2
|
||||
)
|
||||
|
||||
else:
|
||||
res = queuelow.enqueue(
|
||||
handle_zip_file,
|
||||
r.user.email,
|
||||
title,
|
||||
f2
|
||||
)
|
||||
|
||||
return -1,message,f2
|
||||
|
||||
# Some people try to upload Concept2 logbook summaries
|
||||
if fileformat == 'c2log':
|
||||
@@ -770,6 +783,8 @@ def rdata(file,rower=rrower()):
|
||||
res = rrdata(csvfile=file+'.gz',rower=rower)
|
||||
except IOError,IndexError:
|
||||
res = 0
|
||||
except:
|
||||
res = 0
|
||||
|
||||
return res
|
||||
|
||||
@@ -1047,7 +1062,10 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
rhythm = 0.0*forceratio
|
||||
|
||||
f = rowdatadf['TimeStamp (sec)'].diff().mean()
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
if f != 0:
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
else:
|
||||
windowsize = 1
|
||||
if windowsize <= 3:
|
||||
windowsize = 5
|
||||
|
||||
|
||||
@@ -91,6 +91,311 @@ def rdata(file,rower=rrower()):
|
||||
|
||||
return res
|
||||
|
||||
# Processes painsled CSV file to database
|
||||
def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
dosummary=True,title='Workout',
|
||||
notes='',totaldist=0,totaltime=0,
|
||||
summary='',
|
||||
makeprivate=False,
|
||||
oarlength=2.89,inboard=0.88):
|
||||
message = None
|
||||
powerperc = 100*np.array([r.pw_ut2,
|
||||
r.pw_ut1,
|
||||
r.pw_at,
|
||||
r.pw_tr,r.pw_an])/r.ftp
|
||||
|
||||
# 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,ftp=r.ftp,
|
||||
powerperc=powerperc,powerzones=r.powerzones)
|
||||
row = rdata(f2,rower=rr)
|
||||
if row == 0:
|
||||
return (0,'Error: CSV data file not found')
|
||||
|
||||
if dosmooth:
|
||||
# auto smoothing
|
||||
pace = row.df[' Stroke500mPace (sec/500m)'].values
|
||||
velo = 500./pace
|
||||
|
||||
f = row.df['TimeStamp (sec)'].diff().mean()
|
||||
if f !=0:
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
else:
|
||||
windowsize = 1
|
||||
if not 'originalvelo' in row.df:
|
||||
row.df['originalvelo'] = velo
|
||||
|
||||
if windowsize > 3 and windowsize<len(velo):
|
||||
velo2 = savgol_filter(velo,windowsize,3)
|
||||
else:
|
||||
velo2 = velo
|
||||
|
||||
velo3 = pd.Series(velo2)
|
||||
velo3 = velo3.replace([-np.inf,np.inf],np.nan)
|
||||
velo3 = velo3.fillna(method='ffill')
|
||||
|
||||
pace2 = 500./abs(velo3)
|
||||
|
||||
row.df[' Stroke500mPace (sec/500m)'] = pace2
|
||||
|
||||
row.df = row.df.fillna(0)
|
||||
|
||||
row.write_csv(f2,gzip=True)
|
||||
try:
|
||||
os.remove(f2)
|
||||
except:
|
||||
pass
|
||||
|
||||
# recalculate power data
|
||||
if workouttype == 'rower' or workouttype == 'dynamic' or workouttype == 'slides':
|
||||
try:
|
||||
row.erg_recalculatepower()
|
||||
row.write_csv(f2,gzip=True)
|
||||
except:
|
||||
pass
|
||||
|
||||
averagehr = row.df[' HRCur (bpm)'].mean()
|
||||
maxhr = row.df[' HRCur (bpm)'].max()
|
||||
|
||||
if totaldist == 0:
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
if totaltime == 0:
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
|
||||
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
if hours>23:
|
||||
message = 'Warning: The workout duration was longer than 23 hours. '
|
||||
hours = 23
|
||||
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
if minutes>59:
|
||||
minutes = 59
|
||||
if not message:
|
||||
message = 'Warning: there is something wrong with the workout duration'
|
||||
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
if seconds > 59:
|
||||
seconds = 59
|
||||
if not message:
|
||||
message = 'Warning: there is something wrong with the workout duration'
|
||||
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
if tenths > 9:
|
||||
tenths = 9
|
||||
if not message:
|
||||
message = 'Warning: there is something wrong with the workout duration'
|
||||
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
|
||||
if dosummary:
|
||||
summary = row.summary()
|
||||
summary += '\n'
|
||||
summary += row.intervalstats()
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutstartdatetime = thetimezone.localize(row.rowdatetime).astimezone(utc)
|
||||
|
||||
if makeprivate:
|
||||
privacy = 'private'
|
||||
else:
|
||||
privacy = 'visible'
|
||||
|
||||
# check for duplicate start times
|
||||
ws = Workout.objects.filter(startdatetime=workoutstartdatetime,
|
||||
user=r)
|
||||
if (len(ws) != 0):
|
||||
message = "Warning: This workout probably already exists in the database"
|
||||
|
||||
|
||||
w = Workout(user=r,name=title,date=workoutdate,
|
||||
workouttype=workouttype,
|
||||
duration=duration,distance=totaldist,
|
||||
weightcategory=r.weightcategory,
|
||||
starttime=workoutstarttime,
|
||||
csvfilename=f2,notes=notes,summary=summary,
|
||||
maxhr=maxhr,averagehr=averagehr,
|
||||
startdatetime=workoutstartdatetime,
|
||||
inboard=inboard,oarlength=oarlength,
|
||||
privacy=privacy)
|
||||
|
||||
|
||||
w.save()
|
||||
|
||||
if privacy == 'visible':
|
||||
ts = Team.objects.filter(rower=r)
|
||||
for t in ts:
|
||||
w.team.add(t)
|
||||
|
||||
# put stroke data in database
|
||||
res = dataprep(row.df,id=w.id,bands=True,
|
||||
barchart=True,otwpower=True,empower=True,inboard=inboard)
|
||||
|
||||
return (w.id,message)
|
||||
|
||||
def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
oarlength = 2.89
|
||||
inboard = 0.88
|
||||
# handle RowPro:
|
||||
if (fileformat == 'rp'):
|
||||
row = RowProParser(f2)
|
||||
# handle TCX
|
||||
if (fileformat == 'tcx'):
|
||||
row = TCXParser(f2)
|
||||
|
||||
# handle Mystery
|
||||
if (fileformat == 'mystery'):
|
||||
row = MysteryParser(f2)
|
||||
|
||||
# handle TCX no HR
|
||||
if (fileformat == 'tcxnohr'):
|
||||
row = TCXParserNoHR(f2)
|
||||
|
||||
# handle RowPerfect
|
||||
if (fileformat == 'rowperfect3'):
|
||||
row = RowPerfectParser(f2)
|
||||
|
||||
# handle ErgData
|
||||
if (fileformat == 'ergdata'):
|
||||
row = ErgDataParser(f2)
|
||||
|
||||
# handle Mike
|
||||
if (fileformat == 'bcmike'):
|
||||
row = BoatCoachAdvancedParser(f2)
|
||||
|
||||
# handle BoatCoach
|
||||
if (fileformat == 'boatcoach'):
|
||||
row = BoatCoachParser(f2)
|
||||
|
||||
# handle painsled desktop
|
||||
if (fileformat == 'painsleddesktop'):
|
||||
row = painsledDesktopParser(f2)
|
||||
|
||||
# handle speed coach GPS
|
||||
if (fileformat == 'speedcoach'):
|
||||
row = speedcoachParser(f2)
|
||||
|
||||
# handle speed coach GPS 2
|
||||
if (fileformat == 'speedcoach2'):
|
||||
row = SpeedCoach2Parser(f2)
|
||||
try:
|
||||
oarlength,inboard = get_empower_rigging(f2)
|
||||
summary = row.allstats()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# handle ErgStick
|
||||
if (fileformat == 'ergstick'):
|
||||
row = ErgStickParser(f2)
|
||||
|
||||
# handle FIT
|
||||
if (fileformat == 'fit'):
|
||||
row = FITParser(f2)
|
||||
s = fitsummarydata(f2)
|
||||
s.setsummary()
|
||||
summary = s.summarytext
|
||||
|
||||
|
||||
f_to_be_deleted = f2
|
||||
# should delete file
|
||||
f2 = f2[:-4]+'o.csv'
|
||||
row.write_csv(f2,gzip=True)
|
||||
|
||||
#os.remove(f2)
|
||||
try:
|
||||
os.remove(f_to_be_deleted)
|
||||
except:
|
||||
os.remove(f_to_be_deleted+'.gz')
|
||||
|
||||
return (f2,summary,oarlength,inboard)
|
||||
|
||||
# Create new workout from file and store it in the database
|
||||
# This routine should be used everywhere in views.py and mailprocessing.py
|
||||
# Currently there is code duplication
|
||||
def new_workout_from_file(r,f2,
|
||||
workouttype='rower',
|
||||
title='Workout',
|
||||
makeprivate=False,
|
||||
notes=''):
|
||||
message = None
|
||||
fileformat = get_file_type(f2)
|
||||
summary = ''
|
||||
oarlength = 2.89
|
||||
inboard = 0.88
|
||||
if len(fileformat)==3 and fileformat[0]=='zip':
|
||||
f_to_be_deleted = f2
|
||||
with zipfile.ZipFile(f2) as z:
|
||||
for fname in z.namelist():
|
||||
f3 = z.extract(fname,path='media/')
|
||||
id,message,f2 = new_workout_from_file(r,f3,
|
||||
workouttype=workouttype,
|
||||
makeprivate=makeprivate,
|
||||
title = title,
|
||||
notes='')
|
||||
os.remove(f_to_be_deleted)
|
||||
return id,message,f2
|
||||
|
||||
# Some people try to upload Concept2 logbook summaries
|
||||
if fileformat == 'c2log':
|
||||
os.remove(f2)
|
||||
message = "This C2 logbook summary does not contain stroke data. Please download the Export Stroke Data file from the workout details on the C2 logbook."
|
||||
return (0,message,f2)
|
||||
|
||||
if fileformat == 'nostrokes':
|
||||
os.remove(f2)
|
||||
message = "It looks like this file doesn't contain stroke data."
|
||||
return (0,message,f2)
|
||||
|
||||
# Some people try to upload RowPro summary logs
|
||||
if fileformat == 'rowprolog':
|
||||
os.remove(f2)
|
||||
message = "This RowPro logbook summary does not contain stroke data. Please use the Stroke Data CSV file for the individual workout in your log."
|
||||
return (0,message,f2)
|
||||
|
||||
# Sometimes people try an unsupported file type.
|
||||
# Send an email to info@rowsandall.com with the file attached
|
||||
# for me to check if it is a bug, or a new file type
|
||||
# worth supporting
|
||||
if fileformat == 'unknown':
|
||||
message = "We couldn't recognize the file type"
|
||||
if settings.DEBUG:
|
||||
res = handle_sendemail_unrecognized.delay(f2,
|
||||
r.user.email)
|
||||
|
||||
else:
|
||||
res = queuehigh.enqueue(handle_sendemail_unrecognized,
|
||||
f2,r.user.email)
|
||||
return (0,message,f2)
|
||||
|
||||
# handle non-Painsled by converting it to painsled compatible CSV
|
||||
if (fileformat != 'csv'):
|
||||
try:
|
||||
f2,summary,oarlength,inboard = handle_nonpainsled(f2,
|
||||
fileformat,
|
||||
summary=summary)
|
||||
except:
|
||||
errorstring = str(sys.exc_info()[0])
|
||||
message = 'Something went wrong: '+errorstring
|
||||
return (0,message,'')
|
||||
|
||||
|
||||
|
||||
dosummary = (fileformat != 'fit')
|
||||
id,message = save_workout_database(f2,r,
|
||||
workouttype=workouttype,
|
||||
makeprivate=makeprivate,
|
||||
dosummary=dosummary,
|
||||
summary=summary,
|
||||
inboard=inboard,oarlength=oarlength,
|
||||
title=title)
|
||||
|
||||
return (id,message,f2)
|
||||
|
||||
def delete_strokedata(id,debug=True):
|
||||
if debug:
|
||||
engine = create_engine(database_url_debug, echo=False)
|
||||
|
||||
@@ -90,6 +90,24 @@ class UploadOptionsForm(forms.Form):
|
||||
class Meta:
|
||||
fields = ['make_plot','plottype','upload_toc2','makeprivate']
|
||||
|
||||
# The form to indicate additional actions to be performed immediately
|
||||
# after a successful upload. This version allows the Team manager to select
|
||||
# a team member
|
||||
class TeamUploadOptionsForm(forms.Form):
|
||||
plotchoices = (
|
||||
('timeplot','Time Plot'),
|
||||
('distanceplot','Distance Plot'),
|
||||
('pieplot','Pie Chart'),
|
||||
)
|
||||
make_plot = forms.BooleanField(initial=False,required=False)
|
||||
plottype = forms.ChoiceField(required=False,
|
||||
choices=plotchoices,
|
||||
initial='timeplot',
|
||||
label='Plot Type')
|
||||
|
||||
class Meta:
|
||||
fields = ['make_plot','plottype']
|
||||
|
||||
# This form is used on the Analysis page to add a custom distance/time
|
||||
# trial and predict the pace
|
||||
class PredictedPieceForm(forms.Form):
|
||||
|
||||
@@ -63,12 +63,21 @@ class Command(BaseCommand):
|
||||
z = zipfile.ZipFile(a.document)
|
||||
for f in z.namelist():
|
||||
f2 = z.extract(f,path='media/')
|
||||
title = os.path.basename(f2)
|
||||
wid = [
|
||||
make_new_workout_from_email(rr,f2[6:],name)
|
||||
make_new_workout_from_email(rr,f2[6:],title)
|
||||
]
|
||||
res += wid
|
||||
link = 'http://rowsandall.com/rowers/workout/'+str(wid[0])+'/edit'
|
||||
dd = send_confirm(rr.user,name,link)
|
||||
try:
|
||||
dd = send_confirm(rr.user,title,link)
|
||||
time.sleep(10)
|
||||
except:
|
||||
try:
|
||||
time.sleep(10)
|
||||
dd = send_confirm(rr.user,title,link)
|
||||
except:
|
||||
pass
|
||||
|
||||
else:
|
||||
# move attachment and make workout
|
||||
@@ -87,6 +96,7 @@ class Command(BaseCommand):
|
||||
donotdelete = 1
|
||||
try:
|
||||
dd = send_confirm(rr.user,name,link)
|
||||
time.sleep(10)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@@ -195,6 +195,10 @@ class Rower(models.Model):
|
||||
sporttrackstokenexpirydate = models.DateTimeField(blank=True,null=True)
|
||||
sporttracksrefreshtoken = models.CharField(default='',max_length=200,
|
||||
blank=True,null=True)
|
||||
underarmourtoken = models.CharField(default='',max_length=200,blank=True,null=True)
|
||||
underarmourtokenexpirydate = models.DateTimeField(blank=True,null=True)
|
||||
underarmourrefreshtoken = models.CharField(default='',max_length=200,
|
||||
blank=True,null=True)
|
||||
stravatoken = models.CharField(default='',max_length=200,blank=True,null=True)
|
||||
|
||||
runkeepertoken = models.CharField(default='',max_length=200,
|
||||
@@ -360,6 +364,7 @@ class Workout(models.Model):
|
||||
maxhr = models.IntegerField(blank=True,null=True)
|
||||
uploadedtostrava = models.IntegerField(default=0)
|
||||
uploadedtosporttracks = models.IntegerField(default=0)
|
||||
uploadedtounderarmour = models.IntegerField(default=0)
|
||||
uploadedtorunkeeper = models.IntegerField(default=0)
|
||||
|
||||
# empower stuff
|
||||
|
||||
@@ -21,7 +21,7 @@ import stravalib
|
||||
from utils import serialize_list,deserialize_list
|
||||
|
||||
from rowers.dataprepnodjango import update_strokedata
|
||||
|
||||
from rowers.dataprepnodjango import new_workout_from_file
|
||||
|
||||
from django.core.mail import send_mail, BadHeaderError,EmailMessage
|
||||
|
||||
@@ -30,6 +30,16 @@ from django.core.mail import send_mail, BadHeaderError,EmailMessage
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
# create workout
|
||||
@app.task
|
||||
def handle_new_workout_from_file(r,f2,
|
||||
workouttype='rower',
|
||||
title='Workout',
|
||||
makeprivate=False,
|
||||
notes=''):
|
||||
return new_workout_from_file(r,f2,workouttype,
|
||||
title,makeprivate,notes)
|
||||
|
||||
# send email to me when an unrecognized file is uploaded
|
||||
@app.task
|
||||
def handle_sendemail_unrecognized(unrecognizedfile,useremail):
|
||||
@@ -80,6 +90,17 @@ def handle_sendemailtcx(first_name,last_name,email,tcxfile):
|
||||
os.remove(tcxfile)
|
||||
return 1
|
||||
|
||||
@app.task
|
||||
def handle_zip_file(emailfrom,subject,file):
|
||||
message = "... zip processing ... "
|
||||
email = EmailMessage(subject,message,
|
||||
emailfrom,
|
||||
['workouts@rowsandall.com'])
|
||||
email.attach_file(file)
|
||||
res = email.send()
|
||||
time.sleep(60)
|
||||
return 1
|
||||
|
||||
# Send email with CSV attachment
|
||||
@app.task
|
||||
def handle_sendemailcsv(first_name,last_name,email,csvfile):
|
||||
|
||||
@@ -159,7 +159,7 @@ def create_request(team,user):
|
||||
if r2 in Rower.objects.filter(team=team):
|
||||
return (0,'Already a member of that team')
|
||||
|
||||
if count_club_members(team.manager)+count_invites(team.manager) < r.clubsize:
|
||||
if count_club_members(team.manager)+count_invites(team.manager) <= r.clubsize:
|
||||
codes = [i.code for i in TeamRequest.objects.all()]
|
||||
code = uuid.uuid4().hex[:10].upper()
|
||||
# prevent duplicates
|
||||
@@ -200,7 +200,7 @@ def create_invite(team,manager,user=None,email=''):
|
||||
except Rower.MultipleObjectsReturned:
|
||||
return (0,'There is more than one user with that email address')
|
||||
|
||||
if count_club_members(team.manager)+count_invites(team.manager) < r.clubsize:
|
||||
if count_club_members(team.manager)+count_invites(team.manager) <= r.clubsize:
|
||||
codes = [i.code for i in TeamInvite.objects.all()]
|
||||
code = uuid.uuid4().hex[:10].upper()
|
||||
# prevent duplicates
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "bases.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "bases.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "bases.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "bases.html" %}
|
||||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{% load cookielaw_tags %}
|
||||
{% load analytical %}
|
||||
{% load rowerfilters %}
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -143,13 +144,17 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="grid_1 tooltip">
|
||||
{% if user.is_authenticated and teams %}
|
||||
{% if user.is_authenticated and user|has_teams %}
|
||||
<div class="grid_1 alpha dropdown">
|
||||
<button class="grid_1 alpha button gray small dropbtn">
|
||||
Teams
|
||||
Teams
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for t in teams %}
|
||||
<a class="button gray small" href="/rowers/me/teams/">Manage Teams</a>
|
||||
{% if user|is_manager %}
|
||||
<a class="button gray small" href="/rowers/workout/upload/team/">Upload Team Member Workout</a>
|
||||
{% endif %}
|
||||
{% for t in user|user_teams %}
|
||||
<a class="button gray small" href="/rowers/list-workouts/team/{{ t.id }}/">{{ t.name }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -214,7 +219,7 @@
|
||||
<p id="footer">
|
||||
<a href="/rowers/legal">Legal</a></p>
|
||||
</div>
|
||||
<div class="grid_2">
|
||||
<div class="grid_1">
|
||||
<p id="footer">
|
||||
<a href="/rowers/partners">Partners</a></p>
|
||||
</div>
|
||||
@@ -226,9 +231,9 @@
|
||||
<p id="footer">
|
||||
<a href="http://analytics.rowsandall.com/">Rowing Analytics BLOG</a></p>
|
||||
</div>
|
||||
<div class="grid_1 omega">
|
||||
<div class="grid_2 omega">
|
||||
<p id="footer">
|
||||
<a href="/rowers/email">Contact</a></p>
|
||||
<a href="https://www.facebook.com/groups/rowsandall/">Facebook group</a></p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{% load cookielaw_tags %}
|
||||
{% load analytical %}
|
||||
{% load rowerfilters %}
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -31,7 +32,6 @@
|
||||
<style>
|
||||
.splash {
|
||||
background-color: transparent;
|
||||
background-image: url("/static/img/landing1.jpg");
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
@@ -41,11 +41,13 @@
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.container_12 {background-color: rgba(255,255,255,0.7);}
|
||||
.container_12 {background-color: rgba(255,255,255,0.0);}
|
||||
.container_top {background-color: rgba(255,255,255,0.7);}
|
||||
</style>
|
||||
|
||||
<div class="splash">
|
||||
<div id="bgpic" class="splash">
|
||||
{% analytical_body_top %}
|
||||
<div class="container_top">
|
||||
<div class="container_12">
|
||||
<div class="grid_12">
|
||||
|
||||
@@ -161,13 +163,17 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="grid_1 tooltip">
|
||||
{% if user.is_authenticated and teams %}
|
||||
{% if user.is_authenticated and user|user_teams %}
|
||||
<div class="grid_1 alpha dropdown">
|
||||
<button class="grid_1 alpha button gray small dropbtn">
|
||||
Teams
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for t in teams %}
|
||||
<a class="button gray small" href="/rowers/me/teams/">Manage Teams</a>
|
||||
{% if user|is_manager %}
|
||||
<a class="button gray small" href="/rowers/workout/upload/team/">Upload Team Member Workout</a>
|
||||
{% endif %}
|
||||
{% for t in user|user_teams %}
|
||||
<a class="button gray small" href="/rowers/list-workouts/team/{{ t.id }}/">{{ t.name }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -232,7 +238,7 @@
|
||||
<p id="footer">
|
||||
<a href="/rowers/legal">Legal</a></p>
|
||||
</div>
|
||||
<div class="grid_2">
|
||||
<div class="grid_1">
|
||||
<p id="footer">
|
||||
<a href="/rowers/partners">Partners</a></p>
|
||||
</div>
|
||||
@@ -244,15 +250,27 @@
|
||||
<p id="footer">
|
||||
<a href="http://analytics.rowsandall.com/">Rowing Analytics BLOG</a></p>
|
||||
</div>
|
||||
<div class="grid_1 omega">
|
||||
<div class="grid_2 omega">
|
||||
<p id="footer">
|
||||
<a href="/rowers/email">Contact</a></p>
|
||||
<a href="https://www.facebook.com/groups/rowsandall/">Facebook group</a></p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% cookielaw_banner %}
|
||||
</div>
|
||||
</div>
|
||||
<!-- end container -->
|
||||
{% analytical_body_bottom %}
|
||||
<script type="text/javascript">
|
||||
var num = (Math.floor(Math.random()*4));
|
||||
|
||||
var array = ['one', 'two', 'three', 'four'];
|
||||
|
||||
|
||||
var elem = document.getElementById('bgpic');
|
||||
console.log(elem);
|
||||
elem.classList.add(array[num]);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}File loading{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||
<div id="left" class="grid_6 alpha">
|
||||
<h1>Upload Workout File</h1>
|
||||
<h1>Upload Workout File</h1>
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<p>Looking for <a href="/rowers/workout/upload/team/">Team Manager
|
||||
Upload?</a></p>
|
||||
{% endif %}
|
||||
{% if form.errors %}
|
||||
<p style="color: red;">
|
||||
Please correct the error{{ form.errors|pluralize }} below.
|
||||
|
||||
@@ -68,6 +68,14 @@ Bug reports and feature requests can be done through our BitBucket page. Please
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h1>Facebook Group</h1>
|
||||
|
||||
<p>We run a facebook group where you can post questions and report problems,
|
||||
especially if you think the wider user community benefits from the answers.</p>
|
||||
<ul>
|
||||
<li><a href="https://www.facebook.com/groups/rowsandall/">https://www.facebook.com/groups/rowsandall/</a></li>
|
||||
</ul>
|
||||
|
||||
<h1>Twitter</h1>
|
||||
|
||||
<p>You can also check me on Twitter:
|
||||
@@ -79,4 +87,4 @@ When the site is down, this is the appropriate channel to look for apologies, up
|
||||
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
|
||||
|
||||
@@ -111,6 +111,24 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if workout.uploadedtounderarmour == 0 %}
|
||||
{% if user.rower.underarmourtoken == None or user.rower.underarmourtoken == '' %}
|
||||
<div class="grid_1">
|
||||
<a href="/rowers/me/underarmourauthorize">
|
||||
<img src="/static/img/uagray.png" alt="Underarmour icon" width="60" height="60"></a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="grid_1">
|
||||
<a href="/rowers/workout/{{ workout.id }}/underarmouruploadw"><img src="/static/img/uasquare.png" alt="Underarmour icon" width="60" height="60"></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="grid_1">
|
||||
<a href="https://www.mapmyfitness.com/workout/{{ workout.uploadedtounderarmour }}">
|
||||
<img src="/static/img/uachecked.png" alt="Underarmour icon" width="60" height="60"></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -138,8 +156,11 @@
|
||||
|
||||
</div>
|
||||
<div class="grid_6">
|
||||
<div class="grid_2 alpha suffix_4">
|
||||
<p><a href="/rowers/me/runkeeperauthorize/"><img src="/static/img/rk-logo.png" alt="connect with RunKeeper" width="120"></a></p>
|
||||
<div class="grid_2 alpha">
|
||||
<p><a href="/rowers/me/runkeeperauthorize/"><img src="/static/img/rk-logo.png" alt="connect with Runkeeper" width="120"></a></p>
|
||||
</div>
|
||||
<div class="grid_2">
|
||||
<p><a href="/rowers/me/underarmourauthorize/"><img src="/static/img/UAbtn.png" alt="connect with Under Armour" width="120"></a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -43,12 +43,22 @@
|
||||
<p>Import workouts from RunKeeper</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid_6">
|
||||
<div class="grid_3 alpha">
|
||||
<p>
|
||||
<a href="/rowers/workout/underarmourimport"><img src="/static/img/UAbtn.png" alt="Under Armour logo" width="140"></a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid_3 omega">
|
||||
<p>Import workouts from MapMyFitness/UnderArmour</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid_6 omega">
|
||||
<h3>Connect</h3>
|
||||
|
||||
<div class="grid_6">
|
||||
<div class="grid_6 alpha">
|
||||
<p>Click one of the below logos to connect to the service of your choice.
|
||||
You only need to do this once. After that, the site will have access until you
|
||||
revoke the authorization for the "rowingdata" app.</p>
|
||||
@@ -67,10 +77,13 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="grid_6">
|
||||
<div class="grid_2 alpha suffix_4">
|
||||
<div class="grid_6 alpha">
|
||||
<div class="grid_2 alpha">
|
||||
<p><a href="/rowers/me/runkeeperauthorize/"><img src="/static/img/rk-logo.png" alt="connect with RunKeeper" width="120"></a></p>
|
||||
</div>
|
||||
<div class="grid_2 suffix_2 omega">
|
||||
<p><a href="/rowers/me/underarmourauthorize/"><img src="/static/img/UAbtn.png" alt="connect with Under Armour" width="120"></a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -35,7 +35,9 @@
|
||||
|
||||
<div id="workouts_table" class="grid_8 alpha">
|
||||
{% if team %}
|
||||
{% include "teambuttons.html" with teamid=team.id %}
|
||||
<div class="grid_8 alpha">
|
||||
{% include "teambuttons.html" with teamid=team.id %}
|
||||
</div>
|
||||
<h3>{{ team.name }} Team Workouts</h3>
|
||||
{% else %}
|
||||
<h3>My Workouts</h3>
|
||||
|
||||
55
rowers/templates/team_document_form.html
Normal file
@@ -0,0 +1,55 @@
|
||||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}File loading{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||
<div id="left" class="grid_6 alpha">
|
||||
<h1>Upload Workout File</h1>
|
||||
{% if form.errors %}
|
||||
<p style="color: red;">
|
||||
Please correct the error{{ form.errors|pluralize }} below.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<table>
|
||||
{{ rowerform.as_table }}
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
|
||||
<input class="button green" type="submit" value="Submit">
|
||||
</div>
|
||||
</div>
|
||||
<div id="right" class="grid_6 omega">
|
||||
<h1>Optional extra actions</h1>
|
||||
<p>
|
||||
<table>
|
||||
{{ optionsform.as_table }}
|
||||
</table>
|
||||
</p>
|
||||
<p>
|
||||
You can select one static plot to be generated immediately for this workout. You can select to upload to Concept2 automatically. If you check "make private", this workout will not be visible to your followers and will not show up in your teams' workouts list.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Valid file types are:
|
||||
<ul>
|
||||
<li>Painsled iOS Stroke Export (CSV)</li>
|
||||
<li>Painsled desktop version Stroke Export (CSV)</li>
|
||||
<li>A TCX file with location data (lat,long) - with or without Heart Rate value, for example from RiM or CrewNerd</li>
|
||||
<li>RowPro CSV export</li>
|
||||
<li>SpeedCoach GPS and SpeedCoach GPS 2 CSV export</li>
|
||||
<li>ErgData CSV export</li>
|
||||
<li>ErgStick CSV export</li>
|
||||
<li>BoatCoach CSV export</li>
|
||||
<li>A FIT file with location data (experimental)</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -1,3 +1,4 @@
|
||||
{% load rowerfilters %}
|
||||
<div class="grid_2 alpha">
|
||||
<p>
|
||||
<a class="button gray small" href="/rowers/list-workouts/team/{{ teamid }}/">Team Workouts</a>
|
||||
@@ -8,8 +9,17 @@
|
||||
<a class="button gray small" href="/rowers/team-compare-select/team/{{ teamid }}/">Multi Compare</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid_2 suffix_2 omega">
|
||||
<div class="grid_2">
|
||||
<p>
|
||||
<a class="button gray small" href="/rowers/team/{{ teamid }}/">Team Page</a>
|
||||
</p>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid_2 omega">
|
||||
{% if user|is_manager and user|has_teams %}
|
||||
<p>
|
||||
<a class="button gray small" href="/rowers/workout/upload/team/">Upload Workout</a>
|
||||
</p>
|
||||
{% else %}
|
||||
<p> </p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -36,10 +36,76 @@
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="grid_6 omega">
|
||||
{% if otherteams %}
|
||||
<h2>Other Teams</h2>
|
||||
<table width="70%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Manager</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for team in otherteams %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/rowers/team/{{ team.id }}/">{{ team.name }}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ team.manager.first_name }} {{ team.manager.last_name }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% else %}
|
||||
<p> </p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid_12 alpha">
|
||||
<div class="grid_6 alpha">
|
||||
{% if user.rower.rowerplan == 'coach' %}
|
||||
<h2>Teams I manage</h2>
|
||||
<p>Number of members: {{ clubsize }}</p>
|
||||
<p>Maximum club size: {{ max_clubsize }}</p>
|
||||
{% if myteams %}
|
||||
<table width="70%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Manager</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for team in myteams %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/rowers/team/{{ team.id }}/">{{ team.name }}</a>
|
||||
</td>
|
||||
<td>
|
||||
<div class="grid_1">
|
||||
<a class="button small red" href="/rowers/team/{{ team.id }}/deleteconfirm">Delete</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<div class="grid_2 suffix_4 alpha">
|
||||
<a class="button green" href="/rowers/team/create">New Team</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<p> </p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="grid_6 omega">
|
||||
{% if invites or requests or myrequests or myinvites %}
|
||||
<p>
|
||||
<h2>Invitations and Requests</h2>
|
||||
<table width="90%" class="listtable">
|
||||
<thead>
|
||||
@@ -126,70 +192,5 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid_12 alpha">
|
||||
<div class="grid_6 alpha">
|
||||
{% if user.rower.rowerplan == 'coach' %}
|
||||
<h2>Teams I manage</h2>
|
||||
{% if myteams %}
|
||||
<table width="70%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Manager</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for team in myteams %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/rowers/team/{{ team.id }}/">{{ team.name }}</a>
|
||||
</td>
|
||||
<td>
|
||||
<div class="grid_1">
|
||||
<a class="button small red" href="/rowers/team/{{ team.id }}/deleteconfirm">Delete</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<div class="grid_2 suffix_4 alpha">
|
||||
<a class="button green" href="/rowers/team/create">New Team</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<p> </p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="grid_6 omega">
|
||||
{% if otherteams %}
|
||||
<h2>Other Teams</h2>
|
||||
<table width="70%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Manager</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for team in otherteams %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/rowers/team/{{ team.id }}/">{{ team.name }}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ team.manager.first_name }} {{ team.manager.last_name }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% else %}
|
||||
<p> </p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
37
rowers/templates/underarmour_list_import.html
Normal file
@@ -0,0 +1,37 @@
|
||||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}Workouts{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Available on MapMyFitness (UnderArmour)</h1>
|
||||
{% if workouts %}
|
||||
<table width="70%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> Import </th>
|
||||
<th> Date/Time </th>
|
||||
<th> Duration </th>
|
||||
<th> Total Distance</th>
|
||||
<th> Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for workout in workouts %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/rowers/workout/underarmourimport/{{ workout|ualookup:'id' }}/">Import</a></td>
|
||||
<td>{{ workout|ualookup:'starttime' }}</td>
|
||||
<td>{{ workout|ualookup:'duration' }} </td>
|
||||
<td>{{ workout|ualookup:'distance' }} m</td>
|
||||
<td>{{ workout|ualookup:'type' }}</td>
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p> No workouts found. We only list workouts with time data series. </p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -1,5 +1,6 @@
|
||||
from django import template
|
||||
from time import strftime
|
||||
import dateutil.parser
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@@ -27,6 +28,17 @@ def strfdeltah(tdelta):
|
||||
|
||||
return res
|
||||
|
||||
def secondstotimestring(tdelta):
|
||||
hours, rest = divmod(tdelta,3600)
|
||||
minutes,seconds = divmod(rest,60)
|
||||
res = "{hours:0>2}:{minutes:0>2}:{seconds:0>2}".format(
|
||||
hours=hours,
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
@register.filter
|
||||
def durationprint(d,dstring):
|
||||
if (d == None):
|
||||
@@ -57,6 +69,22 @@ def lookup(dict, key):
|
||||
s = s[:22]
|
||||
return s
|
||||
|
||||
@register.filter
|
||||
def ualookup(dict, key):
|
||||
s = dict.get(key)
|
||||
|
||||
if key=='distance':
|
||||
s = int(float(s))
|
||||
|
||||
if key=='duration':
|
||||
s = secondstotimestring(int(s))
|
||||
|
||||
|
||||
if key=='starttime':
|
||||
s = dateutil.parser.parse(s)
|
||||
|
||||
return s
|
||||
|
||||
@register.filter(name='times')
|
||||
def times(number):
|
||||
return range(number)
|
||||
@@ -65,3 +93,35 @@ def times(number):
|
||||
def get_field_id(id,s,form):
|
||||
field_name = s+str(id)
|
||||
return form.__getitem__(field_name)
|
||||
|
||||
from rowers.models import Rower,Team
|
||||
|
||||
@register.filter
|
||||
def is_manager(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
return r.rowerplan == 'coach'
|
||||
|
||||
@register.filter
|
||||
def user_teams(user):
|
||||
try:
|
||||
therower = Rower.objects.get(user=user)
|
||||
teams1 = therower.team.all()
|
||||
teams2 = Team.objects.filter(manager=user)
|
||||
teams = list(set(teams1).union(set(teams2)))
|
||||
except TypeError:
|
||||
teams = []
|
||||
|
||||
return teams
|
||||
|
||||
@register.filter
|
||||
def has_teams(user):
|
||||
try:
|
||||
therower = Rower.objects.get(user=user)
|
||||
teams1 = therower.team.all()
|
||||
teams2 = Team.objects.filter(manager=user)
|
||||
teams = list(set(teams1).union(set(teams2)))
|
||||
return True
|
||||
except TypeError:
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
@@ -702,7 +702,7 @@ class ViewTest(TestCase):
|
||||
|
||||
f.close()
|
||||
|
||||
self.assertRedirects(response, expected_url='/rowers/workout/upload/This%20C2%20logbook%20summary%20does%20not%20contain%20stroke%20data.%20Please%20download%20the%20Export%20Stroke%20Data%20file%20from%20the%20workout%20details%20on%20the%20C2%20logbook.',
|
||||
self.assertRedirects(response, expected_url='/rowers/workout/upload/c/This%20C2%20logbook%20summary%20does%20not%20contain%20stroke%20data.%20Please%20download%20the%20Export%20Stroke%20Data%20file%20from%20the%20workout%20details%20on%20the%20C2%20logbook.',
|
||||
status_code=302,target_status_code=200)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
385
rowers/underarmourstuff.py
Normal file
@@ -0,0 +1,385 @@
|
||||
# All the functionality needed to connect to Runkeeper
|
||||
|
||||
# Python
|
||||
import oauth2 as oauth
|
||||
import cgi
|
||||
import requests
|
||||
import requests.auth
|
||||
import json
|
||||
from django.utils import timezone
|
||||
from datetime import datetime
|
||||
import numpy as np
|
||||
from dateutil import parser
|
||||
import time
|
||||
import math
|
||||
from math import sin,cos,atan2,sqrt
|
||||
import os,sys
|
||||
import urllib
|
||||
|
||||
# Django
|
||||
from django.shortcuts import render_to_response
|
||||
from django.http import HttpResponseRedirect, HttpResponse,JsonResponse
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
# Project
|
||||
# from .models import Profile
|
||||
from rowingdata import rowingdata
|
||||
import pandas as pd
|
||||
from rowers.models import Rower,Workout
|
||||
|
||||
from rowsandall_app.settings import (
|
||||
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
|
||||
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET,
|
||||
UNDERARMOUR_CLIENT_ID, UNDERARMOUR_CLIENT_SECRET,
|
||||
UNDERARMOUR_REDIRECT_URI,UNDERARMOUR_CLIENT_KEY,
|
||||
)
|
||||
|
||||
# Custom error class - to raise a NoTokenError
|
||||
class UnderArmourNoTokenError(Exception):
|
||||
def __init__(self,value):
|
||||
self.value=value
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
|
||||
# Exponentially weighted moving average
|
||||
# Used for data smoothing of the jagged data obtained by Strava
|
||||
# See bitbucket issue 72
|
||||
def ewmovingaverage(interval,window_size):
|
||||
# Experimental code using Exponential Weighted moving average
|
||||
|
||||
try:
|
||||
intervaldf = pd.DataFrame({'v':interval})
|
||||
idf_ewma1 = intervaldf.ewm(span=window_size)
|
||||
idf_ewma2 = intervaldf[::-1].ewm(span=window_size)
|
||||
|
||||
i_ewma1 = idf_ewma1.mean().ix[:,'v']
|
||||
i_ewma2 = idf_ewma2.mean().ix[:,'v']
|
||||
|
||||
interval2 = np.vstack((i_ewma1,i_ewma2[::-1]))
|
||||
interval2 = np.mean( interval2, axis=0) # average
|
||||
except ValueError:
|
||||
interval2 = interval
|
||||
|
||||
return interval2
|
||||
|
||||
from utils import geo_distance
|
||||
|
||||
|
||||
# Custom exception handler, returns a 401 HTTP message
|
||||
# with exception details in the json data
|
||||
def custom_exception_handler(exc,message):
|
||||
|
||||
response = {
|
||||
"errors": [
|
||||
{
|
||||
"code": str(exc),
|
||||
"detail": message,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
res = HttpResponse(message)
|
||||
res.status_code = 401
|
||||
res.json = json.dumps(response)
|
||||
|
||||
return res
|
||||
|
||||
# Refresh ST token using refresh token
|
||||
def do_refresh_token(refreshtoken,access_token):
|
||||
client_auth = requests.auth.HTTPBasicAuth(UNDERARMOUR_CLIENT_KEY, UNDERARMOUR_CLIENT_SECRET)
|
||||
post_data = {"grant_type": "refresh_token",
|
||||
"client_secret": UNDERARMOUR_CLIENT_SECRET,
|
||||
"client_id":UNDERARMOUR_CLIENT_KEY,
|
||||
"refresh_token": refreshtoken,
|
||||
}
|
||||
headers = {'user-agent': 'sanderroosendaal',
|
||||
"Api-Key":UNDERARMOUR_CLIENT_KEY,
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'authorization': 'Bearer %s' % access_token}
|
||||
|
||||
url = "https://api.ua.com/v7.1/oauth2/access_token/"
|
||||
|
||||
response = requests.post(url,
|
||||
data=post_data,
|
||||
headers=headers)
|
||||
|
||||
token_json = response.json()
|
||||
thetoken = token_json['access_token']
|
||||
expires_in = token_json['expires_in']
|
||||
try:
|
||||
refresh_token = token_json['refresh_token']
|
||||
except KeyError:
|
||||
refresh_token = refreshtoken
|
||||
|
||||
return [thetoken,expires_in,refresh_token]
|
||||
|
||||
# Exchange access code for long-lived access token
|
||||
def get_token(code):
|
||||
client_auth = requests.auth.HTTPBasicAuth(UNDERARMOUR_CLIENT_KEY, UNDERARMOUR_CLIENT_SECRET)
|
||||
post_data = {
|
||||
"grant_type": "authorization_code",
|
||||
"code": code,
|
||||
"client_secret": UNDERARMOUR_CLIENT_SECRET,
|
||||
"client_id":UNDERARMOUR_CLIENT_KEY,
|
||||
}
|
||||
headers = {
|
||||
'user-agent': 'sanderroosendaal',
|
||||
"Api-Key":UNDERARMOUR_CLIENT_KEY,
|
||||
}
|
||||
|
||||
response = requests.post("https://api.ua.com/v7.1/oauth2/access_token/",
|
||||
data=post_data,
|
||||
headers=headers)
|
||||
try:
|
||||
token_json = response.json()
|
||||
thetoken = token_json['access_token']
|
||||
expires_in = token_json['expires_in']
|
||||
refresh_token = token_json['refresh_token']
|
||||
except KeyError:
|
||||
thetoken = 0
|
||||
|
||||
return thetoken,expires_in,refresh_token
|
||||
|
||||
# Make authorization URL including random string
|
||||
def make_authorization_url(request):
|
||||
# Generate a random string for the state parameter
|
||||
# Save it for use later to prevent xsrf attacks
|
||||
from uuid import uuid4
|
||||
state = str(uuid4())
|
||||
|
||||
params = {"client_id": UNDERARMOUR_CLIENT_KEY,
|
||||
"response_type": "code",
|
||||
"redirect_uri": UNDERARMOUR_REDIRECT_URI,
|
||||
}
|
||||
url = "https://www.mapmyfitness.com/v7.1/oauth2/uacf/authorize/" +urllib.urlencode(params)
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Get list of workouts available on Underarmour
|
||||
def get_underarmour_workout_list(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.underarmourtoken == '') or (r.underarmourtoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.underarmourtoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'Api-Key': UNDERARMOUR_CLIENT_KEY,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.ua.com/v7.1/workout/?user="+str(get_userid(r.underarmourtoken))
|
||||
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
return s
|
||||
|
||||
# Get workout summary data by Underarmour ID
|
||||
def get_underarmour_workout(user,underarmourid):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.underarmourtoken == '') or (r.underarmourtoken is None):
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.underarmourtoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'Api-Key': UNDERARMOUR_CLIENT_KEY,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.ua.com/v7.1/workout/"+str(underarmourid)+"/?field_set=time_series"
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
return s
|
||||
|
||||
# Create Workout Data for upload to Underarmour
|
||||
def createunderarmourworkoutdata(w):
|
||||
filename = w.csvfilename
|
||||
try:
|
||||
row = rowingdata(filename)
|
||||
except:
|
||||
return 0
|
||||
|
||||
averagehr = int(row.df[' HRCur (bpm)'].mean())
|
||||
maxhr = int(row.df[' HRCur (bpm)'].max())
|
||||
duration = w.duration.hour*3600
|
||||
duration += w.duration.minute*60
|
||||
duration += w.duration.second
|
||||
duration += +1.0e-6*w.duration.microsecond
|
||||
name = w.name
|
||||
notes = w.notes
|
||||
|
||||
# adding diff, trying to see if this is valid
|
||||
#t = row.df.ix[:,'TimeStamp (sec)'].values-10*row.df.ix[0,'TimeStamp (sec)']
|
||||
t = row.df.ix[:,'TimeStamp (sec)'].values-row.df.ix[0,'TimeStamp (sec)']
|
||||
t[0] = t[1]
|
||||
|
||||
d = row.df.ix[:,'cum_dist'].values
|
||||
d[0] = d[1]
|
||||
t = t.astype(int)
|
||||
d = d.astype(int)
|
||||
spm = row.df[' Cadence (stokes/min)'].astype(int)
|
||||
spm[0] = spm[1]
|
||||
hr = row.df[' HRCur (bpm)'].astype(int)
|
||||
|
||||
haslatlon=1
|
||||
|
||||
try:
|
||||
lat = row.df[' latitude'].values
|
||||
lon = row.df[' longitude'].values
|
||||
if not lat.std() and not lon.std():
|
||||
haslatlon = 0
|
||||
except KeyError:
|
||||
haslatlon = 0
|
||||
|
||||
# path data
|
||||
if haslatlon:
|
||||
locdata = []
|
||||
for e in zip(t,lat,lon):
|
||||
point = {
|
||||
'lat':e[1],
|
||||
'lng':e[2],
|
||||
'elevation':0,
|
||||
}
|
||||
locdata.append([e[0],point])
|
||||
|
||||
hrdata = []
|
||||
for e in zip(t,hr):
|
||||
point = [e[0],
|
||||
e[1]
|
||||
]
|
||||
hrdata.append(point)
|
||||
|
||||
distancedata = []
|
||||
for e in zip(t,d):
|
||||
point = [e[0],
|
||||
e[1]
|
||||
]
|
||||
distancedata.append(point)
|
||||
|
||||
spmdata = []
|
||||
for e in zip(t,spm):
|
||||
spmdata.append([e[0],e[1]])
|
||||
|
||||
start_time = w.startdatetime.isoformat()
|
||||
|
||||
timeseries = {
|
||||
"distance": distancedata,
|
||||
"heartrate": hrdata,
|
||||
"cadence": spmdata,
|
||||
}
|
||||
|
||||
aggregrates = {
|
||||
"elapsed_time_total": int(duration),
|
||||
"distance_total": int(max(d)),
|
||||
"heartrate_avg": averagehr,
|
||||
"heart_rate_min": int(min(hr)),
|
||||
"heart_rate_max": int(max(hr)),
|
||||
}
|
||||
|
||||
|
||||
# if haslatlon:
|
||||
# timeseries["position"] = locdata
|
||||
|
||||
data = {
|
||||
"name": name,
|
||||
"start_datetime": start_time,
|
||||
"time_series": timeseries,
|
||||
"start_locale_timezone": "Etc/UTC",
|
||||
"activity_type": "/v7.1/activity_type/128/",
|
||||
"notes": notes,
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
# Obtain Underarmour Workout ID and activity type
|
||||
def get_idfromuri(user,links):
|
||||
id = links['self'][0]['id']
|
||||
typeid = links['activity_type'][0]['id']
|
||||
|
||||
|
||||
typename = get_typefromid(typeid,user)
|
||||
|
||||
return id,typename
|
||||
|
||||
def getidfromresponse(response):
|
||||
t = json.loads(response.text)
|
||||
|
||||
links = t["_links"]
|
||||
|
||||
id = links["self"][0]["id"]
|
||||
|
||||
return int(id)
|
||||
|
||||
def refresh_ua_actlist(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
authorizationstring = str('Bearer ' + r.underarmourtoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'Api-Key': UNDERARMOUR_CLIENT_KEY,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.ua.com/v7.1/activity_type/"
|
||||
response = requests.get(url,headers=headers)
|
||||
|
||||
me_json = response.json()
|
||||
types = me_json["_embedded"]["activity_types"]
|
||||
w = {int(t["_links"]["self"][0]["id"]):t["name"] for t in types}
|
||||
wdf = pd.Series(w,name='Name')
|
||||
wdf.to_csv('static/rigging/ua2.csv',index_label='id',header=True)
|
||||
return w
|
||||
|
||||
try:
|
||||
activities = pd.read_csv('static/rigging/ua2.csv',index_col='id')
|
||||
actdict = activities.to_dict()['Name']
|
||||
except:
|
||||
actdict = {}
|
||||
|
||||
|
||||
def get_typefromid(typeid,user):
|
||||
r = Rower.objects.get(user=user)
|
||||
try:
|
||||
res = actdict[int(typeid)]
|
||||
except KeyError:
|
||||
authorizationstring = str('Bearer ' + r.underarmourtoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'Api-Key': UNDERARMOUR_CLIENT_KEY,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.ua.com/v7.1/activity_type/"+str(typeid)
|
||||
response = requests.get(url,headers=headers)
|
||||
|
||||
me_json = response.json()
|
||||
|
||||
try:
|
||||
res = me_json['name']
|
||||
except KeyError:
|
||||
res = 0
|
||||
|
||||
return res
|
||||
|
||||
|
||||
|
||||
# Get user id, having access token
|
||||
# Handy for checking if the API access is working
|
||||
def get_userid(access_token):
|
||||
authorizationstring = str('Bearer ' + access_token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'Api-Key': UNDERARMOUR_CLIENT_KEY,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.ua.com/v7.1/user/self"
|
||||
response = requests.get(url,headers=headers)
|
||||
|
||||
me_json = response.json()
|
||||
|
||||
try:
|
||||
res = me_json['id']
|
||||
except KeyError:
|
||||
res = 0
|
||||
|
||||
return res
|
||||
@@ -157,8 +157,12 @@ urlpatterns = [
|
||||
url(r'^graph/(\d+)/$',views.graph_show_view),
|
||||
url(r'^graph/(\d+)/deleteconfirm$',views.graph_delete_confirm_view),
|
||||
url(r'^graph/(\d+)/delete$',views.graph_delete_view),
|
||||
url(r'^workout/upload/team/s/(?P<successmessage>\w+.*)/c/(?P<message>\w+.*)/$',views.team_workout_upload_view),
|
||||
url(r'^workout/upload/team/c/(?P<message>\w+.*)/$',views.team_workout_upload_view),
|
||||
url(r'^workout/upload/team/s/(?P<successmessage>\w+.*)/$',views.team_workout_upload_view),
|
||||
url(r'^workout/upload/team/$',views.team_workout_upload_view),
|
||||
url(r'^workout/upload/$',views.workout_upload_view),
|
||||
url(r'^workout/upload/(.+.*)$',views.workout_upload_view),
|
||||
url(r'^workout/upload/c/(?P<message>\w+.*)$',views.workout_upload_view),
|
||||
url(r'^workout/(?P<id>\d+)/histo$',views.workout_histo_view),
|
||||
url(r'^workout/(?P<id>\d+)/forcecurve$',views.workout_forcecurve_view),
|
||||
url(r'^workout/(?P<id>\d+)/unsubscribe$',views.workout_unsubscribe_view),
|
||||
@@ -225,12 +229,15 @@ urlpatterns = [
|
||||
url(r'^workout/sporttracksimport/(\d+)/$',views.workout_getsporttracksworkout_view),
|
||||
url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view),
|
||||
url(r'^workout/runkeeperimport/(\d+)/$',views.workout_getrunkeeperworkout_view),
|
||||
url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view),
|
||||
url(r'^workout/underarmourimport/(\d+)/$',views.workout_getunderarmourworkout_view),
|
||||
url(r'^workout/(\d+)/deleteconfirm$',views.workout_delete_confirm_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),
|
||||
url(r'^workout/(\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view),
|
||||
url(r'^workout/(\d+)/runkeeperuploadw/$',views.workout_runkeeper_upload_view),
|
||||
url(r'^workout/(\d+)/underarmouruploadw/$',views.workout_underarmour_upload_view),
|
||||
url(r'^multi-compare$',views.multi_compare_view),
|
||||
url(r'^me/teams/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.rower_teams_view),
|
||||
url(r'^me/teams/s/(?P<successmessage>\w+.*)$',views.rower_teams_view),
|
||||
@@ -265,8 +272,10 @@ urlpatterns = [
|
||||
url(r'^me/revokeapp/(\d+)$',views.rower_revokeapp_view),
|
||||
url(r'^me/stravaauthorize/$',views.rower_strava_authorize),
|
||||
url(r'^me/sporttracksauthorize/$',views.rower_sporttracks_authorize),
|
||||
url(r'^me/underarmourauthorize/$',views.rower_underarmour_authorize),
|
||||
url(r'^me/runkeeperauthorize/$',views.rower_runkeeper_authorize),
|
||||
url(r'^me/sporttracksrefresh/$',views.rower_sporttracks_token_refresh),
|
||||
url(r'^me/underarmourrefresh/$',views.rower_underarmour_token_refresh),
|
||||
url(r'^me/c2refresh/$',views.rower_c2_token_refresh),
|
||||
url(r'^me/favoritecharts/$',views.rower_favoritecharts_view),
|
||||
url(r'^email/send/$', views.sendmail),
|
||||
|
||||
656
rowers/views.py
@@ -14,7 +14,10 @@ from django.http import (
|
||||
HttpResponseNotFound,Http404
|
||||
)
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from rowers.forms import LoginForm,DocumentsForm,UploadOptionsForm
|
||||
from rowers.forms import (
|
||||
LoginForm,DocumentsForm,UploadOptionsForm,
|
||||
TeamUploadOptionsForm,
|
||||
)
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.template import RequestContext
|
||||
@@ -53,6 +56,7 @@ from sporttracksstuff import SportTracksNoTokenError
|
||||
from iso8601 import ParseError
|
||||
import stravastuff
|
||||
import sporttracksstuff
|
||||
import underarmourstuff
|
||||
import runkeeperstuff
|
||||
import ownapistuff
|
||||
from ownapistuff import TEST_CLIENT_ID, TEST_CLIENT_SECRET, TEST_REDIRECT_URI
|
||||
@@ -61,6 +65,8 @@ from rowsandall_app.settings import (
|
||||
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET,
|
||||
SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI,
|
||||
SPORTTRACKS_CLIENT_SECRET,
|
||||
UNDERARMOUR_CLIENT_ID, UNDERARMOUR_REDIRECT_URI,
|
||||
UNDERARMOUR_CLIENT_SECRET,UNDERARMOUR_CLIENT_KEY,
|
||||
RUNKEEPER_CLIENT_ID,RUNKEEPER_REDIRECT_URI,RUNKEEPER_CLIENT_SECRET,
|
||||
)
|
||||
|
||||
@@ -208,6 +214,15 @@ def get_time(second):
|
||||
def getidfromsturi(uri,length=8):
|
||||
return uri[len(uri)-length:]
|
||||
|
||||
def splituadata(lijst):
|
||||
t = []
|
||||
y = []
|
||||
for d in lijst:
|
||||
t.append(d[0])
|
||||
y.append(d[1])
|
||||
|
||||
return np.array(t),np.array(y)
|
||||
|
||||
def splitrunkeeperlatlongdata(lijst,tname,latname,lonname):
|
||||
t = []
|
||||
lat = []
|
||||
@@ -810,6 +825,173 @@ def add_workout_from_stdata(user,importid,data):
|
||||
|
||||
|
||||
|
||||
unixtime = cum_time+starttimeunix
|
||||
unixtime[0] = starttimeunix
|
||||
|
||||
df['TimeStamp (sec)'] = unixtime
|
||||
|
||||
|
||||
dt = np.diff(cum_time).mean()
|
||||
wsize = round(5./dt)
|
||||
|
||||
velo2 = stravastuff.ewmovingaverage(velo,wsize)
|
||||
|
||||
df[' Stroke500mPace (sec/500m)'] = 500./velo2
|
||||
|
||||
|
||||
df = df.fillna(0)
|
||||
|
||||
df.sort_values(by='TimeStamp (sec)',ascending=True)
|
||||
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
|
||||
csvfilename ='media/Import_'+str(importid)+'.csv'
|
||||
|
||||
res = df.to_csv(csvfilename+'.gz',index_label='index',
|
||||
compression='gzip')
|
||||
|
||||
id,message = dataprep.save_workout_database(csvfilename,r,
|
||||
workouttype=workouttype,
|
||||
title=title,
|
||||
notes=comments)
|
||||
|
||||
return (id,message)
|
||||
|
||||
# Create workout from SportTracks Data, which are slightly different
|
||||
# than Strava or Concept2 data
|
||||
def add_workout_from_underarmourdata(user,importid,data):
|
||||
workouttype = 'water'
|
||||
|
||||
try:
|
||||
comments = data['notes']
|
||||
except:
|
||||
comments = ''
|
||||
|
||||
try:
|
||||
thetimezone = tz(data['start_locale_timezone'])
|
||||
except:
|
||||
thetimezone = 'UTC'
|
||||
|
||||
r = Rower.objects.get(user=user)
|
||||
try:
|
||||
rowdatetime = iso8601.parse_date(data['start_datetime'])
|
||||
except iso8601.ParseError:
|
||||
try:
|
||||
rowdatetime = datetime.datetime.strptime(data['start_datetime'],"%Y-%m-%d %H:%M:%S")
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
except:
|
||||
try:
|
||||
rowdatetime = dateutil.parser.parse(data['start_datetime'])
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
except:
|
||||
rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
starttimeunix = mktime(rowdatetime.utctimetuple())
|
||||
|
||||
|
||||
try:
|
||||
title = data['name']
|
||||
except:
|
||||
title = "Imported data"
|
||||
|
||||
timeseries = data['time_series']
|
||||
|
||||
# position, distance, speed, cadence, power,
|
||||
|
||||
res = splituadata(timeseries['distance'])
|
||||
|
||||
distance = res[1]
|
||||
|
||||
times_distance = res[0]
|
||||
|
||||
print distance[0:5]
|
||||
print times_distance[0:5]
|
||||
|
||||
try:
|
||||
l = timeseries['position']
|
||||
|
||||
res = splituadata(l)
|
||||
times_location = res[0]
|
||||
latlong = res[1]
|
||||
latcoord = []
|
||||
loncoord = []
|
||||
|
||||
for coord in latlong:
|
||||
lat = coord['lat']
|
||||
lon = coord['lng']
|
||||
latcoord.append(lat)
|
||||
loncoord.append(lon)
|
||||
except:
|
||||
times_location = times_distance
|
||||
latcoord = np.zeros(len(times_distance))
|
||||
loncoord = np.zeros(len(times_distance))
|
||||
if workouttype == 'water':
|
||||
workouttype = 'rower'
|
||||
|
||||
try:
|
||||
res = splituadata(timeseries['cadence'])
|
||||
times_spm = res[0]
|
||||
spm = res[1]
|
||||
except KeyError:
|
||||
times_spm = times_distance
|
||||
spm = 0*times_distance
|
||||
|
||||
try:
|
||||
res = splituadata(timeseries['heartrate'])
|
||||
hr = res[1]
|
||||
times_hr = res[0]
|
||||
except KeyError:
|
||||
times_hr = times_distance
|
||||
hr = 0*times_distance
|
||||
|
||||
|
||||
# create data series and remove duplicates
|
||||
distseries = pd.Series(distance,index=times_distance)
|
||||
distseries = distseries.groupby(distseries.index).first()
|
||||
latseries = pd.Series(latcoord,index=times_location)
|
||||
latseries = latseries.groupby(latseries.index).first()
|
||||
lonseries = pd.Series(loncoord,index=times_location)
|
||||
lonseries = lonseries.groupby(lonseries.index).first()
|
||||
spmseries = pd.Series(spm,index=times_spm)
|
||||
spmseries = spmseries.groupby(spmseries.index).first()
|
||||
hrseries = pd.Series(hr,index=times_hr)
|
||||
hrseries = hrseries.groupby(hrseries.index).first()
|
||||
|
||||
|
||||
# Create dicts and big dataframe
|
||||
d = {
|
||||
' Horizontal (meters)': distseries,
|
||||
' latitude': latseries,
|
||||
' longitude': lonseries,
|
||||
' Cadence (stokes/min)': spmseries,
|
||||
' HRCur (bpm)' : hrseries,
|
||||
}
|
||||
|
||||
|
||||
|
||||
df = pd.DataFrame(d)
|
||||
|
||||
df = df.groupby(level=0).last()
|
||||
|
||||
cum_time = df.index.values
|
||||
df[' ElapsedTime (sec)'] = cum_time
|
||||
|
||||
velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff()
|
||||
|
||||
df[' Power (watts)'] = 0.0*velo
|
||||
|
||||
nr_rows = len(velo.values)
|
||||
|
||||
df[' DriveLength (meters)'] = np.zeros(nr_rows)
|
||||
df[' StrokeDistance (meters)'] = np.zeros(nr_rows)
|
||||
df[' DriveTime (ms)'] = np.zeros(nr_rows)
|
||||
df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows)
|
||||
df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows)
|
||||
df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows)
|
||||
df[' lapIdx'] = np.zeros(nr_rows)
|
||||
|
||||
|
||||
|
||||
unixtime = cum_time+starttimeunix
|
||||
unixtime[0] = starttimeunix
|
||||
|
||||
@@ -875,6 +1057,20 @@ def sporttracks_open(user):
|
||||
|
||||
return thetoken
|
||||
|
||||
# Checks if user has UnderArmour token, renews them if they are expired
|
||||
def underarmour_open(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.underarmourtoken == '') or (r.underarmourtoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
raise UnderarmourNoTokenError("User has no token")
|
||||
else:
|
||||
if (timezone.now()>r.underarmourtokenexpirydate):
|
||||
thetoken = underarmourstuff.rower_underarmour_token_refresh(user)
|
||||
else:
|
||||
thetoken = r.underarmourtoken
|
||||
|
||||
return thetoken
|
||||
|
||||
# Checks if user has SportTracks token, renews them if they are expired
|
||||
def runkeeper_open(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
@@ -1004,6 +1200,7 @@ def workout_strava_upload_view(request,id=0):
|
||||
# ready to upload. Hurray
|
||||
try:
|
||||
w = Workout.objects.get(id=id)
|
||||
r = w.user
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("Workout doesn't exist")
|
||||
if (checkworkoutuser(request.user,w)):
|
||||
@@ -1086,16 +1283,18 @@ def workout_strava_upload_view(request,id=0):
|
||||
@login_required()
|
||||
def workout_c2_upload_view(request,id=0):
|
||||
message = ""
|
||||
try:
|
||||
thetoken = c2_open(request.user)
|
||||
except C2NoTokenError:
|
||||
return HttpResponseRedirect("/rowers/me/c2authorize/")
|
||||
|
||||
# ready to upload. Hurray
|
||||
try:
|
||||
w = Workout.objects.get(id=id)
|
||||
r = w.user
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("Workout doesn't exist")
|
||||
|
||||
try:
|
||||
thetoken = c2_open(r.user)
|
||||
except C2NoTokenError:
|
||||
return HttpResponseRedirect("/rowers/me/c2authorize/")
|
||||
|
||||
if (checkworkoutuser(request.user,w)):
|
||||
c2userid = c2stuff.get_userid(thetoken)
|
||||
if not c2userid:
|
||||
@@ -1172,15 +1371,17 @@ def workout_c2_upload_view(request,id=0):
|
||||
def workout_runkeeper_upload_view(request,id=0):
|
||||
message = ""
|
||||
try:
|
||||
thetoken = runkeeper_open(request.user)
|
||||
w = Workout.objects.get(id=id)
|
||||
r = w.user
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("Workout doesn't exist")
|
||||
|
||||
try:
|
||||
thetoken = runkeeper_open(r.user)
|
||||
except RunKeeperNoTokenError:
|
||||
return HttpResponseRedirect("/rowers/me/runkeeperauthorize/")
|
||||
|
||||
# ready to upload. Hurray
|
||||
try:
|
||||
w = Workout.objects.get(id=id)
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("Workout doesn't exist")
|
||||
|
||||
if (checkworkoutuser(request.user,w)):
|
||||
data = runkeeperstuff.createrunkeeperworkoutdata(w)
|
||||
@@ -1229,21 +1430,89 @@ def workout_runkeeper_upload_view(request,id=0):
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Upload workout to Underarmour
|
||||
@login_required()
|
||||
def workout_underarmour_upload_view(request,id=0):
|
||||
message = ""
|
||||
try:
|
||||
w = Workout.objects.get(id=id)
|
||||
r = w.user
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("Workout doesn't exist")
|
||||
|
||||
try:
|
||||
thetoken = underarmour_open(r.user)
|
||||
except UnderarmourNoTokenError:
|
||||
return HttpResponseRedirect("/rowers/me/underarmourauthorize/")
|
||||
|
||||
# ready to upload. Hurray
|
||||
|
||||
if (checkworkoutuser(request.user,w)):
|
||||
data = underarmourstuff.createunderarmourworkoutdata(w)
|
||||
# return HttpResponse(json.dumps(data))
|
||||
if not data:
|
||||
message = "Data error"
|
||||
url = reverse(workout_export_view,
|
||||
kwargs = {
|
||||
'message':str(message),
|
||||
'id':str(w.id),
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
authorizationstring = str('Bearer ' + thetoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'Api-Key': UNDERARMOUR_CLIENT_KEY,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
|
||||
import urllib
|
||||
url = "https://api.ua.com/v7.1/workout/"
|
||||
response = requests.post(url,headers=headers,data=json.dumps(data))
|
||||
|
||||
# check for duplicate error first
|
||||
if (response.status_code == 409 ):
|
||||
message = "Duplicate error"
|
||||
w.uploadedtounderarmour = -1
|
||||
w.save()
|
||||
elif (response.status_code == 201 or response.status_code==200):
|
||||
underarmourid = underarmourstuff.getidfromresponse(response)
|
||||
w.uploadedtounderarmour = underarmourid
|
||||
w.save()
|
||||
url = "/rowers/workout/"+str(w.id)+"/export"
|
||||
return HttpResponseRedirect(url)
|
||||
else:
|
||||
s = response
|
||||
message = "Something went wrong in workout_underarmour_upload_view: %s - %s" % (s.reason,s.text)
|
||||
|
||||
else:
|
||||
message = "You are not authorized to upload this workout"
|
||||
|
||||
url = reverse(workout_export_view,
|
||||
kwargs = {
|
||||
'message':str(message),
|
||||
'id':str(w.id),
|
||||
})
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Upload workout to SportTracks
|
||||
@login_required()
|
||||
def workout_sporttracks_upload_view(request,id=0):
|
||||
message = ""
|
||||
try:
|
||||
thetoken = sporttracks_open(request.user)
|
||||
except SportTracksNoTokenError:
|
||||
return HttpResponseRedirect("/rowers/me/sporttracksauthorize/")
|
||||
|
||||
# ready to upload. Hurray
|
||||
try:
|
||||
w = Workout.objects.get(id=id)
|
||||
r = w.user
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("Workout doesn't exist")
|
||||
|
||||
try:
|
||||
thetoken = sporttracks_open(r.user)
|
||||
except SportTracksNoTokenError:
|
||||
return HttpResponseRedirect("/rowers/me/sporttracksauthorize/")
|
||||
|
||||
|
||||
if (checkworkoutuser(request.user,w)):
|
||||
data = sporttracksstuff.createsporttracksworkoutdata(w)
|
||||
if not data:
|
||||
@@ -1363,6 +1632,23 @@ def rower_sporttracks_authorize(request):
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Underarmour Authorization
|
||||
@login_required()
|
||||
def rower_underarmour_authorize(request):
|
||||
# Generate a random string for the state parameter
|
||||
# Save it for use later to prevent xsrf attacks
|
||||
from uuid import uuid4
|
||||
state = str(uuid4())
|
||||
|
||||
redirect_uri = UNDERARMOUR_REDIRECT_URI
|
||||
|
||||
url = 'https://www.mapmyfitness.com/v7.1/oauth2/authorize/?' \
|
||||
'client_id={0}&response_type=code&redirect_uri={1}'.format(
|
||||
UNDERARMOUR_CLIENT_KEY, redirect_uri
|
||||
)
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Concept2 token refresh. URL for manual refresh. Not visible to users
|
||||
@login_required()
|
||||
def rower_c2_token_refresh(request):
|
||||
@@ -1388,11 +1674,37 @@ def rower_c2_token_refresh(request):
|
||||
|
||||
return imports_view(request,successmessage=successmessage,message=message)
|
||||
|
||||
# Underarmour token refresh. URL for manual refresh. Not visible to users
|
||||
@login_required()
|
||||
def rower_underarmour_token_refresh(request):
|
||||
r = Rower.objects.get(user=request.user)
|
||||
res = underarmourstuff.do_refresh_token(
|
||||
r.underarmourrefreshtoken,
|
||||
r.underarmourtoken
|
||||
)
|
||||
access_token = res[0]
|
||||
expires_in = res[1]
|
||||
refresh_token = res[2]
|
||||
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
|
||||
|
||||
r = Rower.objects.get(user=request.user)
|
||||
r.underarmourtoken = access_token
|
||||
r.underarmourtokenexpirydate = expirydatetime
|
||||
r.underarmourrefreshtoken = refresh_token
|
||||
|
||||
r.save()
|
||||
|
||||
successmessage = "Tokens refreshed. Good to go"
|
||||
return imports_view(request,successmessage=successmessage)
|
||||
|
||||
|
||||
# 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)
|
||||
res = sporttracksstuff.do_refresh_token(r.sporttracksrefreshtoken)
|
||||
res = sporttracksstuff.do_refresh_token(
|
||||
r.sporttracksrefreshtoken,
|
||||
)
|
||||
access_token = res[0]
|
||||
expires_in = res[1]
|
||||
refresh_token = res[2]
|
||||
@@ -1525,6 +1837,28 @@ def rower_process_sporttrackscallback(request):
|
||||
successmessage = "Tokens stored. Good to go"
|
||||
return imports_view(request,successmessage=successmessage)
|
||||
|
||||
# Process Underarmour callback
|
||||
@login_required()
|
||||
def rower_process_underarmourcallback(request):
|
||||
code = request.GET['code']
|
||||
res = underarmourstuff.get_token(code)
|
||||
|
||||
|
||||
access_token = res[0]
|
||||
expires_in = res[1]
|
||||
refresh_token = res[2]
|
||||
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
|
||||
|
||||
r = Rower.objects.get(user=request.user)
|
||||
r.underarmourtoken = access_token
|
||||
r.underarmourtokenexpirydate = expirydatetime
|
||||
r.underarmourrefreshtoken = refresh_token
|
||||
|
||||
r.save()
|
||||
|
||||
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):
|
||||
@@ -3866,6 +4200,7 @@ def workout_flexchart3_view(request,*args,**kwargs):
|
||||
if request.method == 'POST' and 'savefavorite' in request.POST:
|
||||
workstrokesonly = request.POST['workstrokesonlysave']
|
||||
reststrokes = not workstrokesonly
|
||||
r = Rower.objects.get(user=request.user)
|
||||
f = FavoriteChart(user=r,xparam=xparam,
|
||||
yparam1=yparam1,yparam2=yparam2,
|
||||
plottype=plottype,workouttype=workouttype,
|
||||
@@ -4829,6 +5164,57 @@ def workout_runkeeperimport_view(request,message=""):
|
||||
|
||||
return HttpResponse(res)
|
||||
|
||||
# The page where you select which RunKeeper workout to import
|
||||
@login_required()
|
||||
def workout_underarmourimport_view(request,message=""):
|
||||
res = underarmourstuff.get_underarmour_workout_list(request.user)
|
||||
if (res.status_code != 200):
|
||||
if (res.status_code == 401):
|
||||
r = Rower.objects.get(user=request.user)
|
||||
if (r.underarmourtoken == '') or (r.underarmourtoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return HttpResponseRedirect("/rowers/me/underarmourauthorize/")
|
||||
message = "Something went wrong in workout_underarmourimport_view"
|
||||
if settings.DEBUG:
|
||||
return HttpResponse(res)
|
||||
else:
|
||||
url = reverse(workouts_view,
|
||||
kwargs = {
|
||||
'message': str(message)
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
else:
|
||||
workouts = []
|
||||
items = res.json()['_embedded']['workouts']
|
||||
for item in items:
|
||||
if 'has_time_series' in item:
|
||||
if item['has_time_series']:
|
||||
s = item['start_datetime']
|
||||
i,r = underarmourstuff.get_idfromuri(request.user,item['_links'])
|
||||
n = item['name']
|
||||
try:
|
||||
d = item['aggregates']['distance_total']
|
||||
except KeyError:
|
||||
d = 0
|
||||
try:
|
||||
ttot = item['aggregates']['active_time_total']
|
||||
except KeyError:
|
||||
ttot = 0
|
||||
|
||||
keys = ['id','distance','duration','starttime','type']
|
||||
values = [i,d,ttot,s,r]
|
||||
thedict = dict(zip(keys,values))
|
||||
|
||||
workouts.append(thedict)
|
||||
|
||||
return render(request,'underarmour_list_import.html',
|
||||
{'workouts':workouts,
|
||||
'teams':get_my_teams(request.user),
|
||||
'message':message,
|
||||
})
|
||||
|
||||
return HttpResponse(res)
|
||||
|
||||
# The page where you select which SportTracks workout to import
|
||||
@login_required()
|
||||
def workout_sporttracksimport_view(request,message=""):
|
||||
@@ -5011,6 +5397,29 @@ def workout_getrunkeeperworkout_view(request,runkeeperid):
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Imports a workout from Underarmour
|
||||
@login_required()
|
||||
def workout_getunderarmourworkout_view(request,underarmourid):
|
||||
res = underarmourstuff.get_underarmour_workout(request.user,underarmourid)
|
||||
data = res.json()
|
||||
|
||||
id,message = add_workout_from_underarmourdata(request.user,underarmourid,data)
|
||||
w = Workout.objects.get(id=id)
|
||||
w.uploadedtounderarmour=underarmourid
|
||||
w.save()
|
||||
if message:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':id,
|
||||
'message':message,
|
||||
})
|
||||
else:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':id,
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
# Imports a workout from SportTracks
|
||||
@@ -5159,11 +5568,24 @@ def workout_upload_view(request,message="",
|
||||
request.session['uploadoptions'] = uploadoptions
|
||||
|
||||
|
||||
|
||||
makeprivate = uploadoptions['makeprivate']
|
||||
make_plot = uploadoptions['make_plot']
|
||||
plottype = uploadoptions['plottype']
|
||||
upload_toc2 = uploadoptions['upload_to_C2']
|
||||
try:
|
||||
makeprivate = uploadoptions['makeprivate']
|
||||
except KeyError:
|
||||
makeprivate = False
|
||||
try:
|
||||
make_plot = uploadoptions['make_plot']
|
||||
except KeyError:
|
||||
make_plot = False
|
||||
|
||||
try:
|
||||
plottype = uploadoptions['plottype']
|
||||
except KeyError:
|
||||
plottype = 'timeplot'
|
||||
|
||||
try:
|
||||
upload_toc2 = uploadoptions['upload_to_C2']
|
||||
except KeyError:
|
||||
upload_toc2 = False
|
||||
|
||||
r = Rower.objects.get(user=request.user)
|
||||
if request.method == 'POST':
|
||||
@@ -5207,7 +5629,12 @@ def workout_upload_view(request,message="",
|
||||
args=[str(message)])
|
||||
response = HttpResponseRedirect(url)
|
||||
return response
|
||||
|
||||
elif id == -1:
|
||||
message = 'The zip archive will be processed in the background. The files in the archive will only be uploaded without the extra actions. You will receive email when the workouts are ready.'
|
||||
url = reverse(workout_upload_view,
|
||||
args=[str(message)])
|
||||
response = HttpResponseRedirect(url)
|
||||
return response
|
||||
else:
|
||||
if message:
|
||||
url = reverse(workout_edit_view,
|
||||
@@ -5350,6 +5777,183 @@ def workout_upload_view(request,message="",
|
||||
'optionsform': optionsform,
|
||||
'message':message})
|
||||
|
||||
# This is the main view for processing uploaded files
|
||||
@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
|
||||
def team_workout_upload_view(request,message="",
|
||||
successmessage="",
|
||||
uploadoptions={
|
||||
'make_plot':False,
|
||||
'plottype':'timeplot',
|
||||
}):
|
||||
|
||||
if 'uploadoptions' in request.session:
|
||||
uploadoptions = request.session['uploadoptions']
|
||||
else:
|
||||
request.session['uploadoptions'] = uploadoptions
|
||||
|
||||
|
||||
myteams = Team.objects.filter(manager=request.user)
|
||||
|
||||
make_plot = uploadoptions['make_plot']
|
||||
plottype = uploadoptions['plottype']
|
||||
|
||||
r = Rower.objects.get(user=request.user)
|
||||
if request.method == 'POST':
|
||||
form = DocumentsForm(request.POST,request.FILES)
|
||||
optionsform = TeamUploadOptionsForm(request.POST)
|
||||
|
||||
rowerform = TeamInviteForm(request.POST)
|
||||
rowerform.fields.pop('email')
|
||||
rowerform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct()
|
||||
if form.is_valid():
|
||||
f = request.FILES['file']
|
||||
res = handle_uploaded_file(f)
|
||||
t = form.cleaned_data['title']
|
||||
if rowerform.is_valid():
|
||||
u = rowerform.cleaned_data['user']
|
||||
if u:
|
||||
r = Rower.objects.get(user=u)
|
||||
else:
|
||||
message = 'Please select a rower'
|
||||
response = render(request,
|
||||
'team_document_form.html',
|
||||
{'form':form,
|
||||
'teams':get_my_teams(request.user),
|
||||
'optionsform': optionsform,
|
||||
'rowerform': rowerform,
|
||||
'message':message,
|
||||
'successmessage':successmessage,
|
||||
})
|
||||
|
||||
return response
|
||||
|
||||
workouttype = form.cleaned_data['workouttype']
|
||||
|
||||
notes = form.cleaned_data['notes']
|
||||
|
||||
if optionsform.is_valid():
|
||||
make_plot = optionsform.cleaned_data['make_plot']
|
||||
plottype = optionsform.cleaned_data['plottype']
|
||||
|
||||
uploadoptions = {
|
||||
'makeprivate':False,
|
||||
'make_plot':make_plot,
|
||||
'plottype':plottype,
|
||||
'upload_to_C2':False,
|
||||
}
|
||||
|
||||
|
||||
request.session['uploadoptions'] = uploadoptions
|
||||
|
||||
f1 = res[0] # file name
|
||||
f2 = res[1] # file name incl media directory
|
||||
|
||||
|
||||
id,message,f2 = dataprep.new_workout_from_file(r,f2,
|
||||
workouttype=workouttype,
|
||||
makeprivate=False,
|
||||
title = t,
|
||||
notes='')
|
||||
if not id:
|
||||
url = reverse(team_workout_upload_view,
|
||||
args=[str(message)])
|
||||
response = HttpResponseRedirect(url)
|
||||
return response
|
||||
|
||||
else:
|
||||
if message:
|
||||
successmessage = "The workout was added to the user's account"
|
||||
url = reverse(team_workout_upload_view,
|
||||
kwargs = {
|
||||
'message':message,
|
||||
'successmessage':successmessage,
|
||||
})
|
||||
else:
|
||||
successmessage = "The workout was added to the user's account"
|
||||
url = reverse(team_workout_upload_view,
|
||||
kwargs = {
|
||||
'successmessage':successmessage,
|
||||
})
|
||||
|
||||
response = HttpResponseRedirect(url)
|
||||
w = Workout.objects.get(id=id)
|
||||
|
||||
if (make_plot):
|
||||
imagename = f1[:-4]+'.png'
|
||||
fullpathimagename = 'static/plots/'+imagename
|
||||
powerperc = 100*np.array([r.pw_ut2,
|
||||
r.pw_ut1,
|
||||
r.pw_at,
|
||||
r.pw_tr,r.pw_an])/r.ftp
|
||||
|
||||
hrpwrdata = {
|
||||
'hrmax':r.max,
|
||||
'hrut2':r.ut2,
|
||||
'hrut1':r.ut1,
|
||||
'hrat':r.at,
|
||||
'hrtr':r.tr,
|
||||
'hran':r.an,
|
||||
'ftp':r.ftp,
|
||||
'powerperc':serialize_list(powerperc),
|
||||
'powerzones':serialize_list(r.powerzones),
|
||||
}
|
||||
|
||||
# make plot - asynchronous task
|
||||
plotnrs = {
|
||||
'timeplot':1,
|
||||
'distanceplot':2,
|
||||
'pieplot':3,
|
||||
}
|
||||
|
||||
plotnr = plotnrs[plottype]
|
||||
if (workouttype=='water'):
|
||||
plotnr = plotnr+3
|
||||
|
||||
|
||||
if settings.DEBUG:
|
||||
res = handle_makeplot.delay(f1,f2,t,
|
||||
hrpwrdata,plotnr,
|
||||
imagename)
|
||||
else:
|
||||
res = queue.enqueue(handle_makeplot,f1,f2,
|
||||
t,hrpwrdata,
|
||||
plotnr,imagename)
|
||||
|
||||
|
||||
i = GraphImage(workout=w,
|
||||
creationdatetime=timezone.now(),
|
||||
filename=fullpathimagename)
|
||||
i.save()
|
||||
|
||||
|
||||
|
||||
else:
|
||||
response = render(request,
|
||||
'team_document_form.html',
|
||||
{'form':form,
|
||||
'teams':get_my_teams(request.user),
|
||||
'optionsform': optionsform,
|
||||
'rowerform': rowerform,
|
||||
'message':message,
|
||||
'successmessage':successmessage,
|
||||
})
|
||||
|
||||
return response
|
||||
else:
|
||||
form = DocumentsForm()
|
||||
optionsform = TeamUploadOptionsForm(initial=uploadoptions)
|
||||
rowerform = TeamInviteForm()
|
||||
rowerform.fields.pop('email')
|
||||
rowerform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct()
|
||||
return render(request, 'team_document_form.html',
|
||||
{'form':form,
|
||||
'teams':get_my_teams(request.user),
|
||||
'optionsform': optionsform,
|
||||
'rowerform':rowerform,
|
||||
'message':message,
|
||||
'successmessage':successmessage,
|
||||
})
|
||||
|
||||
|
||||
|
||||
# Ask the user if he really wants to delete the workout
|
||||
@@ -6416,11 +7020,14 @@ def rower_teams_view(request,message='',successmessage=''):
|
||||
requests = TeamRequest.objects.filter(user=request.user)
|
||||
myrequests = TeamRequest.objects.filter(team__in=myteams)
|
||||
myinvites = TeamInvite.objects.filter(team__in=myteams)
|
||||
clubsize = teams.count_invites(request.user)+teams.count_club_members(request.user)
|
||||
max_clubsize = r.clubsize
|
||||
|
||||
return render(request, 'teams.html',
|
||||
{
|
||||
'teams':ts,
|
||||
'teams':get_my_teams(request.user),
|
||||
'clubsize':clubsize,
|
||||
'max_clubsize':max_clubsize,
|
||||
'myteams':myteams,
|
||||
'invites':invites,
|
||||
'otherteams':otherteams,
|
||||
@@ -6431,6 +7038,7 @@ def rower_teams_view(request,message='',successmessage=''):
|
||||
'successmessage':successmessage,
|
||||
'myinvites':myinvites,
|
||||
})
|
||||
|
||||
@user_passes_test(iscoachmember,login_url="/",redirect_field_name=None)
|
||||
def invitation_revoke_view(request,id):
|
||||
res,text = teams.revoke_invite(request.user,id)
|
||||
|
||||
@@ -29,7 +29,8 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'z_@2yia858=2i1cygo4ne3+14&i_&@wlty68$q1igdvn=9k5mo'
|
||||
SECRET_KEY = CFG['secret_key']
|
||||
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
@@ -104,7 +105,6 @@ TEMPLATES = [
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django.template.context_processors.i18n',
|
||||
@@ -234,6 +234,14 @@ RUNKEEPER_CLIENT_ID = CFG['runkeeper_client_id']
|
||||
RUNKEEPER_CLIENT_SECRET = CFG['runkeeper_client_secret']
|
||||
RUNKEEPER_REDIRECT_URI = "http://rowsandall.com/runkeeper_callback"
|
||||
|
||||
# Under Armour
|
||||
|
||||
UNDERARMOUR_CLIENT_ID = CFG['underarmour_client_name']
|
||||
UNDERARMOUR_CLIENT_SECRET = CFG['underarmour_client_secret']
|
||||
UNDERARMOUR_CLIENT_KEY = CFG['underarmour_client_key']
|
||||
UNDERARMOUR_REDIRECT_URI = "http://rowsandall.com/underarmour_callback"
|
||||
#UNDERARMOUR_REDIRECT_URI = "http://localhost:8000/underarmour_callback"
|
||||
|
||||
# RQ stuff
|
||||
|
||||
RQ_QUEUES = {
|
||||
|
||||
@@ -55,6 +55,7 @@ urlpatterns += [
|
||||
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'^underarmour\_callback',rowersviews.rower_process_underarmourcallback),
|
||||
url(r'^runkeeper\_callback',rowersviews.rower_process_runkeepercallback),
|
||||
url(r'^twitter\_callback',rowersviews.rower_process_twittercallback),
|
||||
url(r'^i18n/', include('django.conf.urls.i18n')),
|
||||
|
||||
11
static/cookielaw/banner.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div id="CookielawBanner">
|
||||
<div class="container">
|
||||
<h6>{% trans "COOKIE_INFO_HEADER" %}</h6>
|
||||
<p>
|
||||
<a class="btn btn-primary pull-right" href="javascript:Cookielaw.createCookielawCookie();">{% trans "COOKIE_INFO_OK" %}</a>
|
||||
{% trans "COOKIE_INFO_PARA" %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
#CookielawBanner #CookielawCross {
|
||||
background: url('../img/close.png') no-repeat 0 0;
|
||||
background: url('/static/img/close.png') no-repeat 0 0;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
||||
@@ -1,4 +1,30 @@
|
||||
#main {
|
||||
background-color: transparent;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
min-height: 759px;
|
||||
min-width: 1024px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.one {
|
||||
background-image: url("/static/img/landing1.jpg");
|
||||
}
|
||||
|
||||
.two {
|
||||
background-image: url("/static/img/landing2.jpg");
|
||||
}
|
||||
|
||||
.three {
|
||||
background-image: url("/static/img/landing2.jpg");
|
||||
}
|
||||
|
||||
.four {
|
||||
background-image: url("/static/img/landing1.jpg");
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 62.5%;
|
||||
|
||||
BIN
static/img/UAbtn.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
static/img/close.png
Normal file
|
After Width: | Height: | Size: 190 B |
|
Before Width: | Height: | Size: 518 KiB After Width: | Height: | Size: 266 KiB |
BIN
static/img/landing3.jpg
Normal file
|
After Width: | Height: | Size: 404 KiB |
BIN
static/img/landing4.jpg
Normal file
|
After Width: | Height: | Size: 216 KiB |
BIN
static/img/landing5.jpg
Normal file
|
After Width: | Height: | Size: 196 KiB |
BIN
static/img/landing6.jpg
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
static/img/landing7.JPG
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
static/img/uachecked.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
static/img/uagray.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
static/img/uasquare.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
8
static/js/background.js
Normal file
@@ -0,0 +1,8 @@
|
||||
var num = (Math.floor(Math.random()*4));
|
||||
|
||||
|
||||
var array = ['one', 'two', 'three', 'four'];
|
||||
|
||||
var elem = document.getElementById('main');
|
||||
|
||||
elem.classList.add(array[num]);
|
||||
842
static/rigging/ua.csv
Normal file
@@ -0,0 +1,842 @@
|
||||
id,name
|
||||
344,"Shoulders with Weights, Other"
|
||||
345,"Shoulder Press - Dumbbell, Seated"
|
||||
346,"Shoulder Press - Dumbbell, Palms In"
|
||||
347,Standing Low-Pulley Deltoid Raise
|
||||
340,"Rear Delt Raise - Dumbbell, Bent-Over"
|
||||
341,"Squat Press and Rotate, Shoulders"
|
||||
342,Front plate raise
|
||||
343,Side lateral raise
|
||||
810,Insanity Max Cardio Conditioning
|
||||
812,Insanity Max Recovery
|
||||
813,Mixed Martial Arts
|
||||
348,Front Cable Raise
|
||||
349,Incline Shoulder Raise
|
||||
817,Nexersys Round
|
||||
595,Bench Press Chest Close-Grip
|
||||
716,Yourshape
|
||||
714,Longboarding
|
||||
712,Retro Running
|
||||
710,ElliptiGo
|
||||
915,Beginner Bootcamp: Lower Body
|
||||
914,Beginner Bootcamp: Punches & Kicks
|
||||
606,"Shrugs - Barbell, Behind Back"
|
||||
917,Washboard by Basheerah: Chisled Abs
|
||||
594,"Bench Press - Inclined, Hammer Grip"
|
||||
736,CrossFit Video
|
||||
916,Washboard by Basheerah: Ab Sculpt
|
||||
911,Beginner Bootcamp: Upper Body
|
||||
619,General Fixed Gear Ride
|
||||
910,Lean 30: Athletic Stretch
|
||||
913,Beginner Bootcamp: Circuit
|
||||
298,One Leg Bridges
|
||||
299,"Abdominals with Weights, Other"
|
||||
296,Hip Lifts
|
||||
297,Crunch - Excercise Ball
|
||||
294,Fastball
|
||||
295,Crunch- Decline Oblique
|
||||
292,"Sailing, Competitive"
|
||||
293,"Sailing, General"
|
||||
290,Rest Day
|
||||
291,Yourself Fitness Video
|
||||
591,"Flyes - Dumbbell, Declined"
|
||||
590,Front Raise and Pullover
|
||||
593,Bench Press - Dumbell Declined
|
||||
592,Push-ups - Dumbbell
|
||||
199,Calisthenics
|
||||
198,Conditioning
|
||||
597,"Upper Body with Weights, Other"
|
||||
596,"Bench Press - Dumbbell, Flat"
|
||||
195,FireFighting
|
||||
194,"Steps, Machine"
|
||||
197,"Interval Training, Run"
|
||||
196,Shoveling
|
||||
191,New York Body
|
||||
190,Aerobics
|
||||
193,Group Swimming
|
||||
192,Water Aerobics
|
||||
270,Plyometrics
|
||||
271,Cricket
|
||||
272,Brisk Walk
|
||||
273,Rollerblading
|
||||
274,"Intervals, Walk"
|
||||
275,"Nordic, Walk"
|
||||
276,Hunt Fitness
|
||||
277,Water Skiing
|
||||
278,Weaponry
|
||||
279,"Dance, Indoor"
|
||||
738,Kinesis
|
||||
524,"Canoeing, Medium Intensity"
|
||||
525,"Canoeing, High Intensity"
|
||||
526,"Canoeing, Low Intensity"
|
||||
527,Full Range-of-Motion Lat Pulldown
|
||||
520,Triathlon Race
|
||||
521,General Lawn Mowing
|
||||
522,Mowing Lawn (Riding Mower)
|
||||
523,General Track Cycling
|
||||
599,Treadmill/Spin
|
||||
528,Straight-Arm Pulldown
|
||||
529,Pullups - V-Bar
|
||||
449,"Mountain Biking, Moderate Hills"
|
||||
448,"Mountain Biking, Light Intensity"
|
||||
443,"Strength Training with Weights, Other"
|
||||
442,Leg Curls - Standing
|
||||
441,"Stiff-Legged Dumbbell Deadlift, Hamstrings"
|
||||
440,"Hamstrings with Weights, Other"
|
||||
447,"Lower Body, General"
|
||||
446,"Lower Body with Weights, Other"
|
||||
445,Randonneur / Touring
|
||||
444,General Strength Training
|
||||
108,Track Run
|
||||
109,General Hike
|
||||
102,Run Commute
|
||||
103,Sprints
|
||||
100,Indoor Swim Race/Event
|
||||
101,Roller Skating / Skiing
|
||||
106,Casual Walk
|
||||
107,Snowboarding
|
||||
104,Curling
|
||||
105,Power Walk
|
||||
902,Heavy Kettle: Basics
|
||||
903,Heavy Kettle: Blast
|
||||
39,Lower Body
|
||||
38,Touring Bike
|
||||
906,Lean 30: Body Blast Cardio
|
||||
907,Lean 30: Total Body
|
||||
904,Heavy Kettle: Build
|
||||
905,Lean 30: Lower Body Blast
|
||||
33,Fixed Gear (Fixie)
|
||||
32,Hills
|
||||
31,Pilates
|
||||
30,Calves
|
||||
37,Lower Back
|
||||
36,Road Cycling
|
||||
35,Strength Training
|
||||
34,Aerobic
|
||||
641,"Road Cycling, Recovery"
|
||||
640,"Road Cycling, Hill Workout"
|
||||
643,"Football, Australian"
|
||||
642,"Musical Instrument, All"
|
||||
645,"Football, 5-a-Side Touch"
|
||||
644,"Football, 11-a-Side Touch"
|
||||
438,"Stiff-Legged Barbell Deadlift, Hamstrings"
|
||||
439,Leg Curls - Seated
|
||||
436,"Lunges with Dumbbell, Hamstrings"
|
||||
437,Leg Curls - Lying
|
||||
434,"Lunges with Medicine Ball, Hamstrings"
|
||||
435,"BOSU Step Over, Hamstrings"
|
||||
432,"Romanian Deadlift, Hamstrings"
|
||||
433,"Lunge with Rotation, Hamstrings"
|
||||
430,"Lunge Matrix, Hamstrings"
|
||||
431,Flutter Kicks
|
||||
339,"Rear Delt Raise - Dumbbell, Lying"
|
||||
338,Reverse flyes
|
||||
335,Medicine Ball Pullovers
|
||||
334,Plank Hold
|
||||
337,"Rear Delt Row - Barbell, Standing"
|
||||
336,Beach Volleyball
|
||||
331,Toe Touchers
|
||||
330,V-sits
|
||||
333,Hanging pike
|
||||
332,Push Ups - Spiderman
|
||||
744,Belly Dancing
|
||||
855,Dog Run
|
||||
857,Soul Cycle - 45 Minutes
|
||||
819,Table Tennis
|
||||
859,Soul Survivor - 1 hour
|
||||
748,Hula
|
||||
900,Ironsize: Compound Training Cardio
|
||||
848,Activity Tracker
|
||||
99,Rowing Machine
|
||||
98,Abs
|
||||
91,Speed Work
|
||||
90,BLT
|
||||
93,Softball
|
||||
92,Cross Trainer
|
||||
95,Skateboarding
|
||||
94,Wind Surfing
|
||||
97,Pool Games / Lessons
|
||||
96,Nordic Track
|
||||
815,Nexersys Workout
|
||||
740,Tae Bo
|
||||
742,Ballroom Dancing
|
||||
559,"Wrist Curl - Dumbbell, Palms-Down"
|
||||
558,Wrist Roller
|
||||
746,Hip Hop Dancing
|
||||
555,Tyson Shakers
|
||||
554,"Wrist Curl - Barbell, Palms-Up"
|
||||
557,"Wrist Curl - Barbell, Standing, Behind the Back"
|
||||
556,"Wrist Curl - Barbell, Palms-Down"
|
||||
551,"Reverse Cable Curl, Forearms"
|
||||
550,General Cyclocross
|
||||
553,"Reverse Barbell Curl, Forearms"
|
||||
552,Wrist Curl - Cable
|
||||
238,"Pushups, Pullups, Torso"
|
||||
239,Ski Surf
|
||||
234,"Rock Climbing, Indoor"
|
||||
235,Rugby
|
||||
236,"Indoor Sport, Other"
|
||||
237,Yoga Video
|
||||
230,General Workout Video
|
||||
231,Bootcamp Workout
|
||||
232,Fitball
|
||||
233,"Push Ups, Sit Ups"
|
||||
1,Generic
|
||||
614,Upright Rows - Cable
|
||||
146,"Treadmill, Walk"
|
||||
147,Dragon Boat
|
||||
144,Games
|
||||
145,"Golf, Walk"
|
||||
142,Badminton
|
||||
143,Walk Race/Event
|
||||
140,"Total Body, General Gym"
|
||||
141,Ice Hockey
|
||||
612,Shrugs - Cable
|
||||
613,Shrugs - Barbell
|
||||
610,"Traps with Weights, Other"
|
||||
611,Low Pulley Row to Neck
|
||||
616,Singles
|
||||
617,"Tennis, Doubles"
|
||||
148,Cheerleading
|
||||
149,Stretch / Sculpt
|
||||
912,Beginner Bootcamp: Basics
|
||||
951,10Acious: Arms
|
||||
948,10Acious: Shoulders
|
||||
949,10Acious: Abs
|
||||
946,10Acious: Power Flex
|
||||
947,10Acious: HIIT
|
||||
944,Triple Threat: Extreme
|
||||
945,Triple Threat: Abs
|
||||
942,Triple Threat: Legs
|
||||
943,Triple Threat: Total Body
|
||||
940,Triple Threat: Arms
|
||||
941,Triple Threat: Butt
|
||||
768,"Football Game, Tackle"
|
||||
688,P90X X Stretch
|
||||
684,P90X Legs & Back
|
||||
686,P90X Kenpo
|
||||
680,P90X Shoulders and Arms
|
||||
682,P90X YogaX
|
||||
623,Erg Machine
|
||||
622,Dance Class
|
||||
133,"Stairs, Walk"
|
||||
132,Cybex UBE
|
||||
131,Wrestling
|
||||
130,NeuStep
|
||||
137,Horseback Riding
|
||||
136,Long Run
|
||||
135,Hockey
|
||||
134,Baseball
|
||||
494,Leg extensions
|
||||
495,Body Weight Squats
|
||||
139,Bike
|
||||
138,Whitewater Rafting
|
||||
490,Quads - Ball
|
||||
491,Front Barbell Squat
|
||||
492,Barbell Step Ups
|
||||
493,"Quads with Weights, Other"
|
||||
24,Hike
|
||||
25,Indoor Run / Jog
|
||||
26,"Total Body, Weights"
|
||||
27,Neck with Weights
|
||||
20,Indoor Swim
|
||||
21,Sport / Other Activity
|
||||
22,Rock Climb
|
||||
23,Class Workout
|
||||
927,JumpStart: Cardio
|
||||
28,Circuit Training
|
||||
29,Sailing
|
||||
407,Dumbbell Curl - Seated
|
||||
406,Dumbbell Curl - Incline
|
||||
405,Concentration Curl
|
||||
404,"Biceps with Weights, Other"
|
||||
403,Cable Curl - Standing
|
||||
402,Cable Curl - Overhead
|
||||
401,Barbell Curl - Standing
|
||||
400,Barbell Curl - Lying Against Incline
|
||||
933,Cardio Sculpt: Lower Body Burn
|
||||
932,Cardio Sculpt: Dance Sculpt
|
||||
931,Cardio Sculpt: Power
|
||||
930,Cardio Sculpt: Kick & Sculpt
|
||||
937,Venom for Radius IV
|
||||
629,"Road Cycling, Light Intensity"
|
||||
409,Cable Curl - Preacher Curl
|
||||
408,"Hammer Curl - Cable, Rope Attachment"
|
||||
628,Kickboxing Class
|
||||
758,Handball
|
||||
379,"Tricep Press- Dumbbell, Seated"
|
||||
378,Tricep Kickbacks - Dumbbell
|
||||
829,"Single Stroller, Run"
|
||||
371,Calf Press - Leg press machine
|
||||
370,"Calf raise - Dumbbell, seated, one leg"
|
||||
373,"Calf raise - barbell, standing"
|
||||
372,"Calves with Weights, Other"
|
||||
375,Tricep pushdowns - Incline Bench
|
||||
374,Skull Crushers
|
||||
377,"Triceps with Weights, Other"
|
||||
376,Tricep Pushdowns - V-bar
|
||||
708,Motocross
|
||||
704,CrossFit Class
|
||||
706,TRX Suspension Training
|
||||
618,"Bike Ride Commute, Fixed Gear"
|
||||
702,Trikke
|
||||
393,Bench Press Triceps Close-Grip
|
||||
392,Pushups - Hands Close Together
|
||||
88,Paddle
|
||||
89,Speed Workout
|
||||
397,Backcountry Skiing
|
||||
396,"Tricep Extension - Overhead, Cable"
|
||||
395,"Tricep Extension- Dumbbell, Lying, Supine"
|
||||
394,"Tricep Extension - Dumbbell, Pronated"
|
||||
82,Ballet
|
||||
83,Sports Conditioning
|
||||
80,Snorkeling
|
||||
81,"Stationary Bike, Machine"
|
||||
86,Ice Skating
|
||||
87,"Spinning, Indoor"
|
||||
84,Wakeboarding
|
||||
85,Fishing
|
||||
796,Insanity Plyometric Cardio Circuit
|
||||
794,Insanity Dig Deeper
|
||||
792,Insanity Total Body Workout
|
||||
790,Ultralight
|
||||
798,Insanity Cardio Power & Resistance
|
||||
7,Fartleks
|
||||
601,Misc Tasks (Moderate)
|
||||
607,Upright Rows - Dumbbell
|
||||
586,Push-ups - Modified
|
||||
587,"Flyes - Dumbbell, Flat"
|
||||
584,"Bench Press - Dumbbells, Inclined"
|
||||
585,Push-ups - Feet on Exercise Ball
|
||||
582,"Bench Press - Barbell, Declined"
|
||||
583,"Flyes - Cable, Flat Bench"
|
||||
580,Bent-Arm Dumbbell Pullover
|
||||
581,Bench Press - Smith Machine
|
||||
588,"Bench Press - Barbell, Flat"
|
||||
589,Around the Worlds
|
||||
245,Gilad
|
||||
244,Intimacy
|
||||
247,"Yoga, Sport"
|
||||
246,Brick Workout
|
||||
241,Medicine Ball
|
||||
240,Pyramid Pull Ups
|
||||
243,Cross Country Running
|
||||
242,Group Walk
|
||||
615,General Recumbent Bike
|
||||
249,Circle Swim
|
||||
248,Core Secret Ball
|
||||
924,JumpStart: Upper Body
|
||||
925,JumpStart: Abs
|
||||
519,Weighted Ball Hyperextension
|
||||
518,"Stiff-Legged Dumbbell Deadlift, Lower Back"
|
||||
926,JumpStart: Lower Body
|
||||
511,"Romanian Deadlift, Lower Back"
|
||||
510,"Hiking, Light or No Pack"
|
||||
513,Back Extensions
|
||||
512,"Bird Dogs, Lower Back"
|
||||
515,"Ball Floor Bridge, Lower Back"
|
||||
514,"Lower Back with Weights, Other"
|
||||
517,Supermans
|
||||
516,"Stiff-Legged Barbell Deadlift, Lower Back"
|
||||
458,"Easy Training Ride, Mountain Biking"
|
||||
459,"Single Track, Mountain Biking"
|
||||
621,Pump
|
||||
620,Cross Trainer
|
||||
627,Step Aerobics Class
|
||||
626,Spinning Class
|
||||
625,"Body Combat, Misc."
|
||||
624,Boxing Class
|
||||
450,"Mountain Biking, Long Distance"
|
||||
451,"Mountain Biking, High Intensity"
|
||||
452,Mountain Biking Race/Event
|
||||
453,"Group Ride, Mountain Biking"
|
||||
454,Downhill Mountain Biking
|
||||
455,"Double Track, Mountain Biking"
|
||||
456,General Mountain Biking
|
||||
457,"Bike Ride Commute, Mountain Biking"
|
||||
179,General Walk
|
||||
178,Lacrosse
|
||||
177,Cross Country Hiking
|
||||
176,"Soccer, Sport"
|
||||
175,Snow Shoeing
|
||||
174,Pi
|
||||
173,Tempo Run
|
||||
172,Run Race/Event
|
||||
171,Skydiving
|
||||
170,Sit Ups
|
||||
656,Bent Over Dumbbell Row
|
||||
657,"Middle Back with Weights, Other"
|
||||
654,"Inverted Row, Middle Back"
|
||||
253,Walk Commute
|
||||
182,Nordic Rollerskiing
|
||||
183,Dance / Yoga
|
||||
180,Open Water Swim
|
||||
181,Curves
|
||||
186,Body Combat
|
||||
187,Recovery
|
||||
184,"Scuba Diving, Swim"
|
||||
185,Pull Ups
|
||||
886,21 Day Challenge
|
||||
652,"Hybrid Cycling, Shopping / Errands"
|
||||
188,Quick Run
|
||||
189,Snowmobile Riding
|
||||
658,One-Arm Dumbbell Row
|
||||
653,General Hybrid Cycling
|
||||
650,"Total Body, Other"
|
||||
651,General Total Body
|
||||
764,Tae Kwon Do
|
||||
11,Bike Ride
|
||||
10,Winter Sport / Activity
|
||||
13,Indoor Winter Sport / Activity
|
||||
12,Gym Workout
|
||||
15,Swim
|
||||
14,Machine Workout
|
||||
17,Program / Video Workout
|
||||
16,Run
|
||||
19,Indoor Bike Ride
|
||||
18,Weight Workout
|
||||
863,Stand Up Paddling
|
||||
866,Boosted Board
|
||||
884,ChaLEAN Extreme
|
||||
938,Venom for Radius V
|
||||
659,Cable Chop
|
||||
882,Barre Workout
|
||||
880,Muay Thai
|
||||
831,"Double Stroller, Run"
|
||||
752,Salsa
|
||||
928,Cardio Sculpt: Punch & Sculpt
|
||||
62,Forearms
|
||||
888,Aquathlon
|
||||
950,10Acious: Plyo
|
||||
929,Cardio Sculpt: Explosion
|
||||
322,Dumbbell side bend
|
||||
323,"Ball Floor Bridge, Abdominals"
|
||||
320,Exercise ball pull in
|
||||
321,Spiderman Walk
|
||||
326,Push-ups - Pike Up
|
||||
327,Leg Pull-in
|
||||
324,Seated Leg Tucks
|
||||
325,Crunch - Oblique
|
||||
328,Crunch - Decline Reverse
|
||||
329,Opposite Leg Toe touch
|
||||
201,Adventure Race / Event
|
||||
200,Gardening
|
||||
203,Crunches and Leg Lifts
|
||||
202,Orienteering
|
||||
205,Kitesurfing
|
||||
204,Dog Walk
|
||||
207,Skiers Edge
|
||||
206,"Yard Work, General"
|
||||
209,Chicometrics
|
||||
208,"Treadmill, Run"
|
||||
778,Moped
|
||||
77,House Work
|
||||
76,Musical Instrument
|
||||
75,Lap Swim
|
||||
74,Skiing
|
||||
73,Tennis
|
||||
72,Martial Arts
|
||||
71,Brick
|
||||
70,Middle Back
|
||||
655,"Cable Pulls, Middle Back Alternating"
|
||||
79,Biceps
|
||||
78,Yoga Class
|
||||
2,Workout
|
||||
804,Insanity Core Cardio & Balance
|
||||
668,"Climbing Stairs, Running"
|
||||
666,"Climbing Stairs, Walking"
|
||||
665,General Lap Swim
|
||||
664,"Laps, General"
|
||||
663,T-Bar Row - Lying
|
||||
662,"Lat Pulldown, Middle Back Alternating"
|
||||
661,Seated Cable Eows
|
||||
660,T-Bar Row - Standing
|
||||
692,"P90X Chest, Shoulders & Triceps"
|
||||
690,P90X Core Synergistics
|
||||
696,P90X CardioX
|
||||
694,P90X Back & Biceps
|
||||
698,P90X Ab Ripper X
|
||||
542,Cardiovascular (CV) Circuit Training
|
||||
543,Resistance Circuit Training
|
||||
540,"Upper Back with Weights, Other"
|
||||
541,"Lat Pulldown, Upper Back Alternating"
|
||||
546,"Indoor Bike, Trainer"
|
||||
547,Computrainer
|
||||
544,"Unicycling, Long Distance"
|
||||
545,General Unicycling
|
||||
8,Indoor Sport / Other Activity
|
||||
548,Stationary Bike
|
||||
549,Cyclocross Event/Race
|
||||
68,Softball
|
||||
598,General Upper Body
|
||||
868,Swedish Massage
|
||||
120,"Spinning, Indoor "
|
||||
121,Water Polo
|
||||
122,General Sports
|
||||
123,Bootcamp
|
||||
124,Group Run
|
||||
125,Ballroom Dancing
|
||||
126,Power Walk
|
||||
127,Surfing
|
||||
128,Rowing
|
||||
129,Sight Seeing
|
||||
414,EZ-Bar Curl - Close Grip
|
||||
415,Spider Curl
|
||||
416,"Reverse Cable Curl, Biceps"
|
||||
417,Cable Curl- High pulley
|
||||
410,Cable Curl - Lying
|
||||
411,Preacher Curl - Machine
|
||||
412,"Step Up with Curl, Biceps"
|
||||
413,"Dumbbell Curl - Seated, InnerBicep"
|
||||
920,ProSkils: Football
|
||||
498,Bikram
|
||||
922,ProSkils: Basketball
|
||||
923,ProSkils: MMA
|
||||
418,"Chin-ups, Biceps"
|
||||
419,"Zottman Curl, Biceps"
|
||||
776,Motorcycle
|
||||
499,Vinyasa
|
||||
319,"Lunge with Rotation, Abdominals"
|
||||
318,Dead Bugs
|
||||
313,Crunch - Legs on Exercise Ball
|
||||
312,Hanging Leg Raises
|
||||
311,Ab Roller
|
||||
310,Ball Knee Raise - Supine
|
||||
317,Crunches
|
||||
316,Crunch - Cable
|
||||
315,Side Crunch - Ball
|
||||
314,Crunch - Reverse
|
||||
861,Jacobs Ladder
|
||||
921,ProSkils: Track & Field
|
||||
496,Plie Dumbbell Squat
|
||||
833,Nia
|
||||
497,"Lunges with Medicine Ball, Quads"
|
||||
835,Action Cricket / Indoor Cricket
|
||||
839,Drumming
|
||||
808,Insanity Interval Plyo
|
||||
3,General
|
||||
368,"Calf Raise - Barbell, seated"
|
||||
369,Calf raise - with bands
|
||||
366,"Calf raise - smith machine, reversed"
|
||||
367,"Calf raise - seated, machine"
|
||||
364,Shoulder press - machine
|
||||
365,Calf raise - dumbell standing
|
||||
362,Cable internal rotation
|
||||
363,"Lunges with Medicine Ball, Shoulders"
|
||||
360,"Shoulder press - dumbbell, one arm"
|
||||
361,Side Lateral Raise - Seated
|
||||
952,10Acious: Butt
|
||||
380,"Tricep Extension - EZ-Bar, Seated, Overhead"
|
||||
381,Tricep Pushdowns - Straight Bar
|
||||
382,"Tricep Extension - Dumbbell, Lying"
|
||||
383,"Dips, Triceps"
|
||||
384,"Tricep Extension - Dumbbell, One Arm"
|
||||
385,Tricep Pushdowns - One Arm
|
||||
386,"Tricep Extension - Dumbbell, Standing"
|
||||
387,Tricep Pushdowns - Rope
|
||||
388,Bench Dips
|
||||
389,"Tricep Extension - Lying, Cable"
|
||||
784,Fly
|
||||
786,Airplane
|
||||
780,Scooter
|
||||
782,Powerboat
|
||||
788,Helicopter
|
||||
605,Shrugs - Dumbbell
|
||||
579,Incline Flyes - With a Twist
|
||||
578,"Cable Press - One Arm, Rotate"
|
||||
604,Mopping
|
||||
573,Bench Press - Machine
|
||||
572,"Bench Press - Barbell, Flat, Wide Grip"
|
||||
571,"Chest with Weights, Other"
|
||||
570,"Push-ups, Pike Up"
|
||||
577,Butterfly
|
||||
576,Push-ups - Spiderman
|
||||
575,"Flyes - Cable, Inclined Bench"
|
||||
574,"Flyes - Dumbbell, Inclined Bench"
|
||||
60,CycloCross
|
||||
61,Chest
|
||||
258,Netball
|
||||
259,Basketball
|
||||
64,Hybrid Cycling
|
||||
65,"Boxing, Indoor"
|
||||
66,Triceps
|
||||
67,Hamstrings
|
||||
252,Abs Video
|
||||
69,Upper Body
|
||||
250,"Elliptical, Run"
|
||||
251,Kickball
|
||||
256,Indoor Volleyball
|
||||
257,Kayak
|
||||
254,Gymnastics
|
||||
255,"Surfing, Swim"
|
||||
603,Vacuuming
|
||||
602,Misc Tasks (Light)
|
||||
939,Venom for Radius VI
|
||||
730,Stair Machine
|
||||
732,Basic Training
|
||||
734,Body Attack
|
||||
508,"Hiking, Heavy Pack"
|
||||
509,"Hiking, Medium Pack"
|
||||
506,Mat Workout
|
||||
507,Reformer Workout
|
||||
504,"Neck with Weights, Other"
|
||||
505,Lying Face Down Plate Neck Resistance
|
||||
502,Skate
|
||||
503,Lying Face-Up Plate Neck Resistance
|
||||
500,"Yoga, General"
|
||||
501,Traditional Winter Cross Country
|
||||
630,"Road Cycling, Moderate Hills"
|
||||
631,"Road Cycling, Long Distance"
|
||||
632,"Road Cycling, High Intensity"
|
||||
633,Road Cycling Race/Event
|
||||
469,Judo
|
||||
468,Tai Chi
|
||||
636,General Road Cycling
|
||||
637,"Bike Ride Commute, Road Cycling"
|
||||
465,Beach Cruiser
|
||||
464,"Recovery, Mountain Biking"
|
||||
467,Snow / Ice
|
||||
466,General Cruiser Bike Ride
|
||||
461,"Hill Workout, Mountain Biking"
|
||||
460,"Medium Intensity, Mountain Biking"
|
||||
463,"Interval Training, Mountain Biking"
|
||||
462,"Mountain Biking, Extreme"
|
||||
901,Ironsize: Compound Training Combo
|
||||
168,Push Ups
|
||||
169,Inline Skating
|
||||
164,Yolates
|
||||
165,Winsor Pilates
|
||||
166,Various
|
||||
167,Spin
|
||||
160,Inline / Roller Hockey
|
||||
161,Field Hockey
|
||||
162,British Military Fitness
|
||||
163,Squash
|
||||
960,"Carrying Child, Walk"
|
||||
961,Gym Intervals
|
||||
936,Venom for Radius III
|
||||
935,Venom for Radius II
|
||||
934,Venom for Radius I
|
||||
908,Lean 30: Upper Body Blast
|
||||
909,Lean 30: Ab Blast
|
||||
600,Cleaning (Light)
|
||||
878,Post-Recovery
|
||||
876,General Spa Treatment
|
||||
874,Meditation
|
||||
872,Active Release Treatment
|
||||
870,Deep Tissue Massage
|
||||
9,Walk
|
||||
890,Legs
|
||||
891,NBCU Radius
|
||||
892,Ironsize: Upper Body
|
||||
893,Ironsize: Chest & Triceps
|
||||
894,Ironsize: Lower Body
|
||||
647,Pole Video
|
||||
896,Ironsize: Cardio
|
||||
897,Ironsize: Legs
|
||||
898,Ironsize: Abs
|
||||
899,Ironsize: Compound Training Strength
|
||||
646,Ceroc
|
||||
649,Aqua Fit
|
||||
648,General BMX
|
||||
357,Cuban Press
|
||||
356,Cable Seated Rear Lateral Raise
|
||||
355,Front Incline Shoulder Raise
|
||||
354,External Rotation
|
||||
353,Front Dumbbell Raise
|
||||
352,Byron Front raises
|
||||
351,"Shoulder press - barbell, sitting"
|
||||
350,Arnold Dumbbell Press
|
||||
802,Insanity Pure Cardio & Cardio Abs
|
||||
800,Insanity Cardio Recovery
|
||||
806,Insanity Max Interval Circuit
|
||||
359,"Shoulder press - barbell, standing"
|
||||
358,Splint squat push press
|
||||
216,Indoor Soccer
|
||||
217,Camping
|
||||
214,PT Session
|
||||
215,"Kickboxing, Machine"
|
||||
212,You Workout
|
||||
213,Scuba Diving
|
||||
210,Pilates Video
|
||||
211,"Elliptical, Machine"
|
||||
762,Kung Fu
|
||||
955,10Acious: Upper Body
|
||||
760,Jujitsu
|
||||
766,"Indoor Track, Walk"
|
||||
218,Fartleks
|
||||
219,Personal Training
|
||||
956,Washboard by Keoni
|
||||
289,Shopping
|
||||
288,Recovery and Form
|
||||
281,Brick Session
|
||||
280,Jump Rope/Core
|
||||
283,Easy Jog
|
||||
282,Taper
|
||||
285,Home Workout
|
||||
284,Board Diving
|
||||
287,Rep Endurance
|
||||
286,Pliometrics
|
||||
678,P90X Plyometrics
|
||||
674,P90X
|
||||
676,P90X Chest & Back
|
||||
670,"Climbing Stairs, Indoor Walking"
|
||||
672,"Climbing Stairs, Indoor Running"
|
||||
263,Jump Rope
|
||||
262,"Treadmill, General"
|
||||
261,Rowing / Crew
|
||||
260,Aquaforme
|
||||
267,Wood Chopping
|
||||
266,Trail Run
|
||||
265,"Football, Competitive"
|
||||
264,"Hunting, Walk"
|
||||
269,"Hill Workout, Walk"
|
||||
268,"Stairs, Indoor Run"
|
||||
59,Swim Class / Aerobics
|
||||
58,Mountaineering
|
||||
55,Dance Video
|
||||
54,Volleyball
|
||||
57,Canoeing / Rowing
|
||||
56,BMX
|
||||
51,"Football, Casual "
|
||||
50,Recumbent Bike
|
||||
53,"Road Cycling, Indoor"
|
||||
52,Cruiser Bike
|
||||
537,Lat Pulldown - Underhand
|
||||
536,Gironda Sternum Chins
|
||||
535,"Inverted Row, Upper Back"
|
||||
63,"Cross Country, Winter"
|
||||
533,Pullups
|
||||
532,Cable Rope Rear-Delt Rows
|
||||
531,Lat Pulldown - Wide Grip
|
||||
530,Lat Pulldown - V-Bar
|
||||
539,"Cable Pulls, Upper Back Alternating"
|
||||
538,"Chin-ups, Upper Back"
|
||||
774,Car
|
||||
115,Time Trial
|
||||
114,Trekking
|
||||
117,Long Walk
|
||||
116,Bowling
|
||||
111,Water Running
|
||||
110,"Pull Ups, Dips"
|
||||
113,"Push Ups, Leglifts"
|
||||
112,"Boxing, Machine"
|
||||
119,Snowshoeing
|
||||
118,General Run
|
||||
770,Football Practice
|
||||
772,Vehicle
|
||||
953,10Acious: Full Body
|
||||
429,Dumbbell Curl - Incline Inner
|
||||
428,EZ-Bar Curl
|
||||
534,Lat Pulldown - Close-Grip
|
||||
919,ProSkils: Extreme Sports
|
||||
918,ProSkils: Soccer
|
||||
421,"Barbell Curl - Seated, Concentration"
|
||||
420,Dumbbell Curl - Standing
|
||||
423,"Dumbbell Curl - One-Arm, Incline Bench"
|
||||
422,"Cable Curl - Standing, One Arm"
|
||||
425,Hammer Curl - Standing
|
||||
424,"Reverse Barbell Curl, Biceps"
|
||||
427,Preacher Curl
|
||||
426,21s - EZ Bar
|
||||
308,Bicycle Kicks
|
||||
309,"Bird Dogs, Abdominals"
|
||||
300,Stability Ball climbers
|
||||
301,Scissor Kick
|
||||
302,Crunch - Machine
|
||||
303,Crunch - Decline
|
||||
304,Crunch - Cross Body
|
||||
305,Russian Twist
|
||||
306,Alternate Heel Touchers
|
||||
307,Plate twist
|
||||
895,"Ironsize: Shoulders, Back & Biceps"
|
||||
825,"Single Stroller, Walk"
|
||||
827,"Double Stroller, Walk"
|
||||
847,Kettlebell
|
||||
845,Trampoline
|
||||
843,Sitting
|
||||
841,Japanese Taiko
|
||||
849,Fitness Band
|
||||
820,Fitbug Activity
|
||||
823,Hang Gliding
|
||||
822,Walking
|
||||
954,10Acious: Legs
|
||||
568,"Dips, Chest"
|
||||
569,"Bench Press - Barbell, Inclined"
|
||||
750,Latin Dance
|
||||
756,"Indoor Track, Run"
|
||||
754,Zumba
|
||||
560,Dumbbell Lying Pronation
|
||||
561,"Zottman Curl, Forearms"
|
||||
562,"Forearms with Weights, Other"
|
||||
563,"Wrist Curl - Dumbbell, Palms Up"
|
||||
564,Sparring
|
||||
565,Fight
|
||||
566,Push-ups
|
||||
567,Cable Crossover
|
||||
229,Singing
|
||||
228,Racquetball
|
||||
227,"Hill Workout, Run"
|
||||
226,Bowflex Treadclimber
|
||||
225,"Machine Workout, Misc."
|
||||
224,Farming
|
||||
223,Motorcycle / Scooter
|
||||
222,Floorball
|
||||
221,Bouldering
|
||||
220,"Rock Climbing, Outdoor"
|
||||
391,"Tricep Extension - Barbell, Lying"
|
||||
726,Ashtanga Yoga
|
||||
724,Power Yoga
|
||||
390,"Dips, Machine"
|
||||
722,Hot Yoga
|
||||
720,Health Club
|
||||
728,Ergometer
|
||||
151,"Swim Indoor, Long Distance"
|
||||
150,The Bean
|
||||
153,Frisbee / Ultimate
|
||||
152,Quick Walk
|
||||
155,Fencing
|
||||
154,Golf
|
||||
157,"Gym, Misc."
|
||||
156,"Water Skiing, Swim"
|
||||
159,Body Pump
|
||||
158,"Sit Ups, Push Ups"
|
||||
609,Upright Rows - Barbell
|
||||
608,Calf-Machine Shoulder Shrug
|
||||
634,"Group Ride, Road Cycling"
|
||||
399,General Skiing
|
||||
635,"Road Cycling, Interval Training"
|
||||
958,Versa Climber
|
||||
398,Downhill Skiing
|
||||
48,Shoulders
|
||||
49,Upper Back
|
||||
46,Abdominals
|
||||
47,Unicycling
|
||||
44,Track Cycling
|
||||
45,Triathlon
|
||||
42,Quads
|
||||
43,Yard Work
|
||||
40,Traps
|
||||
41,Mountain Biking
|
||||
638,"Easy Training Ride, Road Cycling"
|
||||
639,"Road Cycling, Medium Intensity"
|
||||
489,"Lunge Matrix, Quads"
|
||||
488,Split Squat Push Press
|
||||
487,Thigh abductor
|
||||
486,Iron cross
|
||||
485,"Lunge with Rotation, Quads"
|
||||
484,Leg press
|
||||
483,Split squats
|
||||
482,"Lunges with Dumbbell, Quads"
|
||||
481,"Step Up with Curl, Quads"
|
||||
480,Barbell Deadlift
|
||||
472,"Kickboxing, Martial Arts"
|
||||
473,Aikido
|
||||
470,"Martial Arts, General"
|
||||
471,Karate
|
||||
476,Dumbbell Rear Lunge
|
||||
477,"BOSU Step Over, Quads"
|
||||
474,"Squat Press and Rotate, Quads"
|
||||
475,Hack Squat
|
||||
478,Squats - Barbell
|
||||
479,8 Count Body Builders
|
||||
|
842
static/rigging/ua2.csv
Normal file
@@ -0,0 +1,842 @@
|
||||
id,Name
|
||||
1,Generic
|
||||
2,Workout
|
||||
3,General
|
||||
7,Fartleks
|
||||
8,Indoor Sport / Other Activity
|
||||
9,Walk
|
||||
10,Winter Sport / Activity
|
||||
11,Bike Ride
|
||||
12,Gym Workout
|
||||
13,Indoor Winter Sport / Activity
|
||||
14,Machine Workout
|
||||
15,Swim
|
||||
16,Run
|
||||
17,Program / Video Workout
|
||||
18,Weight Workout
|
||||
19,Indoor Bike Ride
|
||||
20,Indoor Swim
|
||||
21,Sport / Other Activity
|
||||
22,Rock Climb
|
||||
23,Class Workout
|
||||
24,Hike
|
||||
25,Indoor Run / Jog
|
||||
26,"Total Body, Weights"
|
||||
27,Neck with Weights
|
||||
28,Circuit Training
|
||||
29,Sailing
|
||||
30,Calves
|
||||
31,Pilates
|
||||
32,Hills
|
||||
33,Fixed Gear (Fixie)
|
||||
34,Aerobic
|
||||
35,Strength Training
|
||||
36,Road Cycling
|
||||
37,Lower Back
|
||||
38,Touring Bike
|
||||
39,Lower Body
|
||||
40,Traps
|
||||
41,Mountain Biking
|
||||
42,Quads
|
||||
43,Yard Work
|
||||
44,Track Cycling
|
||||
45,Triathlon
|
||||
46,Abdominals
|
||||
47,Unicycling
|
||||
48,Shoulders
|
||||
49,Upper Back
|
||||
50,Recumbent Bike
|
||||
51,"Football, Casual "
|
||||
52,Cruiser Bike
|
||||
53,"Road Cycling, Indoor"
|
||||
54,Volleyball
|
||||
55,Dance Video
|
||||
56,BMX
|
||||
57,Canoeing / Rowing
|
||||
58,Mountaineering
|
||||
59,Swim Class / Aerobics
|
||||
60,CycloCross
|
||||
61,Chest
|
||||
62,Forearms
|
||||
63,"Cross Country, Winter"
|
||||
64,Hybrid Cycling
|
||||
65,"Boxing, Indoor"
|
||||
66,Triceps
|
||||
67,Hamstrings
|
||||
68,Softball
|
||||
69,Upper Body
|
||||
70,Middle Back
|
||||
71,Brick
|
||||
72,Martial Arts
|
||||
73,Tennis
|
||||
74,Skiing
|
||||
75,Lap Swim
|
||||
76,Musical Instrument
|
||||
77,House Work
|
||||
78,Yoga Class
|
||||
79,Biceps
|
||||
80,Snorkeling
|
||||
81,"Stationary Bike, Machine"
|
||||
82,Ballet
|
||||
83,Sports Conditioning
|
||||
84,Wakeboarding
|
||||
85,Fishing
|
||||
86,Ice Skating
|
||||
87,"Spinning, Indoor"
|
||||
88,Paddle
|
||||
89,Speed Workout
|
||||
90,BLT
|
||||
91,Speed Work
|
||||
92,Cross Trainer
|
||||
93,Softball
|
||||
94,Wind Surfing
|
||||
95,Skateboarding
|
||||
96,Nordic Track
|
||||
97,Pool Games / Lessons
|
||||
98,Abs
|
||||
99,Rowing Machine
|
||||
100,Indoor Swim Race/Event
|
||||
101,Roller Skating / Skiing
|
||||
102,Run Commute
|
||||
103,Sprints
|
||||
104,Curling
|
||||
105,Power Walk
|
||||
106,Casual Walk
|
||||
107,Snowboarding
|
||||
108,Track Run
|
||||
109,General Hike
|
||||
110,"Pull Ups, Dips"
|
||||
111,Water Running
|
||||
112,"Boxing, Machine"
|
||||
113,"Push Ups, Leglifts"
|
||||
114,Trekking
|
||||
115,Time Trial
|
||||
116,Bowling
|
||||
117,Long Walk
|
||||
118,General Run
|
||||
119,Snowshoeing
|
||||
120,"Spinning, Indoor "
|
||||
121,Water Polo
|
||||
122,General Sports
|
||||
123,Bootcamp
|
||||
124,Group Run
|
||||
125,Ballroom Dancing
|
||||
126,Power Walk
|
||||
127,Surfing
|
||||
128,Rowing
|
||||
129,Sight Seeing
|
||||
130,NeuStep
|
||||
131,Wrestling
|
||||
132,Cybex UBE
|
||||
133,"Stairs, Walk"
|
||||
134,Baseball
|
||||
135,Hockey
|
||||
136,Long Run
|
||||
137,Horseback Riding
|
||||
138,Whitewater Rafting
|
||||
139,Bike
|
||||
140,"Total Body, General Gym"
|
||||
141,Ice Hockey
|
||||
142,Badminton
|
||||
143,Walk Race/Event
|
||||
144,Games
|
||||
145,"Golf, Walk"
|
||||
146,"Treadmill, Walk"
|
||||
147,Dragon Boat
|
||||
148,Cheerleading
|
||||
149,Stretch / Sculpt
|
||||
150,The Bean
|
||||
151,"Swim Indoor, Long Distance"
|
||||
152,Quick Walk
|
||||
153,Frisbee / Ultimate
|
||||
154,Golf
|
||||
155,Fencing
|
||||
156,"Water Skiing, Swim"
|
||||
157,"Gym, Misc."
|
||||
158,"Sit Ups, Push Ups"
|
||||
159,Body Pump
|
||||
160,Inline / Roller Hockey
|
||||
161,Field Hockey
|
||||
162,British Military Fitness
|
||||
163,Squash
|
||||
164,Yolates
|
||||
165,Winsor Pilates
|
||||
166,Various
|
||||
167,Spin
|
||||
168,Push Ups
|
||||
169,Inline Skating
|
||||
170,Sit Ups
|
||||
171,Skydiving
|
||||
172,Run Race/Event
|
||||
173,Tempo Run
|
||||
174,Pi
|
||||
175,Snow Shoeing
|
||||
176,"Soccer, Sport"
|
||||
177,Cross Country Hiking
|
||||
178,Lacrosse
|
||||
179,General Walk
|
||||
180,Open Water Swim
|
||||
181,Curves
|
||||
182,Nordic Rollerskiing
|
||||
183,Dance / Yoga
|
||||
184,"Scuba Diving, Swim"
|
||||
185,Pull Ups
|
||||
186,Body Combat
|
||||
187,Recovery
|
||||
188,Quick Run
|
||||
189,Snowmobile Riding
|
||||
190,Aerobics
|
||||
191,New York Body
|
||||
192,Water Aerobics
|
||||
193,Group Swimming
|
||||
194,"Steps, Machine"
|
||||
195,FireFighting
|
||||
196,Shoveling
|
||||
197,"Interval Training, Run"
|
||||
198,Conditioning
|
||||
199,Calisthenics
|
||||
200,Gardening
|
||||
201,Adventure Race / Event
|
||||
202,Orienteering
|
||||
203,Crunches and Leg Lifts
|
||||
204,Dog Walk
|
||||
205,Kitesurfing
|
||||
206,"Yard Work, General"
|
||||
207,Skiers Edge
|
||||
208,"Treadmill, Run"
|
||||
209,Chicometrics
|
||||
210,Pilates Video
|
||||
211,"Elliptical, Machine"
|
||||
212,You Workout
|
||||
213,Scuba Diving
|
||||
214,PT Session
|
||||
215,"Kickboxing, Machine"
|
||||
216,Indoor Soccer
|
||||
217,Camping
|
||||
218,Fartleks
|
||||
219,Personal Training
|
||||
220,"Rock Climbing, Outdoor"
|
||||
221,Bouldering
|
||||
222,Floorball
|
||||
223,Motorcycle / Scooter
|
||||
224,Farming
|
||||
225,"Machine Workout, Misc."
|
||||
226,Bowflex Treadclimber
|
||||
227,"Hill Workout, Run"
|
||||
228,Racquetball
|
||||
229,Singing
|
||||
230,General Workout Video
|
||||
231,Bootcamp Workout
|
||||
232,Fitball
|
||||
233,"Push Ups, Sit Ups"
|
||||
234,"Rock Climbing, Indoor"
|
||||
235,Rugby
|
||||
236,"Indoor Sport, Other"
|
||||
237,Yoga Video
|
||||
238,"Pushups, Pullups, Torso"
|
||||
239,Ski Surf
|
||||
240,Pyramid Pull Ups
|
||||
241,Medicine Ball
|
||||
242,Group Walk
|
||||
243,Cross Country Running
|
||||
244,Intimacy
|
||||
245,Gilad
|
||||
246,Brick Workout
|
||||
247,"Yoga, Sport"
|
||||
248,Core Secret Ball
|
||||
249,Circle Swim
|
||||
250,"Elliptical, Run"
|
||||
251,Kickball
|
||||
252,Abs Video
|
||||
253,Walk Commute
|
||||
254,Gymnastics
|
||||
255,"Surfing, Swim"
|
||||
256,Indoor Volleyball
|
||||
257,Kayak
|
||||
258,Netball
|
||||
259,Basketball
|
||||
260,Aquaforme
|
||||
261,Rowing / Crew
|
||||
262,"Treadmill, General"
|
||||
263,Jump Rope
|
||||
264,"Hunting, Walk"
|
||||
265,"Football, Competitive"
|
||||
266,Trail Run
|
||||
267,Wood Chopping
|
||||
268,"Stairs, Indoor Run"
|
||||
269,"Hill Workout, Walk"
|
||||
270,Plyometrics
|
||||
271,Cricket
|
||||
272,Brisk Walk
|
||||
273,Rollerblading
|
||||
274,"Intervals, Walk"
|
||||
275,"Nordic, Walk"
|
||||
276,Hunt Fitness
|
||||
277,Water Skiing
|
||||
278,Weaponry
|
||||
279,"Dance, Indoor"
|
||||
280,Jump Rope/Core
|
||||
281,Brick Session
|
||||
282,Taper
|
||||
283,Easy Jog
|
||||
284,Board Diving
|
||||
285,Home Workout
|
||||
286,Pliometrics
|
||||
287,Rep Endurance
|
||||
288,Recovery and Form
|
||||
289,Shopping
|
||||
290,Rest Day
|
||||
291,Yourself Fitness Video
|
||||
292,"Sailing, Competitive"
|
||||
293,"Sailing, General"
|
||||
294,Fastball
|
||||
295,Crunch- Decline Oblique
|
||||
296,Hip Lifts
|
||||
297,Crunch - Excercise Ball
|
||||
298,One Leg Bridges
|
||||
299,"Abdominals with Weights, Other"
|
||||
300,Stability Ball climbers
|
||||
301,Scissor Kick
|
||||
302,Crunch - Machine
|
||||
303,Crunch - Decline
|
||||
304,Crunch - Cross Body
|
||||
305,Russian Twist
|
||||
306,Alternate Heel Touchers
|
||||
307,Plate twist
|
||||
308,Bicycle Kicks
|
||||
309,"Bird Dogs, Abdominals"
|
||||
310,Ball Knee Raise - Supine
|
||||
311,Ab Roller
|
||||
312,Hanging Leg Raises
|
||||
313,Crunch - Legs on Exercise Ball
|
||||
314,Crunch - Reverse
|
||||
315,Side Crunch - Ball
|
||||
316,Crunch - Cable
|
||||
317,Crunches
|
||||
318,Dead Bugs
|
||||
319,"Lunge with Rotation, Abdominals"
|
||||
320,Exercise ball pull in
|
||||
321,Spiderman Walk
|
||||
322,Dumbbell side bend
|
||||
323,"Ball Floor Bridge, Abdominals"
|
||||
324,Seated Leg Tucks
|
||||
325,Crunch - Oblique
|
||||
326,Push-ups - Pike Up
|
||||
327,Leg Pull-in
|
||||
328,Crunch - Decline Reverse
|
||||
329,Opposite Leg Toe touch
|
||||
330,V-sits
|
||||
331,Toe Touchers
|
||||
332,Push Ups - Spiderman
|
||||
333,Hanging pike
|
||||
334,Plank Hold
|
||||
335,Medicine Ball Pullovers
|
||||
336,Beach Volleyball
|
||||
337,"Rear Delt Row - Barbell, Standing"
|
||||
338,Reverse flyes
|
||||
339,"Rear Delt Raise - Dumbbell, Lying"
|
||||
340,"Rear Delt Raise - Dumbbell, Bent-Over"
|
||||
341,"Squat Press and Rotate, Shoulders"
|
||||
342,Front plate raise
|
||||
343,Side lateral raise
|
||||
344,"Shoulders with Weights, Other"
|
||||
345,"Shoulder Press - Dumbbell, Seated"
|
||||
346,"Shoulder Press - Dumbbell, Palms In"
|
||||
347,Standing Low-Pulley Deltoid Raise
|
||||
348,Front Cable Raise
|
||||
349,Incline Shoulder Raise
|
||||
350,Arnold Dumbbell Press
|
||||
351,"Shoulder press - barbell, sitting"
|
||||
352,Byron Front raises
|
||||
353,Front Dumbbell Raise
|
||||
354,External Rotation
|
||||
355,Front Incline Shoulder Raise
|
||||
356,Cable Seated Rear Lateral Raise
|
||||
357,Cuban Press
|
||||
358,Splint squat push press
|
||||
359,"Shoulder press - barbell, standing"
|
||||
360,"Shoulder press - dumbbell, one arm"
|
||||
361,Side Lateral Raise - Seated
|
||||
362,Cable internal rotation
|
||||
363,"Lunges with Medicine Ball, Shoulders"
|
||||
364,Shoulder press - machine
|
||||
365,Calf raise - dumbell standing
|
||||
366,"Calf raise - smith machine, reversed"
|
||||
367,"Calf raise - seated, machine"
|
||||
368,"Calf Raise - Barbell, seated"
|
||||
369,Calf raise - with bands
|
||||
370,"Calf raise - Dumbbell, seated, one leg"
|
||||
371,Calf Press - Leg press machine
|
||||
372,"Calves with Weights, Other"
|
||||
373,"Calf raise - barbell, standing"
|
||||
374,Skull Crushers
|
||||
375,Tricep pushdowns - Incline Bench
|
||||
376,Tricep Pushdowns - V-bar
|
||||
377,"Triceps with Weights, Other"
|
||||
378,Tricep Kickbacks - Dumbbell
|
||||
379,"Tricep Press- Dumbbell, Seated"
|
||||
380,"Tricep Extension - EZ-Bar, Seated, Overhead"
|
||||
381,Tricep Pushdowns - Straight Bar
|
||||
382,"Tricep Extension - Dumbbell, Lying"
|
||||
383,"Dips, Triceps"
|
||||
384,"Tricep Extension - Dumbbell, One Arm"
|
||||
385,Tricep Pushdowns - One Arm
|
||||
386,"Tricep Extension - Dumbbell, Standing"
|
||||
387,Tricep Pushdowns - Rope
|
||||
388,Bench Dips
|
||||
389,"Tricep Extension - Lying, Cable"
|
||||
390,"Dips, Machine"
|
||||
391,"Tricep Extension - Barbell, Lying"
|
||||
392,Pushups - Hands Close Together
|
||||
393,Bench Press Triceps Close-Grip
|
||||
394,"Tricep Extension - Dumbbell, Pronated"
|
||||
395,"Tricep Extension- Dumbbell, Lying, Supine"
|
||||
396,"Tricep Extension - Overhead, Cable"
|
||||
397,Backcountry Skiing
|
||||
398,Downhill Skiing
|
||||
399,General Skiing
|
||||
400,Barbell Curl - Lying Against Incline
|
||||
401,Barbell Curl - Standing
|
||||
402,Cable Curl - Overhead
|
||||
403,Cable Curl - Standing
|
||||
404,"Biceps with Weights, Other"
|
||||
405,Concentration Curl
|
||||
406,Dumbbell Curl - Incline
|
||||
407,Dumbbell Curl - Seated
|
||||
408,"Hammer Curl - Cable, Rope Attachment"
|
||||
409,Cable Curl - Preacher Curl
|
||||
410,Cable Curl - Lying
|
||||
411,Preacher Curl - Machine
|
||||
412,"Step Up with Curl, Biceps"
|
||||
413,"Dumbbell Curl - Seated, InnerBicep"
|
||||
414,EZ-Bar Curl - Close Grip
|
||||
415,Spider Curl
|
||||
416,"Reverse Cable Curl, Biceps"
|
||||
417,Cable Curl- High pulley
|
||||
418,"Chin-ups, Biceps"
|
||||
419,"Zottman Curl, Biceps"
|
||||
420,Dumbbell Curl - Standing
|
||||
421,"Barbell Curl - Seated, Concentration"
|
||||
422,"Cable Curl - Standing, One Arm"
|
||||
423,"Dumbbell Curl - One-Arm, Incline Bench"
|
||||
424,"Reverse Barbell Curl, Biceps"
|
||||
425,Hammer Curl - Standing
|
||||
426,21s - EZ Bar
|
||||
427,Preacher Curl
|
||||
428,EZ-Bar Curl
|
||||
429,Dumbbell Curl - Incline Inner
|
||||
430,"Lunge Matrix, Hamstrings"
|
||||
431,Flutter Kicks
|
||||
432,"Romanian Deadlift, Hamstrings"
|
||||
433,"Lunge with Rotation, Hamstrings"
|
||||
434,"Lunges with Medicine Ball, Hamstrings"
|
||||
435,"BOSU Step Over, Hamstrings"
|
||||
436,"Lunges with Dumbbell, Hamstrings"
|
||||
437,Leg Curls - Lying
|
||||
438,"Stiff-Legged Barbell Deadlift, Hamstrings"
|
||||
439,Leg Curls - Seated
|
||||
440,"Hamstrings with Weights, Other"
|
||||
441,"Stiff-Legged Dumbbell Deadlift, Hamstrings"
|
||||
442,Leg Curls - Standing
|
||||
443,"Strength Training with Weights, Other"
|
||||
444,General Strength Training
|
||||
445,Randonneur / Touring
|
||||
446,"Lower Body with Weights, Other"
|
||||
447,"Lower Body, General"
|
||||
448,"Mountain Biking, Light Intensity"
|
||||
449,"Mountain Biking, Moderate Hills"
|
||||
450,"Mountain Biking, Long Distance"
|
||||
451,"Mountain Biking, High Intensity"
|
||||
452,Mountain Biking Race/Event
|
||||
453,"Group Ride, Mountain Biking"
|
||||
454,Downhill Mountain Biking
|
||||
455,"Double Track, Mountain Biking"
|
||||
456,General Mountain Biking
|
||||
457,"Bike Ride Commute, Mountain Biking"
|
||||
458,"Easy Training Ride, Mountain Biking"
|
||||
459,"Single Track, Mountain Biking"
|
||||
460,"Medium Intensity, Mountain Biking"
|
||||
461,"Hill Workout, Mountain Biking"
|
||||
462,"Mountain Biking, Extreme"
|
||||
463,"Interval Training, Mountain Biking"
|
||||
464,"Recovery, Mountain Biking"
|
||||
465,Beach Cruiser
|
||||
466,General Cruiser Bike Ride
|
||||
467,Snow / Ice
|
||||
468,Tai Chi
|
||||
469,Judo
|
||||
470,"Martial Arts, General"
|
||||
471,Karate
|
||||
472,"Kickboxing, Martial Arts"
|
||||
473,Aikido
|
||||
474,"Squat Press and Rotate, Quads"
|
||||
475,Hack Squat
|
||||
476,Dumbbell Rear Lunge
|
||||
477,"BOSU Step Over, Quads"
|
||||
478,Squats - Barbell
|
||||
479,8 Count Body Builders
|
||||
480,Barbell Deadlift
|
||||
481,"Step Up with Curl, Quads"
|
||||
482,"Lunges with Dumbbell, Quads"
|
||||
483,Split squats
|
||||
484,Leg press
|
||||
485,"Lunge with Rotation, Quads"
|
||||
486,Iron cross
|
||||
487,Thigh abductor
|
||||
488,Split Squat Push Press
|
||||
489,"Lunge Matrix, Quads"
|
||||
490,Quads - Ball
|
||||
491,Front Barbell Squat
|
||||
492,Barbell Step Ups
|
||||
493,"Quads with Weights, Other"
|
||||
494,Leg extensions
|
||||
495,Body Weight Squats
|
||||
496,Plie Dumbbell Squat
|
||||
497,"Lunges with Medicine Ball, Quads"
|
||||
498,Bikram
|
||||
499,Vinyasa
|
||||
500,"Yoga, General"
|
||||
501,Traditional Winter Cross Country
|
||||
502,Skate
|
||||
503,Lying Face-Up Plate Neck Resistance
|
||||
504,"Neck with Weights, Other"
|
||||
505,Lying Face Down Plate Neck Resistance
|
||||
506,Mat Workout
|
||||
507,Reformer Workout
|
||||
508,"Hiking, Heavy Pack"
|
||||
509,"Hiking, Medium Pack"
|
||||
510,"Hiking, Light or No Pack"
|
||||
511,"Romanian Deadlift, Lower Back"
|
||||
512,"Bird Dogs, Lower Back"
|
||||
513,Back Extensions
|
||||
514,"Lower Back with Weights, Other"
|
||||
515,"Ball Floor Bridge, Lower Back"
|
||||
516,"Stiff-Legged Barbell Deadlift, Lower Back"
|
||||
517,Supermans
|
||||
518,"Stiff-Legged Dumbbell Deadlift, Lower Back"
|
||||
519,Weighted Ball Hyperextension
|
||||
520,Triathlon Race
|
||||
521,General Lawn Mowing
|
||||
522,Mowing Lawn (Riding Mower)
|
||||
523,General Track Cycling
|
||||
524,"Canoeing, Medium Intensity"
|
||||
525,"Canoeing, High Intensity"
|
||||
526,"Canoeing, Low Intensity"
|
||||
527,Full Range-of-Motion Lat Pulldown
|
||||
528,Straight-Arm Pulldown
|
||||
529,Pullups - V-Bar
|
||||
530,Lat Pulldown - V-Bar
|
||||
531,Lat Pulldown - Wide Grip
|
||||
532,Cable Rope Rear-Delt Rows
|
||||
533,Pullups
|
||||
534,Lat Pulldown - Close-Grip
|
||||
535,"Inverted Row, Upper Back"
|
||||
536,Gironda Sternum Chins
|
||||
537,Lat Pulldown - Underhand
|
||||
538,"Chin-ups, Upper Back"
|
||||
539,"Cable Pulls, Upper Back Alternating"
|
||||
540,"Upper Back with Weights, Other"
|
||||
541,"Lat Pulldown, Upper Back Alternating"
|
||||
542,Cardiovascular (CV) Circuit Training
|
||||
543,Resistance Circuit Training
|
||||
544,"Unicycling, Long Distance"
|
||||
545,General Unicycling
|
||||
546,"Indoor Bike, Trainer"
|
||||
547,Computrainer
|
||||
548,Stationary Bike
|
||||
549,Cyclocross Event/Race
|
||||
550,General Cyclocross
|
||||
551,"Reverse Cable Curl, Forearms"
|
||||
552,Wrist Curl - Cable
|
||||
553,"Reverse Barbell Curl, Forearms"
|
||||
554,"Wrist Curl - Barbell, Palms-Up"
|
||||
555,Tyson Shakers
|
||||
556,"Wrist Curl - Barbell, Palms-Down"
|
||||
557,"Wrist Curl - Barbell, Standing, Behind the Back"
|
||||
558,Wrist Roller
|
||||
559,"Wrist Curl - Dumbbell, Palms-Down"
|
||||
560,Dumbbell Lying Pronation
|
||||
561,"Zottman Curl, Forearms"
|
||||
562,"Forearms with Weights, Other"
|
||||
563,"Wrist Curl - Dumbbell, Palms Up"
|
||||
564,Sparring
|
||||
565,Fight
|
||||
566,Push-ups
|
||||
567,Cable Crossover
|
||||
568,"Dips, Chest"
|
||||
569,"Bench Press - Barbell, Inclined"
|
||||
570,"Push-ups, Pike Up"
|
||||
571,"Chest with Weights, Other"
|
||||
572,"Bench Press - Barbell, Flat, Wide Grip"
|
||||
573,Bench Press - Machine
|
||||
574,"Flyes - Dumbbell, Inclined Bench"
|
||||
575,"Flyes - Cable, Inclined Bench"
|
||||
576,Push-ups - Spiderman
|
||||
577,Butterfly
|
||||
578,"Cable Press - One Arm, Rotate"
|
||||
579,Incline Flyes - With a Twist
|
||||
580,Bent-Arm Dumbbell Pullover
|
||||
581,Bench Press - Smith Machine
|
||||
582,"Bench Press - Barbell, Declined"
|
||||
583,"Flyes - Cable, Flat Bench"
|
||||
584,"Bench Press - Dumbbells, Inclined"
|
||||
585,Push-ups - Feet on Exercise Ball
|
||||
586,Push-ups - Modified
|
||||
587,"Flyes - Dumbbell, Flat"
|
||||
588,"Bench Press - Barbell, Flat"
|
||||
589,Around the Worlds
|
||||
590,Front Raise and Pullover
|
||||
591,"Flyes - Dumbbell, Declined"
|
||||
592,Push-ups - Dumbbell
|
||||
593,Bench Press - Dumbell Declined
|
||||
594,"Bench Press - Inclined, Hammer Grip"
|
||||
595,Bench Press Chest Close-Grip
|
||||
596,"Bench Press - Dumbbell, Flat"
|
||||
597,"Upper Body with Weights, Other"
|
||||
598,General Upper Body
|
||||
599,Treadmill/Spin
|
||||
600,Cleaning (Light)
|
||||
601,Misc Tasks (Moderate)
|
||||
602,Misc Tasks (Light)
|
||||
603,Vacuuming
|
||||
604,Mopping
|
||||
605,Shrugs - Dumbbell
|
||||
606,"Shrugs - Barbell, Behind Back"
|
||||
607,Upright Rows - Dumbbell
|
||||
608,Calf-Machine Shoulder Shrug
|
||||
609,Upright Rows - Barbell
|
||||
610,"Traps with Weights, Other"
|
||||
611,Low Pulley Row to Neck
|
||||
612,Shrugs - Cable
|
||||
613,Shrugs - Barbell
|
||||
614,Upright Rows - Cable
|
||||
615,General Recumbent Bike
|
||||
616,Singles
|
||||
617,"Tennis, Doubles"
|
||||
618,"Bike Ride Commute, Fixed Gear"
|
||||
619,General Fixed Gear Ride
|
||||
620,Cross Trainer
|
||||
621,Pump
|
||||
622,Dance Class
|
||||
623,Erg Machine
|
||||
624,Boxing Class
|
||||
625,"Body Combat, Misc."
|
||||
626,Spinning Class
|
||||
627,Step Aerobics Class
|
||||
628,Kickboxing Class
|
||||
629,"Road Cycling, Light Intensity"
|
||||
630,"Road Cycling, Moderate Hills"
|
||||
631,"Road Cycling, Long Distance"
|
||||
632,"Road Cycling, High Intensity"
|
||||
633,Road Cycling Race/Event
|
||||
634,"Group Ride, Road Cycling"
|
||||
635,"Road Cycling, Interval Training"
|
||||
636,General Road Cycling
|
||||
637,"Bike Ride Commute, Road Cycling"
|
||||
638,"Easy Training Ride, Road Cycling"
|
||||
639,"Road Cycling, Medium Intensity"
|
||||
640,"Road Cycling, Hill Workout"
|
||||
641,"Road Cycling, Recovery"
|
||||
642,"Musical Instrument, All"
|
||||
643,"Football, Australian"
|
||||
644,"Football, 11-a-Side Touch"
|
||||
645,"Football, 5-a-Side Touch"
|
||||
646,Ceroc
|
||||
647,Pole Video
|
||||
648,General BMX
|
||||
649,Aqua Fit
|
||||
650,"Total Body, Other"
|
||||
651,General Total Body
|
||||
652,"Hybrid Cycling, Shopping / Errands"
|
||||
653,General Hybrid Cycling
|
||||
654,"Inverted Row, Middle Back"
|
||||
655,"Cable Pulls, Middle Back Alternating"
|
||||
656,Bent Over Dumbbell Row
|
||||
657,"Middle Back with Weights, Other"
|
||||
658,One-Arm Dumbbell Row
|
||||
659,Cable Chop
|
||||
660,T-Bar Row - Standing
|
||||
661,Seated Cable Eows
|
||||
662,"Lat Pulldown, Middle Back Alternating"
|
||||
663,T-Bar Row - Lying
|
||||
664,"Laps, General"
|
||||
665,General Lap Swim
|
||||
666,"Climbing Stairs, Walking"
|
||||
668,"Climbing Stairs, Running"
|
||||
670,"Climbing Stairs, Indoor Walking"
|
||||
672,"Climbing Stairs, Indoor Running"
|
||||
674,P90X
|
||||
676,P90X Chest & Back
|
||||
678,P90X Plyometrics
|
||||
680,P90X Shoulders and Arms
|
||||
682,P90X YogaX
|
||||
684,P90X Legs & Back
|
||||
686,P90X Kenpo
|
||||
688,P90X X Stretch
|
||||
690,P90X Core Synergistics
|
||||
692,"P90X Chest, Shoulders & Triceps"
|
||||
694,P90X Back & Biceps
|
||||
696,P90X CardioX
|
||||
698,P90X Ab Ripper X
|
||||
702,Trikke
|
||||
704,CrossFit Class
|
||||
706,TRX Suspension Training
|
||||
708,Motocross
|
||||
710,ElliptiGo
|
||||
712,Retro Running
|
||||
714,Longboarding
|
||||
716,Yourshape
|
||||
720,Health Club
|
||||
722,Hot Yoga
|
||||
724,Power Yoga
|
||||
726,Ashtanga Yoga
|
||||
728,Ergometer
|
||||
730,Stair Machine
|
||||
732,Basic Training
|
||||
734,Body Attack
|
||||
736,CrossFit Video
|
||||
738,Kinesis
|
||||
740,Tae Bo
|
||||
742,Ballroom Dancing
|
||||
744,Belly Dancing
|
||||
746,Hip Hop Dancing
|
||||
748,Hula
|
||||
750,Latin Dance
|
||||
752,Salsa
|
||||
754,Zumba
|
||||
756,"Indoor Track, Run"
|
||||
758,Handball
|
||||
760,Jujitsu
|
||||
762,Kung Fu
|
||||
764,Tae Kwon Do
|
||||
766,"Indoor Track, Walk"
|
||||
768,"Football Game, Tackle"
|
||||
770,Football Practice
|
||||
772,Vehicle
|
||||
774,Car
|
||||
776,Motorcycle
|
||||
778,Moped
|
||||
780,Scooter
|
||||
782,Powerboat
|
||||
784,Fly
|
||||
786,Airplane
|
||||
788,Helicopter
|
||||
790,Ultralight
|
||||
792,Insanity Total Body Workout
|
||||
794,Insanity Dig Deeper
|
||||
796,Insanity Plyometric Cardio Circuit
|
||||
798,Insanity Cardio Power & Resistance
|
||||
800,Insanity Cardio Recovery
|
||||
802,Insanity Pure Cardio & Cardio Abs
|
||||
804,Insanity Core Cardio & Balance
|
||||
806,Insanity Max Interval Circuit
|
||||
808,Insanity Interval Plyo
|
||||
810,Insanity Max Cardio Conditioning
|
||||
812,Insanity Max Recovery
|
||||
813,Mixed Martial Arts
|
||||
815,Nexersys Workout
|
||||
817,Nexersys Round
|
||||
819,Table Tennis
|
||||
820,Fitbug Activity
|
||||
822,Walking
|
||||
823,Hang Gliding
|
||||
825,"Single Stroller, Walk"
|
||||
827,"Double Stroller, Walk"
|
||||
829,"Single Stroller, Run"
|
||||
831,"Double Stroller, Run"
|
||||
833,Nia
|
||||
835,Action Cricket / Indoor Cricket
|
||||
839,Drumming
|
||||
841,Japanese Taiko
|
||||
843,Sitting
|
||||
845,Trampoline
|
||||
847,Kettlebell
|
||||
848,Activity Tracker
|
||||
849,Fitness Band
|
||||
855,Dog Run
|
||||
857,Soul Cycle - 45 Minutes
|
||||
859,Soul Survivor - 1 hour
|
||||
861,Jacobs Ladder
|
||||
863,Stand Up Paddling
|
||||
866,Boosted Board
|
||||
868,Swedish Massage
|
||||
870,Deep Tissue Massage
|
||||
872,Active Release Treatment
|
||||
874,Meditation
|
||||
876,General Spa Treatment
|
||||
878,Post-Recovery
|
||||
880,Muay Thai
|
||||
882,Barre Workout
|
||||
884,ChaLEAN Extreme
|
||||
886,21 Day Challenge
|
||||
888,Aquathlon
|
||||
890,Legs
|
||||
891,NBCU Radius
|
||||
892,Ironsize: Upper Body
|
||||
893,Ironsize: Chest & Triceps
|
||||
894,Ironsize: Lower Body
|
||||
895,"Ironsize: Shoulders, Back & Biceps"
|
||||
896,Ironsize: Cardio
|
||||
897,Ironsize: Legs
|
||||
898,Ironsize: Abs
|
||||
899,Ironsize: Compound Training Strength
|
||||
900,Ironsize: Compound Training Cardio
|
||||
901,Ironsize: Compound Training Combo
|
||||
902,Heavy Kettle: Basics
|
||||
903,Heavy Kettle: Blast
|
||||
904,Heavy Kettle: Build
|
||||
905,Lean 30: Lower Body Blast
|
||||
906,Lean 30: Body Blast Cardio
|
||||
907,Lean 30: Total Body
|
||||
908,Lean 30: Upper Body Blast
|
||||
909,Lean 30: Ab Blast
|
||||
910,Lean 30: Athletic Stretch
|
||||
911,Beginner Bootcamp: Upper Body
|
||||
912,Beginner Bootcamp: Basics
|
||||
913,Beginner Bootcamp: Circuit
|
||||
914,Beginner Bootcamp: Punches & Kicks
|
||||
915,Beginner Bootcamp: Lower Body
|
||||
916,Washboard by Basheerah: Ab Sculpt
|
||||
917,Washboard by Basheerah: Chisled Abs
|
||||
918,ProSkils: Soccer
|
||||
919,ProSkils: Extreme Sports
|
||||
920,ProSkils: Football
|
||||
921,ProSkils: Track & Field
|
||||
922,ProSkils: Basketball
|
||||
923,ProSkils: MMA
|
||||
924,JumpStart: Upper Body
|
||||
925,JumpStart: Abs
|
||||
926,JumpStart: Lower Body
|
||||
927,JumpStart: Cardio
|
||||
928,Cardio Sculpt: Punch & Sculpt
|
||||
929,Cardio Sculpt: Explosion
|
||||
930,Cardio Sculpt: Kick & Sculpt
|
||||
931,Cardio Sculpt: Power
|
||||
932,Cardio Sculpt: Dance Sculpt
|
||||
933,Cardio Sculpt: Lower Body Burn
|
||||
934,Venom for Radius I
|
||||
935,Venom for Radius II
|
||||
936,Venom for Radius III
|
||||
937,Venom for Radius IV
|
||||
938,Venom for Radius V
|
||||
939,Venom for Radius VI
|
||||
940,Triple Threat: Arms
|
||||
941,Triple Threat: Butt
|
||||
942,Triple Threat: Legs
|
||||
943,Triple Threat: Total Body
|
||||
944,Triple Threat: Extreme
|
||||
945,Triple Threat: Abs
|
||||
946,10Acious: Power Flex
|
||||
947,10Acious: HIIT
|
||||
948,10Acious: Shoulders
|
||||
949,10Acious: Abs
|
||||
950,10Acious: Plyo
|
||||
951,10Acious: Arms
|
||||
952,10Acious: Butt
|
||||
953,10Acious: Full Body
|
||||
954,10Acious: Legs
|
||||
955,10Acious: Upper Body
|
||||
956,Washboard by Keoni
|
||||
958,Versa Climber
|
||||
960,"Carrying Child, Walk"
|
||||
961,Gym Intervals
|
||||
|