diff --git a/rowers/admin.py b/rowers/admin.py index f0db40e8..490fe9c3 100644 --- a/rowers/admin.py +++ b/rowers/admin.py @@ -11,7 +11,7 @@ from .models import ( Team,TeamInvite,TeamRequest, WorkoutComment,C2WorldClassAgePerformance,PlannedSession, GeoCourse,GeoPolygon,GeoPoint,VirtualRace,VirtualRaceResult, - PaidPlan,IndoorVirtualRaceResult,ShareKey + PaidPlan,IndoorVirtualRaceResult,ShareKey, CourseStandard,StandardCollection, ) # Register your models here so you can use them in the Admin module @@ -141,6 +141,12 @@ class IndoorVirtualRaceResultAdmin(admin.ModelAdmin): class PaidPlanAdmin(admin.ModelAdmin): list_display = ('name','shortname','price','paymenttype','paymentprocessor','external_id') +class StandardCollectionAdmin(admin.ModelAdmin): + list_display = ('name','manager') + +class CourseStandardAdmin(admin.ModelAdmin): + list_display = ('name','standardcollection') + admin.site.unregister(User) admin.site.register(User,UserAdmin) admin.site.register(Workout,WorkoutAdmin) @@ -160,3 +166,5 @@ admin.site.register(VirtualRaceResult, VirtualRaceResultAdmin) admin.site.register(IndoorVirtualRaceResult, IndoorVirtualRaceResultAdmin) admin.site.register(PaidPlan,PaidPlanAdmin) admin.site.register(ShareKey,ShareKeyAdmin) +admin.site.register(CourseStandard,CourseStandardAdmin) +admin.site.register(StandardCollection,StandardCollectionAdmin) diff --git a/rowers/courseutils.py b/rowers/courseutils.py index 39fda8bf..6ff83fc7 100644 --- a/rowers/courseutils.py +++ b/rowers/courseutils.py @@ -2,6 +2,11 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals + + + + + # low level methods def coordinate_in_path(latitude,longitude, p): @@ -18,12 +23,12 @@ def time_in_path(df,p,maxmin='max',getall=False): if df.empty: return 0 - + latitude = df.latitude longitude = df.longitude f = lambda x: coordinate_in_path(x['latitude'],x['longitude'],p) - + df['inpolygon'] = df.apply(f,axis=1) if maxmin=='max': @@ -40,7 +45,7 @@ def time_in_path(df,p,maxmin='max',getall=False): raise InvalidTrajectoryError("Trajectory doesn't go through path") - + return 0 @@ -64,7 +69,7 @@ def coursetime_paths(data,paths,finalmaxmin='min'): entrytime = data['time'].max() entrydistance = data['cum_dist'].max() coursecompleted = False - + # corner case - empty list of paths if len(paths) == 0: return 0,True diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 252e2bd9..b5712d7a 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1905,7 +1905,10 @@ def testdata(time, distance, pace, spm): def getrowdata_db(id=0, doclean=False, convertnewtons=True, checkefficiency=True): data = read_df_sql(id) - data['deltat'] = data['time'].diff() + try: + data['deltat'] = data['time'].diff() + except KeyError: + data = pd.DataFrame() if data.empty: rowdata, row = getrowdata(id=id) diff --git a/rowers/forms.py b/rowers/forms.py index bf7f79cd..7110da87 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -212,6 +212,18 @@ class CourseForm(forms.Form): from django.forms.widgets import HiddenInput super(CourseForm, self).__init__(*args, **kwargs) +# The form used for uploading images +class StandardsForm(forms.Form): + name = forms.CharField(max_length=150,label='Course Name') + file = forms.FileField(required=False, + validators=[must_be_csv]) + notes = forms.CharField(required=False, + max_length=200,label='Course Notes', + widget=forms.Textarea) + + def __init__(self, *args, **kwargs): + from django.forms.widgets import HiddenInput + super(StandardsForm, self).__init__(*args, **kwargs) # The form used for uploading files class DocumentsForm(forms.Form): @@ -1218,6 +1230,12 @@ class RaceResultFilterForm(forms.Form): initial=['None','PR1','PR2','PR3','FES'], widget=forms.CheckboxSelectMultiple()) + entrycategory = forms.MultipleChoiceField( + choices = [], + label = 'Groups', + widget=forms.CheckboxSelectMultiple() + ) + def __init__(self, *args, **kwargs): if 'records' in kwargs: records = kwargs.pop('records',None) @@ -1225,6 +1243,21 @@ class RaceResultFilterForm(forms.Form): super(RaceResultFilterForm,self).__init__(*args,**kwargs) if records: + # group + thecategories = [record.entrycategory for record in records] + thecategories = list(set(thecategories)) + if len(thecategories) <= 1: + del self.fields['entrycategory'] + else: + categorychoices = [] + for category in thecategories: + if category is not None: + categorychoices.append( + (category.id,category) + ) + self.fields['entrycategory'].choices = categorychoices + self.fields['entrycategory'].initial = [cat[0] for cat in categorychoices] + # sex thesexes = [record.sex for record in records] thesexes = list(set(thesexes)) diff --git a/rowers/migrations/0001_initial.py b/rowers/migrations/0001_initial.py index 84b67e88..5f0cdb04 100644 --- a/rowers/migrations/0001_initial.py +++ b/rowers/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.7 on 2019-07-26 09:28 +# Generated by Django 2.1.7 on 2020-05-28 03:31 import datetime from django.conf import settings @@ -19,11 +19,33 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name='Alert', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, max_length=150, null=True, verbose_name='Alert Name')), + ('reststrokes', models.BooleanField(default=False, null=True, verbose_name='Include Rest Strokes')), + ('period', models.IntegerField(default=7, verbose_name='Reporting Period (days)')), + ('next_run', models.DateField(default=django.utils.timezone.now)), + ('emailalert', models.BooleanField(default=True, verbose_name='Send email alerts')), + ('workouttype', models.CharField(choices=[('water', 'Standard Racing Shell'), ('rower', 'Indoor Rower'), ('dynamic', 'Dynamic Indoor Rower'), ('slides', 'Indoor Rower on Slides'), ('coastal', 'Coastal'), ('c-boat', 'Dutch C boat'), ('churchboat', 'Finnish Church boat')], default='water', max_length=50, verbose_name='Exercise/Boat Class')), + ('boattype', models.CharField(choices=[('1x', '1x (single)'), ('2x', '2x (double)'), ('2x+', '2x+ (coxed double)'), ('2-', '2- (pair)'), ('2+', '2+ (coxed pair)'), ('3x+', '3x+ (coxed triple)'), ('3x-', '3x- (triple)'), ('4x', '4x (quad)'), ('4x+', '4x+ (coxed quad)'), ('4-', '4- (four)'), ('4+', '4+ (coxed four)'), ('8+', '8+ (eight)'), ('8x+', '8x+ (octuple scull)')], default='1x', max_length=50, verbose_name='Boat Type')), + ], + ), + migrations.CreateModel( + name='BlogPost', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.TextField(max_length=300)), + ('link', models.TextField(max_length=300)), + ('date', models.DateField()), + ], + ), migrations.CreateModel( name='C2WorldClassAgePerformance', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female')], default='female', max_length=30)), ('age', models.IntegerField(default=19, verbose_name='Age')), ('distance', models.IntegerField(default=2000)), @@ -37,8 +59,8 @@ class Migration(migrations.Migration): name='CalcAgePerformance', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), - ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female')], default='female', max_length=30)), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), + ('sex', models.CharField(choices=[('male', 'Open'), ('female', 'Female')], default='female', max_length=30)), ('age', models.IntegerField(default=19, verbose_name='Age')), ('duration', models.FloatField(blank=True, default=1)), ('power', models.IntegerField(default=200)), @@ -70,6 +92,34 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=150, unique=True)), ], ), + migrations.CreateModel( + name='Condition', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('metric', models.CharField(choices=[('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('distance', 'Interval Distance (m)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], max_length=50, verbose_name='Metric')), + ('value1', models.FloatField(default=0)), + ('value2', models.FloatField(blank=True, default=0, null=True)), + ('condition', models.CharField(choices=[('<', '<'), ('>', '>'), ('=', '='), ('between', 'between')], max_length=20, null=True)), + ], + ), + migrations.CreateModel( + name='CourseStandard', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=150)), + ('coursedistance', models.IntegerField()), + ('coursetime', models.CharField(default='', max_length=100)), + ('referencespeed', models.FloatField()), + ('agemin', models.IntegerField(default=0)), + ('agemax', models.IntegerField(default=120)), + ('boatclass', models.CharField(max_length=150)), + ('boattype', models.CharField(choices=[('1x', '1x (single)'), ('2x', '2x (double)'), ('2x+', '2x+ (coxed double)'), ('2-', '2- (pair)'), ('2+', '2+ (coxed pair)'), ('3x+', '3x+ (coxed triple)'), ('3x-', '3x- (triple)'), ('4x', '4x (quad)'), ('4x+', '4x+ (coxed quad)'), ('4-', '4- (four)'), ('4+', '4+ (coxed four)'), ('8+', '8+ (eight)'), ('8x+', '8x+ (octuple scull)')], default='1x', max_length=50)), + ('sex', models.CharField(max_length=150)), + ('weightclass', models.CharField(max_length=150)), + ('adaptiveclass', models.CharField(choices=[('None', 'Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50)), + ('skillclass', models.CharField(max_length=150)), + ], + ), migrations.CreateModel( name='CourseTestResult', fields=[ @@ -122,9 +172,9 @@ class Migration(migrations.Migration): name='FavoriteChart', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('yparam1', models.CharField(choices=[('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distance', 'Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('powerhr', 'Power Heart Rate Efficiency (J/beat)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], max_length=50, verbose_name='Y1')), - ('yparam2', models.CharField(blank=True, choices=[('None', ''), ('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distance', 'Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('powerhr', 'Power Heart Rate Efficiency (J/beat)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], default='None', max_length=50, verbose_name='Y2')), - ('xparam', models.CharField(choices=[('None', ''), ('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distance', 'Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('powerhr', 'Power Heart Rate Efficiency (J/beat)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], max_length=50, verbose_name='X')), + ('yparam1', models.CharField(choices=[('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('distance', 'Interval Distance (m)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], max_length=50, verbose_name='Y1')), + ('yparam2', models.CharField(blank=True, choices=[('None', ''), ('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('distance', 'Interval Distance (m)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], default='None', max_length=50, verbose_name='Y2')), + ('xparam', models.CharField(choices=[('None', ''), ('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('distance', 'Interval Distance (m)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], max_length=50, verbose_name='X')), ('plottype', models.CharField(choices=[('line', 'Line Chart'), ('scatter', 'Scatter Chart')], default='line', max_length=50, verbose_name='Chart Type')), ('workouttype', models.CharField(choices=[('ote', 'Erg/SkiErg'), ('otw', 'On The Water'), ('all', 'All'), ('strava', 'strava'), ('concept2', 'concept2'), ('sporttracks', 'sporttracks'), ('runkeeper', 'runkeeper'), ('mapmyfitness', 'mapmyfitness'), ('csv', 'painsled'), ('tcx', 'tcx'), ('rp', 'rowperfect'), ('mystery', 'mystery'), ('rowperfect3', 'rowperfect3'), ('ergdata', 'ergdata'), ('boatcoach', 'boatcoach'), ('boatcoachotw', 'boatcoachotw'), ('painsleddesktop', 'painsleddesktop'), ('speedcoach', 'speedcoach'), ('speedcoach2', 'speedcoach2'), ('ergstick', 'ergstick'), ('fit', 'fit'), ('unknown', 'unknown')], default='both', max_length=50, verbose_name='Workout Type')), ('reststrokes', models.BooleanField(default=True, verbose_name='Incl. Rest')), @@ -177,15 +227,19 @@ class Migration(migrations.Migration): ('teamname', models.CharField(blank=True, max_length=80, null=True, verbose_name='Team Name')), ('username', models.CharField(max_length=150)), ('workoutid', models.IntegerField(null=True)), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), - ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Class')), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), + ('adaptiveclass', models.CharField(choices=[('None', 'Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Class')), + ('skillclass', models.CharField(default='Open', max_length=50, verbose_name='Skill Class')), ('duration', models.TimeField(default=datetime.time(1, 0))), ('distance', models.IntegerField(default=0)), + ('referencespeed', models.FloatField(default=5.0)), + ('points', models.IntegerField(default=0)), ('boatclass', models.CharField(choices=[('rower', 'Indoor Rower'), ('dynamic', 'Dynamic Indoor Rower'), ('slides', 'Indoor Rower on Slides')], default='rower', max_length=40, verbose_name='Ergometer Class')), ('coursecompleted', models.BooleanField(default=False)), ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female'), ('not specified', 'not specified')], default='not specified', max_length=30, verbose_name='Gender')), ('age', models.IntegerField(null=True)), - ('emailnotifications', models.BooleanField(default=True, verbose_name='Receive race notifications by email')), + ('emailnotifications', models.BooleanField(default=True, verbose_name='Receive challenge notifications by email')), + ('entrycategory', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='rowers.CourseStandard', verbose_name='Group')), ], ), migrations.CreateModel( @@ -207,11 +261,11 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(blank=True, max_length=150, verbose_name='Name')), - ('comment', models.TextField(blank=True, max_length=500)), + ('comment', models.TextField(blank=True, max_length=1000)), ('startdate', models.DateField(default=rowers.models.current_day, verbose_name='On or After')), ('enddate', models.DateField(default=rowers.models.a_week_from_now, verbose_name='On or Before')), ('preferreddate', models.DateField(default=rowers.models.a_week_from_now, verbose_name='Preferred Date')), - ('sessiontype', models.CharField(choices=[('session', 'Training Session'), ('challenge', 'Challenge'), ('test', 'Mandatory Test'), ('cycletarget', 'Total for a time period'), ('coursetest', 'OTW test over a course'), ('race', 'Virtual Race'), ('indoorrace', 'Indoor Virtual Race')], default='session', max_length=150, verbose_name='Session Type')), + ('sessiontype', models.CharField(choices=[('session', 'Training Session'), ('challenge', 'Challenge'), ('test', 'Mandatory Test'), ('cycletarget', 'Total for a time period'), ('coursetest', 'OTW test over a course'), ('race', 'Virtual challenge'), ('indoorrace', 'Indoor Virtual challenge')], default='session', max_length=150, verbose_name='Session Type')), ('sessionvalue', models.IntegerField(default=60, verbose_name='Value')), ('max_nr_of_workouts', models.IntegerField(default=0, verbose_name='Maximum number of workouts')), ('sessionunit', models.CharField(choices=[('min', 'minutes'), ('m', 'meters'), ('None', None)], default='min', max_length=150, verbose_name='Unit')), @@ -219,6 +273,7 @@ class Migration(migrations.Migration): ('verification', models.CharField(choices=[('none', 'None'), ('automatic', 'Automatic'), ('manual', 'Manual')], default='none', max_length=150)), ('sessionmode', models.CharField(choices=[('distance', 'Distance'), ('time', 'Time'), ('rScore', 'rScore'), ('TRIMP', 'TRIMP')], default='time', max_length=150, verbose_name='Session Mode')), ('hasranking', models.BooleanField(default=False)), + ('is_template', models.BooleanField(default=False)), ], ), migrations.CreateModel( @@ -240,7 +295,7 @@ class Migration(migrations.Migration): ('PowerFourMin', models.FloatField(default=0)), ('PowerTwoK', models.FloatField(default=0)), ('PowerOneHour', models.FloatField(default=0)), - ('workoutmode', models.CharField(choices=[('rower', 'Rower'), ('water', 'On the water')], default='rower', max_length=40)), + ('workoutmode', models.CharField(choices=[('rower', 'Rower'), ('water', 'On the water')], default='rower', max_length=41)), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], options={ @@ -279,6 +334,8 @@ class Migration(migrations.Migration): ('offercoaching', models.BooleanField(default=False, verbose_name='Offer Remote Coaching')), ('gdproptin', models.BooleanField(default=False)), ('gdproptindate', models.DateTimeField(blank=True, null=True)), + ('surveydone', models.BooleanField(default=False)), + ('surveydonedate', models.DateTimeField(blank=True, null=True)), ('max', models.IntegerField(default=192, verbose_name='Max Heart Rate')), ('rest', models.IntegerField(default=48, verbose_name='Resting Heart Rate')), ('ut2', models.IntegerField(default=105, verbose_name='UT2 band lower HR')), @@ -287,9 +344,9 @@ class Migration(migrations.Migration): ('tr', models.IntegerField(default=167, verbose_name='TR band lower HR')), ('an', models.IntegerField(default=180, verbose_name='AN band lower HR')), ('hrftp', models.IntegerField(default=0, verbose_name='FTP heart rate')), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female'), ('not specified', 'not specified')], default='not specified', max_length=30)), - ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Classification')), + ('adaptiveclass', models.CharField(choices=[('None', 'Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Classification')), ('birthdate', models.DateField(blank=True, null=True)), ('ftp', models.IntegerField(default=226, verbose_name='Functional Threshold Power')), ('p0', models.FloatField(default=1.0, verbose_name='CP p1')), @@ -346,14 +403,29 @@ class Migration(migrations.Migration): ('emailbounced', models.BooleanField(default=False, verbose_name='Email Address Bounced')), ('getimportantemails', models.BooleanField(default=True, verbose_name='Get Important Emails')), ('privacy', models.CharField(choices=[('visible', 'Visible'), ('hidden', 'Hidden')], default='visible', max_length=30)), - ('defaulttimezone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', max_length=100, verbose_name='Default Time Zone')), + ('defaulttimezone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Nuuk', 'America/Nuuk'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', max_length=100, verbose_name='Default Time Zone')), ('showfavoritechartnotes', models.BooleanField(default=True, verbose_name='Show Notes for Favorite Charts')), + ('staticgrids', models.CharField(choices=[('none', None), ('both', 'both'), ('x', 'x'), ('y', 'y')], default='both', max_length=50, null=True, verbose_name='Chart Grid')), + ('slowpaceerg', models.DurationField(default=datetime.timedelta(0, 160), verbose_name='Slowest Erg Pace')), + ('fastpaceerg', models.DurationField(default=datetime.timedelta(0, 85), verbose_name='Fastest Erg Pace')), + ('slowpaceotw', models.DurationField(default=datetime.timedelta(0, 240), verbose_name='Slowest OTW Pace')), + ('fastpaceotw', models.DurationField(default=datetime.timedelta(0, 85), verbose_name='Fastest OTW Pace')), + ('autojoin', models.BooleanField(default=False, verbose_name='Auto Join Workout Segments')), ('coachinggroups', models.ManyToManyField(related_name='coaches', to='rowers.CoachingGroup')), ('friends', models.ManyToManyField(blank=True, related_name='_rower_friends_+', to='rowers.Rower')), ('mycoachgroup', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='coachingrole', to='rowers.CoachingGroup')), ('paidplan', models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='rowers.PaidPlan')), ], ), + migrations.CreateModel( + name='ShareKey', + fields=[ + ('location', models.TextField()), + ('token', models.CharField(max_length=40, primary_key=True, serialize=False)), + ('creation_date', models.DateTimeField(auto_now_add=True)), + ('expiration_seconds', models.BigIntegerField()), + ], + ), migrations.CreateModel( name='SiteAnnouncement', fields=[ @@ -366,55 +438,13 @@ class Migration(migrations.Migration): ], ), migrations.CreateModel( - name='StrokeData', + name='StandardCollection', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('workoutid', models.IntegerField(null=True)), - ('workoutstate', models.IntegerField(default=1, null=True)), - ('ftime', models.CharField(max_length=30)), - ('fpace', models.CharField(max_length=30)), - ('hr_ut2', models.IntegerField(null=True)), - ('hr_ut1', models.IntegerField(null=True)), - ('hr_at', models.IntegerField(null=True)), - ('hr_tr', models.IntegerField(null=True)), - ('hr_an', models.IntegerField(null=True)), - ('hr_max', models.IntegerField(null=True)), - ('hr_bottom', models.IntegerField(null=True)), - ('x_right', models.FloatField(null=True)), - ('ergpace', models.FloatField(null=True)), - ('nowindpace', models.FloatField(null=True)), - ('equivergpower', models.FloatField(null=True)), - ('fergpace', models.CharField(max_length=30)), - ('fnowindpace', models.CharField(max_length=30)), - ('time', models.FloatField(null=True, verbose_name='Time')), - ('hr', models.IntegerField(null=True, verbose_name='Heart Rate (bpm)')), - ('pace', models.FloatField(null=True, verbose_name='Pace (/500m)')), - ('velo', models.FloatField(default=0, null=True, verbose_name='Boat Speed (m/s)')), - ('powerhr', models.FloatField(null=True, verbose_name='Power Heart Rate Efficiency (J/beat)')), - ('spm', models.FloatField(null=True, verbose_name='Stroke Rate (spm)')), - ('driveenergy', models.FloatField(null=True, verbose_name='Work Per Stroke (J)')), - ('power', models.FloatField(null=True, verbose_name='Power (W)')), - ('averageforce', models.FloatField(null=True, verbose_name='Average Drive Force (N)')), - ('peakforce', models.FloatField(null=True, verbose_name='Peak Drive Force (N)')), - ('drivelength', models.FloatField(null=True, verbose_name='Drive Length (m)')), - ('forceratio', models.FloatField(null=True, verbose_name='Average/Peak Force Ratio')), - ('distance', models.FloatField(null=True, verbose_name='Distance (m)')), - ('cumdist', models.FloatField(null=True, verbose_name='Cumulative Distance (m)')), - ('drivespeed', models.FloatField(default=0, null=True, verbose_name='Drive Speed (m/s)')), - ('catch', models.FloatField(default=0, null=True, verbose_name='Catch Angle (degrees)')), - ('slip', models.FloatField(default=0, null=True, verbose_name='Slip (degrees)')), - ('finish', models.FloatField(default=0, null=True, verbose_name='Finish Angle (degrees)')), - ('wash', models.FloatField(default=0, null=True, verbose_name='Wash (degrees)')), - ('peakforceangle', models.FloatField(default=0, null=True, verbose_name='Peak Force Angle')), - ('totalangle', models.FloatField(default=0, null=True, verbose_name='Drive Length (deg)')), - ('effectiveangle', models.FloatField(default=0, null=True, verbose_name='Effective Drive Length (deg)')), - ('rhythm', models.FloatField(default=1.0, null=True, verbose_name='Stroke Rhythm')), - ('efficiency', models.FloatField(default=0, null=True, verbose_name='OTW Efficiency (%)')), - ('distanceperstroke', models.FloatField(default=0, null=True, verbose_name='Distance per Stroke (m)')), + ('name', models.CharField(max_length=150)), + ('notes', models.CharField(blank=True, max_length=1000, null=True)), + ('manager', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], - options={ - 'db_table': 'strokedata', - }, ), migrations.CreateModel( name='Team', @@ -527,6 +557,7 @@ class Migration(migrations.Migration): ('name', models.CharField(blank=True, max_length=150)), ('status', models.BooleanField(default=True, verbose_name='Active')), ('startdate', models.DateField(default=rowers.models.current_day)), + ('notes', models.CharField(blank=True, max_length=200, null=True, verbose_name='Plan Notes')), ('enddate', models.DateField(default=rowers.models.half_year_from_now)), ('manager', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='planmanager', to='rowers.Rower')), ('rowers', models.ManyToManyField(related_name='planathletes', to='rowers.Rower', verbose_name='Athletes')), @@ -543,6 +574,16 @@ class Migration(migrations.Migration): ('rowers', models.ManyToManyField(related_name='targetathletes', to='rowers.Rower', verbose_name='Athletes')), ], ), + migrations.CreateModel( + name='VideoAnalysis', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, default='', max_length=150, null=True)), + ('video_id', models.CharField(default='', max_length=150)), + ('delay', models.IntegerField(default=0)), + ('metricsgroups', rowers.models.TemplateListField(default=['basic'])), + ], + ), migrations.CreateModel( name='VirtualRaceResult', fields=[ @@ -551,16 +592,22 @@ class Migration(migrations.Migration): ('teamname', models.CharField(blank=True, max_length=80, null=True, verbose_name='Team Name')), ('username', models.CharField(max_length=150)), ('workoutid', models.IntegerField(null=True)), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), - ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Class')), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), + ('adaptiveclass', models.CharField(choices=[('None', 'Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Class')), + ('skillclass', models.CharField(default='Open', max_length=50, verbose_name='Skill Class')), ('duration', models.TimeField(default=datetime.time(1, 0))), ('distance', models.IntegerField(default=0)), + ('points', models.IntegerField(default=0)), ('boatclass', models.CharField(choices=[('water', 'Standard Racing Shell'), ('coastal', 'Coastal'), ('c-boat', 'Dutch C boat'), ('churchboat', 'Finnish Church boat')], default='water', max_length=40, verbose_name='Boat Class')), ('boattype', models.CharField(choices=[('1x', '1x (single)'), ('2x', '2x (double)'), ('2x+', '2x+ (coxed double)'), ('2-', '2- (pair)'), ('2+', '2+ (coxed pair)'), ('3x+', '3x+ (coxed triple)'), ('3x-', '3x- (triple)'), ('4x', '4x (quad)'), ('4x+', '4x+ (coxed quad)'), ('4-', '4- (four)'), ('4+', '4+ (coxed four)'), ('8+', '8+ (eight)'), ('8x+', '8x+ (octuple scull)')], default='1x', max_length=40, verbose_name='Boat Type')), ('coursecompleted', models.BooleanField(default=False)), ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female'), ('not specified', 'not specified')], default='not specified', max_length=30, verbose_name='Gender')), ('age', models.IntegerField(null=True)), - ('emailnotifications', models.BooleanField(default=True, verbose_name='Receive race notifications by email')), + ('emailnotifications', models.BooleanField(default=True, verbose_name='Receive challenge notifications by email')), + ('startsecond', models.FloatField(default=0)), + ('endsecond', models.FloatField(default=0)), + ('referencespeed', models.FloatField(default=5.0)), + ('entrycategory', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='rowers.CourseStandard', verbose_name='Group')), ], ), migrations.CreateModel( @@ -572,8 +619,8 @@ class Migration(migrations.Migration): ('workouttype', models.CharField(choices=[('water', 'Standard Racing Shell'), ('rower', 'Indoor Rower'), ('skierg', 'Ski Erg'), ('bikeerg', 'Bike Erg'), ('dynamic', 'Dynamic Indoor Rower'), ('slides', 'Indoor Rower on Slides'), ('paddle', 'Paddle Adapter'), ('snow', 'On-snow'), ('coastal', 'Coastal'), ('c-boat', 'Dutch C boat'), ('churchboat', 'Finnish Church boat'), ('Ride', 'Ride'), ('Bike', 'Bike'), ('Run', 'Run'), ('NordicSki', 'NordicSki'), ('Swim', 'Swim'), ('Hike', 'Hike'), ('Walk', 'Walk'), ('Canoeing', 'Canoeing'), ('Crossfit', 'Crossfit'), ('StandUpPaddling', 'StandUpPaddling'), ('IceSkate', 'IceSkate'), ('WeightTraining', 'WeightTraining'), ('InlineSkate', 'InlineSkate'), ('Kayaking', 'Kayaking'), ('Workout', 'Workout'), ('Yoga', 'Yoga'), ('other', 'Other')], max_length=50, verbose_name='Exercise/Boat Class')), ('workoutsource', models.CharField(default='unknown', max_length=100)), ('boattype', models.CharField(choices=[('1x', '1x (single)'), ('2x', '2x (double)'), ('2x+', '2x+ (coxed double)'), ('2-', '2- (pair)'), ('2+', '2+ (coxed pair)'), ('3x+', '3x+ (coxed triple)'), ('3x-', '3x- (triple)'), ('4x', '4x (quad)'), ('4x+', '4x+ (coxed quad)'), ('4-', '4- (four)'), ('4+', '4+ (coxed four)'), ('8+', '8+ (eight)'), ('8x+', '8x+ (octuple scull)')], default='1x', max_length=50, verbose_name='Boat Type')), - ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Classification')), - ('starttime', models.TimeField(blank=True, null=True)), + ('adaptiveclass', models.CharField(choices=[('None', 'Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Classification')), + ('starttime', models.TimeField(default=datetime.time(12, 0))), ('startdatetime', models.DateTimeField(blank=True, null=True)), ('timezone', models.CharField(default='UTC', max_length=100)), ('distance', models.IntegerField(blank=True, default=0)), @@ -585,7 +632,7 @@ class Migration(migrations.Migration): ('normp', models.IntegerField(blank=True, default=-1)), ('normv', models.FloatField(blank=True, default=-1)), ('normw', models.FloatField(blank=True, default=-1)), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), ('weightvalue', models.FloatField(blank=True, default=80.0, verbose_name='Average Crew Weight (kg)')), ('csvfilename', models.CharField(blank=True, max_length=150)), ('uploadedtoc2', models.IntegerField(default=0)), @@ -604,6 +651,7 @@ class Migration(migrations.Migration): ('privacy', models.CharField(choices=[('private', 'Private'), ('visible', 'Visible')], default='visible', max_length=30)), ('rankingpiece', models.BooleanField(default=False, verbose_name='Ranking Piece')), ('duplicate', models.BooleanField(default=False, verbose_name='Duplicate Workout')), + ('impeller', models.BooleanField(default=False, verbose_name='Impeller')), ], ), migrations.CreateModel( @@ -622,15 +670,16 @@ class Migration(migrations.Migration): name='VirtualRace', fields=[ ('plannedsession_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='rowers.PlannedSession')), - ('registration_form', models.CharField(choices=[('windowstart', 'Start of Race Window'), ('windowend', 'End of Race Window'), ('deadline', 'Evaluation Closure Deadline'), ('manual', 'Manual - select below')], default='windowstart', max_length=100, verbose_name='Registration Closure Quick Selector')), + ('registration_form', models.CharField(choices=[('windowstart', 'Start of challenge Window'), ('windowend', 'End of challenge Window'), ('deadline', 'Evaluation Closure Deadline'), ('manual', 'Manual - select below')], default='windowstart', max_length=100, verbose_name='Registration Closure Quick Selector')), ('registration_closure', models.DateTimeField(blank=True, null=True)), ('evaluation_closure', models.DateTimeField(blank=True, null=True)), ('start_time', models.TimeField(blank=True, null=True)), ('end_time', models.TimeField(blank=True, null=True)), ('country', models.CharField(blank=True, max_length=100)), - ('timezone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', max_length=100)), + ('timezone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Nuuk', 'America/Nuuk'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', max_length=100)), ('contact_phone', models.CharField(blank=True, max_length=17, validators=[django.core.validators.RegexValidator(message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.", regex='^\\+?1?\\d{9,15}$')])), ('contact_email', models.EmailField(blank=True, max_length=254, validators=[django.core.validators.EmailValidator()])), + ('coursestandards', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='rowers.StandardCollection', verbose_name='Standard Times')), ], bases=('rowers.plannedsession',), ), @@ -649,6 +698,11 @@ class Migration(migrations.Migration): name='user', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.Rower'), ), + migrations.AddField( + model_name='videoanalysis', + name='workout', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.Workout'), + ), migrations.AddField( model_name='trainingplan', name='target', @@ -659,14 +713,10 @@ class Migration(migrations.Migration): name='plan', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.TrainingPlan'), ), - migrations.AlterIndexTogether( - name='strokedata', - index_together={('workoutid',)}, - ), migrations.AddField( model_name='rower', name='team', - field=models.ManyToManyField(blank=True, to='rowers.Team'), + field=models.ManyToManyField(blank=True, related_name='rower', to='rowers.Team'), ), migrations.AddField( model_name='rower', @@ -740,6 +790,11 @@ class Migration(migrations.Migration): name='plannedsession', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.PlannedSession'), ), + migrations.AddField( + model_name='coursestandard', + name='standardcollection', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.StandardCollection'), + ), migrations.AddField( model_name='coachrequest', name='coach', @@ -764,11 +819,35 @@ class Migration(migrations.Migration): name='c2worldclassageperformance', unique_together={('age', 'sex', 'weightcategory', 'distance')}, ), + migrations.AddField( + model_name='alert', + name='filter', + field=models.ManyToManyField(related_name='filters', to='rowers.Condition', verbose_name='Filters'), + ), + migrations.AddField( + model_name='alert', + name='manager', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='alert', + name='measured', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='measured', to='rowers.Condition', verbose_name='Measuring'), + ), + migrations.AddField( + model_name='alert', + name='rower', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.Rower'), + ), migrations.AddField( model_name='virtualraceresult', name='race', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.VirtualRace'), ), + migrations.AlterUniqueTogether( + name='videoanalysis', + unique_together={('video_id', 'workout')}, + ), migrations.AddField( model_name='racelogo', name='race', @@ -779,4 +858,8 @@ class Migration(migrations.Migration): name='race', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.VirtualRace'), ), + migrations.AlterUniqueTogether( + name='coursestandard', + unique_together={('name', 'standardcollection')}, + ), ] diff --git a/rowers/models.py b/rowers/models.py index f0659bf1..9f0e8d46 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -243,15 +243,9 @@ def update_records(url=c2url,verbose=True): class CalcAgePerformance(models.Model): - weightcategories = ( - ('hwt','heavy-weight'), - ('lwt','light-weight'), - ) + weightcategories = mytypes.weightcategories - sexcategories = ( - ('male','male'), - ('female','female'), - ) + sexcategories = mytypes.sexcategories weightcategory = models.CharField(default="hwt", max_length=30, @@ -288,10 +282,7 @@ class PowerTimeFitnessMetric(models.Model): @python_2_unicode_compatible class C2WorldClassAgePerformance(models.Model): - weightcategories = ( - ('hwt','heavy-weight'), - ('lwt','light-weight'), - ) + weightcategories = mytypes.weightcategories sexcategories = ( ('male','male'), @@ -593,10 +584,8 @@ sexcategories = ( ('female','female'), ('not specified','not specified'), ) -weightcategories = ( - ('hwt','heavy-weight'), - ('lwt','light-weight'), -) + +weightcategories = mytypes.weightcategories # Plan @@ -2194,7 +2183,38 @@ class PlannedSession(models.Model): from django.core.validators import RegexValidator,validate_email +class StandardCollection(models.Model): + name = models.CharField(max_length=150) + manager = models.ForeignKey(User, null=True,on_delete=models.CASCADE) + notes = models.CharField(blank=True,null=True,max_length=1000) + active = models.BooleanField(default=True) + def __str__(self): + return self.name + +class CourseStandard(models.Model): + name = models.CharField(max_length=150) + coursedistance = models.IntegerField() + coursetime = models.CharField(max_length=100,default="") + referencespeed = models.FloatField() # average boat speed + agemin = models.IntegerField(default=0) + agemax = models.IntegerField(default=120) + boatclass = models.CharField(max_length=150) # corresponds to workout workouttype + boattype = models.CharField(choices=mytypes.boattypes,max_length=50,default='1x') + sex = models.CharField(max_length=150) + weightclass = models.CharField(max_length=150) + adaptiveclass = models.CharField(choices=mytypes.adaptivetypes,max_length=50,default="None") + skillclass = models.CharField(max_length=150) + standardcollection = models.ForeignKey(StandardCollection,on_delete=models.CASCADE) + + class Meta: + unique_together = ( + ('name','standardcollection') + ) + + + def __str__(self): + return self.name registerchoices = ( ('windowstart','Start of challenge Window'), @@ -2233,6 +2253,9 @@ class VirtualRace(PlannedSession): contact_email = models.EmailField(max_length=254, validators=[validate_email],blank=True) + coursestandards = models.ForeignKey(StandardCollection,null=True,on_delete=models.SET_NULL, + verbose_name='Standard Times',blank=True) + def __str__(self): name = self.name @@ -2401,6 +2424,7 @@ class IndoorVirtualRaceForm(ModelForm): 'registration_closure', 'evaluation_closure', 'comment', + 'coursestandards', 'contact_phone', 'contact_email', ] @@ -2434,6 +2458,7 @@ class IndoorVirtualRaceForm(ModelForm): self.fields['sessionunit'].initial = 'm' if timezone: self.fields['timezone'].initial = timezone + self.fields['coursestandards'].queryset = StandardCollection.objects.filter(active=True) def clean(self): cd = self.cleaned_data @@ -2537,6 +2562,7 @@ class VirtualRaceForm(ModelForm): 'registration_closure', 'evaluation_closure', 'course', + 'coursestandards', 'comment', 'contact_phone', 'contact_email', @@ -2560,6 +2586,7 @@ class VirtualRaceForm(ModelForm): def __init__(self,*args,**kwargs): super(VirtualRaceForm, self).__init__(*args, **kwargs) self.fields['course'].queryset = GeoCourse.objects.all().order_by("country","name") + self.fields['coursestandards'].queryset = StandardCollection.objects.filter(active=True) def clean(self): @@ -2905,9 +2932,12 @@ class VirtualRaceResult(models.Model): adaptiveclass = models.CharField(default="None",max_length=50, choices=mytypes.adaptivetypes, verbose_name="Adaptive Class") + skillclass = models.CharField(default="Open",max_length=50, + verbose_name="Skill Class") race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) + points = models.IntegerField(default=0) boatclass = models.CharField(choices=boatclasses, max_length=40, default='water', @@ -2928,6 +2958,9 @@ class VirtualRaceResult(models.Model): startsecond = models.FloatField(default=0) endsecond = models.FloatField(default=0) + referencespeed = models.FloatField(default=5.0) + entrycategory = models.ForeignKey(CourseStandard,null=True,on_delete=models.SET_NULL, + verbose_name='Group') def __str__(self): rr = Rower.objects.get(id=self.userid) @@ -2936,6 +2969,14 @@ class VirtualRaceResult(models.Model): u2 = rr.user.last_name, ) if self.teamname: + if self.entrycategory: + return u'Entry for {n} for "{r}" in {g} with {t}'.format( + n = name, + r = self.race, + g = self.entrycategory, + t = self.teamname, + ) + return u'Entry for {n} for "{r}" in {c} {d} with {t} ({s})'.format( n = name, r = self.race, @@ -2945,6 +2986,12 @@ class VirtualRaceResult(models.Model): s = self.sex, ) else: + if self.entrycategory: + return u'Entry for {n} for "{r}" in {g}'.format( + n = name, + r = self.race, + g = self.entrycategory, + ) return u'Entry for {n} for "{r}" in {c} {d} ({s})'.format( n = name, r = self.race, @@ -2968,9 +3015,13 @@ class IndoorVirtualRaceResult(models.Model): adaptiveclass = models.CharField(default="None",max_length=50, choices=mytypes.adaptivetypes, verbose_name="Adaptive Class") + skillclass = models.CharField(default="Open",max_length=50, + verbose_name="Skill Class") race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) + referencespeed = models.FloatField(default=5.0) + points = models.IntegerField(default=0) boatclass = models.CharField(choices=boatclasses, max_length=40, default='rower', @@ -2984,6 +3035,8 @@ class IndoorVirtualRaceResult(models.Model): age = models.IntegerField(null=True) emailnotifications = models.BooleanField(default=True, verbose_name = 'Receive challenge notifications by email') + entrycategory = models.ForeignKey(CourseStandard,null=True,on_delete=models.SET_NULL, + verbose_name='Group') def __str__(self): rr = Rower.objects.get(id=self.userid) @@ -2992,6 +3045,13 @@ class IndoorVirtualRaceResult(models.Model): u2 = rr.user.last_name, ) if self.teamname: + if self.entrycategory: + return u'Entry for {n} for "{r}" in {g} with {t}'.format( + n = name, + r = self.race, + g = self.entrycategory, + t = self.teamname, + ) return u'Entry for {n} for "{r}" on {c} with {t} ({s})'.format( n = name, r = self.race, @@ -3000,6 +3060,12 @@ class IndoorVirtualRaceResult(models.Model): s = self.sex, ) else: + if self.entrycategory: + return u'Entry for {n} for "{r}" in {g}'.format( + n = name, + r = self.race, + g = self.entrycategory, + ) return u'Entry for {n} for "{r}" on {c} ({s})'.format( n = name, r = self.race, @@ -3019,22 +3085,29 @@ class CourseTestResult(models.Model): class IndoorVirtualRaceResultForm(ModelForm): class Meta: model = IndoorVirtualRaceResult - fields = ['teamname','weightcategory','boatclass','age','adaptiveclass'] + fields = ['teamname','weightcategory','boatclass','age','adaptiveclass', + 'entrycategory'] def __init__(self, *args, **kwargs): + categories = kwargs.pop('categories',None) super(IndoorVirtualRaceResultForm, self).__init__(*args, **kwargs) - + if categories is not None: + self.fields['entrycategory'].queryset = categories + self.fields['entrycategory'].empty_label = None + else: + self.fields.pop('entrycategory') class VirtualRaceResultForm(ModelForm): class Meta: model = VirtualRaceResult fields = ['teamname','weightcategory','boatclass','boattype', - 'age','adaptiveclass'] + 'age','adaptiveclass','entrycategory'] def __init__(self, *args, **kwargs): boattypes = kwargs.pop('boattypes',None) + categories = kwargs.pop('categories',None) super(VirtualRaceResultForm, self).__init__(*args, **kwargs) if boattypes: @@ -3044,6 +3117,12 @@ class VirtualRaceResultForm(ModelForm): required=False, label='Mixed Gender') + if categories is not None: + self.fields['entrycategory'].queryset = categories + self.fields['entrycategory'].empty_label = None + else: + self.fields.pop('entrycategory') + from rowers.metrics import rowingmetrics strokedatafields = { diff --git a/rowers/mytypes.py b/rowers/mytypes.py index c70ffbcc..294cb8bb 100644 --- a/rowers/mytypes.py +++ b/rowers/mytypes.py @@ -316,13 +316,23 @@ boattypes = ( ) adaptivetypes = ( - ('None','None'), + ('None','Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)'), ) +weightcategories = ( + ('hwt','open-weight'), + ('lwt','light-weight'), + ) + +sexcategories = ( + ('male','Open'), + ('female','Female'), + ) + waterboattype = [i[0] for i in boattypes] privacychoices = ( diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 4c859b65..f703e206 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -1514,6 +1514,7 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0): return 0,comments,errors,0 if ws[0].workouttype != record.boatclass: + print(ws[0].workouttype,record.boatclass) errors.append('Your workout boat class is different than on your race registration') return 0,comments,errors,0 @@ -1551,7 +1552,8 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0): comments.append('Workouts submitted to virtual events have to be public. We have changed the workout to a public workout.') job = myqueue(queue,handle_check_race_course,ws[0].csvfilename, - ws[0].id,race.course.id,record.id,splitsecond=splitsecond) + ws[0].id,race.course.id,record.id,splitsecond=splitsecond, + referencespeed=record.referencespeed,coursedistance=race.course.distance) diff --git a/rowers/scoring.py b/rowers/scoring.py new file mode 100644 index 00000000..8e24257b --- /dev/null +++ b/rowers/scoring.py @@ -0,0 +1,177 @@ +from rowers.models import StandardCollection,CourseStandard, VirtualRaceResult,IndoorVirtualRaceResult + +import pandas as pd +import arrow +import datetime + +def save_scoring(name,user,filename,id=0,notes=""): + if id==0: + collection = StandardCollection(name=name,manager=user,notes=notes) + collection.save() + standards = CourseStandard.objects.filter(standardcollection=collection) + for standard in standards: + standards.delete() + + else: + try: + collection = StandardCollection.objects.get(id=id) + collection.name = name + collection.notes = notes + collection.save() + standards = CourseStandard.objects.filter(standardcollection=collection) + for standard in standards: + records1 = VirtualRaceResult.objects.filter(entrycategory=standard) + records2 = IndoorVirtualRaceResult.objects.filter(entrycategory=standard) + if records1.count()+records2.count() == 0: + standard.delete() + + + except StandardCollection.DoesNotExist: + return 0 + + try: + df = pd.read_csv(filename) + except: + return 0 + + df.rename( + columns={ + 'name':'Name', + 'agemax':'MaxAge', + 'agemin':'MinAge', + 'adaptiveclass':'AdaptiveClass', + 'coursedistance':'CourseDistance', + 'coursetime':'CourseStandard', + 'boatclass':'BoatClass', + 'boattype':'BoatType', + 'sex':'Gender', + 'weightclass':'WeightClass', + 'skillclass':'SkillClass', + }, + inplace=True) + + df = df.drop_duplicates(['Name']) + + for index, row in df.iterrows(): + try: + name = row['Name'] + except KeyError: + continue + + try: + coursedistance = row['CourseDistance'] + coursetime = row['CourseStandard'] + t = datetime.datetime.strptime(coursetime,'%M:%S.%f') + delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second,microseconds=t.microsecond) + seconds = delta.total_seconds() + + referencespeed = coursedistance/seconds + except KeyError: + continue + + try: + agemin = row['MinAge'] + agemax = row['MaxAge'] + agemin = int(agemin) + agemax = int(agemax) + except KeyError: + agemin = 0 + agemax = 120 + + try: + boatclass = row['BoatClass'] + if boatclass.lower() in ['standard','olympic','normal','water']: + boatclass = 'water' + elif boatclass.lower() in ['erg','c2','concept','static','rower']: + boatclass = 'rower' + elif boatclass.lower() in ['dynamic']: + boatclass = 'dynamic' + elif boatclass.lower() in ['slides','slide','slider','sliders']: + boatclass = 'slides' + elif boatclass.lower() in ['c','c-boat']: + boatclass = 'c-boat' + elif boatclass.lower() in ['coastal','coast']: + boatclass = 'coastal' + elif boatclass.lower() in ['church','churchboat','finnish','finland']: + boatclass = 'churchboat' + except KeyError: + boatclass = 'water' + + try: + boattype = row['BoatType'] + except KeyError: + boattype = '1x' + + try: + sex = row['Gender'] + if sex.lower() in ['m','men','male','open']: + sex = 'male' + elif sex.lower() in ['mix','mixed']: + sex = 'mixed' + else: + sex = 'female' + except KeyError: + sex = 'female' + + try: + weightclass = row['WeightClass'] + if weightclass.lower() in ['hwt','h','o','heavy','open']: + weightclass = 'hwt' + elif weightclass.lower() in ['lwt','l','light','lights','lighties']: + weightclass = 'lwt' + except KeyError: + weightclass = 'hwt' + + adaptiveclass = 'None' + try: + adaptiveclass = row['AdaptiveClass'] + if adaptiveclass.lower() in ['o','open','none','no']: + adaptiveclass = 'None' + except KeyError: + adaptiveclass = 'None' + + try: + skillclass = row['SkillClass'] + except KeyError: + skillclass = 'Open' + + # finding existing standard + existingstandards = CourseStandard.objects.filter(name=name,standardcollection=collection) + #print(existingstandards,collection) + if existingstandards: + existingstandards.update( + name=name, + coursedistance=coursedistance, + referencespeed=referencespeed, + coursetime=coursetime, + agemin=agemin, + agemax=agemax, + boatclass=boatclass, + boattype=boattype, + sex=sex, + weightclass=weightclass, + adaptiveclass=adaptiveclass, + skillclass=skillclass, + standardcollection = collection, + ) + else: + #print('not') + standard = CourseStandard( + name=name, + coursedistance=coursedistance, + referencespeed=referencespeed, + coursetime=coursetime, + agemin=agemin, + agemax=agemax, + boatclass=boatclass, + boattype=boattype, + sex=sex, + weightclass=weightclass, + adaptiveclass=adaptiveclass, + skillclass=skillclass, + standardcollection = collection, + ) + + standard.save() + + return collection.id diff --git a/rowers/tasks.py b/rowers/tasks.py index 71eca7bb..f2408632 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -353,6 +353,16 @@ def handle_check_race_course(self, else: splitsecond = 0 + if 'referencespeed' in kwargs: + referencespeed = kwargs['referencespeed'] + else: + referencespeed = 5.0 + + if 'coursedistance' in kwargs: + coursedistance = kwargs['coursedistance'] + else: + coursedistance = 0 + mode = 'race' if 'mode' in kwargs: mode = kwargs['mode'] @@ -479,22 +489,28 @@ def handle_check_race_course(self, else: coursecompleted = False - + points = 0 if coursecompleted: - query = 'UPDATE rowers_virtualraceresult SET coursecompleted = 1, duration = "{duration}", distance = {distance}, workoutid = {workoutid}, startsecond = {startsecond}, endsecond = {endsecond} WHERE id={recordid}'.format( + if coursedistance == 0: + coursedistance = coursemeters + velo = coursedistance/coursetimeseconds + points = int(100*(2.-referencespeed/velo)) + query = 'UPDATE rowers_virtualraceresult SET coursecompleted = 1, duration = "{duration}", distance = {distance}, workoutid = {workoutid}, startsecond = {startsecond}, endsecond = {endsecond}, points={points} WHERE id={recordid}'.format( recordid=recordid, duration=totaltime_sec_to_string(coursetimeseconds), distance=int(coursemeters), + points=points, workoutid=workoutid, startsecond=startsecond, endsecond=endsecond, ) if mode == 'coursetest': - query = 'UPDATE rowers_coursetestresult SET coursecompleted = 1, duration = "{duration}", distance = {distance}, workoutid = {workoutid}, startsecond = {startsecond}, endsecond = {endsecond} WHERE id={recordid}'.format( + query = 'UPDATE rowers_coursetestresult SET coursecompleted = 1, duration = "{duration}", distance = {distance}, workoutid = {workoutid}, startsecond = {startsecond}, endsecond = {endsecond}, points={points} WHERE id={recordid}'.format( recordid=recordid, duration=totaltime_sec_to_string(coursetimeseconds), distance=int(coursemeters), + points=points, workoutid=workoutid, startsecond=startsecond, endsecond=endsecond, diff --git a/rowers/templates/course_form.html b/rowers/templates/course_form.html index fe6e1962..5a346104 100644 --- a/rowers/templates/course_form.html +++ b/rowers/templates/course_form.html @@ -30,7 +30,7 @@ Please correct the error{{ form.errors|pluralize }} below.

{% endif %} - + {{ form.as_table }}
@@ -71,13 +71,13 @@ if (!formdatasetok) { $("#id_dropregion").remove(); } - + if (formdatasetok) { - + $(document).ready(function() { var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); console.log("CSRF token",csrftoken); - + function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); @@ -95,11 +95,11 @@ $(window).on('dragenter', function() { $("#id_drop-files").css("background-color","#E9E9E4"); $("#id_dropregion").addClass("watermark").removeClass("invisible");}) - + $(window).on('dragleave', function() { $("#id_drop-files").css("background-color","#FFFFFF"); $("#id_dropregion").removeClass("watermark").addClass("invisible");}) - + var frm = $("#file_form"); if( window.FormData === undefined ) { @@ -108,7 +108,7 @@ } else { console.log('we have formdata'); } - + var data = new FormData(frm[0]); @@ -144,7 +144,7 @@ } } -}); +}); $('input').each(function( i ) { $(this).change(function() { @@ -159,7 +159,14 @@ console.log($(this).attr('name'),$(this).val()); }; });}); - + + $('textarea').each(function( i ) { + $(this).change(function() { + data.set($(this).attr('name'),$(this).val()); + console.log($(this).attr('name'),$(this).val()); + }); + }); + $('select').each(function( i ) { console.log($(this).attr('name'),$(this).val()); $(this).change(function() { @@ -200,7 +207,7 @@ console.log(result," reloading"); location.reload(); }; - } + } }); return false; }); @@ -236,7 +243,7 @@ $("#id_file").value = 0; return false; } - data.set("file",f); + data.set("file",f); // data.append("file",f); $("#id_file").replaceWith('
'+files[0].name+'  X
'); diff --git a/rowers/templates/indoorvirtualeventcreate.html b/rowers/templates/indoorvirtualeventcreate.html index 2fcc477b..8ec29004 100644 --- a/rowers/templates/indoorvirtualeventcreate.html +++ b/rowers/templates/indoorvirtualeventcreate.html @@ -55,6 +55,15 @@ If you require a screenshot of the PM monitor, do mention this in the comment.

+

+ Standard Times are a way to compare results in a race category with + a course record or golden standard for that event. A point score is calculated + which compares the participant's result with the standard. This offers an + engaging way to compete on points across different categories, boat types, and skill + levels. + If you select a Standard Times set from the drop-down list, race categories will + be limited to those in the selected set of Standard Times. +

diff --git a/rowers/templates/list_standards.html b/rowers/templates/list_standards.html new file mode 100644 index 00000000..b99ac07f --- /dev/null +++ b/rowers/templates/list_standards.html @@ -0,0 +1,84 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Rowsandall Course Standards List{% endblock %} + +{% block scripts %} + +{% endblock %} + +{% block main %} + + + + +

Standards Collections

+ +
    +
  • + {% if standards %} +

    + + + + + + + + + {% for standard in standards %} + + + + + + + + {% endfor %} + +
    Name Maintainer
    {{ standard.name }} {{ standard.manager.first_name }} {{ standard.manager.last_name }} + {% if standard.manager == user %} + {{ standard.name }} + {% else %} + {{ standard.name }} + {% endif %} +
    +

    + {% else %} +

    No standards found

    + {% endif %} +
  • +
  • +

    +

    + {{ searchform }} + +
    +

    +

    + Add Standards +

    + +
  • + +
  • +

    How-to

    +

    + A set of Course Standard Times allows you to calculate a score for + each participant on how well they have done against the course + standard time for their category. This allows for comparison + and competition between the different categories. +

    +
  • +
+ {% endblock %} + +{% block sidebar %} +{% include 'menu_racing.html' %} +{% endblock %} diff --git a/rowers/templates/menu_racing.html b/rowers/templates/menu_racing.html index c1eb9178..8dd74087 100644 --- a/rowers/templates/menu_racing.html +++ b/rowers/templates/menu_racing.html @@ -55,12 +55,14 @@  Upload your Challenge result + {% if race.sessiontype != 'race' %}
  • - +  Enter Result
  • {% endif %} + {% endif %} {% if button == 'resubmitbutton' %}
  • Submit New Result @@ -131,6 +133,11 @@
  • {% endif %} +
  • + +  Course Time Standards + +
  • {% include 'menuscript.html' %} diff --git a/rowers/templates/standard_form.html b/rowers/templates/standard_form.html new file mode 100644 index 00000000..282ba443 --- /dev/null +++ b/rowers/templates/standard_form.html @@ -0,0 +1,276 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}File loading{% endblock %} + +{% block meta %} + + + +{% endblock %} + +{% block main %} +

    Upload Course Standard Times File

    + +
      +
    • +
      +

      Drag and drop files here. +

      +

      + If you're updating an existing set of standard times, + existing groups with challenge entries will be updated. New + groups will be created. All groups with challenge entries will + remain, even if you delete them from the CSV file. So, it + is not possible to remove groups if there have been starts in this group.

      +

      + If you want to still remove those groups, it is better to set the + existing set of standard times to inactive and upload a new one. +

      +
      +
      +
      + {% if form.errors %} +

      + Please correct the error{{ form.errors|pluralize }} below. +

      + {% endif %} + + + {{ form.as_table }} +
      + {% csrf_token %} +

      + +

      +
      +
      +
    • +
    + + + + +{% endblock %} + +{% block sidebar %} +{% include 'menu_racing.html' %} +{% endblock %} + + +{% block scripts %} + + + + {% endblock %} diff --git a/rowers/templates/standard_view.html b/rowers/templates/standard_view.html new file mode 100644 index 00000000..222282e5 --- /dev/null +++ b/rowers/templates/standard_view.html @@ -0,0 +1,79 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} +{% load leaflet_tags %} + +{% block meta %} +{% leaflet_js %} +{% leaflet_css %} +{% endblock %} + +{% block scripts %} +{% include "monitorjobs.html" %} +{% endblock %} + +{% block title %}{{ standard.name }} {% endblock %} +{% block og_title %}{{ standard.name }} {% endblock %} +{% block main %} + +

    {{ standard.name }}

    + +
      +
    • + + + + + + + + + + +
      Name{{ collection.name }}
      Manager{{ collection.manager.first_name }} {{ collection.manager.last_name }}
      Notes{{ collection.notes|linebreaks }}
      +
    • +
    • + {% if request.user == collection.manager %} +

      Update these Standard Times

      +

      Deactivate this standard

      + {% endif %} +

      Download as CSV file

      +
    • +
    • +

      Standard Times

      + + + + + + + + + + + + + {% for standard in standards %} + + + + + + + + + + + + + {% endfor %} +
      NameDistanceStandard TimeBoat ClassBoat TypeGenderWeight ClassAdaptive ClassSkill ClassMinimum/Maximum Age
      {{ standard.name }}{{ standard.coursedistance }}{{ standard.coursetime }}{{ standard.boatclass|boatclass }}{{ standard.boattype }}{{ standard.sex|sex }}{{ standard.weightclass|weight }}{{ standard.adaptiveclass|adaptive }}{{ standard.skillclass }}{{ standard.agemin }}/{{ standard.agemax }}
      +
    • +
    + +{% endblock %} + +{% block sidebar %} +{% include 'menu_racing.html' %} +{% endblock %} diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index b3e1ff57..3e2297ce 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -104,6 +104,11 @@ Challenge Time Zone{{ race.timezone }} {% endif %} + {% if race.coursestandards %} + + Standard Times{{ race.coursestandards }} + + {% endif %} {{ race.sessionmode }} challenge @@ -263,7 +268,9 @@   Name Team Name -   + {% if race.coursestandards %} + Group + {% else %}       @@ -271,8 +278,12 @@ {% if race.sessiontype == 'race' %} Boat {% endif %} - Time - Distance + {% endif %} + Time▼ + Distance▼ + {% if race.coursestandards %} + Points + {% endif %} Details   @@ -285,6 +296,9 @@ {{ result.username }} {{ result.teamname }} + {% if race.coursestandards %} + {{ result.entrycategory }} + {% else %} {{ result.age }} {{ result.sex }} {{ result.weightcategory }} @@ -299,11 +313,17 @@ {% if race.sessiontype == 'race' %} {{ result.boattype }} {% endif %} + {% endif %} {{ result.duration |durationprint:"%H:%M:%S.%f" }} {{ result.distance }} m + {% if race.coursestandards %} + {{ result.points }} + {% endif %} - Details + Details + + {% if race.manager == request.user and not race|is_final %} @@ -389,22 +409,29 @@ Name Team Name - {% if race.sessiontype == 'race' %} - Class - Boat + {% if race.coursestandards %} + Group + Age {% else %} - Class + {% if race.sessiontype == 'race' %} + Boat {% endif %} + Class Age Gender Weight Category Adaptive + {% endif %} {% for record in records %} {{ record.username }} {{ record.teamname }} + {% if race.coursestandards %} + {{ record.entrycategory }} + {{ record.age }} + {% else %} {{ record.boatclass }} {% if race.sessiontype == 'race' %} {{ record.boattype }} @@ -419,6 +446,7 @@ {{ record.adaptiveclass }} {% endif %} + {% endif %} {% if record.userid == rower.id and 'withdrawbutton' in buttons %} Withdraw @@ -431,7 +459,7 @@ {% endif %} {% for record in records %} - {% if record.userid == request.user.rower.id %} + {% if record.userid == request.user.rower.id and forloop.counter == 1 %} {% if race.sessiontype == 'race' %} {% if record.emailnotifications %} @@ -541,6 +569,17 @@ review and reject entries. If you are disqualified in this way, you will receive an email with the reason.

    + {% if race.coursestandards %} +

    + Standard Times are a way to compare results in a race category with + a course record or golden standard for that event. A point score is calculated + which compares the participant's result with the standard. This offers an + engaging way to compete on points across different categories, boat types, and skill + levels. + If you select a Standard Times set from the drop-down list, race categories will + be limited to those in the selected set of Standard Times. +

    + {% endif %} diff --git a/rowers/templates/virtualeventcreate.html b/rowers/templates/virtualeventcreate.html index c26e54c2..6bd65d53 100644 --- a/rowers/templates/virtualeventcreate.html +++ b/rowers/templates/virtualeventcreate.html @@ -49,6 +49,15 @@ is strongly recommended that you fill out a contact email or phone number.

    +

    + Standard Times are a way to compare results in a race category with + a course record or golden standard for that event. A point score is calculated + which compares the participant's result with the standard. This offers an + engaging way to compete on points across different categories, boat types, and skill + levels. + If you select a Standard Times set from the drop-down list, race categories will + be limited to those in the selected set of Standard Times. +

    diff --git a/rowers/templates/virtualeventregister.html b/rowers/templates/virtualeventregister.html index 5ed6c79a..6a925ac7 100644 --- a/rowers/templates/virtualeventregister.html +++ b/rowers/templates/virtualeventregister.html @@ -21,7 +21,7 @@ -

    If you are participating in a single, we will take the age and weight @@ -35,6 +35,16 @@ as a Male crew. Check the "Mixed gender" check box to register as a mixed gender crew (except for 1x where this check box does nothing).

    + {% if race.coursestandards %} +

    This race uses standard times and limits the race groups to those where + standard times exist. The "Group" form choice will overrule other selections you + make in the form (boat type, weight, etc) and your entry will be rejected + if the age and gender doesn't match. +

    +

    + You can check the valid race groups and standard times here. +

    + {% endif %}
    {{ form.as_table }} diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index 4974bce7..84b5c947 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -22,7 +22,9 @@ from rowers import c2stuff, runkeeperstuff from rowers.c2stuff import c2_open from rowers.runkeeperstuff import runkeeper_open from rowers.rower_rules import is_coach_user, is_workout_user, isplanmember,ispromember -from rowers.mytypes import otwtypes +from rowers.mytypes import ( + otwtypes,adaptivetypes,sexcategories,weightcategories,workouttypes, + ) from rowers.utils import NoTokenError import rowers.payments as payments @@ -38,6 +40,50 @@ from django.template.defaultfilters import stringfilter from six import string_types +@register.filter +def adaptive(s): + u = s + + for e,v in adaptivetypes: + if e.lower() == u.lower(): + u = v + continue + + return u + +@register.filter +def boatclass(s): + u = s + + for e,v in workouttypes: + if e.lower() == u.lower(): + u = v + continue + + return u + +@register.filter +def sex(s): + u = s + + for e,v in sexcategories: + if e.lower() == u.lower(): + u = v + continue + + return u + +@register.filter +def weight(s): + u = s + + for e,v in weightcategories: + if e.lower() == u.lower(): + u = v + continue + + return u + @register.filter def sigdig(value, digits = 3): try: diff --git a/rowers/urls.py b/rowers/urls.py index ad52fd3b..1997e73f 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -201,8 +201,11 @@ urlpatterns = [ views.virtualevent_results_download_view,name='virtualevent_results_download_view'), re_path(r'^list-workouts/$',views.workouts_view,name='workouts_view'), re_path(r'^list-courses/$',views.courses_view,name='courses_view'), + re_path(r'^list-standards/$',views.standards_view,name='standards_view'), re_path(r'^courses/upload/$',views.course_upload_view,name='course_upload_view'), - re_path(r'^workout/addmanual/(?P\d+)$',views.addmanual_view,name='addmanual_view'), + re_path(r'^standards/upload/$',views.standards_upload_view,name='standards_upload_view'), + re_path(r'^standards/upload/(?P\d+)/$',views.standards_upload_view,name='standards_upload_view'), + re_path(r'^workout/addmanual/(?P\d+)/$',views.addmanual_view,name='addmanual_view'), re_path(r'^workout/addmanual/$',views.addmanual_view,name='addmanual_view'), re_path(r'^team-compare-select/workout/(?P\d+)/team/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), # re_path(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), @@ -752,6 +755,11 @@ urlpatterns = [ re_path(r'^courses/(?P\d+)/replace/$',views.course_replace_view, name='course_replace_view'), re_path(r'^courses/(?P\d+)/$',views.course_view,name='course_view'), + re_path(r'^standards/(?P\d+)/$',views.standard_view,name='standard_view'), + re_path(r'^standards/(?P\d+)/download/$',views.standards_download_view, + name='standards_download_view'), + re_path(r'^standards/(?P\d+)/deactivate/$',views.standard_deactivate_view, + name='standard_decativate_view'), re_path(r'^courses/(?P\d+)/map/$',views.course_map_view,name='course_map_view'), # URLS to be created re_path(r'^help/$',TemplateView.as_view(template_name='help.html'), name='help'), diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 606dbdb0..44cc7cc3 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals from rowers.views.statements import * from rowsandall_app.settings import SITE_URL +from rowers.scoring import * # List Courses def courses_view(request): @@ -35,6 +36,35 @@ def courses_view(request): 'rower':r, }) +# List Courses +def standards_view(request): + r = getrower(request.user) + + standards = StandardCollection.objects.filter(active=True).order_by("name") + + # add search processing + query = request.GET.get('q') + if query: + query_list = query.split() + standards = StandardCollection.objects.filter( + reduce(operator.and_, + (Q(name__icontains=q) for q in query_list)) | + reduce(operator.and_, + (Q(notes__icontains=q) for q in query_list)) + ) + searchform = SearchForm(initial={'q':query}) + else: + searchform = SearchForm() + + + return render(request,'list_standards.html', + {'standards':standards, + 'active':'nav-racing', + 'searchform':searchform, + 'rower':r, + }) + + # for ajax calls def course_map_view(request,id=0): @@ -249,6 +279,50 @@ def course_view(request,id=0): } ) +def standard_view(request,id=0): + try: + collection = StandardCollection.objects.get(id=id) + except StandardCollection.DoesNotExist: + return Http404("Standard Collection does not exist") + + r = getrower(request.user) + + orderby = request.GET.get('order_by') + + if orderby is not None: + standards = CourseStandard.objects.filter( + standardcollection=collection + ).order_by(orderby,"-referencespeed","agemax","agemin","sex","name") + else: + standards = CourseStandard.objects.filter( + standardcollection=collection + ).order_by("-referencespeed","agemax","agemin","sex","name") + + breadcrumbs = [ + { + 'url': reverse('virtualevents_view'), + 'name': 'Challenges' + }, + { + 'url': reverse(standards_view), + 'name': 'Standards' + }, + { + 'url': reverse(standard_view,kwargs={'id':collection.id}), + 'name': collection.name + }, + ] + + return render(request, 'standard_view.html', + { + 'active':'nav-racing', + 'breadcrumbs':breadcrumbs, + 'collection':collection, + 'standards':standards, + 'rower':r, + } + ) + @login_required() @permission_required('racelogo.delete_logo',fn=get_logo_by_pk,raise_exception=True) def logo_delete_view(request,id=0): @@ -387,7 +461,7 @@ def virtualevent_uploadimage_view(request,id=0): }) -# Image upload +# Course upload @login_required() def course_upload_view(request): is_ajax = False @@ -447,6 +521,125 @@ def course_upload_view(request): else: return {'result':0} +# Standards deactivate +@login_required() +def standard_deactivate_view(request,id=0): + is_ajax = False + if request.is_ajax(): + is_ajax = True + + r = getrower(request.user) + + try: + collection = StandardCollection.objects.get(id=id) + except StandardCollection.DoesNotExist: + raise Http404("Does not exist") + + if request.user != collection.manager: + raise PermissionDenied("You cannot change this set of time standards") + + collection.active = False + collection.save() + + url = reverse(standards_view) + + return HttpResponseRedirect(url) + +def standards_download_view(request,id=0): + try: + collection = StandardCollection.objects.get(id=id) + except StandardCollection.DoesNotExist: + raise Http404("Does not exist") + + filename = 'Standard Times {name} {id} {date}.csv'.format( + id=id, + name=collection.name, + date=timezone.now().strftime("%Y-%m-%d %H:%M:%S %Z") + ) + + standards = CourseStandard.objects.filter(standardcollection=collection) + df = pd.DataFrame.from_records(standards.values()) + + response = HttpResponse(df.to_csv()) + + response['Content-Disposition'] = 'attachment; filename="%s"' % filename + response['Content-Type'] = 'application/octet-stream' + + return response + + +# Standards upload +@login_required() +def standards_upload_view(request,id=0): + is_ajax = False + if request.is_ajax(): + is_ajax = True + r = getrower(request.user) + + if id != 0: + collection = StandardCollection.objects.get(id=id) + if request.user != collection.manager: + raise PermissionDenied("You cannot change this set of time standards") + + + if request.method == 'POST': + form = StandardsForm(request.POST,request.FILES) + + if form.is_valid(): + f = form.cleaned_data['file'] + name = form.cleaned_data['name'] + notes = form.cleaned_data['notes'] + if f is not None: + filename,path_and_filename = handle_uploaded_file(f) + + id = save_scoring(name,request.user,path_and_filename,notes=notes,id=id) + + + os.remove(path_and_filename) + + + + if id==0: + url = reverse(standards_view) + else: + url = reverse(standard_view,kwargs={'id':id}) + + if is_ajax: + return JSONResponse({'result':1,'url':url}) + + return HttpResponseRedirect(url) + + else: + messages.error(request,'Something went wrong - no file attached') + url = reverse(standards_upload_view) + if is_ajax: + return JSONResponse({'result':0,'url':0}) + + return HttpResponseRedirect(url) + else: + messages.error(request,'Form is not valid') + return render(request,'standard_form.html', + {'form':form, + 'active':'nav-racing', + 'id':id, + }) + + else: + if not is_ajax: + form = StandardsForm() + if id != 0: + collection = StandardCollection.objects.get(id=id) + form = StandardsForm(initial={ + 'name':collection.name, + 'notes': collection.notes, + }) + return render(request,'standard_form.html', + {'form':form, + 'active':'nav-racing', + 'id':id, + }) + return {'result':0} + def virtualevents_view(request): is_ajax = False @@ -523,7 +716,6 @@ def virtualevents_view(request): country__in=countries ).order_by("startdate","start_time") else: - form = VirtualRaceSelectForm() if is_ajax: @@ -935,6 +1127,11 @@ def virtualevent_view(request,id=0): except KeyError: adaptiveclass = ['None','PR1','PR2','PR3','FES'] + try: + entrycategory = cd['entrycategory'] + except KeyError: + entrycategory = None + if race.sessiontype == 'race': results = resultobj.objects.filter( race=race, @@ -945,7 +1142,7 @@ def virtualevent_view(request,id=0): weightcategory__in=weightcategory, adaptiveclass__in=adaptiveclass, age__gte=age_min, - age__lte=age_max + age__lte=age_max, ).order_by("duration") else: results = resultobj.objects.filter( @@ -956,9 +1153,11 @@ def virtualevent_view(request,id=0): weightcategory__in=weightcategory, adaptiveclass__in=adaptiveclass, age__gte=age_min, - age__lte=age_max + age__lte=age_max, ).order_by("duration","-distance") + if entrycategory is not None: + results = results.filter(entrycategory__in=entrycategory) # to-do - add DNS dns = [] @@ -985,8 +1184,6 @@ def virtualevent_view(request,id=0): else: form = None - - breadcrumbs = [ { 'url':reverse('virtualevents_view'), @@ -1000,6 +1197,10 @@ def virtualevent_view(request,id=0): } ] + orderby = request.GET.get('order_by') + if orderby is not None: + results = results.order_by(orderby) + racelogos = race.logos.all() if racelogos: @@ -1278,6 +1479,12 @@ def virtualevent_addboat_view(request,id=0): except VirtualRace.DoesNotExist: raise Http404("Virtual Challenge does not exist") + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + + if not race_can_adddiscipline(r,race): messages.error(request,"You cannot register for this race") @@ -1301,7 +1508,7 @@ def virtualevent_addboat_view(request,id=0): # we're still here if request.method == 'POST': # process form - form = VirtualRaceResultForm(request.POST) + form = VirtualRaceResultForm(request.POST,categories=categories) if form.is_valid(): cd = form.cleaned_data teamname = cd['teamname'] @@ -1323,7 +1530,7 @@ def virtualevent_addboat_view(request,id=0): if sex == 'not specified': sex = 'male' - if boattype in boattypes and boatclass in boatclasses: + if boattype in boattypes and boatclass in boatclasses and race.coursestandards is None: # check if different sexes therecords = records.filter( boattype=boattype, @@ -1344,6 +1551,49 @@ def virtualevent_addboat_view(request,id=0): return HttpResponseRedirect(url) + coursestandard = None + referencespeed = 5.0 + + if race.coursestandards is not None: + coursestandard = cd['entrycategory'] + thegroups = [record.entrycategory for record in records] + if coursestandard in thegroups: + messages.error(request,"You have already registered in that group") + url = reverse('virtualevent_view', + kwargs = { + 'id': race.id + } + ) + + return HttpResponseRedirect(url) + + referencespeed = coursestandard.referencespeed + boattype = coursestandard.boattype + boatclass = coursestandard.boatclass + weightcategory = coursestandard.weightclass + adaptiveclass = coursestandard.adaptiveclass + skillclass = coursestandard.skillclass + + returnurl = reverse(virtualevent_register_view, + kwargs={'id':race.id}) + + if age < coursestandard.agemin: + messages.error(request,'You are younger than the minimum age for this group') + return HttpResponseRedirect(returnurl) + + if age > coursestandard.agemax: + messages.error(request,'You are older than the maximum age for this group') + return HttpResponseRedirect(returnurl) + + if sex == 'male' and coursestandard.sex != 'male': + messages.error(request,'Men are not allowed to enter this category') + return HttpResponseRedirect(returnurl) + + if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: + messages.error(request,'Mixed crews are not allowed to enter this category') + return HttpResponseRedirect(returnurl) + + record = VirtualRaceResult( userid=r.id, teamname=teamname, @@ -1358,8 +1608,10 @@ def virtualevent_addboat_view(request,id=0): boattype=boattype, boatclass=boatclass, coursecompleted=False, + referencespeed=referencespeed, + entrycategory=coursestandard, sex=sex, - age=age + age=age, ) record.save() @@ -1387,7 +1639,13 @@ def virtualevent_addboat_view(request,id=0): 'adaptiveclass': r.adaptiveclass, } - form = VirtualRaceResultForm(initial=initial) + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + + + form = VirtualRaceResultForm(initial=initial,categories=categories) breadcrumbs = [ { @@ -1448,6 +1706,11 @@ def virtualevent_register_view(request,id=0): except VirtualRace.DoesNotExist: raise Http404("Virtual Challenge does not exist") + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + if not race_can_register(r,race): messages.error(request,"You cannot register for this race") @@ -1461,7 +1724,7 @@ def virtualevent_register_view(request,id=0): # we're still here if request.method == 'POST': # process form - form = VirtualRaceResultForm(request.POST) + form = VirtualRaceResultForm(request.POST,categories=categories) if form.is_valid(): cd = form.cleaned_data teamname = cd['teamname'] @@ -1483,6 +1746,40 @@ def virtualevent_register_view(request,id=0): if sex == 'not specified': sex = 'male' + + coursestandard = None + referencespeed = 5.0 + + if race.coursestandards is not None: + coursestandard = cd['entrycategory'] + referencespeed = coursestandard.referencespeed + boattype = coursestandard.boattype + boatclass = coursestandard.boatclass + weightcategory = coursestandard.weightclass + adaptiveclass = coursestandard.adaptiveclass + skillclass = coursestandard.skillclass + + returnurl = reverse(virtualevent_register_view, + kwargs={'id':race.id}) + + if age < coursestandard.agemin: + messages.error(request,'You are younger than the minimum age for this group') + return HttpResponseRedirect(returnurl) + + if age > coursestandard.agemax: + messages.error(request,'You are older than the maximum age for this group') + return HttpResponseRedirect(returnurl) + + if sex == 'male' and coursestandard.sex != 'male': + messages.error(request,'Men are not allowed to enter this category') + return HttpResponseRedirect(returnurl) + + if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: + messages.error(request,'Mixed crews are not allowed to enter this category') + return HttpResponseRedirect(returnurl) + + + record = VirtualRaceResult( userid=r.id, teamname=teamname, @@ -1498,7 +1795,9 @@ def virtualevent_register_view(request,id=0): boattype=boattype, coursecompleted=False, sex=sex, - age=age + age=age, + entrycategory=coursestandard, + referencespeed=referencespeed, ) record.save() @@ -1542,7 +1841,12 @@ def virtualevent_register_view(request,id=0): 'adaptiveclass': r.adaptiveclass, } - form = VirtualRaceResultForm(initial=initial) + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + + form = VirtualRaceResultForm(initial=initial,categories=categories) breadcrumbs = [ { @@ -1644,6 +1948,11 @@ def indoorvirtualevent_register_view(request,id=0): except VirtualRace.DoesNotExist: raise Http404("Virtual Challenge does not exist") + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + if not race_can_register(r,race): messages.error(request,"You cannot register for this race") @@ -1657,7 +1966,7 @@ def indoorvirtualevent_register_view(request,id=0): # we're still here if request.method == 'POST': # process form - form = IndoorVirtualRaceResultForm(request.POST) + form = IndoorVirtualRaceResultForm(request.POST,categories=categories) if form.is_valid(): cd = form.cleaned_data teamname = cd['teamname'] @@ -1675,6 +1984,38 @@ def indoorvirtualevent_register_view(request,id=0): if sex == 'not specified': sex = 'male' + coursestandard = None + referencespeed = 5.0 + + if race.coursestandards is not None: + coursestandard = cd['entrycategory'] + referencespeed = coursestandard.referencespeed + boatclass = coursestandard.boatclass + weightcategory = coursestandard.weightclass + adaptiveclass = coursestandard.adaptiveclass + skillclass = coursestandard.skillclass + + returnurl = reverse(virtualevent_register_view, + kwargs={'id':race.id}) + + if age < coursestandard.agemin: + messages.error(request,'You are younger than the minimum age for this group') + return HttpResponseRedirect(returnurl) + + if age > coursestandard.agemax: + messages.error(request,'You are older than the maximum age for this group') + return HttpResponseRedirect(returnurl) + + if sex == 'male' and coursestandard.sex != 'male': + messages.error(request,'Men are not allowed to enter this category') + return HttpResponseRedirect(returnurl) + + if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: + messages.error(request,'Mixed crews are not allowed to enter this category') + return HttpResponseRedirect(returnurl) + + + record = IndoorVirtualRaceResult( userid=r.id, teamname=teamname, @@ -1689,7 +2030,9 @@ def indoorvirtualevent_register_view(request,id=0): boatclass=boatclass, coursecompleted=False, sex=sex, - age=age + age=age, + entrycategory=coursestandard, + referencespeed=referencespeed ) record.save() @@ -1733,7 +2076,12 @@ def indoorvirtualevent_register_view(request,id=0): 'adaptiveclass': r.adaptiveclass, } - form = IndoorVirtualRaceResultForm(initial=initial) + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + + form = IndoorVirtualRaceResultForm(initial=initial,categories=categories) breadcrumbs = [ { @@ -1806,6 +2154,7 @@ def indoorvirtualevent_create_view(request): evaluation_closure = cd['evaluation_closure'] contact_phone = cd['contact_phone'] contact_email = cd['contact_email'] + coursestandards = cd['coursestandards'] # correct times @@ -1860,6 +2209,7 @@ def indoorvirtualevent_create_view(request): sessionvalue = sessionvalue, course=None, timezone=timezone_str, + coursestandards=coursestandards, evaluation_closure=evaluation_closure, registration_closure=registration_closure, contact_phone=contact_phone, @@ -1946,6 +2296,7 @@ def virtualevent_create_view(request): evaluation_closure = cd['evaluation_closure'] contact_phone = cd['contact_phone'] contact_email = cd['contact_email'] + coursestandards = cd['coursestandards'] # correct times @@ -1997,6 +2348,7 @@ def virtualevent_create_view(request): evaluation_closure=evaluation_closure, registration_closure=registration_closure, contact_phone=contact_phone, + coursestandards=coursestandards, contact_email=contact_email, country = course.country, manager=request.user, diff --git a/rowers/views/statements.py b/rowers/views/statements.py index 156919f9..2d6f0761 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -93,7 +93,7 @@ from rowers.forms import ( FitnessMetricForm,PredictedPieceFormNoDistance, EmailForm, RegistrationForm, RegistrationFormTermsOfService, RegistrationFormUniqueEmail,RegistrationFormSex, - CNsummaryForm,UpdateWindForm, + CNsummaryForm,UpdateWindForm,StandardsForm, UpdateStreamForm,WorkoutMultipleCompareForm,ChartParamChoiceForm, FusionMetricChoiceForm,BoxPlotChoiceForm,MultiFlexChoiceForm, TrendFlexModalForm,WorkoutSplitForm,WorkoutJoinParamForm, @@ -113,7 +113,7 @@ from rowers.models import ( RaceLogo,RowerBillingAddressForm,PaidPlan, AlertEditForm, ConditionEditForm, PlannedSessionComment,CoachRequest,CoachOffer, - VideoAnalysis,ShareKey, + VideoAnalysis,ShareKey,StandardCollection,CourseStandard, ) from rowers.models import ( RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm, diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py index 75ee64e3..04a621a1 100644 --- a/rowsandall_app/settings.py +++ b/rowsandall_app/settings.py @@ -42,6 +42,10 @@ TESTING = False ALLOWED_HOSTS = CFG['allowed_hosts'] +OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = 'oauth2_provider.AccessToken' +OAUTH2_PROVIDER_APPLICATION_MODEL = 'oauth2_provider.Application' +OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = 'oauth2_provider.RefreshToken' + # Application definition diff --git a/static/css/rowsandall2.css b/static/css/rowsandall2.css index f096204a..e4054cb8 100644 --- a/static/css/rowsandall2.css +++ b/static/css/rowsandall2.css @@ -50,7 +50,7 @@ } html { - font-size: 62.5%; + font-size: 62.5%; margin: 0px; height: 100%; width: 100%; @@ -96,13 +96,13 @@ cox { ------------------------------------------------------------------------------- */ -th { +th { font-weight: bold; align: left; } .listtable tbody tr:nth-of-type(even) { background-color: #DDD; } -.listtable thead th { +.listtable thead th { font-weight: bold; align: left; } @@ -112,6 +112,10 @@ th { .paddedtable td { padding: 1px 20px } +.shortpadded th { padding: 3px 3px } + +.paddedtable th { padding: 1px 20px } + .cortable { border-collapse: collapse; } @@ -124,12 +128,12 @@ th { th.rotate { /* Something you can count on */ - height: 120px; + height: 120px; white-space: nowrap; } th.rotate > div { - transform: + transform: /* Magic Numbers */ translate(28px, 91px) /* 45 is really 360 - 45 */ @@ -141,12 +145,12 @@ th.rotate > div > span { padding: 5px 5px; } -.fixtable table { +.fixtable table { table-layout: fixed; width: 60%; } -.message { +.message { border: 1px solid #000; background-color: #f88; font-weight: bold; @@ -172,7 +176,7 @@ th.rotate > div > span { background-color: #fee; } -.successmessage { +.successmessage { border: 1px solid #000; background-color: #8f8; color: #000; @@ -180,7 +184,7 @@ th.rotate > div > span { font-weight: bold; } -.deletelink { +.deletelink { border: 1px solid #000; background-color: #f88; color: #000; @@ -189,7 +193,7 @@ th.rotate > div > span { } .navbar { - border: 1px solid #666; + border: 1px solid #666; color: #000; @@ -199,7 +203,7 @@ th.rotate > div > span { text-align: center; } -.navbutton { +.navbutton { background-color: #ddd; -moz-border-radius: 15px; -webkit-border-radius: 15px; @@ -242,7 +246,7 @@ th.rotate > div > span { transition-delay:1s; } -.caption { +.caption { text-align: center; } @@ -263,7 +267,7 @@ th.rotate > div > span { font: 1.0em/1.2em sans-serif; text-decoration: none; display: block; - padding: .2em .5em .2em .5em; + padding: .2em .5em .2em .5em; zoom: 1; /* border-radius: .5em; */ /* -moz-border-radius: .5em; */ @@ -276,7 +280,7 @@ th.rotate > div > span { font: 1.0em/1.2em sans-serif; text-decoration: none; display: block; - padding: .2em .5em .2em .5em; + padding: .2em .5em .2em .5em; zoom: 1; /* border-radius: .5em; */ /* -moz-border-radius: .5em; */ @@ -304,7 +308,7 @@ th.rotate > div > span { } .dot:hover { - text-decoration: none; + text-decoration: none; } .rounder { @@ -345,9 +349,9 @@ th.rotate > div > span { -webkit-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); -moz-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); - + line-height: 0; /* ensure no space between bottom */ - + } .vignet img { @@ -367,9 +371,9 @@ th.rotate > div > span { -webkit-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); -moz-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); - + line-height: 0; /* ensure no space between bottom */ - + } .vignet2 img { @@ -751,7 +755,7 @@ th.rotate > div > span { padding: 1em; text-align: left; line-height: 1.5em; - word-wrap: break-word; + word-wrap: break-word; } .talktext p{ /* remove webkit p margins */ @@ -776,7 +780,7 @@ th.rotate > div > span { /* paleblue */ .paleblue { -# padding: 8px; +# padding: 8px; background: aliceblue; box-shadow:inset 0px 0px 0px 6px #fff; -moz-box-shadow:inset 0px 0px 0px 6px #fff; @@ -948,7 +952,7 @@ th.rotate > div > span { .greenbar { - border: 1px solid #666; + border: 1px solid #666; color: #000; @@ -959,7 +963,7 @@ th.rotate > div > span { } -#footer { +#footer { text-align:center; } @@ -1016,21 +1020,21 @@ th.rotate > div > span { background-color: #3e8e41; } -.flexplot { +.flexplot { position: relative; z-index: 10; } -a.wh:link { +a.wh:link { color: #e9e9e9; } -a.wh:visited { +a.wh:visited { color: #e9e9e9; } -a.wh:hover { +a.wh:hover { color: #e9e9e9; } @@ -1067,7 +1071,7 @@ a.wh:hover { .icon-link a:hover, a:active, a:visited, a:link { /* color: #1c75bc; */ - text-decoration: none; + text-decoration: none; } @@ -1086,9 +1090,9 @@ a.wh:hover { } .mystyle { - font-size: 11pt; + font-size: 11pt; font-family: Arial; - border-collapse: collapse; + border-collapse: collapse; border: 1px solid silver; } diff --git a/static/css/rowsandall2.min.css b/static/css/rowsandall2.min.css index d995d025..ab482e51 100644 --- a/static/css/rowsandall2.min.css +++ b/static/css/rowsandall2.min.css @@ -1 +1 @@ -#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/landing1.jpg")}.three{background-image:url("/static/img/landing2.jpg")}.four{background-image:url("/static/img/landing8b.jpg")}.errorlist{color:red}.watermark{position:absolute;float:center;opacity:.25;font-size:3em;width:100%;top:50%;left:50%;transform:translateX(-25%) translateY(-50%);text-align:center;vertical-align:middle;z-index:1000}.invisible{display:none}html{font-size:62.5%;margin:0;height:100%;width:100%;min-height:100%}body{color:#333;font-size:1.2em;width:100%;min-height:100%;margin:0;box-sizing:border-box}.notyellow{font-size:1.2em;height:auto;padding:0}.yellow{color:#1c75bc;font-size:1.2em;height:auto;padding:0}cox{font-weight:normal;text-align:center;font-size:2em}th{font-weight:bold;align:left}.listtable tbody tr:nth-of-type(even){background-color:#DDD}.listtable thead th{font-weight:bold;align:left}.shortpadded td{padding:3px 3px}.paddedtable td{padding:1px 20px}.cortable{border-collapse:collapse}.cortable td{border:1px solid #999;text-align:center}th.rotate{height:120px;white-space:nowrap}th.rotate>div{transform:translate(28px,91px) rotate(315deg);width:30px}th.rotate>div>span{border-bottom:1px solid #ccc;padding:5px 5px}.fixtable table{table-layout:fixed;width:60%}.message{border:1px solid #000;background-color:#f88;font-weight:bold;color:#000;text-align:center}.midden{text-align:center}.poscor{background-color:#8f8}.weakposcor{background-color:#efe}.negcor{background-color:#f88}.weaknegcor{background-color:#fee}.successmessage{border:1px solid #000;background-color:#8f8;color:#000;text-align:center;font-weight:bold}.deletelink{border:1px solid #000;background-color:#f88;color:#000;text-align:center;font-weight:bold}.navbar{border:1px solid #666;color:#000;overflow:hidden;background-color:#ddd;text-align:center}.navbutton{background-color:#ddd;-moz-border-radius:15px;-webkit-border-radius:15px;border:2px solid #666;padding:5px;text-align:center}.transparentbutton{padding:1px;text-align:center}.tooltip{position:relative;display:inline-block;color:#000}.tooltip a{color:black}.tooltip .tooltiptext{visibility:hidden;width:120px;background-color:#ff6;color:black;text-align:center;border-radius:6px;padding:5px 5px;position:absolute;z-index:999}.tooltip:hover .tooltiptext{visibility:visible;transition-delay:1s}.caption{text-align:center}.site-announcement-box{padding:.2em .5em .2em 0;width:100%;max-width:200px}@media only screen and (max-width:450px){.site-announcement-box{max-width:100%}}.site-announcement{font:1.0/1.2em sans-serif;text-decoration:none;display:block;padding:.2em .5em .2em .5em;zoom:1;text-align:left;border:solid 1px #333}.site-announcement-white{font:1.0/1.2em sans-serif;text-decoration:none;display:block;padding:.2em .5em .2em .5em;zoom:1;text-align:left;border:solid 1px #fff}.contentli{margin-left:30px;display:list-item;list-style-type:circle}.dot{border-radius:50%;display:block;text-align:center;width:25px;height:25px;border:solid 1px #333}.dot:hover{text-decoration:none}.rounder{border-radius:10px;display:block;overflow-x:hidden;border:solid 1px #333;padding:5px;margin:2px}.whiteborder{border:solid 2px #aaa}.frontitem{background-color:rgba(255,255,255,0.7);border:solid 1px wite;padding:5px;margin:5px;color:black}.frontitem label{color:black}.frontitem a{color:#1c75bc}.vignet{border-radius:50%;display:block;overflow:hidden;padding:5px;margin:5px;-webkit-box-shadow:inset 0 0 85px rgba(0,0,0,0.4);-moz-box-shadow:inset 0 0 85px rgba(0,0,0,0.4);box-shadow:inset 0 0 85px rgba(0,0,0,0.4);line-height:0}.vignet img{position:relative;transform:scale(1.5);z-index:-1}.vignet2{border-radius:50%;width:200px;height:200px;display:block;overflow:hidden;padding:5px;margin:5px;-webkit-box-shadow:inset 0 0 85px rgba(0,0,0,0.4);-moz-box-shadow:inset 0 0 85px rgba(0,0,0,0.4);box-shadow:inset 0 0 85px rgba(0,0,0,0.4);line-height:0}.vignet2 img{position:center;z-index:-1}.button{font:1.1em/1.5em sans-serif;text-decoration:none;display:block;margin:0;padding:0;zoom:1;text-align:center}.button:active{position:relative;top:1px}.red{color:#faddde;border:solid 1px #980c10;background:#d81b21}.red:hover{background:#b61318}.red:active{color:#de898c}.green{color:#e8f0de;border:solid 1px #538312;background:#64991e}.green:hover{background:#538018}.green:active{color:#a9c08c}.lightgreen{background:#e2f0da;color:#fdffc;border:solid 1px #b2bfaa}.lightgreen:active{color:#f5faf2}.lightgreen:hover{background:#b2bfaa}.mediumgreen{background:#aad090;color:#fafff7;border:solid 1px #8db374}.mediumgreen:active{color:#d8e6cf}.mediumgreen:hover{background:#8db374}.purple{background:#8c1ec1;color:#e9ddf0;border:solid 1px #6b0f99}.purple:active{color:#cfa160}.purple:hover{background:#6b0f99}.violet{background:#c20d60;color:#f0dae5;border:solid 1px #99034e}.violet:active{color:#e595bd}.violet:hover{background:#99034e}.blue{color:#fae7e9;border:solid 1px #27aae2;background:#27aae2}.blue:hover{background:#1c74bb;border:solid 1px #27aae2}.blue:active{color:#fff}.leafletmap{padding:0;margin:0;display:grid;grid-gap:0}.orange{color:#fef4e9;border:solid 1px #da7c0c;background:#f78d1d}.orange:hover{background:#f47c20}.orange:active{color:#fcd3a5}.talk-bubble{margin:40px;display:inline-block;position:relative;width:200px;height:auto;background-color:lightyellow}.border{border:8px solid #666}.round{border-radius:30px;-webkit-border-radius:30px;-moz-border-radius:30px}.tri-right.border.left-top:before{content:' ';position:absolute;width:0;height:0;left:-40px;right:auto;top:-8px;bottom:auto;border:32px solid;border-color:#666 transparent transparent transparent}.tri-right.left-top:after{content:' ';position:absolute;width:0;height:0;left:-20px;right:auto;top:0;bottom:auto;border:22px solid;border-color:lightyellow transparent transparent transparent}.tri-right.border.left-in:before{content:' ';position:absolute;width:0;height:0;left:-40px;right:auto;top:30px;bottom:auto;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.left-in:after{content:' ';position:absolute;width:0;height:0;left:-20px;right:auto;top:38px;bottom:auto;border:12px solid;border-color:lightyellow lightyellow transparent transparent}.tri-right.border.btm-left:before{content:' ';position:absolute;width:0;height:0;left:-8px;right:auto;top:auto;bottom:-40px;border:32px solid;border-color:transparent transparent transparent #666}.tri-right.btm-left:after{content:' ';position:absolute;width:0;height:0;left:0;right:auto;top:auto;bottom:-20px;border:22px solid;border-color:transparent transparent transparent lightyellow}.tri-right.border.btm-left-in:before{content:' ';position:absolute;width:0;height:0;left:30px;right:auto;top:auto;bottom:-40px;border:20px solid;border-color:#666 transparent transparent #666}.tri-right.btm-left-in:after{content:' ';position:absolute;width:0;height:0;left:38px;right:auto;top:auto;bottom:-20px;border:12px solid;border-color:lightyellow transparent transparent lightyellow}.tri-right.border.btm-right-in:before{content:' ';position:absolute;width:0;height:0;left:auto;right:30px;bottom:-40px;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.btm-right-in:after{content:' ';position:absolute;width:0;height:0;left:auto;right:38px;bottom:-20px;border:12px solid;border-color:lightyellow lightyellow transparent transparent}.tri-right.border.btm-right:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-8px;bottom:-40px;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.btm-right:after{content:' ';position:absolute;width:0;height:0;left:auto;right:0;bottom:-20px;border:12px solid;border-color:lightyellow lightyellow transparent transparent}.tri-right.border.right-in:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-40px;top:30px;bottom:auto;border:20px solid;border-color:#666 transparent transparent #666}.tri-right.right-in:after{content:' ';position:absolute;width:0;height:0;left:auto;right:-20px;top:38px;bottom:auto;border:12px solid;border-color:lightyellow transparent transparent lightyellow}.tri-right.border.right-top:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-40px;top:-8px;bottom:auto;border:32px solid;border-color:#666 transparent transparent transparent}.tri-right.right-top:after{content:' ';position:absolute;width:0;height:0;left:auto;right:-20px;top:0;bottom:auto;border:20px solid;border-color:lightyellow transparent transparent transparent}.talktext{padding:1em;text-align:left;line-height:1.5em;word-wrap:break-word}.talktext p{-webkit-margin-before:0;-webkit-margin-after:0}.drop-files{border:1px solid #000;color:#000}.palegreen{background:palegreen;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.paleblue{# padding:8px;background:aliceblue;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.lightsalmon{# padding:4px;background:lightsalmon;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.filler{background:darkgray;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.padded{padding:10px}.input{font:1.1em/1.5em sans-serif;text-decoration:none;display:block;color:white;padding:.2em 0 .2em 0;zoom:1;border-radius:.5em;-moz-border-radius:.5em;-webkit-border-radius:.5em;text-align:center}.blueicon{text-decoration:none;display:block;color:#1c75bc;padding:.2em 0 .2em 0;zoom:1}.bigrounded{-webkit-border-radius:2em;-moz-border-radius:2em;border-radius:2em;border:solid 1px white}.medium{font-size:1.2em}.small{font-size:1.0}.black{color:#d7d7d7;border:solid 1px #333;background:#333}.black:hover{background:#000}.black:active{color:#666}.gray{color:#e9e9e9;border:solid 1px #555;background:#6e6e6e}.gray:hover{background:#616161}.gray:active{color:#afafaf}.white{color:#606060;border:solid 1px #b7b7b7;background:#fff}.white:hover{background:#ededed}.white:active{color:#999}.bluetext{color:#27aae2}.rbluetext{color:#27aae1}.rdarkbluetext{color:#1c75bc}.rblue{color:#fae7e9;border:solid 1px #27aae1;background:#27aae1}.rblue:active{color:#fff}.rblue:hover{background:#1c75bc;border:solid 1px #27aae1}.rosy{color:#fae7e9;border:solid 1px #b73948;background:#da5867}.rosy:hover{background:#ba4b58}.rosy:active{color:#dca4ab}.pink{color:#feeef5;border:solid 1px #d2729e;background:#f895c2}.pink:hover{background:#d57ea5}.pink:active{color:#f3c3d9}.greenbar{border:1px solid #666;color:#000;overflow:hidden;background-color:#8f8;text-align:center}#footer{text-align:center}.container_12,.container_16,.container_24{background-color:#fff;background-repeat:repeat-y}.dropbtn{color:white}.dropdown{position:relative;display:inline-block}.dropdown-content{display:none;position:absolute;min-width:160px;z-index:999}.dropdown-content a{text-decoration:none;display:block;z-index:999}.dropdown:hover .dropdown-content{display:block}.dropdown:hover .dropbtn{background-color:#3e8e41}.flexplot{position:relative;z-index:10}a.wh:link{color:#e9e9e9}a.wh:visited{color:#e9e9e9}a.wh:hover{color:#e9e9e9}.bk-canvas-map{overflow:hidden}.container{padding:5% 5%}.wrapwords{-ms-word-break:break-all;word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.icon-link a{text-decoration:none}.icon-link a:hover,a:active,a:visited,a:link{text-decoration:none}.mapdiv{padding:0 !important}.mapdiv img{float:left !important;padding:0 !important}.paypalpix{width:auto !important;max-width:1px}.mystyle{font-size:11pt;font-family:Arial;border-collapse:collapse;border:1px solid silver}.pandastable tr{display:block}.pandastable th,.pandastable td{width:100px}.pandastable tbody{display:block;height:1200px;overflow:auto}.pandastable td,.pandastable th{padding:5px}.pandastable tr:nth-child(even){background:#e0e0e0}.pandastable tr:hover{background:silver;cursor:pointer}table.djangoform tbody>tr>th{vertical-align:top} \ No newline at end of file +#main{background-color:initial;-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/landing1.jpg)}.three{background-image:url(/static/img/landing2.jpg)}.four{background-image:url(/static/img/landing8b.jpg)}.errorlist{color:red}.watermark{position:absolute;float:center;opacity:.25;font-size:3em;width:100%;top:50%;left:50%;transform:translateX(-25%)translateY(-50%);text-align:center;vertical-align:middle;z-index:1000}.invisible{display:none}html{font-size:62.5%;margin:0;height:100%;width:100%;min-height:100%}body{color:#333;font-size:1.2em;width:100%;min-height:100%;margin:0;box-sizing:border-box}.notyellow{font-size:1.2em;height:auto;padding:0}.yellow{color:#1c75bc;font-size:1.2em;height:auto;padding:0}cox{font-weight:400;text-align:center;font-size:2em}th{font-weight:700;align:left}.listtable tbody tr:nth-of-type(even){background-color:#ddd}.listtable thead th{font-weight:700;align:left}.shortpadded td{padding:3px}.paddedtable td{padding:1px 20px}.shortpadded th{padding:3px}.paddedtable th{padding:1px 20px}.cortable{border-collapse:collapse}.cortable td{border:1px solid #999;text-align:center}th.rotate{height:120px;white-space:nowrap}th.rotate>div{transform:translate(28px,91px)rotate(315deg);width:30px}th.rotate>div>span{border-bottom:1px solid #ccc;padding:5px}.fixtable table{table-layout:fixed;width:60%}.message{border:1px solid #000;background-color:#f88;font-weight:700;color:#000;text-align:center}.midden{text-align:center}.poscor{background-color:#8f8}.weakposcor{background-color:#efe}.negcor{background-color:#f88}.weaknegcor{background-color:#fee}.successmessage{border:1px solid #000;background-color:#8f8;color:#000;text-align:center;font-weight:700}.deletelink{border:1px solid #000;background-color:#f88;color:#000;text-align:center;font-weight:700}.navbar{border:1px solid #666;color:#000;overflow:hidden;background-color:#ddd;text-align:center}.navbutton{background-color:#ddd;-moz-border-radius:15px;-webkit-border-radius:15px;border:2px solid #666;padding:5px;text-align:center}.transparentbutton{padding:1px;text-align:center}.tooltip{position:relative;display:inline-block;color:#000}.tooltip a{color:#000}.tooltip .tooltiptext{visibility:hidden;width:120px;background-color:#ff6;color:#000;text-align:center;border-radius:6px;padding:5px;position:absolute;z-index:999}.tooltip:hover .tooltiptext{visibility:visible;transition-delay:1s}.caption{text-align:center}.site-announcement-box{padding:.2em .5em .2em 0;width:100%;max-width:200px}@media only screen and (max-width:450px){.site-announcement-box{max-width:100%}}.site-announcement{font:1em/1.2em sans-serif;text-decoration:none;display:block;padding:.2em .5em;zoom:1;text-align:left;border:solid 1px #333}.site-announcement-white{font:1em/1.2em sans-serif;text-decoration:none;display:block;padding:.2em .5em;zoom:1;text-align:left;border:solid 1px #fff}.contentli{margin-left:30px;display:list-item;list-style-type:circle}.dot{border-radius:50%;display:block;text-align:center;width:25px;height:25px;border:solid 1px #333}.dot:hover{text-decoration:none}.rounder{border-radius:10px;display:block;overflow-x:hidden;border:solid 1px #333;padding:5px;margin:2px}.whiteborder{border:solid 2px #aaa}.frontitem{background-color:rgba(255,255,255,.7);border:solid 1px wite;padding:5px;margin:5px;color:#000}.frontitem label{color:#000}.frontitem a{color:#1c75bc}.vignet{border-radius:50%;display:block;overflow:hidden;padding:5px;margin:5px;-webkit-box-shadow:inset 0 0 85px rgba(0,0,0,.4);-moz-box-shadow:inset 0 0 85px rgba(0,0,0,.4);box-shadow:inset 0 0 85px rgba(0,0,0,.4);line-height:0}.vignet img{position:relative;transform:scale(1.5);z-index:-1}.vignet2{border-radius:50%;width:200px;height:200px;display:block;overflow:hidden;padding:5px;margin:5px;-webkit-box-shadow:inset 0 0 85px rgba(0,0,0,.4);-moz-box-shadow:inset 0 0 85px rgba(0,0,0,.4);box-shadow:inset 0 0 85px rgba(0,0,0,.4);line-height:0}.vignet2 img{position:center;z-index:-1}.button{font:1.1em/1.5em sans-serif;text-decoration:none;display:block;margin:0;padding:0;zoom:1;text-align:center}.button:active{position:relative;top:1px}.red{color:#faddde;border:solid 1px #980c10;background:#d81b21}.red:hover{background:#b61318}.red:active{color:#de898c}.green{color:#e8f0de;border:solid 1px #538312;background:#64991e}.green:hover{background:#538018}.green:active{color:#a9c08c}.lightgreen{background:#e2f0da;color:#fdffc;border:solid 1px #b2bfaa}.lightgreen:active{color:#f5faf2}.lightgreen:hover{background:#b2bfaa}.mediumgreen{background:#aad090;color:#fafff7;border:solid 1px #8db374}.mediumgreen:active{color:#d8e6cf}.mediumgreen:hover{background:#8db374}.purple{background:#8c1ec1;color:#e9ddf0;border:solid 1px #6b0f99}.purple:active{color:#cfa160}.purple:hover{background:#6b0f99}.violet{background:#c20d60;color:#f0dae5;border:solid 1px #99034e}.violet:active{color:#e595bd}.violet:hover{background:#99034e}.blue{color:#fae7e9;border:solid 1px #27aae2;background:#27aae2}.blue:hover{background:#1c74bb;border:solid 1px #27aae2}.blue:active{color:#fff}.leafletmap{padding:0;margin:0;display:grid;grid-gap:0}.orange{color:#fef4e9;border:solid 1px #da7c0c;background:#f78d1d}.orange:hover{background:#f47c20}.orange:active{color:#fcd3a5}.talk-bubble{margin:40px;display:inline-block;position:relative;width:200px;height:auto;background-color:#ffffe0}.border{border:8px solid #666}.round{border-radius:30px;-webkit-border-radius:30px;-moz-border-radius:30px}.tri-right.border.left-top:before{content:' ';position:absolute;width:0;height:0;left:-40px;right:auto;top:-8px;bottom:auto;border:32px solid;border-color:#666 transparent transparent transparent}.tri-right.left-top:after{content:' ';position:absolute;width:0;height:0;left:-20px;right:auto;top:0;bottom:auto;border:22px solid;border-color:#ffffe0 transparent transparent transparent}.tri-right.border.left-in:before{content:' ';position:absolute;width:0;height:0;left:-40px;right:auto;top:30px;bottom:auto;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.left-in:after{content:' ';position:absolute;width:0;height:0;left:-20px;right:auto;top:38px;bottom:auto;border:12px solid;border-color:#ffffe0 #ffffe0 transparent transparent}.tri-right.border.btm-left:before{content:' ';position:absolute;width:0;height:0;left:-8px;right:auto;top:auto;bottom:-40px;border:32px solid;border-color:transparent transparent transparent #666}.tri-right.btm-left:after{content:' ';position:absolute;width:0;height:0;left:0;right:auto;top:auto;bottom:-20px;border:22px solid;border-color:transparent transparent transparent #ffffe0}.tri-right.border.btm-left-in:before{content:' ';position:absolute;width:0;height:0;left:30px;right:auto;top:auto;bottom:-40px;border:20px solid;border-color:#666 transparent transparent #666}.tri-right.btm-left-in:after{content:' ';position:absolute;width:0;height:0;left:38px;right:auto;top:auto;bottom:-20px;border:12px solid;border-color:#ffffe0 transparent transparent #ffffe0}.tri-right.border.btm-right-in:before{content:' ';position:absolute;width:0;height:0;left:auto;right:30px;bottom:-40px;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.btm-right-in:after{content:' ';position:absolute;width:0;height:0;left:auto;right:38px;bottom:-20px;border:12px solid;border-color:#ffffe0 #ffffe0 transparent transparent}.tri-right.border.btm-right:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-8px;bottom:-40px;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.btm-right:after{content:' ';position:absolute;width:0;height:0;left:auto;right:0;bottom:-20px;border:12px solid;border-color:#ffffe0 #ffffe0 transparent transparent}.tri-right.border.right-in:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-40px;top:30px;bottom:auto;border:20px solid;border-color:#666 transparent transparent #666}.tri-right.right-in:after{content:' ';position:absolute;width:0;height:0;left:auto;right:-20px;top:38px;bottom:auto;border:12px solid;border-color:#ffffe0 transparent transparent #ffffe0}.tri-right.border.right-top:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-40px;top:-8px;bottom:auto;border:32px solid;border-color:#666 transparent transparent transparent}.tri-right.right-top:after{content:' ';position:absolute;width:0;height:0;left:auto;right:-20px;top:0;bottom:auto;border:20px solid;border-color:#ffffe0 transparent transparent transparent}.talktext{padding:1em;text-align:left;line-height:1.5em;word-wrap:break-word}.talktext p{-webkit-margin-before:0;-webkit-margin-after:0}.drop-files{border:1px solid #000;color:#000}.palegreen{background:#98fb98;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.paleblue{# padding: 8px;background:#f0f8ff;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.lightsalmon{# padding: 4px;background:#ffa07a;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.filler{background:#a9a9a9;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.padded{padding:10px}.input{font:1.1em/1.5em sans-serif;text-decoration:none;display:block;color:#fff;padding:.2em 0;zoom:1;border-radius:.5em;-moz-border-radius:.5em;-webkit-border-radius:.5em;text-align:center}.blueicon{text-decoration:none;display:block;color:#1c75bc;padding:.2em 0;zoom:1}.bigrounded{-webkit-border-radius:2em;-moz-border-radius:2em;border-radius:2em;border:solid 1px #fff}.medium{font-size:1.2em}.small{font-size:1em}.black{color:#d7d7d7;border:solid 1px #333;background:#333}.black:hover{background:#000}.black:active{color:#666}.gray{color:#e9e9e9;border:solid 1px #555;background:#6e6e6e}.gray:hover{background:#616161}.gray:active{color:#afafaf}.white{color:#606060;border:solid 1px #b7b7b7;background:#fff}.white:hover{background:#ededed}.white:active{color:#999}.bluetext{color:#27aae2}.rbluetext{color:#27aae1}.rdarkbluetext{color:#1c75bc}.rblue{color:#fae7e9;border:solid 1px #27aae1;background:#27aae1}.rblue:active{color:#fff}.rblue:hover{background:#1c75bc;border:solid 1px #27aae1}.rosy{color:#fae7e9;border:solid 1px #b73948;background:#da5867}.rosy:hover{background:#ba4b58}.rosy:active{color:#dca4ab}.pink{color:#feeef5;border:solid 1px #d2729e;background:#f895c2}.pink:hover{background:#d57ea5}.pink:active{color:#f3c3d9}.greenbar{border:1px solid #666;color:#000;overflow:hidden;background-color:#8f8;text-align:center}#footer{text-align:center}.container_12,.container_16,.container_24{background-color:#fff;background-repeat:repeat-y}.container_12{}.dropbtn{color:#fff}.dropdown{position:relative;display:inline-block}.dropdown-content{display:none;position:absolute;min-width:160px;z-index:999}.dropdown-content a{text-decoration:none;display:block;z-index:999}.dropdown:hover .dropdown-content{display:block}.dropdown:hover .dropbtn{background-color:#3e8e41}.flexplot{position:relative;z-index:10}a.wh:link{color:#e9e9e9}a.wh:visited{color:#e9e9e9}a.wh:hover{color:#e9e9e9}.bk-canvas-map{overflow:hidden}.container{padding:5%}.wrapwords{-ms-word-break:break-all;word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.icon-link a{text-decoration:none}.icon-link a:hover,a:active,a:visited,a:link{text-decoration:none}.mapdiv{padding:0!important}.mapdiv img{float:left!important;padding:0!important}.paypalpix{width:auto!important;max-width:1px}.mystyle{font-size:11pt;font-family:Arial;border-collapse:collapse;border:1px solid silver}.pandastable tr{display:block}.pandastable th,.pandastable td{width:100px}.pandastable tbody{display:block;height:1200px;overflow:auto}.pandastable td,.pandastable th{padding:5px}.pandastable tr:nth-child(even){background:#e0e0e0}.pandastable tr:hover{background:silver;cursor:pointer}table.djangoform tbody>tr>th{vertical-align:top} \ No newline at end of file