Index: README.txt
===================================================================
--- README.txt	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ README.txt	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -2,4 +2,28 @@
 ============
 
-TBW, if you look for installation instructions, take a look at the script
-bin/install
+Getting Started
+---------------
+
+- Change directory into your newly created project.
+
+    cd ow
+
+- Create a Python virtual environment.
+
+    python3 -m venv env
+
+- Upgrade packaging tools.
+
+    env/bin/pip install --upgrade pip setuptools
+
+- Install the project in editable mode with its testing requirements.
+
+    env/bin/pip install -e ".[testing]"
+
+- Run your project's tests.
+
+    env/bin/pytest
+
+- Run your project.
+
+    env/bin/pserve development.ini
Index: bin/install
===================================================================
--- bin/install	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ bin/install	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -58,5 +58,5 @@
 install_openworkouts() {
     . ${env_path}/bin/activate
-    yes | pip install --upgrade -e ${current}[testing]
+    yes | pip install --upgrade --process-dependency-links -e ${current}[testing]
     deactivate
 }
Index: ow/models/user.py
===================================================================
--- ow/models/user.py	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ ow/models/user.py	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -9,5 +9,5 @@
 
 from ow.catalog import get_catalog, reindex_object
-from ow.utilities import get_week_days, get_month_week_number
+from ow.utilities import get_week_days
 
 
@@ -77,5 +77,5 @@
         reindex_object(catalog, workout)
 
-    def workouts(self, year=None, month=None, week=None):
+    def workouts(self, year=None, month=None):
         """
         Return this user workouts, sorted by date, from newer to older
@@ -84,10 +84,6 @@
         if year:
             workouts = [w for w in workouts if w.start.year == year]
-            if month:
-                workouts = [w for w in workouts if w.start.month == month]
-            if week:
-                week = int(week)
-                workouts = [
-                    w for w in workouts if w.start.isocalendar()[1] == week]
+        if month:
+            workouts = [w for w in workouts if w.start.month == month]
         workouts = sorted(workouts, key=attrgetter('start'))
         workouts.reverse()
@@ -292,65 +288,2 @@
 
         return stats
-
-    @property
-    def weekly_year_stats(self):
-        """
-        Return per-week stats for the last 12 months
-        """
-        # set the boundaries for looking for workouts afterwards,
-        # we need the current date as the "end date" and one year
-        # ago from that date. Then we set the start at the first
-        # day of that month.
-        end = datetime.now(timezone.utc)
-        start = (end - timedelta(days=365)).replace(day=1)
-
-        stats = {}
-
-        # first initialize the stats dict
-        for days in range((end - start).days):
-            day = (start + timedelta(days=days)).date()
-            week = day.isocalendar()[1]
-            month_week = get_month_week_number(day)
-            key = (day.year, day.month, week, month_week)
-            if key not in stats.keys():
-                stats[key] = {
-                    'workouts': 0,
-                    'time': timedelta(0),
-                    'distance': Decimal(0),
-                    'elevation': Decimal(0),
-                    'sports': {}
-                }
-
-        # now loop over the workouts, filtering and then adding stats
-        # to the proper place
-        for workout in self.workouts():
-            if start.date() <= workout.start.date() <= end.date():
-                # less typing, avoid long lines
-                start_date = workout.start.date()
-                week = start_date.isocalendar()[1]
-                month_week = get_month_week_number(start_date)
-                week = stats[(start_date.year,
-                              start_date.month,
-                              week,
-                              month_week)]
-
-                week['workouts'] += 1
-                week['time'] += workout.duration or timedelta(seconds=0)
-                week['distance'] += workout.distance or Decimal(0)
-                week['elevation'] += workout.uphill or Decimal(0)
-                if workout.sport not in week['sports']:
-                    week['sports'][workout.sport] = {
-                        'workouts': 0,
-                        'time': timedelta(seconds=0),
-                        'distance': Decimal(0),
-                        'elevation': Decimal(0),
-                    }
-                week['sports'][workout.sport]['workouts'] += 1
-                week['sports'][workout.sport]['time'] += (
-                    workout.duration or timedelta(0))
-                week['sports'][workout.sport]['distance'] += (
-                    workout.distance or Decimal(0))
-                week['sports'][workout.sport]['elevation'] += (
-                    workout.uphill or Decimal(0))
-
-        return stats
Index: ow/static/css/main.css
===================================================================
--- ow/static/css/main.css	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ ow/static/css/main.css	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -1006,18 +1006,5 @@
 <a class="login-remember" href="#">Forgot your password?</a>
 */
-.user-profile .workout-options {
-  font-size: 13px;
-  font-size: 0.8125rem;
-}
-.user-profile-account {
-  background-color: #fbfbfb;
-  padding: 2em  1em;
-}
-@media (min-width: 480px) {
-  .user-profile-account {
-    padding: 2em 6em;
-  }
-}
-.user-profile-account img {
+.user-profile img {
   width: 140px;
   height: 140px;
@@ -1026,4 +1013,17 @@
   margin-bottom: 0.5em;
 }
+.user-profile .workout-options {
+  font-size: 13px;
+  font-size: 0.8125rem;
+}
+.user-profile-account {
+  background-color: #fbfbfb;
+  padding: 2em  1em;
+}
+@media (min-width: 480px) {
+  .user-profile-account {
+    padding: 2em 6em;
+  }
+}
 .user-profile-account h2 {
   margin: 0 0 0.15em 0;
@@ -1040,7 +1040,7 @@
   color: #959595;
 }
-.total-workouts {
-  font-size: 13px;
-  font-size: 0.8125rem;
+.user-profile-account .workouts {
+  font-size: 18px;
+  font-size: 1.125rem;
   font-weight: bold;
 }
Index: ow/static/js/ow.js
===================================================================
--- ow/static/js/ow.js	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ ow/static/js/ow.js	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -244,11 +244,7 @@
     var chart_selector = spec.chart_selector,
         filters_selector = spec.filters_selector,
-        switcher_selector = spec.switcher_selector,
-        urls = spec.urls,
+        url = spec.url,
         current_month = spec.current_month,
-        current_week = spec.current_week,
-        y_axis_labels = spec.y_axis_labels,
-        filter_by = spec.filter_by,
-        url = spec.url;
+        y_axis_labels = spec.y_axis_labels;
 
     // Helpers
@@ -268,35 +264,17 @@
     };
 
-    function get_name_for_x(d) {
-        if (d.week == undefined || d.week == 0) {
-            return d.name;
-        }
-        else {
-            return d.id.split('-')[2];
-        }
-    }
-
     // Methods
     var filters_setup = function filters_setup() {
         $(filters_selector).on('click', function(e) {
+            var filter_by = 'distance';
             e.preventDefault();
             filter_by = $(this).attr('class').split('-')[1]
             var chart = d3.select(chart_selector);
             chart.selectAll("*").remove();
-            render(filter_by, url);
-        });
-    };
-
-    var switcher_setup = function switcher_setup() {
-        $(switcher_selector).on('click', function(e) {
-            e.preventDefault();
-            url = $(this).attr('class').split('-')[1]
-            var chart = d3.select(chart_selector);
-            chart.selectAll("*").remove();
-            render(filter_by, url);
-        });
-    };
-
-    var render = function render(filter_by, url) {
+            render(filter_by);
+        });
+    };
+
+    var render = function render(filter_by) {
         /*
           Build a d3 bar chart, populated with data from the given url.
@@ -310,8 +288,7 @@
             y = d3.scaleLinear().rangeRound([height, 0]);
 
-        d3.json(urls[url]).then(function (data) {
+        d3.json(url).then(function (data) {
 	    x.domain(data.map(function (d) {
-                return get_name_for_x(d);
-	        // return d.name;
+	        return d.name;
 	    }));
 
@@ -339,29 +316,14 @@
 	        .enter().append("rect")
                 .attr("class", function(d) {
-                    var sel_week = current_month + '-' + current_week;
-                    if (d.id == current_month || d.id == sel_week){
-                        /* Bar for the currently selected month or week */
+                    if (d.id == current_month){
                         select_x_axis_label(d).attr('style', "font-weight: bold;");
-                        return 'bar current';
+                        return 'bar current'
                     }
                     else {
-                        if (!current_week && d.id.indexOf(current_month) >=0 ) {
-                            /*
-                               User selected a month, then switched to weekly
-                               view, we do highlight all the bars for weeks in
-                               that month
-                            */
-                            select_x_axis_label(d).attr('style', "font-weight: bold;");
-                            return 'bar current';
-                        }
-                        else {
-                            /* Non-selected bar */
-                            return 'bar';
-                        }
-
+                        return 'bar'
                     }
                 })
 	        .attr("x", function (d) {
-		    return x(get_name_for_x(d));
+		    return x(d.name);
 	        })
 	        .attr("y", function (d) {
@@ -381,51 +343,32 @@
         	        select_x_axis_label(d).attr('style', "font-weight: regular;");
                     }
-                })
-                .on('click', function(d) {
-                    window.location.href = d.url;
                 });
 
-            if (url == 'monthly') {
-                g.selectAll(".text")
-                    .data(data)
-                    .enter()
-                    .append("text")
-                    .attr("class","label")
-	            .attr("x", function (d) {
-		        return x(get_name_for_x(d)) + x.bandwidth()/2;
-	            })
-	            .attr("y", function (d) {
-                        /*
-                          Get the value for the current bar, then get the maximum
-                          value to be displayed in the bar, which is used to
-                          calculate the proper position of the label for this bar,
-                          relatively to its height (1% above the bar)
-                        */
-                        var value = get_y_value(d, filter_by);
-                        var max = y.domain()[1];
-                        return y(value + y.domain()[1] * 0.01);
-	            })
-                    .text(function(d) {
-                        var value = get_y_value(d, filter_by)
-                        if ( value > 0) {
-                            return value;
-                        }
-                    });
-            }
-
-            if (url == 'weekly') {
-                g.selectAll(".tick")
-                    .each(function (d, i) {
-                        /*
-                          Remove from the x-axis tickets those without letters
-                          on them (useful for the weekly chart)
-                        */
-                        if (d !== parseInt(d, 10)) {
-                            if(!d.match(/[a-z]/i)) {
-                                this.remove();
-                            }
-                        }
-                    });
-            }
+            g.selectAll(".text")
+                .data(data)
+                .enter()
+                .append("text")
+                .attr("class","label")
+	        .attr("x", function (d) {
+		    return x(d.name) + x.bandwidth()/2;
+	        })
+	        .attr("y", function (d) {
+                    /*
+                      Get the value for the current bar, then get the maximum
+                      value to be displayed in the bar, which is used to
+                      calculate the proper position of the label for this bar,
+                      relatively to its height (1% above the bar)
+                     */
+                    var value = get_y_value(d, filter_by);
+                    var max = y.domain()[1];
+                    return y(value + y.domain()[1] * 0.01);
+	        })
+                .text(function(d) {
+                    var value = get_y_value(d, filter_by)
+                    if ( value > 0) {
+                        return value;
+                    }
+                });
+
         });
     };
@@ -433,5 +376,4 @@
     var that = {}
     that.filters_setup = filters_setup;
-    that.switcher_setup = switcher_setup;
     that.render = render;
     return that
Index: ow/static/less/pages/profile.less
===================================================================
--- ow/static/less/pages/profile.less	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ ow/static/less/pages/profile.less	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -1,3 +1,10 @@
 .user-profile {
+    img {
+        width: 140px;
+        height: 140px;
+        object-fit: cover;
+        border-radius: 50%;
+        margin-bottom: .5em;
+    }
     .workout-options {
     	.font-size(13);
@@ -10,11 +17,4 @@
     @media (min-width: @screen-s){
         padding: 2em 6em;
-    }
-    img {
-        width: 140px;
-        height: 140px;
-        object-fit: cover;
-        border-radius: 50%;
-        margin-bottom: .5em;
     }
 	h2 {
@@ -30,8 +30,8 @@
 		}
 	}
-}
-.total-workouts {
-	.font-size(13);
-	font-weight: bold;
+	.workouts {
+		.font-size(18);
+		font-weight: bold;
+	}
 }
 
Index: ow/templates/profile.pt
===================================================================
--- ow/templates/profile.pt	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ ow/templates/profile.pt	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -26,5 +26,5 @@
           <tal:has-nickname tal:condition="context.nickname">
               <tal:nickname tal:content="context.nickname"></tal:nickname>
-          </tal:has-nickname> |
+          </tal:has-nickname> | 
           <span><tal:email tal:content="context.email"></tal:email></span>
         </p>
@@ -60,14 +60,14 @@
              i18n:translate="">change password</a></li>
         </ul>
-      </div>
 
-      <div class="total-workouts">
-        <tal:w tal:replace="context.num_workouts"></tal:w>
-        <tal:t i18n:translate="">workouts</tal:t>
+        <div class="workouts">
+          <tal:w tal:replace="context.num_workouts"></tal:w>
+          <tal:t i18n:translate="">Workouts</tal:t>
+        </div>
       </div>
 
       <div class="month-stats js-month-stats">
         <div class="svg-cotent">
-          <svg width="800" height="180" viewBox="0 0 800 180"></svg>
+          <svg width="600" height="300" viewBox="0 0 600 300"></svg>
         </div>
         <ul class="workout-options filters js-filters">
@@ -76,70 +76,23 @@
           <li><a href="#" class="js-elevation" i18n:translate="">elevation</a></li>
         </ul>
-
-        <ul class="workout-options switcher js-switcher">
-          <li><a href="#" class="js-weekly" i18n:translate="">weekly</a></li>
-          <li><a href="#" class="js-monthly is-active" i18n:translate="">monthly</a></li>
-        </ul>
       </div>
 
+      <div class="latest-workouts">
+        <h3 i18n:translate="">Latest workouts</h3>
+        <tal:r tal:repeat="workout context.workouts()[:5]">
+          <div class="workout">
+            <h4>
+              <a href="" tal:content="workout.title"
+               tal:attributes="href request.resource_url(workout)"></a>
+            </h4>
+            <span><tal:c tal:content="workout.sport"></tal:c></span>
+            <p><tal:c tal:content="workout.start"></tal:c>,
+            <tal:c tal:content="workout.duration"></tal:c>,
+            <tal:c tal:content="workout.rounded_distance"></tal:c> km
+            </p>
+          </div>
+        </tal:r>
+      </div>
 
-      <tal:r tal:repeat="workout workouts">
-
-        <a name="workouts"></a>
-
-
-        <article class="workout-resume">
-
-          <h2 class="workout-title">
-            <a href="" tal:content="workout.title"
-               tal:attributes="href request.resource_url(workout)"></a>
-          </h2>
-
-          <ul class="workout-info">
-            <li>
-              <tal:c tal:content="workout.start_in_timezone(context.timezone)"></tal:c>
-            </li>
-            <li>
-              <!--! use the properly formatted duration instead of the timedelta object -->
-              <tal:c tal:content="workout._duration"></tal:c>
-            </li>
-            <li tal:condition="workout.distance">
-              <tal:c tal:content="workout.rounded_distance"></tal:c> km
-            </li>
-          </ul>
-
-          <ul class="workout-info" tal:define="hr workout.hr; cad workout.cad">
-            <li tal:condition="hr">
-              <span i18n:translate="">HR (bpm)</span>:
-              <tal:c tal:content="hr['min']"></tal:c>
-              <tal:t i18n:translate="">Min.</tal:t>,
-              <tal:c tal:content="hr['avg']"></tal:c>
-              <tal:t i18n:translate="">Avg.</tal:t>,
-              <tal:c tal:content="hr['max']"></tal:c>
-              <tal:t i18n:translate="">Max.</tal:t>
-            </li>
-            <li tal:condition="cad">
-              <span i18n:translate="">Cad</span>:
-              <tal:c tal:content="cad['min']"></tal:c>
-              <tal:t i18n:translate="">Min.</tal:t>,
-              <tal:c tal:content="cad['avg']"></tal:c>
-              <tal:t i18n:translate="">Avg.</tal:t>,
-              <tal:c tal:content="cad['max']"></tal:c>
-              <tal:t i18n:translate="">Max.</tal:t>
-            </li>
-          </ul>
-
-          <div class="workout-intro" tal:content="workout.notes"></div>
-
-          <div class="workout-map" tal:condition="workout.has_gpx">
-            <a href="" tal:attributes="href request.resource_url(workout)">
-              <img src="" tal:attributes="src request.static_url(workout.map_screenshot);
-                        alt workout.title; title workout.title">
-            </a>
-          </div>
-
-        </article>
-
-      </tal:r>
     </div>
 
@@ -161,16 +114,10 @@
          chart_selector: '.js-month-stats svg',
          filters_selector: '.js-month-stats .js-filters a',
-         switcher_selector: '.js-month-stats .js-switcher a',
-         urls: {"monthly": "${request.resource_url(context, 'monthly')}",
-                "weekly": "${request.resource_url(context, 'weekly')}"},
+         url: "${request.resource_url(context, 'yearly')}",
          current_month: "${current_month}",
-         current_week: "${current_week}",
          y_axis_labels: y_axis_labels,
-         filter_by: "distance",
-         url: "${'monthly' if current_week is None else 'weekly'}",
      });
-     year_chart.render("distance", "${'monthly' if current_week is None else 'weekly'}");
+     year_chart.render("distance");
      year_chart.filters_setup();
-     year_chart.switcher_setup();
     </script>
 
Index: ow/tests/views/test_user.py
===================================================================
--- ow/tests/views/test_user.py	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ ow/tests/views/test_user.py	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -267,37 +267,8 @@
         """
         request = dummy_request
-        # profile page for the current day (no workouts avalable)
         response = user_views.profile(john, request)
-        assert len(response.keys()) == 3
+        assert len(response.keys()) == 1
         current_month = datetime.now(timezone.utc).strftime('%Y-%m')
         assert response['current_month'] == current_month
-        assert response['current_week'] is None
-        assert response['workouts'] == []
-        # profile page for a previous date, that has workouts
-        request.GET['year'] = 2015
-        request.GET['month'] = 8
-        response = user_views.profile(john, request)
-        assert len(response.keys()) == 3
-        assert response['current_month'] == '2015-08'
-        assert response['current_week'] is None
-        assert response['workouts'] == john.workouts(2015, 8)
-        # same, passing a week, first on a week without workouts
-        request.GET['year'] = 2015
-        request.GET['month'] = 8
-        request.GET['week'] = 25
-        response = user_views.profile(john, request)
-        assert len(response.keys()) == 3
-        assert response['current_month'] == '2015-08'
-        assert response['current_week'] is 25
-        assert response['workouts'] == []
-        # now in a week with workoutss
-        request.GET['year'] = 2015
-        request.GET['month'] = 8
-        request.GET['week'] = 26
-        response = user_views.profile(john, request)
-        assert len(response.keys()) == 3
-        assert response['current_month'] == '2015-08'
-        assert response['current_week'] is 26
-        assert response['workouts'] == john.workouts(2015, 8)
 
     def test_login_get(self, dummy_request):
Index: ow/utilities.py
===================================================================
--- ow/utilities.py	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ ow/utilities.py	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -2,5 +2,4 @@
 import os
 import logging
-import calendar
 import subprocess
 from datetime import datetime, timedelta
@@ -235,14 +234,2 @@
     week_days = [first_day + timedelta(days=i) for i in range(7)]
     return week_days
-
-
-def get_month_week_number(day):
-    """
-    Given a datetime object (day), return the number of week the day is
-    in the current month (week 1, 2, 3, etc)
-    """
-    weeks = calendar.monthcalendar(day.year, day.month)
-    for week in weeks:
-        if day.day in week:
-            return weeks.index(week)
-    return None
Index: ow/views/user.py
===================================================================
--- ow/views/user.py	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ ow/views/user.py	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -166,12 +166,6 @@
     """
     now = datetime.now(timezone.utc)
-    year = int(request.GET.get('year', now.year))
-    month = int(request.GET.get('month', now.month))
-    week = request.GET.get('week', None)
-    return {
-        'workouts': context.workouts(year, month, week),
-        'current_month': '{year}-{month}'.format(
-            year=str(year), month=str(month).zfill(2)),
-        'current_week': week
+    return {
+        'current_month': now.strftime('%Y-%m')
     }
 
@@ -264,5 +258,5 @@
     context=User,
     permission='view',
-    name='monthly')
+    name='yearly')
 def last_months_stats(context, request):
     """
@@ -286,9 +280,5 @@
             'distance': int(round(stats[month]['distance'])),
             'elevation': int(stats[month]['elevation']),
-            'workouts': stats[month]['workouts'],
-            'url': request.resource_url(
-                context, 'profile',
-                query={'year': str(month[0]), 'month': str(month[1])},
-                anchor='workouts')
+            'workouts': stats[month]['workouts']
         }
         json_stats.append(month_stats)
@@ -296,43 +286,2 @@
                     charset='utf-8',
                     body=json.dumps(json_stats))
-
-
-@view_config(
-    context=User,
-    permission='view',
-    name='weekly')
-def last_weeks_stats(context, request):
-    """
-    Return a json-encoded stream with statistics for the last 12-months, but
-    in a per-week basis
-    """
-    stats = context.weekly_year_stats
-    # this sets which month is 2 times in the stats, once this year, once
-    # the previous year. We will show it a bit different in the UI (showing
-    # the year too to prevent confusion)
-    repeated_month = datetime.now(timezone.utc).date().month
-    json_stats = []
-    for week in stats:
-        hms = timedelta_to_hms(stats[week]['time'])
-        name = month_name[week[1]][:3]
-        if week[1] == repeated_month:
-            name += ' ' + str(week[0])
-        week_stats = {
-            'id': '-'.join(
-                [str(week[0]), str(week[1]).zfill(2), str(week[2])]),
-            'week': str(week[3]),  # the number of week in the current month
-            'name': name,
-            'time': str(hms[0]).zfill(2),
-            'distance': int(round(stats[week]['distance'])),
-            'elevation': int(stats[week]['elevation']),
-            'workouts': stats[week]['workouts'],
-            'url': request.resource_url(
-                context, 'profile',
-                query={'year': str(week[0]),
-                       'month': str(week[1]),
-                       'week': str(week[2])})
-        }
-        json_stats.append(week_stats)
-    return Response(content_type='application/json',
-                    charset='utf-8',
-                    body=json.dumps(json_stats))
Index: setup.py
===================================================================
--- setup.py	(revision 6993c72dd26b4d7afd587ce77eb4d08ed1347caf)
+++ setup.py	(revision bf0153484cfac7dcdb4e1ed456ca276ba5beeb2b)
@@ -21,6 +21,5 @@
     'waitress',
     'repoze.folder',
-    'repoze.catalog @ git+https://github.com/WuShell/repoze.catalog.git@0.8.4'
-    '#egg=repoze.catalog-0.8.4',
+    'repoze.catalog==0.8.4',
     'bcrypt',
     'FormEncode',
@@ -40,4 +39,9 @@
     'pytest-xdist',
     'pytest-codestyle',
+]
+
+dependency_links = [
+    'git+https://github.com/WuShell/repoze.catalog.git@0.8.4'
+    '#egg=repoze.catalog-0.8.4'
 ]
 
@@ -60,4 +64,5 @@
     include_package_data=True,
     zip_safe=False,
+    dependency_links=dependency_links,
     extras_require={
         'testing': tests_require,
