[CalendarServer-changes] [10810] CalendarServer/trunk/calendarserver/tools

source_changes at macosforge.org source_changes at macosforge.org
Tue Feb 26 07:31:16 PST 2013


Revision: 10810
          http://trac.calendarserver.org//changeset/10810
Author:   cdaboo at apple.com
Date:     2013-02-26 07:31:16 -0800 (Tue, 26 Feb 2013)
Log Message:
-----------
Improve double-booking detection to avoid some false positives.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tools/calverify.py
    CalendarServer/trunk/calendarserver/tools/test/test_calverify.py

Modified: CalendarServer/trunk/calendarserver/tools/calverify.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/calverify.py	2013-02-26 15:29:13 UTC (rev 10809)
+++ CalendarServer/trunk/calendarserver/tools/calverify.py	2013-02-26 15:31:16 UTC (rev 10810)
@@ -2021,15 +2021,15 @@
 
         self.output.write("\n---- Scanning calendar data ----\n")
 
+        self.tzid = PyCalendarTimezone(tzid=self.options["tzid"] if self.options["tzid"] else "America/Los_Angeles")
         self.now = PyCalendarDateTime.getNowUTC()
         self.start = PyCalendarDateTime.getToday()
         self.start.setDateOnly(False)
+        self.start.setTimezone(self.tzid)
         self.end = self.start.duplicate()
         self.end.offsetYear(1)
         self.fix = self.options["fix"]
 
-        self.tzid = PyCalendarTimezone(tzid=self.options["tzid"] if self.options["tzid"] else "America/Los_Angeles")
-
         if self.options["verbose"] and self.options["summary"]:
             ot = time.time()
 
@@ -2065,7 +2065,7 @@
             if not record.thisServer() or not record.enabledForCalendaring:
                 continue
 
-            rname = record.shortNames[0]
+            rname = record.fullName
             auto = record.autoSchedule
 
             if len(uuids) > 1 and not self.options["summary"]:
@@ -2116,14 +2116,15 @@
             table.addHeader(("GUID", "Name", "Auto-Schedule", "Double-Booked",))
             doubled = 0
             for item in sorted(self.uuid_details):
+                if not item.doubled:
+                    continue
                 table.addRow((
                     item.uuid,
                     item.rname,
                     item.auto,
                     item.doubled,
                 ))
-                if item.doubled:
-                    doubled += 1
+                doubled += 1
             table.addFooter(("Total", "", "", "%d of %d" % (doubled, len(self.uuid_details),),))
             self.output.write("\n")
             table.printTable(os=self.output)
@@ -2171,7 +2172,7 @@
         if self.options["verbose"]:
             t = time.time()
 
-        InstanceDetails = collections.namedtuple("InstanceDetails", ("resid", "uid", "start", "end",))
+        InstanceDetails = collections.namedtuple("InstanceDetails", ("resid", "uid", "start", "end", "organizer", "summary",))
 
         end = start.duplicate()
         end.offsetDay(int(self.options["days"]))
@@ -2181,6 +2182,8 @@
         booked_instances = 0
         details = []
         rjust = 10
+        tzid = None
+        hasFloating = False
         for resid in rows:
             resid = resid[0]
             caldata = yield self.getCalendar(resid, self.fix)
@@ -2193,7 +2196,7 @@
             cal = Component(None, pycalendar=caldata)
             cal = PerUserDataFilter(uuid).filter(cal)
             uid = cal.resourceUID()
-            instances = cal.expandTimeRanges(end, start, ignoreInvalidInstances=True)
+            instances = cal.expandTimeRanges(end, start, ignoreInvalidInstances=False)
             count += 1
 
             for instance in instances.instances.values():
@@ -2204,8 +2207,12 @@
                     continue
                 if instance.component.propertyValue("TRANSP") == "TRANSPARENT":
                     continue
+                dtstart = instance.component.propertyValue("DTSTART")
+                if tzid is None and dtstart.getTimezoneID():
+                    tzid = PyCalendarTimezone(tzid=dtstart.getTimezoneID())
+                hasFloating |= dtstart.isDateOnly() or dtstart.floating()
 
-                details.append(InstanceDetails(resid, uid, instance.start, instance.end,))
+                details.append(InstanceDetails(resid, uid, instance.start, instance.end, instance.component.getOrganizer(), instance.component.propertyValue("SUMMARY")))
                 booked_instances += 1
 
             if self.options["verbose"] and not self.options["summary"]:
@@ -2241,13 +2248,24 @@
             self.logResult("Number of instances in time-range", total_instances)
             self.logResult("Number of booked instances", booked_instances)
 
+        # Adjust floating and sort
+        if hasFloating and tzid is not None:
+            utc = PyCalendarTimezone(utc=True)
+            for item in details:
+                if item.start.floating():
+                    item.start.setTimezone(tzid)
+                    item.start.adjustTimezone(utc)
+                if item.end.floating():
+                    item.end.setTimezone(tzid)
+                    item.end.adjustTimezone(utc)
+        details.sort(key=lambda x: x.start)
+
         # Now look for double-bookings
         DoubleBookedDetails = collections.namedtuple("DoubleBookedDetails", ("resid1", "uid1", "resid2", "uid2", "start",))
         double_booked = []
-        details.sort(key=lambda x: x.start)
         current = details[0] if details else None
         for next in details[1:]:
-            if current.end > next.start:
+            if current.end > next.start and current.resid != next.resid and not (current.organizer == next.organizer and current.summary == next.summary):
                 dt = next.start.duplicate()
                 dt.adjustTimezone(self.tzid)
                 double_booked.append(DoubleBookedDetails(current.resid, current.uid, next.resid, next.uid, dt,))

Modified: CalendarServer/trunk/calendarserver/tools/test/test_calverify.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_calverify.py	2013-02-26 15:29:13 UTC (rev 10809)
+++ CalendarServer/trunk/calendarserver/tools/test/test_calverify.py	2013-02-26 15:31:16 UTC (rev 10810)
@@ -1884,7 +1884,7 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP_ICS
 TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP_ICS
 DTSTART:%(year)s0307T100000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
@@ -1905,7 +1905,7 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP1_1_ICS
 TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP1_1_ICS
 DTSTART:%(year)s0307T110000Z
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
@@ -1925,7 +1925,7 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP1_2_ICS
 TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP1_2_ICS
 DTSTART:%(year)s0307T120000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
@@ -1946,7 +1946,7 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP2_1_ICS
 TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP2_1_ICS
 DTSTART:%(year)s0307T140000Z
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
@@ -1965,7 +1965,7 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP2_2_ICS
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP2_2_ICS
 DTSTART:%(year)s0307T150000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
@@ -2006,7 +2006,7 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP3_2_ICS
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP3_2_ICS
 DTSTART:%(year)s0307T180000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
@@ -2028,7 +2028,7 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP4_1_ICS
 TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP4_1_ICS
 DTSTART:%(year)s0308T120000Z
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
@@ -2048,7 +2048,7 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP4_2_ICS
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP4_2_ICS
 DTSTART:%(year)s0309T120000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
@@ -2070,7 +2070,7 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP5_1_ICS
 TRANSP:OPAQUE
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP5_1_ICS
 DTSTART:%(year)s0312T120000Z
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
@@ -2090,7 +2090,7 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP5_2_ICS
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP5_2_ICS
 DTSTART:%(year)s0313T140000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
@@ -2103,7 +2103,7 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP5_2_ICS
-SUMMARY:Ancient event
+SUMMARY:INVITE_NO_OVERLAP5_2_ICS
 RECURRENCE-ID:%(year)s0314T140000Z
 DTSTART:%(year)s0314T130000Z
 DURATION:PT1H
@@ -2116,22 +2116,126 @@
 END:VCALENDAR
 """.replace("\n", "\r\n") % {"year": now}
 
+    # Two not overlapping - one all-day
+    INVITE_NO_OVERLAP6_1_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:America/Los_Angeles
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:INVITE_NO_OVERLAP6_1_ICS
+TRANSP:OPAQUE
+SUMMARY:INVITE_NO_OVERLAP6_1_ICS
+DTSTART;TZID=America/Los_Angeles:%(year)s0320T200000
+DURATION:PT2H
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % {"year": now}
+
+    INVITE_NO_OVERLAP6_2_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:INVITE_NO_OVERLAP6_2_ICS
+TRANSP:OPAQUE
+SUMMARY:INVITE_NO_OVERLAP6_2_ICS
+DTSTART;VALUE=DATE:%(year)s0321
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % {"year": now}
+
+    # Two overlapping - same organizer and summary
+    INVITE_NO_OVERLAP7_1_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:INVITE_NO_OVERLAP7_1_ICS
+TRANSP:OPAQUE
+SUMMARY:INVITE_NO_OVERLAP7_1_ICS
+DTSTART:%(year)s0323T110000Z
+DURATION:PT2H
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % {"year": now}
+
+    INVITE_NO_OVERLAP7_2_ICS = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+CREATED:20100303T181216Z
+UID:INVITE_NO_OVERLAP7_2_ICS
+TRANSP:OPAQUE
+SUMMARY:INVITE_NO_OVERLAP7_1_ICS
+DTSTART:%(year)s0323T120000Z
+DURATION:PT1H
+DTSTAMP:20100303T181220Z
+SEQUENCE:2
+ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
+ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % {"year": now}
+
+    allEvents = {
+        "invite1.ics"      : (INVITE_NO_OVERLAP_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite2.ics"      : (INVITE_NO_OVERLAP1_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite3.ics"      : (INVITE_NO_OVERLAP1_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite4.ics"      : (INVITE_NO_OVERLAP2_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite5.ics"      : (INVITE_NO_OVERLAP2_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite6.ics"      : (INVITE_NO_OVERLAP3_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite7.ics"      : (INVITE_NO_OVERLAP3_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite8.ics"      : (INVITE_NO_OVERLAP4_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite9.ics"      : (INVITE_NO_OVERLAP4_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite10.ics"     : (INVITE_NO_OVERLAP5_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite11.ics"     : (INVITE_NO_OVERLAP5_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite12.ics"     : (INVITE_NO_OVERLAP6_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite13.ics"     : (INVITE_NO_OVERLAP6_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite14.ics"     : (INVITE_NO_OVERLAP7_1_ICS, CalVerifyMismatchTestsBase.metadata,),
+        "invite15.ics"     : (INVITE_NO_OVERLAP7_2_ICS, CalVerifyMismatchTestsBase.metadata,),
+    }
+
     requirements = {
         CalVerifyMismatchTestsBase.uuid1 : {
-            "calendar" : {
-                 "invite1.ics"      : (INVITE_NO_OVERLAP_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite2.ics"      : (INVITE_NO_OVERLAP1_1_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite3.ics"      : (INVITE_NO_OVERLAP1_2_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite4.ics"      : (INVITE_NO_OVERLAP2_1_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite5.ics"      : (INVITE_NO_OVERLAP2_2_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite6.ics"      : (INVITE_NO_OVERLAP3_1_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite7.ics"      : (INVITE_NO_OVERLAP3_2_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite8.ics"      : (INVITE_NO_OVERLAP4_1_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite9.ics"      : (INVITE_NO_OVERLAP4_2_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite10.ics"     : (INVITE_NO_OVERLAP5_1_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite11.ics"     : (INVITE_NO_OVERLAP5_2_ICS, CalVerifyMismatchTestsBase.metadata,),
-           },
-           "inbox" : {},
+            "calendar" : allEvents,
+            "inbox" : {},
         },
         CalVerifyMismatchTestsBase.uuid2 : {
             "calendar" : {},
@@ -2142,20 +2246,8 @@
             "inbox" : {},
         },
         CalVerifyMismatchTestsBase.uuidl1 : {
-            "calendar" : {
-                 "invite1.ics"      : (INVITE_NO_OVERLAP_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite2.ics"      : (INVITE_NO_OVERLAP1_1_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite3.ics"      : (INVITE_NO_OVERLAP1_2_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite4.ics"      : (INVITE_NO_OVERLAP2_1_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite5.ics"      : (INVITE_NO_OVERLAP2_2_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite6.ics"      : (INVITE_NO_OVERLAP3_1_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite7.ics"      : (INVITE_NO_OVERLAP3_2_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite8.ics"      : (INVITE_NO_OVERLAP4_1_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite9.ics"      : (INVITE_NO_OVERLAP4_2_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite10.ics"     : (INVITE_NO_OVERLAP5_1_ICS, CalVerifyMismatchTestsBase.metadata,),
-                 "invite11.ics"     : (INVITE_NO_OVERLAP5_2_ICS, CalVerifyMismatchTestsBase.metadata,),
-           },
-           "inbox" : {},
+            "calendar" : allEvents,
+            "inbox" : {},
         },
     }
 
@@ -2207,3 +2299,69 @@
         sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
         self.assertEqual(sync_token_old1, sync_token_new1)
         self.assertEqual(sync_token_oldl1, sync_token_newl1)
+
+
+    def test_instance(self):
+        """
+        CalVerifyService.doScan without fix for mismatches. Make sure it detects
+        as much as it can. Make sure sync-token is not changed.
+        """
+
+        s = """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:America/Los_Angeles
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:4760FF93-C7F8-4EB0-B3E8-0B22A96DB1BC
+DTSTART;TZID=America/Los_Angeles:20130221T170000
+DTEND;TZID=America/Los_Angeles:20130221T180000
+ATTENDEE;CN=Casa Blanca APPLE EMP ONLY (12) DA03 4th;CUTYPE=ROOM;PARTSTAT=
+ ACCEPTED;ROLE=REQ-PARTICIPANT:urn:uuid:366CC7BE-FEF7-4FFF-B713-6B883538A24
+ 9
+ATTENDEE;CN=Mark Chu;CUTYPE=INDIVIDUAL;EMAIL=markchu at apple.com;PARTSTAT=AC
+ CEPTED;ROLE=REQ-PARTICIPANT:urn:uuid:46F9D5D9-08E8-4987-9636-CC796F4093C6
+ATTENDEE;CN=Kristie Phan;CUTYPE=INDIVIDUAL;EMAIL=kristie_phan at apple.com;PA
+ RTSTAT=ACCEPTED:urn:uuid:97E8720F-4364-DBEC-6721-123E9A92B980
+CREATED:20130220T200530Z
+DTSTAMP:20130222T002246Z
+EXDATE:20130228T010000Z
+EXDATE:20130314T000000Z
+EXDATE:20130321T000000Z
+EXDATE:20130327T000000Z
+EXDATE:20130328T000000Z
+EXDATE:20130403T000000Z
+LOCATION:Casa Blanca APPLE EMP ONLY (12) DA03 4th
+ORGANIZER;CN=Kristie Phan;EMAIL=kristie_phan at apple.com;SCHEDULE-STATUS=1.2
+ :urn:uuid:97E8720F-4364-DBEC-6721-123E9A92B980
+RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;WKST=SU
+SEQUENCE:13
+SUMMARY:ESD Daily Meeting
+END:VEVENT
+END:VCALENDAR
+"""
+        from twistedcaldav.ical import Component
+        c = Component.fromString(s)
+        start = PyCalendarDateTime.getToday()
+        start.setDateOnly(False)
+        end = start.duplicate()
+        end.offsetDay(30)
+        config.MaxAllowedInstances = 3000
+        i = c.expandTimeRanges(end, start, ignoreInvalidInstances=True)
+        print i
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130226/54cc0e0a/attachment-0001.html>


More information about the calendarserver-changes mailing list