We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Schedule rendering bug when an item is offset from a column spanning item
Given the following setup, the schedule renders incorrectly

Item A - slot A & B, expands over venues 1 & 2
Item B - slot A, venue 3
Item C - slot B, venue 3

Inserting an extra blank item between Item A and Item C in the table

For example

![buggy](https://cloud.githubusercontent.com/assets/642056/18672017/9bab9372-7f46-11e6-9898-0c4c0cc390cb.png)

When the expected outcome is

![fixed](https://cloud.githubusercontent.com/assets/642056/18672028/a9871c1e-7f46-11e6-8c58-dae8fbb2abe7.png)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wafer/schedule/views.py`
Content:
```
1 import datetime
2 
3 from django.views.generic import DetailView, TemplateView
4 
5 from rest_framework import viewsets
6 from rest_framework.permissions import IsAdminUser
7 from wafer.pages.models import Page
8 from wafer.schedule.models import Venue, Slot, Day
9 from wafer.schedule.admin import check_schedule, validate_schedule
10 from wafer.schedule.models import ScheduleItem
11 from wafer.schedule.serializers import ScheduleItemSerializer
12 from wafer.talks.models import ACCEPTED
13 from wafer.talks.models import Talk
14 
15 
16 class ScheduleRow(object):
17     """This is a helpful containter for the schedule view to keep sanity"""
18     def __init__(self, schedule_day, slot):
19         self.schedule_day = schedule_day
20         self.slot = slot
21         self.items = {}
22 
23     def get_sorted_items(self):
24         sorted_items = []
25         for venue in self.schedule_day.venues:
26             if venue in self.items:
27                 sorted_items.append(self.items[venue])
28         return sorted_items
29 
30     def __repr__(self):
31         """Debugging aid"""
32         return '%s - %s' % (self.slot, self.get_sorted_items())
33 
34 
35 class ScheduleDay(object):
36     """A helpful container for information a days in a schedule view."""
37     def __init__(self, day):
38         self.day = day
39         self.venues = list(day.venue_set.all())
40         self.rows = []
41 
42 
43 class VenueView(DetailView):
44     template_name = 'wafer.schedule/venue.html'
45     model = Venue
46 
47 
48 def make_schedule_row(schedule_day, slot, seen_items):
49     """Create a row for the schedule table."""
50     row = ScheduleRow(schedule_day, slot)
51     skip = []
52     expanding = {}
53     all_items = list(slot.scheduleitem_set
54                      .select_related('talk', 'page', 'venue')
55                      .all())
56 
57     for item in all_items:
58         if item in seen_items:
59             # Inc rowspan
60             seen_items[item]['rowspan'] += 1
61             # Note that we need to skip this during colspan checks
62             skip.append(item.venue)
63             continue
64         scheditem = {'item': item, 'rowspan': 1, 'colspan': 1}
65         row.items[item.venue] = scheditem
66         seen_items[item] = scheditem
67         if item.expand:
68             expanding[item.venue] = []
69 
70     empty = []
71     expanding_right = None
72     for venue in schedule_day.venues:
73         if venue in skip:
74             # Nothing to see here
75             continue
76 
77         if venue in expanding:
78             item = row.items[venue]
79             for empty_venue in empty:
80                 row.items.pop(empty_venue)
81                 item['colspan'] += 1
82             empty = []
83             expanding_right = item
84         elif venue in row.items:
85             empty = []
86             expanding_right = None
87         elif expanding_right:
88             expanding_right['colspan'] += 1
89         else:
90             empty.append(venue)
91             row.items[venue] = {'item': None, 'rowspan': 1, 'colspan': 1}
92 
93     return row
94 
95 
96 def generate_schedule(today=None):
97     """Helper function which creates an ordered list of schedule days"""
98     # We create a list of slots and schedule items
99     schedule_days = {}
100     seen_items = {}
101     for slot in Slot.objects.all().order_by('end_time', 'start_time', 'day'):
102         day = slot.get_day()
103         if today and day != today:
104             # Restrict ourselves to only today
105             continue
106         schedule_day = schedule_days.get(day)
107         if schedule_day is None:
108             schedule_day = schedule_days[day] = ScheduleDay(day)
109         row = make_schedule_row(schedule_day, slot, seen_items)
110         schedule_day.rows.append(row)
111     return sorted(schedule_days.values(), key=lambda x: x.day.date)
112 
113 
114 class ScheduleView(TemplateView):
115     template_name = 'wafer.schedule/full_schedule.html'
116 
117     def get_context_data(self, **kwargs):
118         context = super(ScheduleView, self).get_context_data(**kwargs)
119         # Check if the schedule is valid
120         context['active'] = False
121         if not check_schedule():
122             return context
123         context['active'] = True
124         day = self.request.GET.get('day', None)
125         dates = dict([(x.date.strftime('%Y-%m-%d'), x) for x in
126                       Day.objects.all()])
127         # We choose to return the full schedule if given an invalid date
128         day = dates.get(day, None)
129         context['schedule_days'] = generate_schedule(day)
130         return context
131 
132 
133 class ScheduleXmlView(ScheduleView):
134     template_name = 'wafer.schedule/penta_schedule.xml'
135     content_type = 'application/xml'
136 
137 
138 class CurrentView(TemplateView):
139     template_name = 'wafer.schedule/current.html'
140 
141     def _parse_today(self, day):
142         if day is None:
143             day = str(datetime.date.today())
144         dates = dict([(x.date.strftime('%Y-%m-%d'), x) for x in
145                       Day.objects.all()])
146         if day not in dates:
147             return None
148         return ScheduleDay(dates[day])
149 
150     def _parse_time(self, time):
151         now = datetime.datetime.now().time()
152         if time is None:
153             return now
154         try:
155             return datetime.datetime.strptime(time, '%H:%M').time()
156         except ValueError:
157             pass
158         return now
159 
160     def _add_note(self, row, note, overlap_note):
161         for item in row.items.values():
162             if item['rowspan'] == 1:
163                 item['note'] = note
164             else:
165                 # Must overlap with current slot
166                 item['note'] = overlap_note
167 
168     def _current_slots(self, schedule_day, time):
169         today = schedule_day.day
170         cur_slot, prev_slot, next_slot = None, None, None
171         for slot in Slot.objects.all():
172             if slot.get_day() != today:
173                 continue
174             if slot.get_start_time() <= time and slot.end_time > time:
175                 cur_slot = slot
176             elif slot.end_time <= time:
177                 if not prev_slot or prev_slot.end_time < slot.end_time:
178                     prev_slot = slot
179             elif slot.get_start_time() >= time:
180                 if not next_slot or next_slot.end_time > slot.end_time:
181                     next_slot = slot
182         cur_rows = self._current_rows(
183             schedule_day, cur_slot, prev_slot, next_slot)
184         return cur_slot, cur_rows
185 
186     def _current_rows(self, schedule_day, cur_slot, prev_slot, next_slot):
187         seen_items = {}
188         rows = []
189         for slot in (prev_slot, cur_slot, next_slot):
190             if slot:
191                 row = make_schedule_row(schedule_day, slot, seen_items)
192             else:
193                 row = None
194             rows.append(row)
195         # Add styling hints. Needs to be after all the schedule rows are
196         # created so the spans are set correctly
197         if prev_slot:
198             self._add_note(rows[0], 'complete', 'current')
199         if cur_slot:
200             self._add_note(rows[1], 'current', 'current')
201         if next_slot:
202             self._add_note(rows[2], 'forthcoming', 'current')
203         return [r for r in rows if r]
204 
205     def get_context_data(self, **kwargs):
206         context = super(CurrentView, self).get_context_data(**kwargs)
207         # If the schedule is invalid, return a context with active=False
208         context['active'] = False
209         if not check_schedule():
210             return context
211         # The schedule is valid, so add active=True and empty slots
212         context['active'] = True
213         context['slots'] = []
214         # Allow refresh time to be overridden
215         context['refresh'] = self.request.GET.get('refresh', None)
216         # If there are no items scheduled for today, return an empty slots list
217         schedule_day = self._parse_today(self.request.GET.get('day', None))
218         if schedule_day is None:
219             return context
220         context['schedule_day'] = schedule_day
221         # Allow current time to be overridden
222         time = self._parse_time(self.request.GET.get('time', None))
223 
224         cur_slot, current_rows = self._current_slots(schedule_day, time)
225         context['cur_slot'] = cur_slot
226         context['slots'].extend(current_rows)
227 
228         return context
229 
230 
231 class ScheduleItemViewSet(viewsets.ModelViewSet):
232     """
233     API endpoint that allows groups to be viewed or edited.
234     """
235     queryset = ScheduleItem.objects.all()
236     serializer_class = ScheduleItemSerializer
237     permission_classes = (IsAdminUser, )
238 
239 
240 class ScheduleEditView(TemplateView):
241     template_name = 'wafer.schedule/edit_schedule.html'
242 
243     def _slot_context(self, slot, venues):
244         slot_context = {
245             'name': slot.name,
246             'start_time': slot.get_start_time(),
247             'end_time': slot.end_time,
248             'id': slot.id,
249             'venues': []
250         }
251         for venue in venues:
252             venue_context = {
253                 'name': venue.name,
254                 'id': venue.id,
255             }
256             for schedule_item in slot.scheduleitem_set.all():
257                 if schedule_item.venue.name == venue.name:
258                     venue_context['scheduleitem_id'] = schedule_item.id
259                     if schedule_item.talk:
260                         talk = schedule_item.talk
261                         venue_context['title'] = talk.title
262                         venue_context['talk'] = talk
263                     if (schedule_item.page and
264                             not schedule_item.page.exclude_from_static):
265                         page = schedule_item.page
266                         venue_context['title'] = page.name
267                         venue_context['page'] = page
268             slot_context['venues'].append(venue_context)
269         return slot_context
270 
271     def get_context_data(self, day_id=None, **kwargs):
272         context = super(ScheduleEditView, self).get_context_data(**kwargs)
273 
274         days = Day.objects.all()
275         if day_id:
276             day = days.get(id=day_id)
277         else:
278             day = days.first()
279 
280         accepted_talks = Talk.objects.filter(status=ACCEPTED)
281         venues = Venue.objects.filter(days__in=[day])
282         slots = Slot.objects.all().select_related(
283             'day', 'previous_slot').prefetch_related(
284             'scheduleitem_set', 'slot_set').order_by(
285                 'end_time', 'start_time', 'day')
286         aggregated_slots = []
287 
288         for slot in slots:
289             if day != slot.get_day():
290                 continue
291             aggregated_slots.append(self._slot_context(slot, venues))
292 
293         context['day'] = day
294         context['venues'] = venues
295         context['slots'] = aggregated_slots
296         context['talks_all'] = accepted_talks
297         context['talks_unassigned'] = accepted_talks.filter(scheduleitem=None)
298         context['pages'] = Page.objects.all()
299         context['days'] = days
300         context['validation_errors'] = validate_schedule()
301         return context
302
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/wafer/schedule/views.py b/wafer/schedule/views.py
--- a/wafer/schedule/views.py
+++ b/wafer/schedule/views.py
@@ -48,7 +48,7 @@
 def make_schedule_row(schedule_day, slot, seen_items):
     """Create a row for the schedule table."""
     row = ScheduleRow(schedule_day, slot)
-    skip = []
+    skip = {}
     expanding = {}
     all_items = list(slot.scheduleitem_set
                      .select_related('talk', 'page', 'venue')
@@ -59,7 +59,7 @@
             # Inc rowspan
             seen_items[item]['rowspan'] += 1
             # Note that we need to skip this during colspan checks
-            skip.append(item.venue)
+            skip[item.venue] = seen_items[item]
             continue
         scheditem = {'item': item, 'rowspan': 1, 'colspan': 1}
         row.items[item.venue] = scheditem
@@ -69,11 +69,14 @@
 
     empty = []
     expanding_right = None
+    skipping = 0
+    skip_item = None
     for venue in schedule_day.venues:
         if venue in skip:
-            # Nothing to see here
+            # We need to skip all the venues this item spans over
+            skipping = 1
+            skip_item = skip[venue]
             continue
-
         if venue in expanding:
             item = row.items[venue]
             for empty_venue in empty:
@@ -86,7 +89,10 @@
             expanding_right = None
         elif expanding_right:
             expanding_right['colspan'] += 1
+        elif skipping > 0 and skipping < skip_item['colspan']:
+            skipping += 1
         else:
+            skipping = 0
             empty.append(venue)
             row.items[venue] = {'item': None, 'rowspan': 1, 'colspan': 1}

{"golden_diff": "diff --git a/wafer/schedule/views.py b/wafer/schedule/views.py\n--- a/wafer/schedule/views.py\n+++ b/wafer/schedule/views.py\n@@ -48,7 +48,7 @@\n def make_schedule_row(schedule_day, slot, seen_items):\n     \"\"\"Create a row for the schedule table.\"\"\"\n     row = ScheduleRow(schedule_day, slot)\n-    skip = []\n+    skip = {}\n     expanding = {}\n     all_items = list(slot.scheduleitem_set\n                      .select_related('talk', 'page', 'venue')\n@@ -59,7 +59,7 @@\n             # Inc rowspan\n             seen_items[item]['rowspan'] += 1\n             # Note that we need to skip this during colspan checks\n-            skip.append(item.venue)\n+            skip[item.venue] = seen_items[item]\n             continue\n         scheditem = {'item': item, 'rowspan': 1, 'colspan': 1}\n         row.items[item.venue] = scheditem\n@@ -69,11 +69,14 @@\n \n     empty = []\n     expanding_right = None\n+    skipping = 0\n+    skip_item = None\n     for venue in schedule_day.venues:\n         if venue in skip:\n-            # Nothing to see here\n+            # We need to skip all the venues this item spans over\n+            skipping = 1\n+            skip_item = skip[venue]\n             continue\n-\n         if venue in expanding:\n             item = row.items[venue]\n             for empty_venue in empty:\n@@ -86,7 +89,10 @@\n             expanding_right = None\n         elif expanding_right:\n             expanding_right['colspan'] += 1\n+        elif skipping > 0 and skipping < skip_item['colspan']:\n+            skipping += 1\n         else:\n+            skipping = 0\n             empty.append(venue)\n             row.items[venue] = {'item': None, 'rowspan': 1, 'colspan': 1}\n", "issue": "Schedule rendering bug when an item is offset from a column spanning item\nGiven the following setup, the schedule renders incorrectly\n\nItem A - slot A & B, expands over venues 1 & 2\nItem B - slot A, venue 3\nItem C - slot B, venue 3\n\nInserting an extra blank item between Item A and Item C in the table\n\nFor example\n\n![buggy](https://cloud.githubusercontent.com/assets/642056/18672017/9bab9372-7f46-11e6-9898-0c4c0cc390cb.png)\n\nWhen the expected outcome is\n\n![fixed](https://cloud.githubusercontent.com/assets/642056/18672028/a9871c1e-7f46-11e6-8c58-dae8fbb2abe7.png)\n\n", "before_files": [{"content": "import datetime\n\nfrom django.views.generic import DetailView, TemplateView\n\nfrom rest_framework import viewsets\nfrom rest_framework.permissions import IsAdminUser\nfrom wafer.pages.models import Page\nfrom wafer.schedule.models import Venue, Slot, Day\nfrom wafer.schedule.admin import check_schedule, validate_schedule\nfrom wafer.schedule.models import ScheduleItem\nfrom wafer.schedule.serializers import ScheduleItemSerializer\nfrom wafer.talks.models import ACCEPTED\nfrom wafer.talks.models import Talk\n\n\nclass ScheduleRow(object):\n    \"\"\"This is a helpful containter for the schedule view to keep sanity\"\"\"\n    def __init__(self, schedule_day, slot):\n        self.schedule_day = schedule_day\n        self.slot = slot\n        self.items = {}\n\n    def get_sorted_items(self):\n        sorted_items = []\n        for venue in self.schedule_day.venues:\n            if venue in self.items:\n                sorted_items.append(self.items[venue])\n        return sorted_items\n\n    def __repr__(self):\n        \"\"\"Debugging aid\"\"\"\n        return '%s - %s' % (self.slot, self.get_sorted_items())\n\n\nclass ScheduleDay(object):\n    \"\"\"A helpful container for information a days in a schedule view.\"\"\"\n    def __init__(self, day):\n        self.day = day\n        self.venues = list(day.venue_set.all())\n        self.rows = []\n\n\nclass VenueView(DetailView):\n    template_name = 'wafer.schedule/venue.html'\n    model = Venue\n\n\ndef make_schedule_row(schedule_day, slot, seen_items):\n    \"\"\"Create a row for the schedule table.\"\"\"\n    row = ScheduleRow(schedule_day, slot)\n    skip = []\n    expanding = {}\n    all_items = list(slot.scheduleitem_set\n                     .select_related('talk', 'page', 'venue')\n                     .all())\n\n    for item in all_items:\n        if item in seen_items:\n            # Inc rowspan\n            seen_items[item]['rowspan'] += 1\n            # Note that we need to skip this during colspan checks\n            skip.append(item.venue)\n            continue\n        scheditem = {'item': item, 'rowspan': 1, 'colspan': 1}\n        row.items[item.venue] = scheditem\n        seen_items[item] = scheditem\n        if item.expand:\n            expanding[item.venue] = []\n\n    empty = []\n    expanding_right = None\n    for venue in schedule_day.venues:\n        if venue in skip:\n            # Nothing to see here\n            continue\n\n        if venue in expanding:\n            item = row.items[venue]\n            for empty_venue in empty:\n                row.items.pop(empty_venue)\n                item['colspan'] += 1\n            empty = []\n            expanding_right = item\n        elif venue in row.items:\n            empty = []\n            expanding_right = None\n        elif expanding_right:\n            expanding_right['colspan'] += 1\n        else:\n            empty.append(venue)\n            row.items[venue] = {'item': None, 'rowspan': 1, 'colspan': 1}\n\n    return row\n\n\ndef generate_schedule(today=None):\n    \"\"\"Helper function which creates an ordered list of schedule days\"\"\"\n    # We create a list of slots and schedule items\n    schedule_days = {}\n    seen_items = {}\n    for slot in Slot.objects.all().order_by('end_time', 'start_time', 'day'):\n        day = slot.get_day()\n        if today and day != today:\n            # Restrict ourselves to only today\n            continue\n        schedule_day = schedule_days.get(day)\n        if schedule_day is None:\n            schedule_day = schedule_days[day] = ScheduleDay(day)\n        row = make_schedule_row(schedule_day, slot, seen_items)\n        schedule_day.rows.append(row)\n    return sorted(schedule_days.values(), key=lambda x: x.day.date)\n\n\nclass ScheduleView(TemplateView):\n    template_name = 'wafer.schedule/full_schedule.html'\n\n    def get_context_data(self, **kwargs):\n        context = super(ScheduleView, self).get_context_data(**kwargs)\n        # Check if the schedule is valid\n        context['active'] = False\n        if not check_schedule():\n            return context\n        context['active'] = True\n        day = self.request.GET.get('day', None)\n        dates = dict([(x.date.strftime('%Y-%m-%d'), x) for x in\n                      Day.objects.all()])\n        # We choose to return the full schedule if given an invalid date\n        day = dates.get(day, None)\n        context['schedule_days'] = generate_schedule(day)\n        return context\n\n\nclass ScheduleXmlView(ScheduleView):\n    template_name = 'wafer.schedule/penta_schedule.xml'\n    content_type = 'application/xml'\n\n\nclass CurrentView(TemplateView):\n    template_name = 'wafer.schedule/current.html'\n\n    def _parse_today(self, day):\n        if day is None:\n            day = str(datetime.date.today())\n        dates = dict([(x.date.strftime('%Y-%m-%d'), x) for x in\n                      Day.objects.all()])\n        if day not in dates:\n            return None\n        return ScheduleDay(dates[day])\n\n    def _parse_time(self, time):\n        now = datetime.datetime.now().time()\n        if time is None:\n            return now\n        try:\n            return datetime.datetime.strptime(time, '%H:%M').time()\n        except ValueError:\n            pass\n        return now\n\n    def _add_note(self, row, note, overlap_note):\n        for item in row.items.values():\n            if item['rowspan'] == 1:\n                item['note'] = note\n            else:\n                # Must overlap with current slot\n                item['note'] = overlap_note\n\n    def _current_slots(self, schedule_day, time):\n        today = schedule_day.day\n        cur_slot, prev_slot, next_slot = None, None, None\n        for slot in Slot.objects.all():\n            if slot.get_day() != today:\n                continue\n            if slot.get_start_time() <= time and slot.end_time > time:\n                cur_slot = slot\n            elif slot.end_time <= time:\n                if not prev_slot or prev_slot.end_time < slot.end_time:\n                    prev_slot = slot\n            elif slot.get_start_time() >= time:\n                if not next_slot or next_slot.end_time > slot.end_time:\n                    next_slot = slot\n        cur_rows = self._current_rows(\n            schedule_day, cur_slot, prev_slot, next_slot)\n        return cur_slot, cur_rows\n\n    def _current_rows(self, schedule_day, cur_slot, prev_slot, next_slot):\n        seen_items = {}\n        rows = []\n        for slot in (prev_slot, cur_slot, next_slot):\n            if slot:\n                row = make_schedule_row(schedule_day, slot, seen_items)\n            else:\n                row = None\n            rows.append(row)\n        # Add styling hints. Needs to be after all the schedule rows are\n        # created so the spans are set correctly\n        if prev_slot:\n            self._add_note(rows[0], 'complete', 'current')\n        if cur_slot:\n            self._add_note(rows[1], 'current', 'current')\n        if next_slot:\n            self._add_note(rows[2], 'forthcoming', 'current')\n        return [r for r in rows if r]\n\n    def get_context_data(self, **kwargs):\n        context = super(CurrentView, self).get_context_data(**kwargs)\n        # If the schedule is invalid, return a context with active=False\n        context['active'] = False\n        if not check_schedule():\n            return context\n        # The schedule is valid, so add active=True and empty slots\n        context['active'] = True\n        context['slots'] = []\n        # Allow refresh time to be overridden\n        context['refresh'] = self.request.GET.get('refresh', None)\n        # If there are no items scheduled for today, return an empty slots list\n        schedule_day = self._parse_today(self.request.GET.get('day', None))\n        if schedule_day is None:\n            return context\n        context['schedule_day'] = schedule_day\n        # Allow current time to be overridden\n        time = self._parse_time(self.request.GET.get('time', None))\n\n        cur_slot, current_rows = self._current_slots(schedule_day, time)\n        context['cur_slot'] = cur_slot\n        context['slots'].extend(current_rows)\n\n        return context\n\n\nclass ScheduleItemViewSet(viewsets.ModelViewSet):\n    \"\"\"\n    API endpoint that allows groups to be viewed or edited.\n    \"\"\"\n    queryset = ScheduleItem.objects.all()\n    serializer_class = ScheduleItemSerializer\n    permission_classes = (IsAdminUser, )\n\n\nclass ScheduleEditView(TemplateView):\n    template_name = 'wafer.schedule/edit_schedule.html'\n\n    def _slot_context(self, slot, venues):\n        slot_context = {\n            'name': slot.name,\n            'start_time': slot.get_start_time(),\n            'end_time': slot.end_time,\n            'id': slot.id,\n            'venues': []\n        }\n        for venue in venues:\n            venue_context = {\n                'name': venue.name,\n                'id': venue.id,\n            }\n            for schedule_item in slot.scheduleitem_set.all():\n                if schedule_item.venue.name == venue.name:\n                    venue_context['scheduleitem_id'] = schedule_item.id\n                    if schedule_item.talk:\n                        talk = schedule_item.talk\n                        venue_context['title'] = talk.title\n                        venue_context['talk'] = talk\n                    if (schedule_item.page and\n                            not schedule_item.page.exclude_from_static):\n                        page = schedule_item.page\n                        venue_context['title'] = page.name\n                        venue_context['page'] = page\n            slot_context['venues'].append(venue_context)\n        return slot_context\n\n    def get_context_data(self, day_id=None, **kwargs):\n        context = super(ScheduleEditView, self).get_context_data(**kwargs)\n\n        days = Day.objects.all()\n        if day_id:\n            day = days.get(id=day_id)\n        else:\n            day = days.first()\n\n        accepted_talks = Talk.objects.filter(status=ACCEPTED)\n        venues = Venue.objects.filter(days__in=[day])\n        slots = Slot.objects.all().select_related(\n            'day', 'previous_slot').prefetch_related(\n            'scheduleitem_set', 'slot_set').order_by(\n                'end_time', 'start_time', 'day')\n        aggregated_slots = []\n\n        for slot in slots:\n            if day != slot.get_day():\n                continue\n            aggregated_slots.append(self._slot_context(slot, venues))\n\n        context['day'] = day\n        context['venues'] = venues\n        context['slots'] = aggregated_slots\n        context['talks_all'] = accepted_talks\n        context['talks_unassigned'] = accepted_talks.filter(scheduleitem=None)\n        context['pages'] = Page.objects.all()\n        context['days'] = days\n        context['validation_errors'] = validate_schedule()\n        return context\n", "path": "wafer/schedule/views.py"}], "after_files": [{"content": "import datetime\n\nfrom django.views.generic import DetailView, TemplateView\n\nfrom rest_framework import viewsets\nfrom rest_framework.permissions import IsAdminUser\nfrom wafer.pages.models import Page\nfrom wafer.schedule.models import Venue, Slot, Day\nfrom wafer.schedule.admin import check_schedule, validate_schedule\nfrom wafer.schedule.models import ScheduleItem\nfrom wafer.schedule.serializers import ScheduleItemSerializer\nfrom wafer.talks.models import ACCEPTED\nfrom wafer.talks.models import Talk\n\n\nclass ScheduleRow(object):\n    \"\"\"This is a helpful containter for the schedule view to keep sanity\"\"\"\n    def __init__(self, schedule_day, slot):\n        self.schedule_day = schedule_day\n        self.slot = slot\n        self.items = {}\n\n    def get_sorted_items(self):\n        sorted_items = []\n        for venue in self.schedule_day.venues:\n            if venue in self.items:\n                sorted_items.append(self.items[venue])\n        return sorted_items\n\n    def __repr__(self):\n        \"\"\"Debugging aid\"\"\"\n        return '%s - %s' % (self.slot, self.get_sorted_items())\n\n\nclass ScheduleDay(object):\n    \"\"\"A helpful container for information a days in a schedule view.\"\"\"\n    def __init__(self, day):\n        self.day = day\n        self.venues = list(day.venue_set.all())\n        self.rows = []\n\n\nclass VenueView(DetailView):\n    template_name = 'wafer.schedule/venue.html'\n    model = Venue\n\n\ndef make_schedule_row(schedule_day, slot, seen_items):\n    \"\"\"Create a row for the schedule table.\"\"\"\n    row = ScheduleRow(schedule_day, slot)\n    skip = {}\n    expanding = {}\n    all_items = list(slot.scheduleitem_set\n                     .select_related('talk', 'page', 'venue')\n                     .all())\n\n    for item in all_items:\n        if item in seen_items:\n            # Inc rowspan\n            seen_items[item]['rowspan'] += 1\n            # Note that we need to skip this during colspan checks\n            skip[item.venue] = seen_items[item]\n            continue\n        scheditem = {'item': item, 'rowspan': 1, 'colspan': 1}\n        row.items[item.venue] = scheditem\n        seen_items[item] = scheditem\n        if item.expand:\n            expanding[item.venue] = []\n\n    empty = []\n    expanding_right = None\n    skipping = 0\n    skip_item = None\n    for venue in schedule_day.venues:\n        if venue in skip:\n            # We need to skip all the venues this item spans over\n            skipping = 1\n            skip_item = skip[venue]\n            continue\n        if venue in expanding:\n            item = row.items[venue]\n            for empty_venue in empty:\n                row.items.pop(empty_venue)\n                item['colspan'] += 1\n            empty = []\n            expanding_right = item\n        elif venue in row.items:\n            empty = []\n            expanding_right = None\n        elif expanding_right:\n            expanding_right['colspan'] += 1\n        elif skipping > 0 and skipping < skip_item['colspan']:\n            skipping += 1\n        else:\n            skipping = 0\n            empty.append(venue)\n            row.items[venue] = {'item': None, 'rowspan': 1, 'colspan': 1}\n\n    return row\n\n\ndef generate_schedule(today=None):\n    \"\"\"Helper function which creates an ordered list of schedule days\"\"\"\n    # We create a list of slots and schedule items\n    schedule_days = {}\n    seen_items = {}\n    for slot in Slot.objects.all().order_by('end_time', 'start_time', 'day'):\n        day = slot.get_day()\n        if today and day != today:\n            # Restrict ourselves to only today\n            continue\n        schedule_day = schedule_days.get(day)\n        if schedule_day is None:\n            schedule_day = schedule_days[day] = ScheduleDay(day)\n        row = make_schedule_row(schedule_day, slot, seen_items)\n        schedule_day.rows.append(row)\n    return sorted(schedule_days.values(), key=lambda x: x.day.date)\n\n\nclass ScheduleView(TemplateView):\n    template_name = 'wafer.schedule/full_schedule.html'\n\n    def get_context_data(self, **kwargs):\n        context = super(ScheduleView, self).get_context_data(**kwargs)\n        # Check if the schedule is valid\n        context['active'] = False\n        if not check_schedule():\n            return context\n        context['active'] = True\n        day = self.request.GET.get('day', None)\n        dates = dict([(x.date.strftime('%Y-%m-%d'), x) for x in\n                      Day.objects.all()])\n        # We choose to return the full schedule if given an invalid date\n        day = dates.get(day, None)\n        context['schedule_days'] = generate_schedule(day)\n        return context\n\n\nclass ScheduleXmlView(ScheduleView):\n    template_name = 'wafer.schedule/penta_schedule.xml'\n    content_type = 'application/xml'\n\n\nclass CurrentView(TemplateView):\n    template_name = 'wafer.schedule/current.html'\n\n    def _parse_today(self, day):\n        if day is None:\n            day = str(datetime.date.today())\n        dates = dict([(x.date.strftime('%Y-%m-%d'), x) for x in\n                      Day.objects.all()])\n        if day not in dates:\n            return None\n        return ScheduleDay(dates[day])\n\n    def _parse_time(self, time):\n        now = datetime.datetime.now().time()\n        if time is None:\n            return now\n        try:\n            return datetime.datetime.strptime(time, '%H:%M').time()\n        except ValueError:\n            pass\n        return now\n\n    def _add_note(self, row, note, overlap_note):\n        for item in row.items.values():\n            if item['rowspan'] == 1:\n                item['note'] = note\n            else:\n                # Must overlap with current slot\n                item['note'] = overlap_note\n\n    def _current_slots(self, schedule_day, time):\n        today = schedule_day.day\n        cur_slot, prev_slot, next_slot = None, None, None\n        for slot in Slot.objects.all():\n            if slot.get_day() != today:\n                continue\n            if slot.get_start_time() <= time and slot.end_time > time:\n                cur_slot = slot\n            elif slot.end_time <= time:\n                if not prev_slot or prev_slot.end_time < slot.end_time:\n                    prev_slot = slot\n            elif slot.get_start_time() >= time:\n                if not next_slot or next_slot.end_time > slot.end_time:\n                    next_slot = slot\n        cur_rows = self._current_rows(\n            schedule_day, cur_slot, prev_slot, next_slot)\n        return cur_slot, cur_rows\n\n    def _current_rows(self, schedule_day, cur_slot, prev_slot, next_slot):\n        seen_items = {}\n        rows = []\n        for slot in (prev_slot, cur_slot, next_slot):\n            if slot:\n                row = make_schedule_row(schedule_day, slot, seen_items)\n            else:\n                row = None\n            rows.append(row)\n        # Add styling hints. Needs to be after all the schedule rows are\n        # created so the spans are set correctly\n        if prev_slot:\n            self._add_note(rows[0], 'complete', 'current')\n        if cur_slot:\n            self._add_note(rows[1], 'current', 'current')\n        if next_slot:\n            self._add_note(rows[2], 'forthcoming', 'current')\n        return [r for r in rows if r]\n\n    def get_context_data(self, **kwargs):\n        context = super(CurrentView, self).get_context_data(**kwargs)\n        # If the schedule is invalid, return a context with active=False\n        context['active'] = False\n        if not check_schedule():\n            return context\n        # The schedule is valid, so add active=True and empty slots\n        context['active'] = True\n        context['slots'] = []\n        # Allow refresh time to be overridden\n        context['refresh'] = self.request.GET.get('refresh', None)\n        # If there are no items scheduled for today, return an empty slots list\n        schedule_day = self._parse_today(self.request.GET.get('day', None))\n        if schedule_day is None:\n            return context\n        context['schedule_day'] = schedule_day\n        # Allow current time to be overridden\n        time = self._parse_time(self.request.GET.get('time', None))\n\n        cur_slot, current_rows = self._current_slots(schedule_day, time)\n        context['cur_slot'] = cur_slot\n        context['slots'].extend(current_rows)\n\n        return context\n\n\nclass ScheduleItemViewSet(viewsets.ModelViewSet):\n    \"\"\"\n    API endpoint that allows groups to be viewed or edited.\n    \"\"\"\n    queryset = ScheduleItem.objects.all()\n    serializer_class = ScheduleItemSerializer\n    permission_classes = (IsAdminUser, )\n\n\nclass ScheduleEditView(TemplateView):\n    template_name = 'wafer.schedule/edit_schedule.html'\n\n    def _slot_context(self, slot, venues):\n        slot_context = {\n            'name': slot.name,\n            'start_time': slot.get_start_time(),\n            'end_time': slot.end_time,\n            'id': slot.id,\n            'venues': []\n        }\n        for venue in venues:\n            venue_context = {\n                'name': venue.name,\n                'id': venue.id,\n            }\n            for schedule_item in slot.scheduleitem_set.all():\n                if schedule_item.venue.name == venue.name:\n                    venue_context['scheduleitem_id'] = schedule_item.id\n                    if schedule_item.talk:\n                        talk = schedule_item.talk\n                        venue_context['title'] = talk.title\n                        venue_context['talk'] = talk\n                    if (schedule_item.page and\n                            not schedule_item.page.exclude_from_static):\n                        page = schedule_item.page\n                        venue_context['title'] = page.name\n                        venue_context['page'] = page\n            slot_context['venues'].append(venue_context)\n        return slot_context\n\n    def get_context_data(self, day_id=None, **kwargs):\n        context = super(ScheduleEditView, self).get_context_data(**kwargs)\n\n        days = Day.objects.all()\n        if day_id:\n            day = days.get(id=day_id)\n        else:\n            day = days.first()\n\n        accepted_talks = Talk.objects.filter(status=ACCEPTED)\n        venues = Venue.objects.filter(days__in=[day])\n        slots = Slot.objects.all().select_related(\n            'day', 'previous_slot').prefetch_related(\n            'scheduleitem_set', 'slot_set').order_by(\n                'end_time', 'start_time', 'day')\n        aggregated_slots = []\n\n        for slot in slots:\n            if day != slot.get_day():\n                continue\n            aggregated_slots.append(self._slot_context(slot, venues))\n\n        context['day'] = day\n        context['venues'] = venues\n        context['slots'] = aggregated_slots\n        context['talks_all'] = accepted_talks\n        context['talks_unassigned'] = accepted_talks.filter(scheduleitem=None)\n        context['pages'] = Page.objects.all()\n        context['days'] = days\n        context['validation_errors'] = validate_schedule()\n        return context\n", "path": "wafer/schedule/views.py"}]}