<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[15127] PyCalendar/branches/rscale</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/15127">15127</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2015-09-14 09:49:28 -0700 (Mon, 14 Sep 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merge from trunk.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#PyCalendarbranchesrscaleREADME">PyCalendar/branches/rscale/README</a></li>
<li><a href="#PyCalendarbranchesrscalesetuppy">PyCalendar/branches/rscale/setup.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendar__init__py">PyCalendar/branches/rscale/src/pycalendar/__init__.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendardatetimepy">PyCalendar/branches/rscale/src/pycalendar/datetime.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendargeovaluepy">PyCalendar/branches/rscale/src/pycalendar/geovalue.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarcalendarpy">PyCalendar/branches/rscale/src/pycalendar/icalendar/calendar.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendardefinitionspy">PyCalendar/branches/rscale/src/pycalendar/icalendar/definitions.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarpropertypy">PyCalendar/branches/rscale/src/pycalendar/icalendar/property.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarrecurrencepy">PyCalendar/branches/rscale/src/pycalendar/icalendar/recurrence.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarrecurrencesetpy">PyCalendar/branches/rscale/src/pycalendar/icalendar/recurrenceset.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarrequeststatusvaluepy">PyCalendar/branches/rscale/src/pycalendar/icalendar/requeststatusvalue.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarteststest_calendarpy">PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_calendar.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarteststest_jsonpy">PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_json.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarteststest_propertypy">PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_property.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarteststest_recurrencepy">PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_recurrence.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarteststest_vpollpy">PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_vpoll.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarvpollpy">PyCalendar/branches/rscale/src/pycalendar/icalendar/vpoll.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendarparserpy">PyCalendar/branches/rscale/src/pycalendar/parser.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendarperiodpy">PyCalendar/branches/rscale/src/pycalendar/period.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendarplaintextvaluepy">PyCalendar/branches/rscale/src/pycalendar/plaintextvalue.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendarpropertypy">PyCalendar/branches/rscale/src/pycalendar/property.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendartimezonepy">PyCalendar/branches/rscale/src/pycalendar/timezone.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendartimezonedbpy">PyCalendar/branches/rscale/src/pycalendar/timezonedb.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendarvalidatorpy">PyCalendar/branches/rscale/src/pycalendar/validator.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendarvcardadrpy">PyCalendar/branches/rscale/src/pycalendar/vcard/adr.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendarvcardnpy">PyCalendar/branches/rscale/src/pycalendar/vcard/n.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendarvcardorgvaluepy">PyCalendar/branches/rscale/src/pycalendar/vcard/orgvalue.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrczonaltzconvertpy">PyCalendar/branches/rscale/src/zonal/tzconvert.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrczonaltzdumppy">PyCalendar/branches/rscale/src/zonal/tzdump.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrczonaltzverifypy">PyCalendar/branches/rscale/src/zonal/tzverify.py</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarexceptionspy">PyCalendar/branches/rscale/src/pycalendar/icalendar/exceptions.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendartestsrrule_examplesjson">PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/rrule_examples.json</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendartestsrscale_examplesjson">PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/rscale_examples.json</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarvotepy">PyCalendar/branches/rscale/src/pycalendar/icalendar/vote.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendaricalendarvvoterpy">PyCalendar/branches/rscale/src/pycalendar/icalendar/vvoter.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendarteststest_geovaluepy">PyCalendar/branches/rscale/src/pycalendar/tests/test_geovalue.py</a></li>
<li><a href="#PyCalendarbranchesrscalesrcpycalendarteststest_periodpy">PyCalendar/branches/rscale/src/pycalendar/tests/test_period.py</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#PyCalendarbranchesrscale">PyCalendar/branches/rscale/</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="PyCalendarbranchesrscale"></a>
<div class="propset"><h4>Property changes: PyCalendar/branches/rscale</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4>Modified: svn:mergeinfo</h4></div>
<span class="cx">/PyCalendar/branches/json-2:11324-11912
</span><span class="cx">/PyCalendar/branches/revised-api-126:10457-10463
</span><span class="cx">/PyCalendar/branches/server:10466-10553
</span><span class="cx">/PyCalendar/trunk:14191
</span><span class="cx">   + /PyCalendar/branches/duplicate-items:10464-10465
</span><span class="cx">/PyCalendar/branches/json-2:11324-11912
</span><span class="cx">/PyCalendar/branches/revised-api-126:10457-10463
</span><span class="cx">/PyCalendar/branches/server:10466-10553
</span><span class="cx">/PyCalendar/trunk:14191,14218-15020
</span><a id="PyCalendarbranchesrscaleREADME"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/README (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/README        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/README        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -7,7 +7,7 @@
</span><span class="cx"> Copyright and License
</span><span class="cx"> =====================
</span><span class="cx"> 
</span><del>-Copyright (c) 2005-2013 Apple Inc.  All rights reserved.
</del><ins>+Copyright (c) 2005-2015 Apple Inc.  All rights reserved.
</ins><span class="cx"> 
</span><span class="cx"> This software is licensed under the Apache License, Version 2.0.  The
</span><span class="cx"> Apache License is a well-established open source license, enabling
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesetuppy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/setup.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/setup.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/setup.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -27,5 +27,6 @@
</span><span class="cx">         'pycalendar',
</span><span class="cx">         'pycalendar.icalendar',
</span><span class="cx">         'pycalendar.vcard',
</span><ins>+        'zonal',
</ins><span class="cx">     ]
</span><span class="cx"> )
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendar__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/__init__.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/__init__.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/__init__.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2015 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> #    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
</span><span class="cx"> #    you may not use this file except in compliance with the License.
</span><span class="lines">@@ -44,8 +44,10 @@
</span><span class="cx"> import icalendar.vfreebusy
</span><span class="cx"> import icalendar.vjournal
</span><span class="cx"> import icalendar.vpoll
</span><ins>+import icalendar.vote
</ins><span class="cx"> import icalendar.vtimezone
</span><span class="cx"> import icalendar.vtimezonedaylight
</span><span class="cx"> import icalendar.vtimezonestandard
</span><span class="cx"> import icalendar.vtodo
</span><span class="cx"> import icalendar.vunknown
</span><ins>+import icalendar.vvoter
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendardatetimepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/datetime.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/datetime.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/datetime.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -50,38 +50,50 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, year=None, month=None, day=None, hours=None, minutes=None, seconds=None, tzid=None, utcoffset=None):
</span><span class="cx"> 
</span><del>-        self.mYear = 1970
-        self.mMonth = 1
-        self.mDay = 1
-
-        self.mHours = 0
-        self.mMinutes = 0
-        self.mSeconds = 0
-
-        self.mDateOnly = False
-
-        self.mTZUTC = False
-        self.mTZID = None
-        self.mTZOffset = None
-
-        self.mPosixTimeCached = False
-        self.mPosixTime = 0
-
</del><span class="cx">         if (year is not None) and (month is not None) and (day is not None):
</span><ins>+
</ins><span class="cx">             self.mYear = year
</span><span class="cx">             self.mMonth = month
</span><span class="cx">             self.mDay = day
</span><ins>+
</ins><span class="cx">             if (hours is not None) and (minutes is not None) and (seconds is not None):
</span><span class="cx">                 self.mHours = hours
</span><span class="cx">                 self.mMinutes = minutes
</span><span class="cx">                 self.mSeconds = seconds
</span><ins>+                self.mDateOnly = False
</ins><span class="cx">             else:
</span><ins>+                self.mHours = 0
+                self.mMinutes = 0
+                self.mSeconds = 0
</ins><span class="cx">                 self.mDateOnly = True
</span><ins>+
</ins><span class="cx">             if tzid:
</span><span class="cx">                 self.mTZUTC = tzid.getUTC()
</span><span class="cx">                 self.mTZID = tzid.getTimezoneID()
</span><ins>+            else:
+                self.mTZUTC = False
+                self.mTZID = None
+            self.mTZOffset = None
</ins><span class="cx"> 
</span><ins>+        else:
+            self.mYear = 1970
+            self.mMonth = 1
+            self.mDay = 1
</ins><span class="cx"> 
</span><ins>+            self.mHours = 0
+            self.mMinutes = 0
+            self.mSeconds = 0
+
+            self.mDateOnly = False
+
+            self.mTZUTC = False
+            self.mTZID = None
+            self.mTZOffset = None
+
+        self.mPosixTimeCached = False
+        self.mPosixTime = 0
+
+
</ins><span class="cx">     def duplicate(self):
</span><span class="cx">         other = DateTime(self.mYear, self.mMonth, self.mDay, self.mHours, self.mMinutes, self.mSeconds)
</span><span class="cx"> 
</span><span class="lines">@@ -194,76 +206,31 @@
</span><span class="cx">             return 1
</span><span class="cx">         # If either are date only, then just do date compare
</span><span class="cx">         if self.mDateOnly or comp.mDateOnly:
</span><del>-            if self.mYear == comp.mYear:
-                if self.mMonth == comp.mMonth:
-                    if self.mDay == comp.mDay:
-                        return 0
-                    else:
-                        if self.mDay &lt; comp.mDay:
-                            return -1
-                        else:
-                            return 1
-                else:
-                    if self.mMonth &lt; comp.mMonth:
-                        return -1
-                    else:
-                        return 1
-            else:
-                if self.mYear &lt; comp.mYear:
-                    return -1
-                else:
-                    return 1
</del><ins>+            c = cmp(self.mYear, comp.mYear)
+            if c == 0:
+                c = cmp(self.mMonth, comp.mMonth)
+                if c == 0:
+                    c = cmp(self.mDay, comp.mDay)
+            return c
</ins><span class="cx"> 
</span><span class="cx">         # If they have the same timezone do simple compare - no posix calc
</span><span class="cx">         # needed
</span><span class="cx">         elif (Timezone.same(self.mTZUTC, self.mTZID, comp.mTZUTC, comp.mTZID)):
</span><del>-            if self.mYear == comp.mYear:
-                if self.mMonth == comp.mMonth:
-                    if self.mDay == comp.mDay:
-                        if self.mHours == comp.mHours:
-                            if self.mMinutes == comp.mMinutes:
-                                if self.mSeconds == comp.mSeconds:
-                                    return 0
-                                else:
-                                    if self.mSeconds &lt; comp.mSeconds:
-                                        return -1
-                                    else:
-                                        return 1
-                            else:
-                                if self.mMinutes &lt; comp.mMinutes:
-                                    return -1
-                                else:
-                                    return 1
-                        else:
-                            if self.mHours &lt; comp.mHours:
-                                return -1
-                            else:
-                                return 1
-                    else:
-                        if self.mDay &lt; comp.mDay:
-                            return -1
-                        else:
-                            return 1
-                else:
-                    if self.mMonth &lt; comp.mMonth:
-                        return -1
-                    else:
-                        return 1
-            else:
-                if self.mYear &lt; comp.mYear:
-                    return -1
-                else:
-                    return 1
</del><ins>+            c = cmp(self.mYear, comp.mYear)
+            if c == 0:
+                c = cmp(self.mMonth, comp.mMonth)
+                if c == 0:
+                    c = cmp(self.mDay, comp.mDay)
+                    if c == 0:
+                        c = cmp(self.mHours, comp.mHours)
+                        if c == 0:
+                            c = cmp(self.mMinutes, comp.mMinutes)
+                            if c == 0:
+                                c = cmp(self.mSeconds, comp.mSeconds)
+            return c
+
</ins><span class="cx">         else:
</span><del>-            posix1 = self.getPosixTime()
-            posix2 = comp.getPosixTime()
-            if posix1 == posix2:
-                return 0
-            else:
-                if posix1 &lt; posix2:
-                    return -1
-                else:
-                    return 1
</del><ins>+            return cmp(self.getPosixTime(), comp.getPosixTime())
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def compareDate(self, comp):
</span><span class="lines">@@ -872,11 +839,11 @@
</span><span class="cx">             self.changed()
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def getLocaleDate(self, locale):
</del><ins>+    def getLocaleDate(self, dateTimeFormat):
</ins><span class="cx"> 
</span><span class="cx">         buf = StringIO.StringIO()
</span><span class="cx"> 
</span><del>-        if locale == DateTime.FULLDATE:
</del><ins>+        if dateTimeFormat == DateTime.FULLDATE:
</ins><span class="cx">             buf.write(locale.getDay(self.getDayOfWeek(), locale.LONG))
</span><span class="cx">             buf.write(&quot;, &quot;)
</span><span class="cx">             buf.write(locale.getMonth(self.mMonth, locale.LONG))
</span><span class="lines">@@ -884,7 +851,7 @@
</span><span class="cx">             buf.write(str(self.mDay))
</span><span class="cx">             buf.write(&quot;, &quot;)
</span><span class="cx">             buf.write(str(self.mYear))
</span><del>-        elif locale == DateTime.ABBREVDATE:
</del><ins>+        elif dateTimeFormat == DateTime.ABBREVDATE:
</ins><span class="cx">             buf.write(locale.getDay(self.getDayOfWeek(), locale.SHORT))
</span><span class="cx">             buf.write(&quot;, &quot;)
</span><span class="cx">             buf.write(locale.getMonth(self.mMonth, locale.SHORT))
</span><span class="lines">@@ -892,25 +859,25 @@
</span><span class="cx">             buf.write(str(self.mDay))
</span><span class="cx">             buf.write(&quot;, &quot;)
</span><span class="cx">             buf.write(str(self.mYear))
</span><del>-        elif locale == DateTime.NUMERICDATE:
</del><ins>+        elif dateTimeFormat == DateTime.NUMERICDATE:
</ins><span class="cx">             buf.write(str(self.mMonth))
</span><span class="cx">             buf.write(&quot;/&quot;)
</span><span class="cx">             buf.write(str(self.mDay))
</span><span class="cx">             buf.write(&quot;/&quot;)
</span><span class="cx">             buf.write(str(self.mYear))
</span><del>-        elif locale == DateTime.FULLDATENOYEAR:
</del><ins>+        elif dateTimeFormat == DateTime.FULLDATENOYEAR:
</ins><span class="cx">             buf.write(locale.getDay(self.getDayOfWeek(), locale.LONG))
</span><span class="cx">             buf.write(&quot;, &quot;)
</span><span class="cx">             buf.write(locale.getMonth(self.mMonth, locale.LONG))
</span><span class="cx">             buf.write(&quot; &quot;)
</span><span class="cx">             buf.write(str(self.mDay))
</span><del>-        elif locale == DateTime.ABBREVDATENOYEAR:
</del><ins>+        elif dateTimeFormat == DateTime.ABBREVDATENOYEAR:
</ins><span class="cx">             buf.write(locale.getDay(self. getDayOfWeek(), locale.SHORT))
</span><span class="cx">             buf.write(&quot;, &quot;)
</span><span class="cx">             buf.write(locale.getMonth(self.mMonth, locale.SHORT))
</span><span class="cx">             buf.write(&quot; &quot;)
</span><span class="cx">             buf.write(str(self.mDay))
</span><del>-        elif locale == DateTime.NUMERICDATENOYEAR:
</del><ins>+        elif dateTimeFormat == DateTime.NUMERICDATENOYEAR:
</ins><span class="cx">             buf.write(str(self.mMonth))
</span><span class="cx">             buf.write(&quot;/&quot;)
</span><span class="cx">             buf.write(str(self.mDay))
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendargeovaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/geovalue.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/geovalue.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/geovalue.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -52,7 +52,13 @@
</span><span class="cx">         try:
</span><span class="cx">             self.mValue = [float(splits[0]), float(splits[1])]
</span><span class="cx">         except ValueError:
</span><del>-            raise InvalidData(&quot;GEO value incorrect&quot;, data)
</del><ins>+            if splits[0][-1] == '\\':
+                try:
+                    self.mValue = [float(splits[0][:-1]), float(splits[1])]
+                except ValueError:
+                    raise InvalidData(&quot;GEO value incorrect&quot;, data)
+            else:
+                raise InvalidData(&quot;GEO value incorrect&quot;, data)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     # os - StringIO object
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarcalendarpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/calendar.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/calendar.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/calendar.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -351,6 +351,80 @@
</span><span class="cx">                 del self.mMasterComponentsByTypeAndUID[component.getType()][uid]
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def deriveComponent(self, recurrenceID):
+        &quot;&quot;&quot;
+        Derive an overridden component for the associated RECURRENCE-ID. This assumes
+        that the R-ID is valid for the actual recurrence being used.
+
+        @param recurrenceID: the recurrence instance
+        @type recurrenceID: L{DateTime}
+
+        @return: the derived component
+        @rtype: L{ComponentRecur} or L{None}
+        &quot;&quot;&quot;
+        master = self.masterComponent()
+        if master is None:
+            return None
+
+        # Create the derived instance
+        newcomp = master.duplicate()
+
+        # Strip out unwanted recurrence properties
+        for propname in (
+            definitions.cICalProperty_RRULE,
+            definitions.cICalProperty_RDATE,
+            definitions.cICalProperty_EXRULE,
+            definitions.cICalProperty_EXDATE,
+            definitions.cICalProperty_RECURRENCE_ID,
+        ):
+            newcomp.removeProperties(propname)
+
+        # New DTSTART is the RECURRENCE-ID we are deriving but adjusted to the
+        # original DTSTART's localtime
+        dtstart = newcomp.getStart()
+        dtend = newcomp.getEnd()
+        oldduration = dtend - dtstart
+
+        newdtstartValue = recurrenceID.duplicate()
+        if not dtstart.isDateOnly():
+            if dtstart.local():
+                newdtstartValue.adjustTimezone(dtstart.getTimezone())
+        else:
+            newdtstartValue.setDateOnly(True)
+
+        newcomp.removeProperties(definitions.cICalProperty_DTSTART)
+        newcomp.removeProperties(definitions.cICalProperty_DTEND)
+        prop = Property(definitions.cICalProperty_DTSTART, newdtstartValue)
+        newcomp.addProperty(prop)
+        if not newcomp.useDuration():
+            prop = Property(definitions.cICalProperty_DTEND, newdtstartValue + oldduration)
+            newcomp.addProperty(prop)
+
+        newcomp.addProperty(Property(&quot;RECURRENCE-ID&quot;, newdtstartValue))
+
+        # After creating/changing a component we need to do this to keep PyCalendar happy
+        newcomp.finalise()
+
+        return newcomp
+
+
+    def masterComponent(self):
+        &quot;&quot;&quot;
+        Return the first sub-component of a recurring type that represents the master
+        instance.
+
+        @return: the master component
+        @rtype: L{ComponentRecur} or L{None}
+        &quot;&quot;&quot;
+        for component in self.getComponents():
+            if isinstance(component, ComponentRecur):
+                rid = component.getRecurrenceID()
+                if rid is None:
+                    return component
+        else:
+            return None
+
+
</ins><span class="cx">     def getText(self, includeTimezones=None, format=None):
</span><span class="cx"> 
</span><span class="cx">         if format is None or format == self.sFormatText:
</span><span class="lines">@@ -382,10 +456,10 @@
</span><span class="cx">         return root
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def getTextJSON(self, includeTimezones=None):
</del><ins>+    def getTextJSON(self, includeTimezones=None, sort_keys=False):
</ins><span class="cx">         jobject = []
</span><span class="cx">         self.writeJSON(jobject, includeTimezones)
</span><del>-        return json.dumps(jobject[0], indent=2, separators=(',', ':'))
</del><ins>+        return json.dumps(jobject[0], indent=2, separators=(',', ':'), sort_keys=sort_keys)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def writeJSON(self, jobject, includeTimezones=None):
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendardefinitionspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/definitions.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/definitions.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/definitions.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2015 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> #    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
</span><span class="cx"> #    you may not use this file except in compliance with the License.
</span><span class="lines">@@ -346,24 +346,27 @@
</span><span class="cx"> cICalProperty_ACTION_NONE = &quot;NONE&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-#    Extensions: draft-york-vpoll-00.txt
</del><ins>+#    Extensions: draft-york-vpoll-03.txt
</ins><span class="cx"> 
</span><del>-#    Section 4.1
-cICalParamater_PUBLIC_COMMENT = &quot;PUBLIC-COMMENT&quot;
-cICalParamater_RESPONSE = &quot;RESPONSE&quot;
</del><ins>+#    Section 4.3
+cICalParamater_REQUIRED = &quot;REQUIRED&quot;
</ins><span class="cx"> cICalParamater_STAY_INFORMED = &quot;STAY-INFORMED&quot;
</span><span class="cx"> 
</span><del>-#    Section 4.2
</del><ins>+#    Section 4.4
</ins><span class="cx"> cICalProperty_ACCEPT_RESPONSE = &quot;ACCEPT-RESPONSE&quot;
</span><ins>+cICalProperty_POLL_COMPLETION = &quot;POLL-COMPLETION&quot;
</ins><span class="cx"> cICalProperty_POLL_ITEM_ID = &quot;POLL-ITEM-ID&quot;
</span><del>-cICalProperty_POLL_WINNER = &quot;POLL-WINNER&quot;
</del><span class="cx"> cICalProperty_POLL_MODE = &quot;POLL-MODE&quot;
</span><span class="cx"> cICalProperty_POLL_MODE_BASIC = &quot;BASIC&quot;
</span><span class="cx"> cICalProperty_POLL_PROPERTIES = &quot;POLL-PROPERTIES&quot;
</span><ins>+cICalProperty_POLL_WINNER = &quot;POLL-WINNER&quot;
+cICalProperty_RESPONSE = &quot;RESPONSE&quot;
</ins><span class="cx"> cICalProperty_VOTER = &quot;VOTER&quot;
</span><span class="cx"> 
</span><del>-#    Section 4.3
</del><ins>+#    Section 4.5
</ins><span class="cx"> cICalComponent_VPOLL = &quot;VPOLL&quot;
</span><ins>+cICalComponent_VVOTER = &quot;VVOTER&quot;
+cICalComponent_VOTE = &quot;VOTE&quot;
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> #     Mulberry extensions
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarexceptionspyfromrev15020PyCalendartrunksrcpycalendaricalendarexceptionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/branches/rscale/src/pycalendar/icalendar/exceptions.py (from rev 15020, PyCalendar/trunk/src/pycalendar/icalendar/exceptions.py) (0 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/exceptions.py                                (rev 0)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/exceptions.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+##
+#    Copyright (c) 2015 Cyrus Daboo. All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+##
+
+from pycalendar.exceptions import ErrorBase
+
+class TooManyInstancesError(ErrorBase):
+    pass
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarpropertypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/property.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/property.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/property.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2015 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> #    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
</span><span class="cx"> #    you may not use this file except in compliance with the License.
</span><span class="lines">@@ -105,10 +105,12 @@
</span><span class="cx">         # Extensions: draft-york-vpoll-00.txt
</span><span class="cx">         # Section 4.2
</span><span class="cx">         definitions.cICalProperty_ACCEPT_RESPONSE   : Value.VALUETYPE_TEXT,
</span><del>-        definitions.cICalProperty_POLL_ITEM_ID      : Value.VALUETYPE_TEXT,
-        definitions.cICalProperty_POLL_WINNER       : Value.VALUETYPE_TEXT,
</del><ins>+        definitions.cICalProperty_POLL_COMPLETION   : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_POLL_ITEM_ID      : Value.VALUETYPE_INTEGER,
</ins><span class="cx">         definitions.cICalProperty_POLL_MODE         : Value.VALUETYPE_TEXT,
</span><span class="cx">         definitions.cICalProperty_POLL_PROPERTIES   : Value.VALUETYPE_TEXT,
</span><ins>+        definitions.cICalProperty_POLL_WINNER       : Value.VALUETYPE_INTEGER,
+        definitions.cICalProperty_RESPONSE          : Value.VALUETYPE_INTEGER,
</ins><span class="cx">         definitions.cICalProperty_VOTER             : Value.VALUETYPE_CALADDRESS,
</span><span class="cx"> 
</span><span class="cx">         # Apple Extensions
</span><span class="lines">@@ -193,6 +195,10 @@
</span><span class="cx">         elif isinstance(value, str):
</span><span class="cx">             self._init_attr_value_text(value, valuetype if valuetype else self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_UNKNOWN))
</span><span class="cx"> 
</span><ins>+        elif isinstance(value, unicode):
+            value = value.encode(&quot;utf-8&quot;)
+            self._init_attr_value_text(value, valuetype if valuetype else self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_UNKNOWN))
+
</ins><span class="cx">         elif isinstance(value, DateTime):
</span><span class="cx">             self._init_attr_value_datetime(value)
</span><span class="cx"> 
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarrecurrencepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/recurrence.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/recurrence.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/recurrence.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -17,6 +17,7 @@
</span><span class="cx"> from pycalendar import xmlutils
</span><span class="cx"> from pycalendar.datetime import DateTime
</span><span class="cx"> from pycalendar.icalendar import definitions, xmldefinitions
</span><ins>+from pycalendar.icalendar.exceptions import TooManyInstancesError
</ins><span class="cx"> from pycalendar.period import Period
</span><span class="cx"> from pycalendar.valueutils import ValueMixin
</span><span class="cx"> import cStringIO as StringIO
</span><span class="lines">@@ -385,7 +386,10 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def setByMonth(self, by):
</span><del>-        self._setAndclearIfChanged(&quot;mByMonth&quot;, by[:])
</del><ins>+        # Convert int values in the list to (int, False) L{tuple}'s to match the new API
+        # that includes the leap month indicator
+        items = [(item, False) if isinstance(item, int) else item for item in by]
+        self._setAndclearIfChanged(&quot;mByMonth&quot;, items)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getByMonthDay(self):
</span><span class="lines">@@ -1013,7 +1017,7 @@
</span><span class="cx">         return result
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def expand(self, start, range, items, float_offset=0):
</del><ins>+    def expand(self, start, range, items, float_offset=0, maxInstances=None):
</ins><span class="cx"> 
</span><span class="cx">         # Have to normalize this to be very sure we are starting with a valid date, as otherwise
</span><span class="cx">         # we could end up looping forever when doing recurrence.
</span><span class="lines">@@ -1039,9 +1043,9 @@
</span><span class="cx"> 
</span><span class="cx">             # Simple expansion is one where there is no BYXXX rule part
</span><span class="cx">             if not self.hasBy():
</span><del>-                self.mFullyCached = self.simpleExpand(start, range, self.mRecurrences, float_offset)
</del><ins>+                self.mFullyCached = self.simpleExpand(start, range, self.mRecurrences, float_offset, maxInstances=maxInstances)
</ins><span class="cx">             else:
</span><del>-                self.mFullyCached = self.complexExpand(start, range, self.mRecurrences, float_offset)
</del><ins>+                self.mFullyCached = self.complexExpand(start, range, self.mRecurrences, float_offset, maxInstances=maxInstances)
</ins><span class="cx"> 
</span><span class="cx">             # Set cache values
</span><span class="cx">             self.mCached = True
</span><span class="lines">@@ -1058,7 +1062,7 @@
</span><span class="cx">         return limited
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def simpleExpand(self, start, range, results, float_offset):
</del><ins>+    def simpleExpand(self, start, range, results, float_offset, maxInstances=None):
</ins><span class="cx"> 
</span><span class="cx">         if self.mUseUntil:
</span><span class="cx">             float_until = self.mUntil.duplicate()
</span><span class="lines">@@ -1081,6 +1085,8 @@
</span><span class="cx"> 
</span><span class="cx">             # Add current one to list
</span><span class="cx">             results.append(start_iter)
</span><ins>+            if maxInstances and len(results) &gt; maxInstances:
+                raise TooManyInstancesError(&quot;Too many instances&quot;)
</ins><span class="cx"> 
</span><span class="cx">             # Check limits
</span><span class="cx">             if self.mUseCount:
</span><span class="lines">@@ -1089,7 +1095,7 @@
</span><span class="cx">                     return True
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def complexExpand(self, start, range, results, float_offset):
</del><ins>+    def complexExpand(self, start, range, results, float_offset, maxInstances=None):
</ins><span class="cx"> 
</span><span class="cx">         if self.mUseUntil:
</span><span class="cx">             float_until = self.mUntil.duplicate()
</span><span class="lines">@@ -1129,7 +1135,7 @@
</span><span class="cx">             elif self.mFreq == definitions.eRecurrence_YEARLY:
</span><span class="cx">                 self.generateYearlySet(start_iter, set_items)
</span><span class="cx"> 
</span><del>-            # Ignore if it is invalid
</del><ins>+            # Remove invalid items before BYSETPOS
</ins><span class="cx">             def _invalidMap(dt):
</span><span class="cx">                 dt.invalidSkip(self.effectiveSkip())
</span><span class="cx">                 return dt
</span><span class="lines">@@ -1171,6 +1177,8 @@
</span><span class="cx"> 
</span><span class="cx">                 # Add current one to list
</span><span class="cx">                 results.append(iter)
</span><ins>+                if maxInstances and len(results) &gt; maxInstances:
+                    raise TooManyInstancesError(&quot;Too many instances&quot;)
</ins><span class="cx"> 
</span><span class="cx">                 # Check limits
</span><span class="cx">                 if self.mUseCount:
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarrecurrencesetpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/recurrenceset.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/recurrenceset.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/recurrenceset.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -14,6 +14,7 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><ins>+from pycalendar.icalendar.exceptions import TooManyInstancesError
</ins><span class="cx"> from pycalendar.utils import set_difference
</span><span class="cx"> 
</span><span class="cx"> class RecurrenceSet(object):
</span><span class="lines">@@ -182,7 +183,7 @@
</span><span class="cx">         return self.mExperiods
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def expand(self, start, range, items, float_offset=0):
</del><ins>+    def expand(self, start, range, items, float_offset=0, maxInstances=None):
</ins><span class="cx">         # Need to return whether the limit was applied or not
</span><span class="cx">         limited = False
</span><span class="cx"> 
</span><span class="lines">@@ -197,18 +198,22 @@
</span><span class="cx"> 
</span><span class="cx">         # RRULES
</span><span class="cx">         for iter in self.mRrules:
</span><del>-            if iter.expand(start, range, include, float_offset=float_offset):
</del><ins>+            if iter.expand(start, range, include, float_offset=float_offset, maxInstances=maxInstances):
</ins><span class="cx">                 limited = True
</span><span class="cx"> 
</span><span class="cx">         # RDATES
</span><span class="cx">         for iter in self.mRdates:
</span><span class="cx">             if range.isDateWithinPeriod(iter):
</span><span class="cx">                 include.append(iter)
</span><ins>+                if maxInstances and len(include) &gt; maxInstances:
+                    raise TooManyInstancesError(&quot;Too many instances&quot;)
</ins><span class="cx">             else:
</span><span class="cx">                 limited = True
</span><span class="cx">         for iter in self.mRperiods:
</span><span class="cx">             if range.isPeriodOverlap(iter):
</span><span class="cx">                 include.append(iter.getStart())
</span><ins>+                if maxInstances and len(include) &gt; maxInstances:
+                    raise TooManyInstancesError(&quot;Too many instances&quot;)
</ins><span class="cx">             else:
</span><span class="cx">                 limited = True
</span><span class="cx"> 
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarrequeststatusvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/requeststatusvalue.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/requeststatusvalue.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/requeststatusvalue.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -97,7 +97,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def parseJSONValue(self, jobject):
</span><del>-        self.mValue = jobject
</del><ins>+        self.mValue = map(lambda x: x.encode(&quot;utf-8&quot;), jobject)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def writeJSONValue(self, jobject):
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendartestsrrule_examplesjsonfromrev15020PyCalendartrunksrcpycalendaricalendartestsrrule_examplesjson"></a>
<div class="copfile"><h4>Copied: PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/rrule_examples.json (from rev 15020, PyCalendar/trunk/src/pycalendar/icalendar/tests/rrule_examples.json) (0 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/rrule_examples.json                                (rev 0)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/rrule_examples.json        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -0,0 +1,231 @@
</span><ins>+[
+        {
+                &quot;rule&quot;: &quot;FREQ=YEARLY;BYWEEKNO=1,2&quot;,
+                &quot;start&quot;: &quot;20130101T000000&quot;,
+                &quot;end&quot;: &quot;20170101T000000&quot;,
+                &quot;results&quot;: [
+            &quot;20130101T000000&quot;,
+            &quot;20130108T000000&quot;,
+            &quot;20140101T000000&quot;,
+            &quot;20140108T000000&quot;,
+            &quot;20150101T000000&quot;,
+            &quot;20150108T000000&quot;,
+            &quot;20160108T000000&quot;,
+            &quot;20160115T000000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=MONTHLY&quot;,
+                &quot;start&quot;: &quot;20140140T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+            &quot;20140209T120000&quot;,
+            &quot;20140309T120000&quot;,
+            &quot;20140409T120000&quot;,
+            &quot;20140509T120000&quot;,
+            &quot;20140609T120000&quot;,
+            &quot;20140709T120000&quot;,
+            &quot;20140809T120000&quot;,
+            &quot;20140909T120000&quot;,
+            &quot;20141009T120000&quot;,
+            &quot;20141109T120000&quot;,
+            &quot;20141209T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=MONTHLY&quot;,
+                &quot;start&quot;: &quot;20140131T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20140131T120000&quot;,
+                        &quot;20140331T120000&quot;,
+                        &quot;20140531T120000&quot;,
+                        &quot;20140731T120000&quot;,
+                        &quot;20140831T120000&quot;,
+                        &quot;20141031T120000&quot;,
+                        &quot;20141231T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=MONTHLY;BYMONTHDAY=31&quot;,
+                &quot;start&quot;: &quot;20140131T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20140131T120000&quot;,
+                        &quot;20140331T120000&quot;,
+                        &quot;20140531T120000&quot;,
+                        &quot;20140731T120000&quot;,
+                        &quot;20140831T120000&quot;,
+                        &quot;20141031T120000&quot;,
+                        &quot;20141231T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=MONTHLY;BYMONTHDAY=-31&quot;,
+                &quot;start&quot;: &quot;20140101T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20140101T120000&quot;,
+                        &quot;20140301T120000&quot;,
+                        &quot;20140501T120000&quot;,
+                        &quot;20140701T120000&quot;,
+                        &quot;20140801T120000&quot;,
+                        &quot;20141001T120000&quot;,
+                        &quot;20141201T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=MONTHLY;BYDAY=-1FR&quot;,
+                &quot;start&quot;: &quot;20140131T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20140131T120000&quot;,
+                        &quot;20140228T120000&quot;,
+                        &quot;20140328T120000&quot;,
+                        &quot;20140425T120000&quot;,
+                        &quot;20140530T120000&quot;,
+                        &quot;20140627T120000&quot;,
+                        &quot;20140725T120000&quot;,
+                        &quot;20140829T120000&quot;,
+                        &quot;20140926T120000&quot;,
+                        &quot;20141031T120000&quot;,
+                        &quot;20141128T120000&quot;,
+                        &quot;20141226T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=MONTHLY;BYDAY=5FR&quot;,
+                &quot;start&quot;: &quot;20140131T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20140131T120000&quot;,
+                        &quot;20140530T120000&quot;,
+                        &quot;20140829T120000&quot;,
+                        &quot;20141031T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1&quot;,
+                &quot;start&quot;: &quot;20140131T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20140131T120000&quot;,
+                        &quot;20140228T120000&quot;,
+                        &quot;20140331T120000&quot;,
+                        &quot;20140430T120000&quot;,
+                        &quot;20140530T120000&quot;,
+                        &quot;20140630T120000&quot;,
+                        &quot;20140731T120000&quot;,
+                        &quot;20140829T120000&quot;,
+                        &quot;20140930T120000&quot;,
+                        &quot;20141031T120000&quot;,
+                        &quot;20141128T120000&quot;,
+                        &quot;20141231T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1&quot;,
+                &quot;start&quot;: &quot;20140127T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20140131T120000&quot;,
+                        &quot;20140228T120000&quot;,
+                        &quot;20140331T120000&quot;,
+                        &quot;20140430T120000&quot;,
+                        &quot;20140530T120000&quot;,
+                        &quot;20140630T120000&quot;,
+                        &quot;20140731T120000&quot;,
+                        &quot;20140829T120000&quot;,
+                        &quot;20140930T120000&quot;,
+                        &quot;20141031T120000&quot;,
+                        &quot;20141128T120000&quot;,
+                        &quot;20141231T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=MONTHLY;INTERVAL=2;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1&quot;,
+                &quot;start&quot;: &quot;20140127T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20140131T120000&quot;,
+                        &quot;20140331T120000&quot;,
+                        &quot;20140530T120000&quot;,
+                        &quot;20140731T120000&quot;,
+                        &quot;20140930T120000&quot;,
+                        &quot;20141128T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=MONTHLY;BYDAY=-1MO,-1TU,-1WE,-1TH,-1FR;BYSETPOS=-1&quot;,
+                &quot;start&quot;: &quot;20140130T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20140131T120000&quot;,
+                        &quot;20140228T120000&quot;,
+                        &quot;20140331T120000&quot;,
+                        &quot;20140430T120000&quot;,
+                        &quot;20140530T120000&quot;,
+                        &quot;20140630T120000&quot;,
+                        &quot;20140731T120000&quot;,
+                        &quot;20140829T120000&quot;,
+                        &quot;20140930T120000&quot;,
+                        &quot;20141031T120000&quot;,
+                        &quot;20141128T120000&quot;,
+                        &quot;20141231T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=YEARLY&quot;,
+                &quot;start&quot;: &quot;20120229T120000&quot;,
+                &quot;end&quot;: &quot;20200101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20120229T120000&quot;,
+                        &quot;20160229T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=YEARLY;BYYEARDAY=366&quot;,
+                &quot;start&quot;: &quot;20121231T120000&quot;,
+                &quot;end&quot;: &quot;20200101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20121231T120000&quot;,
+                        &quot;20161231T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=YEARLY;BYDAY=-1FR;BYMONTH=10&quot;,
+                &quot;start&quot;: &quot;20101029T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20101029T120000&quot;,
+                        &quot;20111028T120000&quot;,
+                        &quot;20121026T120000&quot;,
+                        &quot;20131025T120000&quot;,
+                        &quot;20141031T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=YEARLY;BYDAY=1FR;BYMONTH=4&quot;,
+                &quot;start&quot;: &quot;20100402T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20100402T120000&quot;,
+                        &quot;20110401T120000&quot;,
+                        &quot;20120406T120000&quot;,
+                        &quot;20130405T120000&quot;,
+                        &quot;20140404T120000&quot;
+                ]
+        },
+        {
+                &quot;rule&quot;: &quot;FREQ=YEARLY;BYDAY=FR;BYMONTHDAY=21,22,23,24,25,26,27;BYMONTH=10&quot;,
+                &quot;start&quot;: &quot;20101022T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+                        &quot;20101022T120000&quot;,
+                        &quot;20111021T120000&quot;,
+                        &quot;20121026T120000&quot;,
+                        &quot;20131025T120000&quot;,
+                        &quot;20141024T120000&quot;
+                ]
+        }
+]
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendartestsrscale_examplesjson"></a>
<div class="addfile"><h4>Added: PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/rscale_examples.json (0 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/rscale_examples.json                                (rev 0)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/rscale_examples.json        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -0,0 +1,304 @@
</span><ins>+[
+        {
+                &quot;title&quot;: &quot;MonthlyRscaleStartInLeapYearSkipYes - start: {C}46501230&quot;,
+                &quot;rule&quot;: [&quot;RSCALE=CHINESE;FREQ=MONTHLY;SKIP=YES&quot;],
+                &quot;start&quot;: &quot;20140130&quot;,
+                &quot;end&quot;: &quot;20180101&quot;,
+                &quot;results&quot;: [
+            &quot;20140130&quot;,
+            &quot;20140330&quot;,
+            &quot;20140528&quot;,
+            &quot;20140726&quot;,
+            &quot;20140923&quot;,
+            &quot;20141023&quot;,
+            &quot;20141221&quot;,
+            &quot;20150218&quot;,
+            &quot;20150418&quot;,
+            &quot;20150715&quot;,
+            &quot;20150912&quot;,
+            &quot;20151012&quot;,
+            &quot;20151111&quot;,
+            &quot;20160109&quot;,
+            &quot;20160308&quot;,
+            &quot;20160506&quot;,
+            &quot;20160802&quot;,
+            &quot;20160930&quot;,
+            &quot;20161030&quot;,
+            &quot;20161228&quot;,
+            &quot;20170127&quot;,
+            &quot;20170327&quot;,
+            &quot;20170525&quot;,
+            &quot;20170821&quot;,
+            &quot;20171019&quot;,
+            &quot;20171217&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;MonthlyRscaleStartInLeapYearSkipForward - start: {C}46501230&quot;,
+                &quot;rule&quot;: [&quot;RSCALE=CHINESE;FREQ=MONTHLY;SKIP=FORWARD&quot;],
+                &quot;start&quot;: &quot;20140130&quot;,
+                &quot;end&quot;: &quot;20180101&quot;,
+                &quot;results&quot;: [
+            &quot;20140130&quot;,
+            &quot;20140301&quot;,
+            &quot;20140330&quot;,
+            &quot;20140429&quot;,
+            &quot;20140528&quot;,
+            &quot;20140627&quot;,
+            &quot;20140726&quot;,
+            &quot;20140825&quot;,
+            &quot;20140923&quot;,
+            &quot;20141023&quot;,
+            &quot;20141122&quot;,
+            &quot;20141221&quot;,
+            &quot;20150120&quot;,
+            &quot;20150218&quot;,
+            &quot;20150320&quot;,
+            &quot;20150418&quot;,
+            &quot;20150518&quot;,
+            &quot;20150616&quot;,
+            &quot;20150715&quot;,
+            &quot;20150814&quot;,
+            &quot;20150912&quot;,
+            &quot;20151012&quot;,
+            &quot;20151111&quot;,
+            &quot;20151211&quot;,
+            &quot;20160109&quot;,
+            &quot;20160208&quot;,
+            &quot;20160308&quot;,
+            &quot;20160407&quot;,
+            &quot;20160506&quot;,
+            &quot;20160605&quot;,
+            &quot;20160704&quot;,
+            &quot;20160802&quot;,
+            &quot;20160901&quot;,
+            &quot;20160930&quot;,
+            &quot;20161030&quot;,
+            &quot;20161129&quot;,
+            &quot;20161228&quot;,
+            &quot;20170127&quot;,
+            &quot;20170226&quot;,
+            &quot;20170327&quot;,
+            &quot;20170426&quot;,
+            &quot;20170525&quot;,
+            &quot;20170624&quot;,
+            &quot;20170723&quot;,
+            &quot;20170821&quot;,
+            &quot;20170920&quot;,
+            &quot;20171019&quot;,
+            &quot;20171118&quot;,
+            &quot;20171217&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;MonthlyRscaleStartInLeapYearSkipBackwardDefault - start: {C}46501230&quot;,
+                &quot;rule&quot;: [
+            &quot;RSCALE=CHINESE;FREQ=MONTHLY;SKIP=BACKWARD&quot;,
+            &quot;RSCALE=CHINESE;FREQ=MONTHLY&quot;
+                ],
+                &quot;start&quot;: &quot;20140130&quot;,
+                &quot;end&quot;: &quot;20180101&quot;,
+                &quot;results&quot;: [
+            &quot;20140130&quot;,
+            &quot;20140228&quot;,
+            &quot;20140330&quot;,
+            &quot;20140428&quot;,
+            &quot;20140528&quot;,
+            &quot;20140626&quot;,
+            &quot;20140726&quot;,
+            &quot;20140824&quot;,
+            &quot;20140923&quot;,
+            &quot;20141023&quot;,
+            &quot;20141121&quot;,
+            &quot;20141221&quot;,
+            &quot;20150119&quot;,
+            &quot;20150218&quot;,
+            &quot;20150319&quot;,
+            &quot;20150418&quot;,
+            &quot;20150517&quot;,
+            &quot;20150615&quot;,
+            &quot;20150715&quot;,
+            &quot;20150813&quot;,
+            &quot;20150912&quot;,
+            &quot;20151012&quot;,
+            &quot;20151111&quot;,
+            &quot;20151210&quot;,
+            &quot;20160109&quot;,
+            &quot;20160207&quot;,
+            &quot;20160308&quot;,
+            &quot;20160406&quot;,
+            &quot;20160506&quot;,
+            &quot;20160604&quot;,
+            &quot;20160703&quot;,
+            &quot;20160802&quot;,
+            &quot;20160831&quot;,
+            &quot;20160930&quot;,
+            &quot;20161030&quot;,
+            &quot;20161128&quot;,
+            &quot;20161228&quot;,
+            &quot;20170127&quot;,
+            &quot;20170225&quot;,
+            &quot;20170327&quot;,
+            &quot;20170425&quot;,
+            &quot;20170525&quot;,
+            &quot;20170623&quot;,
+            &quot;20170722&quot;,
+            &quot;20170821&quot;,
+            &quot;20170919&quot;,
+            &quot;20171019&quot;,
+            &quot;20171117&quot;,
+            &quot;20171217&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;YearlyLeapDaySkipYes&quot;,
+                &quot;rule&quot;: [&quot;RSCALE=GREGORIAN;FREQ=YEARLY;SKIP=YES;COUNT=5&quot;],
+                &quot;start&quot;: &quot;20160229&quot;,
+                &quot;end&quot;: &quot;21000101&quot;,
+                &quot;results&quot;: [
+            &quot;20160229&quot;,
+            &quot;20200229&quot;,
+            &quot;20240229&quot;,
+            &quot;20280229&quot;,
+            &quot;20320229&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;YearlyLeapDaySkipForward&quot;,
+                &quot;rule&quot;: [&quot;RSCALE=GREGORIAN;FREQ=YEARLY;SKIP=FORWARD;COUNT=5&quot;],
+                &quot;start&quot;: &quot;20160229&quot;,
+                &quot;end&quot;: &quot;21000101&quot;,
+                &quot;results&quot;: [
+            &quot;20160229&quot;,
+            &quot;20170301&quot;,
+            &quot;20180301&quot;,
+            &quot;20190301&quot;,
+            &quot;20200229&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;YearlyLeapDaySkipBackwardDefault&quot;,
+                &quot;rule&quot;: [
+            &quot;RSCALE=GREGORIAN;FREQ=YEARLY;SKIP=BACKWARD;COUNT=5&quot;,
+            &quot;RSCALE=GREGORIAN;FREQ=YEARLY;COUNT=5&quot;
+                ],
+                &quot;start&quot;: &quot;20160229&quot;,
+                &quot;end&quot;: &quot;21000101&quot;,
+                &quot;results&quot;: [
+            &quot;20160229&quot;,
+            &quot;20170228&quot;,
+            &quot;20180228&quot;,
+            &quot;20190228&quot;,
+            &quot;20200229&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;ChineseMonthlyByMonthDay30SkipYes&quot;,
+                &quot;rule&quot;: [&quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=30;SKIP=YES&quot;],
+                &quot;start&quot;: &quot;20140130T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+            &quot;20140130T120000&quot;,
+            &quot;20140330T120000&quot;,
+            &quot;20140528T120000&quot;,
+            &quot;20140726T120000&quot;,
+            &quot;20140923T120000&quot;,
+            &quot;20141023T120000&quot;,
+            &quot;20141221T120000&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;ChineseMonthlyByMonthDay30SkipBackward&quot;,
+                &quot;rule&quot;: [&quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=30;SKIP=BACKWARD&quot;],
+                &quot;start&quot;: &quot;20140130T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+            &quot;20140130T120000&quot;,
+            &quot;20140228T120000&quot;,
+            &quot;20140330T120000&quot;,
+            &quot;20140428T120000&quot;,
+            &quot;20140528T120000&quot;,
+            &quot;20140626T120000&quot;,
+            &quot;20140726T120000&quot;,
+            &quot;20140824T120000&quot;,
+            &quot;20140923T120000&quot;,
+            &quot;20141023T120000&quot;,
+            &quot;20141121T120000&quot;,
+            &quot;20141221T120000&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;ChineseMonthlyByMonthDay30SkipForward&quot;,
+                &quot;rule&quot;: [&quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=30;SKIP=FORWARD&quot;],
+                &quot;start&quot;: &quot;20140130T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+            &quot;20140130T120000&quot;,
+            &quot;20140301T120000&quot;,
+            &quot;20140330T120000&quot;,
+            &quot;20140429T120000&quot;,
+            &quot;20140528T120000&quot;,
+            &quot;20140627T120000&quot;,
+            &quot;20140726T120000&quot;,
+            &quot;20140825T120000&quot;,
+            &quot;20140923T120000&quot;,
+            &quot;20141023T120000&quot;,
+            &quot;20141122T120000&quot;,
+            &quot;20141221T120000&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;ChineseMonthlyByMonthDayMinus30SkipYes&quot;,
+                &quot;rule&quot;: [&quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=-30;SKIP=YES&quot;],
+                &quot;start&quot;: &quot;20140130T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+            &quot;20140301T120000&quot;,
+            &quot;20140429T120000&quot;,
+            &quot;20140627T120000&quot;,
+            &quot;20140825T120000&quot;,
+            &quot;20140924T120000&quot;,
+            &quot;20141122T120000&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;ChineseMonthlyByMonthDayMinus30SkipBackward&quot;,
+                &quot;rule&quot;: [&quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=-30;SKIP=BACKWARD&quot;],
+                &quot;start&quot;: &quot;20140130T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+            &quot;20140130T120000&quot;,
+            &quot;20140301T120000&quot;,
+            &quot;20140330T120000&quot;,
+            &quot;20140429T120000&quot;,
+            &quot;20140528T120000&quot;,
+            &quot;20140627T120000&quot;,
+            &quot;20140726T120000&quot;,
+            &quot;20140825T120000&quot;,
+            &quot;20140924T120000&quot;,
+            &quot;20141023T120000&quot;,
+            &quot;20141122T120000&quot;,
+            &quot;20141221T120000&quot;
+                ]
+        },
+        {
+                &quot;title&quot;: &quot;ChineseMonthlyByMonthDayMinus30SkipForward&quot;,
+                &quot;rule&quot;: [&quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=-30;SKIP=FORWARD&quot;],
+                &quot;start&quot;: &quot;20140130T120000&quot;,
+                &quot;end&quot;: &quot;20150101T000000&quot;,
+                &quot;results&quot;: [
+            &quot;20140131T120000&quot;,
+            &quot;20140301T120000&quot;,
+            &quot;20140331T120000&quot;,
+            &quot;20140429T120000&quot;,
+            &quot;20140529T120000&quot;,
+            &quot;20140627T120000&quot;,
+            &quot;20140727T120000&quot;,
+            &quot;20140825T120000&quot;,
+            &quot;20140924T120000&quot;,
+            &quot;20141024T120000&quot;,
+            &quot;20141122T120000&quot;,
+            &quot;20141222T120000&quot;
+                ]
+        }
+]
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarteststest_calendarpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_calendar.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_calendar.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_calendar.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -20,6 +20,7 @@
</span><span class="cx"> from pycalendar.icalendar.property import Property
</span><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> from pycalendar.period import Period
</span><ins>+from pycalendar.timezone import Timezone
</ins><span class="cx"> import cStringIO as StringIO
</span><span class="cx"> import difflib
</span><span class="cx"> import unittest
</span><span class="lines">@@ -852,3 +853,390 @@
</span><span class="cx">             )
</span><span class="cx">             instances = tuple([instance.getInstanceStart() for instance in instances])
</span><span class="cx">             self.assertEqual(instances, result, &quot;Failed in %s: got %s, expected %s&quot; % (title, instances, result))
</span><ins>+
+
+    def testMasterComponent(self):
+
+        data = (
+            (
+                &quot;1.1 Non-recurring no VTIMEZONE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20110601
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                &quot;&quot;&quot;BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20110601
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+            ),
+            (
+                &quot;1.2 Non-recurring with VTIMEZONE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VTIMEZONE
+TZID:Etc/GMT+1
+X-LIC-LOCATION:Etc/GMT+1
+BEGIN:STANDARD
+DTSTART:18000101T000000
+RDATE:18000101T000000
+TZNAME:GMT+1
+TZOFFSETFROM:-0100
+TZOFFSETTO:-0100
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;TZID=Etc/GMT+1:20110601T000000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                &quot;&quot;&quot;BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;TZID=Etc/GMT+1:20110601T000000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+            ),
+            (
+                &quot;2.1 Recurring no VTIMEZONE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20110601
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY
+SUMMARY:New Year's Day
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110602
+DTSTART;VALUE=DATE:20110602
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                &quot;&quot;&quot;BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20110601
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY
+SUMMARY:New Year's Day
+END:VEVENT
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+            ),
+            (
+                &quot;2.2 Recurring with VTIMEZONE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VTIMEZONE
+TZID:Etc/GMT+1
+X-LIC-LOCATION:Etc/GMT+1
+BEGIN:STANDARD
+DTSTART:18000101T000000
+RDATE:18000101T000000
+TZNAME:GMT+1
+TZOFFSETFROM:-0100
+TZOFFSETTO:-0100
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;TZID=Etc/GMT+1:20110601T000000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;TZID=Etc/GMT+1:20110602T000000
+DTSTART;TZID=Etc/GMT+1:20110602T000000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                &quot;&quot;&quot;BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;TZID=Etc/GMT+1:20110601T000000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY
+SUMMARY:New Year's Day
+END:VEVENT
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+            ),
+            (
+                &quot;3.1 Recurring no master, no VTIMEZONE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110602
+DTSTART;VALUE=DATE:20110602
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                &quot;&quot;,
+            ),
+            (
+                &quot;3.2 Recurring no master, with VTIMEZONE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VTIMEZONE
+TZID:Etc/GMT+1
+X-LIC-LOCATION:Etc/GMT+1
+BEGIN:STANDARD
+DTSTART:18000101T000000
+RDATE:18000101T000000
+TZNAME:GMT+1
+TZOFFSETFROM:-0100
+TZOFFSETTO:-0100
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;TZID=Etc/GMT+1:20110602T000000
+DTSTART;TZID=Etc/GMT+1:20110602T000000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                &quot;&quot;,
+            ),
+        )
+
+        for title, caldata, result in data:
+            calendar = Calendar.parseText(caldata)
+            master = calendar.masterComponent()
+            if master is None:
+                master = &quot;&quot;
+            self.assertEqual(str(master), result, &quot;Failed in %s: got %s, expected %s&quot; % (title, master, result))
+
+
+    def testDeriveComponent(self):
+
+        data = (
+            (
+                &quot;1.1 Recurring no VTIMEZONE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20110601
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY
+SUMMARY:New Year's Day
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110602
+DTSTART;VALUE=DATE:20110602
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                DateTime(2011, 6, 3),
+                &quot;&quot;&quot;BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110603
+DTSTART;VALUE=DATE:20110603
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+            ),
+            (
+                &quot;2.2 Recurring with VTIMEZONE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VTIMEZONE
+TZID:Etc/GMT+1
+X-LIC-LOCATION:Etc/GMT+1
+BEGIN:STANDARD
+DTSTART:18000101T000000
+RDATE:18000101T000000
+TZNAME:GMT+1
+TZOFFSETFROM:-0100
+TZOFFSETTO:-0100
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;TZID=Etc/GMT+1:20110601T000000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;TZID=Etc/GMT+1:20110602T000000
+DTSTART;TZID=Etc/GMT+1:20110602T000000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                DateTime(2011, 6, 3, 1, 0, 0, Timezone(utc=True)),
+                &quot;&quot;&quot;BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;TZID=Etc/GMT+1:20110603T000000
+DTSTART;TZID=Etc/GMT+1:20110603T000000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+            ),
+            (
+                &quot;2.3 Recurring with VTIMEZONE, DTEND&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VTIMEZONE
+TZID:Etc/GMT+1
+X-LIC-LOCATION:Etc/GMT+1
+BEGIN:STANDARD
+DTSTART:18000101T000000
+RDATE:18000101T000000
+TZNAME:GMT+1
+TZOFFSETFROM:-0100
+TZOFFSETTO:-0100
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;TZID=Etc/GMT+1:20110601T000000
+DTEND;TZID=Etc/GMT+1:20110601T020000
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;TZID=Etc/GMT+1:20110602T000000
+DTSTART;TZID=Etc/GMT+1:20110602T000000
+DTEND;TZID=Etc/GMT+1:20110602T020000
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                DateTime(2011, 6, 3, 1, 0, 0, Timezone(utc=True)),
+                &quot;&quot;&quot;BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;TZID=Etc/GMT+1:20110603T000000
+DTSTART;TZID=Etc/GMT+1:20110603T000000
+DTEND;TZID=Etc/GMT+1:20110603T020000
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+            ),
+            (
+                &quot;2.1 Recurring no master, no VTIMEZONE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110602
+DTSTART;VALUE=DATE:20110602
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                DateTime(2011, 6, 3),
+                &quot;&quot;,
+            ),
+            (
+                &quot;2.2 Recurring no master, with VTIMEZONE&quot;,
+                &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VTIMEZONE
+TZID:Etc/GMT+1
+X-LIC-LOCATION:Etc/GMT+1
+BEGIN:STANDARD
+DTSTART:18000101T000000
+RDATE:18000101T000000
+TZNAME:GMT+1
+TZOFFSETFROM:-0100
+TZOFFSETTO:-0100
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;TZID=Etc/GMT+1:20110602T000000
+DTSTART;TZID=Etc/GMT+1:20110602T000000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                DateTime(2011, 6, 3, 1, 0, 0, Timezone(utc=True)),
+                &quot;&quot;,
+            ),
+        )
+
+        for title, caldata, rid, result in data:
+            calendar = Calendar.parseText(caldata)
+            master = calendar.deriveComponent(rid)
+            if master is None:
+                master = &quot;&quot;
+            self.assertEqual(str(master), result, &quot;Failed in %s: got %s, expected %s&quot; % (title, master, result))
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarteststest_jsonpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_json.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_json.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_json.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+# -*- coding: utf-8 -*-
</ins><span class="cx"> ##
</span><span class="cx"> #    Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</span><span class="cx"> #
</span><span class="lines">@@ -14,10 +15,12 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> from pycalendar.icalendar.calendar import Calendar
</span><span class="cx"> from pycalendar.icalendar.property import Property
</span><span class="cx"> import difflib
</span><span class="cx"> import unittest
</span><ins>+import json
</ins><span class="cx"> 
</span><span class="cx"> class TestJSON(unittest.TestCase):
</span><span class="cx"> 
</span><span class="lines">@@ -387,14 +390,380 @@
</span><span class="cx">         ),
</span><span class="cx">     )
</span><span class="cx"> 
</span><ins>+    i18ndata = (
+        (
+            &quot;&quot;&quot;BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20080205T191224Z
+DTSTART;VALUE=DATE:20081006
+SUMMARY:Planning meeting Ã¥
+UID:4088E990AD89CB3DBB484909
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+            &quot;&quot;&quot;[
+  &quot;vcalendar&quot;,
+  [
+    [
+      &quot;version&quot;,
+      {},
+      &quot;text&quot;,
+      &quot;2.0&quot;
+    ],
+    [
+      &quot;calscale&quot;,
+      {},
+      &quot;text&quot;,
+      &quot;GREGORIAN&quot;
+    ],
+    [
+      &quot;prodid&quot;,
+      {},
+      &quot;text&quot;,
+      &quot;-//Example Inc.//Example Calendar//EN&quot;
+    ]
+  ],
+  [
+    [
+      &quot;vevent&quot;,
+      [
+        [
+          &quot;uid&quot;,
+          {},
+          &quot;text&quot;,
+          &quot;4088E990AD89CB3DBB484909&quot;
+        ],
+        [
+          &quot;dtstart&quot;,
+          {},
+          &quot;date&quot;,
+          &quot;2008-10-06&quot;
+        ],
+        [
+          &quot;dtstamp&quot;,
+          {},
+          &quot;date-time&quot;,
+          &quot;2008-02-05T19:12:24Z&quot;
+        ],
+        [
+          &quot;summary&quot;,
+          {},
+          &quot;text&quot;,
+          &quot;Planning meeting Ã¥&quot;
+        ]
+      ],
+      []
+    ]
+  ]
+]&quot;&quot;&quot;,
+        ),
+        (
+            &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Example Corp.//Example Client//EN
+BEGIN:VTIMEZONE
+LAST-MODIFIED:20040110T032845Z
+TZID:US/Eastern
+BEGIN:DAYLIGHT
+DTSTART:20000404T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20001026T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20060206T001121Z
+DTSTART;TZID=US/Eastern:20060102T120000
+DURATION:PT1H
+GEO:-123.45;67.89
+RRULE:FREQ=DAILY;COUNT=5
+RDATE;TZID=US/Eastern;VALUE=PERIOD:20060102T150000/PT2H
+SUMMARY:Event #2 Ã¥
+DESCRIPTION:We are having a meeting all this week at 12 pm fo
+ r one hour\\, with an additional meeting on the first day 2 h
+ ours long.\\nPlease bring your own lunch for the 12 pm meetin
+ gs.
+UID:00959BC664CA650E933C892C@example.com
+END:VEVENT
+BEGIN:VEVENT
+DTSTAMP:20060206T001121Z
+DTSTART;TZID=US/Eastern:20060104T140000
+DURATION:PT1H
+RECURRENCE-ID;TZID=US/Eastern:20060104T120000
+SUMMARY:Event #2 bis Ã¥
+UID:00959BC664CA650E933C892C@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+            &quot;&quot;&quot;[
+  &quot;vcalendar&quot;,
+  [
+    [
+      &quot;version&quot;,
+      {},
+      &quot;text&quot;,
+      &quot;2.0&quot;
+    ],
+    [
+      &quot;prodid&quot;,
+      {},
+      &quot;text&quot;,
+      &quot;-//Example Corp.//Example Client//EN&quot;
+    ]
+  ],
+  [
+    [
+      &quot;vtimezone&quot;,
+      [
+        [
+          &quot;tzid&quot;,
+          {},
+          &quot;text&quot;,
+          &quot;US/Eastern&quot;
+        ],
+        [
+          &quot;last-modified&quot;,
+          {},
+          &quot;date-time&quot;,
+          &quot;2004-01-10T03:28:45Z&quot;
+        ]
+      ],
+      [
+        [
+          &quot;daylight&quot;,
+          [
+            [
+              &quot;dtstart&quot;,
+              {},
+              &quot;date-time&quot;,
+              &quot;2000-04-04T02:00:00&quot;
+            ],
+            [
+              &quot;rrule&quot;,
+              {},
+              &quot;recur&quot;,
+              {
+                &quot;bymonth&quot;:[
+                  4
+                ],
+                &quot;freq&quot;:&quot;YEARLY&quot;,
+                &quot;byday&quot;:[
+                  &quot;1SU&quot;
+                ]
+              }
+            ],
+            [
+              &quot;tzname&quot;,
+              {},
+              &quot;text&quot;,
+              &quot;EDT&quot;
+            ],
+            [
+              &quot;tzoffsetfrom&quot;,
+              {},
+              &quot;utc-offset&quot;,
+              &quot;-05:00&quot;
+            ],
+            [
+              &quot;tzoffsetto&quot;,
+              {},
+              &quot;utc-offset&quot;,
+              &quot;-04:00&quot;
+            ]
+          ],
+          []
+        ],
+        [
+          &quot;standard&quot;,
+          [
+            [
+              &quot;dtstart&quot;,
+              {},
+              &quot;date-time&quot;,
+              &quot;2000-10-26T02:00:00&quot;
+            ],
+            [
+              &quot;rrule&quot;,
+              {},
+              &quot;recur&quot;,
+              {
+                &quot;bymonth&quot;:[
+                  10
+                ],
+                &quot;freq&quot;:&quot;YEARLY&quot;,
+                &quot;byday&quot;:[
+                  &quot;-1SU&quot;
+                ]
+              }
+            ],
+            [
+              &quot;tzname&quot;,
+              {},
+              &quot;text&quot;,
+              &quot;EST&quot;
+            ],
+            [
+              &quot;tzoffsetfrom&quot;,
+              {},
+              &quot;utc-offset&quot;,
+              &quot;-04:00&quot;
+            ],
+            [
+              &quot;tzoffsetto&quot;,
+              {},
+              &quot;utc-offset&quot;,
+              &quot;-05:00&quot;
+            ]
+          ],
+          []
+        ]
+      ]
+    ],
+    [
+      &quot;vevent&quot;,
+      [
+        [
+          &quot;uid&quot;,
+          {},
+          &quot;text&quot;,
+          &quot;00959BC664CA650E933C892C@example.com&quot;
+        ],
+        [
+          &quot;dtstart&quot;,
+          {
+            &quot;tzid&quot;:&quot;US/Eastern&quot;
+          },
+          &quot;date-time&quot;,
+          &quot;2006-01-02T12:00:00&quot;
+        ],
+        [
+          &quot;duration&quot;,
+          {},
+          &quot;duration&quot;,
+          &quot;PT1H&quot;
+        ],
+        [
+          &quot;description&quot;,
+          {},
+          &quot;text&quot;,
+          &quot;We are having a meeting all this week at 12 pm for one hour, with an additional meeting on the first day 2 hours long.\\nPlease bring your own lunch for the 12 pm meetings.&quot;
+        ],
+        [
+          &quot;dtstamp&quot;,
+          {},
+          &quot;date-time&quot;,
+          &quot;2006-02-06T00:11:21Z&quot;
+        ],
+        [
+          &quot;geo&quot;,
+          {},
+          &quot;float&quot;,
+          [
+            -123.45,
+            67.89
+          ]
+        ],
+        [
+          &quot;rdate&quot;,
+          {
+            &quot;tzid&quot;:&quot;US/Eastern&quot;
+          },
+          &quot;period&quot;,
+          [
+            &quot;2006-01-02T15:00:00&quot;,
+            &quot;PT2H&quot;
+          ]
+        ],
+        [
+          &quot;rrule&quot;,
+          {},
+          &quot;recur&quot;,
+          {
+            &quot;count&quot;:5,
+            &quot;freq&quot;:&quot;DAILY&quot;
+          }
+        ],
+        [
+          &quot;summary&quot;,
+          {},
+          &quot;text&quot;,
+          &quot;Event #2 Ã¥&quot;
+        ]
+      ],
+      []
+    ],
+    [
+      &quot;vevent&quot;,
+      [
+        [
+          &quot;uid&quot;,
+          {},
+          &quot;text&quot;,
+          &quot;00959BC664CA650E933C892C@example.com&quot;
+        ],
+        [
+          &quot;recurrence-id&quot;,
+          {
+            &quot;tzid&quot;:&quot;US/Eastern&quot;
+          },
+          &quot;date-time&quot;,
+          &quot;2006-01-04T12:00:00&quot;
+        ],
+        [
+          &quot;dtstart&quot;,
+          {
+            &quot;tzid&quot;:&quot;US/Eastern&quot;
+          },
+          &quot;date-time&quot;,
+          &quot;2006-01-04T14:00:00&quot;
+        ],
+        [
+          &quot;duration&quot;,
+          {},
+          &quot;duration&quot;,
+          &quot;PT1H&quot;
+        ],
+        [
+          &quot;dtstamp&quot;,
+          {},
+          &quot;date-time&quot;,
+          &quot;2006-02-06T00:11:21Z&quot;
+        ],
+        [
+          &quot;summary&quot;,
+          {},
+          &quot;text&quot;,
+          &quot;Event #2 bis Ã¥&quot;
+        ]
+      ],
+      []
+    ]
+  ]
+]&quot;&quot;&quot;,
+        ),
+    )
+
</ins><span class="cx">     def testGenerateJSON(self):
</span><span class="cx"> 
</span><span class="cx">         def _doRoundtrip(caldata, resultdata):
</span><del>-            test1 = resultdata
</del><ins>+            test1 = json.dumps(json.loads(resultdata), indent=2, separators=(',', ':'), sort_keys=True)
</ins><span class="cx"> 
</span><span class="cx">             cal = Calendar.parseText(caldata)
</span><span class="cx"> 
</span><del>-            test2 = cal.getTextJSON()
</del><ins>+            test2 = cal.getTextJSON(sort_keys=True)
</ins><span class="cx">             self.assertEqual(
</span><span class="cx">                 test1,
</span><span class="cx">                 test2,
</span><span class="lines">@@ -424,6 +793,25 @@
</span><span class="cx">             _doRoundtrip(item1, item2)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def testParseJSONi18n(self):
+
+        def _doRoundtrip(caldata, jcaldata):
+            cal1 = Calendar.parseText(caldata)
+            test1 = cal1.getText()
+
+            cal2 = Calendar.parseJSONData(jcaldata)
+            test2 = cal2.getText()
+
+            self.assertEqual(
+                test1,
+                test2,
+                &quot;\n&quot;.join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+            )
+
+        for item1, item2 in self.i18ndata:
+            _doRoundtrip(item1, item2)
+
+
</ins><span class="cx">     def testjCalExample1(self):
</span><span class="cx"> 
</span><span class="cx">         jcaldata = &quot;&quot;&quot;[&quot;vcalendar&quot;,
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarteststest_propertypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_property.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_property.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_property.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -115,6 +115,7 @@
</span><span class="cx"> 
</span><span class="cx">         test_data = (
</span><span class="cx">             (&quot;ATTENDEE&quot;, &quot;mailto:attendee@example.com&quot;, &quot;ATTENDEE:mailto:attendee@example.com\r\n&quot;),
</span><ins>+            (&quot;ATTENDEE&quot;, u&quot;mailto:attendee@example.com&quot;, &quot;ATTENDEE:mailto:attendee@example.com\r\n&quot;),
</ins><span class="cx">             (&quot;attendee&quot;, &quot;mailto:attendee@example.com&quot;, &quot;attendee:mailto:attendee@example.com\r\n&quot;),
</span><span class="cx">             (&quot;ORGANIZER&quot;, &quot;mailto:organizer@example.com&quot;, &quot;ORGANIZER:mailto:organizer@example.com\r\n&quot;),
</span><span class="cx">             (&quot;ORGANizer&quot;, &quot;mailto:organizer@example.com&quot;, &quot;ORGANizer:mailto:organizer@example.com\r\n&quot;),
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarteststest_recurrencepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_recurrence.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_recurrence.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_recurrence.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -19,6 +19,8 @@
</span><span class="cx"> from pycalendar.icalendar.recurrence import Recurrence
</span><span class="cx"> import unittest
</span><span class="cx"> from pycalendar.timezone import Timezone
</span><ins>+import os
+import json
</ins><span class="cx"> 
</span><span class="cx"> class TestRecurrence(unittest.TestCase):
</span><span class="cx"> 
</span><span class="lines">@@ -58,7 +60,6 @@
</span><span class="cx">         &quot;RSCALE=GREGORIAN;FREQ=YEARLY;COUNT=400;SKIP=BACKWARD&quot;,
</span><span class="cx">         &quot;RSCALE=GREGORIAN;FREQ=YEARLY;COUNT=400;SKIP=FORWARD&quot;,
</span><span class="cx">         &quot;RSCALE=CHINESE;FREQ=YEARLY;BYMONTH=5,6,6L,7&quot;,
</span><del>-
</del><span class="cx">     )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -67,7 +68,7 @@
</span><span class="cx">         for item in TestRecurrence.items:
</span><span class="cx">             recur = Recurrence()
</span><span class="cx">             recur.parse(item)
</span><del>-            self.assertEqual(recur.getText(), item, &quot;Failed to parse and re-generate '%s' '%s'&quot; % (item, recur.getText()))
</del><ins>+            self.assertEqual(recur.getText(), item, &quot;Failed to parse and re-generate '%s' '%s'&quot; % (item, recur.getText(),))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def testParseInvalid(self):
</span><span class="lines">@@ -126,778 +127,149 @@
</span><span class="cx">             self.assertNotEqual(hashes[i - 1], hashes[i])
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def testByWeekNoExpand(self):
-
-        rule = &quot;FREQ=YEARLY;BYWEEKNO=1,2&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2013, 1, 1, 0, 0, 0)
-            end = DateTime(2017, 1, 1, 0, 0, 0)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2013, 1, 1, 0, 0, 0),
-                    DateTime(2013, 1, 8, 0, 0, 0),
-                    DateTime(2014, 1, 1, 0, 0, 0),
-                    DateTime(2014, 1, 8, 0, 0, 0),
-                    DateTime(2015, 1, 1, 0, 0, 0),
-                    DateTime(2015, 1, 8, 0, 0, 0),
-                    DateTime(2016, 1, 8, 0, 0, 0),
-                    DateTime(2016, 1, 15, 0, 0, 0),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
-    def testMonthlyInvalidStart(self):
-
-        rule = &quot;FREQ=MONTHLY&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2014, 1, 40, 12, 0, 0)
-            end = DateTime(2015, 1, 1, 0, 0, 0)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2014, 2, 9, 12, 0, 0),
-                    DateTime(2014, 3, 9, 12, 0, 0),
-                    DateTime(2014, 4, 9, 12, 0, 0),
-                    DateTime(2014, 5, 9, 12, 0, 0),
-                    DateTime(2014, 6, 9, 12, 0, 0),
-                    DateTime(2014, 7, 9, 12, 0, 0),
-                    DateTime(2014, 8, 9, 12, 0, 0),
-                    DateTime(2014, 9, 9, 12, 0, 0),
-                    DateTime(2014, 10, 9, 12, 0, 0),
-                    DateTime(2014, 11, 9, 12, 0, 0),
-                    DateTime(2014, 12, 9, 12, 0, 0),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
</del><span class="cx">     def testWeeklyTwice(self):
</span><span class="cx"> 
</span><del>-        rule = &quot;FREQ=WEEKLY&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
-            end = DateTime(2014, 2, 1, 0, 0, 0, tzid=Timezone(utc=True))
-            items = []
-            range = Period(start, end)
-            recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)), range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 1, 8, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 1, 15, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 1, 22, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 1, 29, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-            start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
-            end = DateTime(2014, 3, 1, 0, 0, 0, tzid=Timezone(utc=True))
-            items = []
-            range = Period(start, end)
-            recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)), range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 1, 8, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 1, 15, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 1, 22, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 1, 29, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 2, 5, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 2, 12, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 2, 19, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 2, 26, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
-    def testMonthlyInUTC(self):
-
-        rule = &quot;FREQ=MONTHLY&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
-            end = DateTime(2015, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
-            items = []
-            range = Period(start, end)
-            recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)), range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 2, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 3, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 4, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 5, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 6, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 7, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 8, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 9, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
-                    DateTime(2014, 10, 1, 12, 0, 0),
-                    DateTime(2014, 11, 1, 12, 0, 0),
-                    DateTime(2014, 12, 1, 12, 0, 0),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
-    def testMonthlyStart31st(self):
-
-        rule = &quot;FREQ=MONTHLY&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2014, 1, 31, 12, 0, 0)
-            end = DateTime(2015, 1, 1, 0, 0, 0)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2014, 1, 31, 12, 0, 0),
-                    DateTime(2014, 3, 31, 12, 0, 0),
-                    DateTime(2014, 5, 31, 12, 0, 0),
-                    DateTime(2014, 7, 31, 12, 0, 0),
-                    DateTime(2014, 8, 31, 12, 0, 0),
-                    DateTime(2014, 10, 31, 12, 0, 0),
-                    DateTime(2014, 12, 31, 12, 0, 0),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
-    def testMonthlyByMonthDay31(self):
-
-        rule = &quot;FREQ=MONTHLY;BYMONTHDAY=31&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2014, 1, 31, 12, 0, 0)
-            end = DateTime(2015, 1, 1, 0, 0, 0)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2014, 1, 31, 12, 0, 0),
-                    DateTime(2014, 3, 31, 12, 0, 0),
-                    DateTime(2014, 5, 31, 12, 0, 0),
-                    DateTime(2014, 7, 31, 12, 0, 0),
-                    DateTime(2014, 8, 31, 12, 0, 0),
-                    DateTime(2014, 10, 31, 12, 0, 0),
-                    DateTime(2014, 12, 31, 12, 0, 0),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
-    def testMonthlyByMonthDayMinus31(self):
-
-        rule = &quot;FREQ=MONTHLY;BYMONTHDAY=-31&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2014, 1, 1, 12, 0, 0)
-            end = DateTime(2015, 1, 1, 0, 0, 0)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2014, 1, 1, 12, 0, 0),
-                    DateTime(2014, 3, 1, 12, 0, 0),
-                    DateTime(2014, 5, 1, 12, 0, 0),
-                    DateTime(2014, 7, 1, 12, 0, 0),
-                    DateTime(2014, 8, 1, 12, 0, 0),
-                    DateTime(2014, 10, 1, 12, 0, 0),
-                    DateTime(2014, 12, 1, 12, 0, 0),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
-    def testMonthlyByLastFridayExpand(self):
-
-        rule = &quot;FREQ=MONTHLY;BYDAY=-1FR&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2014, 1, 31, 12, 0, 0)
-            end = DateTime(2015, 1, 1, 0, 0, 0)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2014, 1, 31, 12, 0, 0),
-                    DateTime(2014, 2, 28, 12, 0, 0),
-                    DateTime(2014, 3, 28, 12, 0, 0),
-                    DateTime(2014, 4, 25, 12, 0, 0),
-                    DateTime(2014, 5, 30, 12, 0, 0),
-                    DateTime(2014, 6, 27, 12, 0, 0),
-                    DateTime(2014, 7, 25, 12, 0, 0),
-                    DateTime(2014, 8, 29, 12, 0, 0),
-                    DateTime(2014, 9, 26, 12, 0, 0),
-                    DateTime(2014, 10, 31, 12, 0, 0),
-                    DateTime(2014, 11, 28, 12, 0, 0),
-                    DateTime(2014, 12, 26, 12, 0, 0),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
-    def testMonthlyByFifthFridayExpand(self):
-
-        rule = &quot;FREQ=MONTHLY;BYDAY=5FR&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2014, 1, 31, 12, 0, 0)
-            end = DateTime(2015, 1, 1, 0, 0, 0)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2014, 1, 31, 12, 0, 0),
-                    DateTime(2014, 5, 30, 12, 0, 0),
-                    DateTime(2014, 8, 29, 12, 0, 0),
-                    DateTime(2014, 10, 31, 12, 0, 0),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
-    def testYearlyLeapDay(self):
-
-        rule = &quot;FREQ=YEARLY&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2012, 2, 29, 12, 0, 0)
-            end = DateTime(2020, 1, 1, 0, 0, 0)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2012, 2, 29, 12, 0, 0),
-                    DateTime(2016, 2, 29, 12, 0, 0),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
-    def testYearlyYearDay(self):
-
-        rule = &quot;FREQ=YEARLY;BYYEARDAY=366&quot;
-        for rrule in (
-            rule,
-            &quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rule)
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2012, 12, 31, 12, 0, 0)
-            end = DateTime(2020, 1, 1, 0, 0, 0)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2012, 12, 31, 12, 0, 0),
-                    DateTime(2016, 12, 31, 12, 0, 0),
-                ],
-                msg=&quot;Failed: {}&quot;.format(rrule),
-            )
-
-
-    def testClearOnChange(self):
-
</del><span class="cx">         recur = Recurrence()
</span><del>-        recur.parse(&quot;FREQ=DAILY&quot;)
-
-        start = DateTime(2013, 1, 1, 0, 0, 0)
-        end = DateTime(2017, 1, 1, 0, 0, 0)
-        range = Period(start, end)
</del><ins>+        recur.parse(&quot;FREQ=WEEKLY&quot;)
+        start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
+        end = DateTime(2014, 2, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         items = []
</span><del>-        recur.expand(start, range, items)
-        self.assertTrue(recur.mCached)
-        self.assertTrue(len(items) &gt; 100)
-
-        recur.setUseCount(True)
-        recur.setCount(10)
-        self.assertFalse(recur.mCached)
-        items = []
-        recur.expand(start, range, items)
-        self.assertEqual(len(items), 10)
-
-
-
-class TestRecurrenceRscale(unittest.TestCase):
-
-    def testMonthlyRscaleStartInLeapYearSkipYes(self):
-
-        recur = Recurrence()
-        recur.parse(&quot;RSCALE=CHINESE;FREQ=MONTHLY;SKIP=YES&quot;)
-        start = DateTime(2014, 1, 30) # {C}46501230
-        end = DateTime(2018, 1, 1)
-        items = []
</del><span class="cx">         range = Period(start, end)
</span><del>-        recur.expand(start, range, items)
</del><ins>+        recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)), range, items)
</ins><span class="cx">         self.assertEqual(
</span><span class="cx">             items,
</span><span class="cx">             [
</span><del>-                DateTime(2014, 1, 30),
-                DateTime(2014, 3, 30),
-                DateTime(2014, 5, 28),
-                DateTime(2014, 7, 26),
-                DateTime(2014, 9, 23),
-                DateTime(2014, 10, 23),
-                DateTime(2014, 12, 21),
-                DateTime(2015, 2, 18),
-                DateTime(2015, 4, 18),
-                DateTime(2015, 7, 15),
-                DateTime(2015, 9, 12),
-                DateTime(2015, 10, 12),
-                DateTime(2015, 11, 11),
-                DateTime(2016, 1, 9),
-                DateTime(2016, 3, 8),
-                DateTime(2016, 5, 6),
-                DateTime(2016, 8, 2),
-                DateTime(2016, 9, 30),
-                DateTime(2016, 10, 30),
-                DateTime(2016, 12, 28),
-                DateTime(2017, 1, 27),
-                DateTime(2017, 3, 27),
-                DateTime(2017, 5, 25),
-                DateTime(2017, 8, 21),
-                DateTime(2017, 10, 19),
-                DateTime(2017, 12, 17),
</del><ins>+                DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 1, 8, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 1, 15, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 1, 22, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 1, 29, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+
</ins><span class="cx">             ],
</span><span class="cx">         )
</span><span class="cx"> 
</span><del>-
-    def testMonthlyRscaleStartInLeapYearSkipForward(self):
-
-        recur = Recurrence()
-        recur.parse(&quot;RSCALE=CHINESE;FREQ=MONTHLY;SKIP=FORWARD&quot;)
-        start = DateTime(2014, 1, 30) # {C}46501230
-        end = DateTime(2018, 1, 1)
</del><ins>+        start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
+        end = DateTime(2014, 3, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         items = []
</span><span class="cx">         range = Period(start, end)
</span><del>-        recur.expand(start, range, items)
</del><ins>+        recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)), range, items)
</ins><span class="cx">         self.assertEqual(
</span><span class="cx">             items,
</span><span class="cx">             [
</span><del>-                DateTime(2014, 1, 30),
-                DateTime(2014, 3, 1),
-                DateTime(2014, 3, 30),
-                DateTime(2014, 4, 29),
-                DateTime(2014, 5, 28),
-                DateTime(2014, 6, 27),
-                DateTime(2014, 7, 26),
-                DateTime(2014, 8, 25),
-                DateTime(2014, 9, 23),
-                DateTime(2014, 10, 23),
-                DateTime(2014, 11, 22),
-                DateTime(2014, 12, 21),
-                DateTime(2015, 1, 20),
-                DateTime(2015, 2, 18),
-                DateTime(2015, 3, 20),
-                DateTime(2015, 4, 18),
-                DateTime(2015, 5, 18),
-                DateTime(2015, 6, 16),
-                DateTime(2015, 7, 15),
-                DateTime(2015, 8, 14),
-                DateTime(2015, 9, 12),
-                DateTime(2015, 10, 12),
-                DateTime(2015, 11, 11),
-                DateTime(2015, 12, 11),
-                DateTime(2016, 1, 9),
-                DateTime(2016, 2, 8),
-                DateTime(2016, 3, 8),
-                DateTime(2016, 4, 7),
-                DateTime(2016, 5, 6),
-                DateTime(2016, 6, 5),
-                DateTime(2016, 7, 4),
-                DateTime(2016, 8, 2),
-                DateTime(2016, 9, 1),
-                DateTime(2016, 9, 30),
-                DateTime(2016, 10, 30),
-                DateTime(2016, 11, 29),
-                DateTime(2016, 12, 28),
-                DateTime(2017, 1, 27),
-                DateTime(2017, 2, 26),
-                DateTime(2017, 3, 27),
-                DateTime(2017, 4, 26),
-                DateTime(2017, 5, 25),
-                DateTime(2017, 6, 24),
-                DateTime(2017, 7, 23),
-                DateTime(2017, 8, 21),
-                DateTime(2017, 9, 20),
-                DateTime(2017, 10, 19),
-                DateTime(2017, 11, 18),
-                DateTime(2017, 12, 17),
</del><ins>+                DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 1, 8, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 1, 15, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 1, 22, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 1, 29, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 2, 5, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 2, 12, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 2, 19, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 2, 26, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
</ins><span class="cx">             ],
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def testMonthlyRscaleStartInLeapYearSkipBackwardDefault(self):
</del><ins>+    def testMonthlyInUTC(self):
</ins><span class="cx"> 
</span><del>-        for rrule in (
-            &quot;RSCALE=CHINESE;FREQ=MONTHLY;SKIP=BACKWARD&quot;,
-            &quot;RSCALE=CHINESE;FREQ=MONTHLY&quot;
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2014, 1, 30) # {C}46501230
-            end = DateTime(2018, 1, 1)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2014, 1, 30),
-                    DateTime(2014, 2, 28),
-                    DateTime(2014, 3, 30),
-                    DateTime(2014, 4, 28),
-                    DateTime(2014, 5, 28),
-                    DateTime(2014, 6, 26),
-                    DateTime(2014, 7, 26),
-                    DateTime(2014, 8, 24),
-                    DateTime(2014, 9, 23),
-                    DateTime(2014, 10, 23),
-                    DateTime(2014, 11, 21),
-                    DateTime(2014, 12, 21),
-                    DateTime(2015, 1, 19),
-                    DateTime(2015, 2, 18),
-                    DateTime(2015, 3, 19),
-                    DateTime(2015, 4, 18),
-                    DateTime(2015, 5, 17),
-                    DateTime(2015, 6, 15),
-                    DateTime(2015, 7, 15),
-                    DateTime(2015, 8, 13),
-                    DateTime(2015, 9, 12),
-                    DateTime(2015, 10, 12),
-                    DateTime(2015, 11, 11),
-                    DateTime(2015, 12, 10),
-                    DateTime(2016, 1, 9),
-                    DateTime(2016, 2, 7),
-                    DateTime(2016, 3, 8),
-                    DateTime(2016, 4, 6),
-                    DateTime(2016, 5, 6),
-                    DateTime(2016, 6, 4),
-                    DateTime(2016, 7, 3),
-                    DateTime(2016, 8, 2),
-                    DateTime(2016, 8, 31),
-                    DateTime(2016, 9, 30),
-                    DateTime(2016, 10, 30),
-                    DateTime(2016, 11, 28),
-                    DateTime(2016, 12, 28),
-                    DateTime(2017, 1, 27),
-                    DateTime(2017, 2, 25),
-                    DateTime(2017, 3, 27),
-                    DateTime(2017, 4, 25),
-                    DateTime(2017, 5, 25),
-                    DateTime(2017, 6, 23),
-                    DateTime(2017, 7, 22),
-                    DateTime(2017, 8, 21),
-                    DateTime(2017, 9, 19),
-                    DateTime(2017, 10, 19),
-                    DateTime(2017, 11, 17),
-                    DateTime(2017, 12, 17),
-                ],
-            )
-
-
-    def testYearlyLeapDaySkipYes(self):
-
</del><span class="cx">         recur = Recurrence()
</span><del>-        recur.parse(&quot;RSCALE=GREGORIAN;FREQ=YEARLY;SKIP=YES;COUNT=5&quot;)
-        start = DateTime(2016, 2, 29)
-        end = DateTime(2100, 1, 1)
</del><ins>+        recur.parse(&quot;FREQ=MONTHLY&quot;)
+        start = DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(utc=True))
+        end = DateTime(2015, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         items = []
</span><span class="cx">         range = Period(start, end)
</span><del>-        recur.expand(start, range, items)
</del><ins>+        recur.expand(DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)), range, items)
</ins><span class="cx">         self.assertEqual(
</span><span class="cx">             items,
</span><span class="cx">             [
</span><del>-                DateTime(2016, 2, 29),
-                DateTime(2020, 2, 29),
-                DateTime(2024, 2, 29),
-                DateTime(2028, 2, 29),
-                DateTime(2032, 2, 29),
-            ]
</del><ins>+                DateTime(2014, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 2, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 3, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 4, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 5, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 6, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 7, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 8, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 9, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 10, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 11, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+                DateTime(2014, 12, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)),
+            ],
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def testYearlyLeapDaySkipForward(self):
</del><ins>+    def testExampleRules(self):
</ins><span class="cx"> 
</span><del>-        recur = Recurrence()
-        recur.parse(&quot;RSCALE=GREGORIAN;FREQ=YEARLY;SKIP=FORWARD;COUNT=5&quot;)
-        start = DateTime(2016, 2, 29)
-        end = DateTime(2100, 1, 1)
-        items = []
-        range = Period(start, end)
-        recur.expand(start, range, items)
-        self.assertEqual(
-            items,
-            [
-                DateTime(2016, 2, 29),
-                DateTime(2017, 3, 1),
-                DateTime(2018, 3, 1),
-                DateTime(2019, 3, 1),
-                DateTime(2020, 2, 29),
-            ]
-        )
</del><ins>+        examples = os.path.join(os.path.dirname(__file__), &quot;rrule_examples.json&quot;)
+        with open(examples) as f:
+            examples = json.loads(f.read())
</ins><span class="cx"> 
</span><ins>+        for ctr, i in enumerate(examples):
</ins><span class="cx"> 
</span><del>-    def testYearlyLeapDaySkipBackwardDefault(self):
</del><ins>+            rules = [i[&quot;rule&quot;]]
+            if &quot;RSCALE&quot; not in rules[0]:
+                rules.append(&quot;RSCALE=GREGORIAN;{};SKIP=YES&quot;.format(rules[0]))
+            for rule in rules:
+                recur = Recurrence()
+                recur.parse(rule)
+                start = DateTime.parseText(i[&quot;start&quot;])
+                end = DateTime.parseText(i[&quot;end&quot;])
+                results = map(DateTime.parseText, i[&quot;results&quot;])
</ins><span class="cx"> 
</span><del>-        for rrule in (
-            &quot;RSCALE=GREGORIAN;FREQ=YEARLY;SKIP=BACKWARD;COUNT=5&quot;,
-            &quot;RSCALE=GREGORIAN;FREQ=YEARLY;COUNT=5&quot;,
-        ):
-            recur = Recurrence()
-            recur.parse(rrule)
-            start = DateTime(2016, 2, 29)
-            end = DateTime(2100, 1, 1)
-            items = []
-            range = Period(start, end)
-            recur.expand(start, range, items)
-            self.assertEqual(
-                items,
-                [
-                    DateTime(2016, 2, 29),
-                    DateTime(2017, 2, 28),
-                    DateTime(2018, 2, 28),
-                    DateTime(2019, 2, 28),
-                    DateTime(2020, 2, 29),
-                ]
-            )
</del><ins>+                items = []
+                range = Period(start, end)
+                recur.expand(start, range, items)
+                self.assertEqual(
+                    items,
+                    results,
+                    msg=&quot;Failed rule: #{} {}&quot;.format(ctr + 1, rule)
+                )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def testChineseMonthlyByMonthDay30SkipYes(self):
</del><ins>+    def testClearOnChange(self):
</ins><span class="cx"> 
</span><del>-        rrule = &quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=30;SKIP=YES&quot;
</del><span class="cx">         recur = Recurrence()
</span><del>-        recur.parse(rrule)
-        start = DateTime(2014, 1, 30, 12, 0, 0)
-        end = DateTime(2015, 1, 1, 0, 0, 0)
-        items = []
-        range = Period(start, end)
-        recur.expand(start, range, items)
-        self.assertEqual(
-            items,
-            [
-                DateTime(2014, 1, 30, 12, 0, 0),
-                DateTime(2014, 3, 30, 12, 0, 0),
-                DateTime(2014, 5, 28, 12, 0, 0),
-                DateTime(2014, 7, 26, 12, 0, 0),
-                DateTime(2014, 9, 23, 12, 0, 0),
-                DateTime(2014, 10, 23, 12, 0, 0),
-                DateTime(2014, 12, 21, 12, 0, 0),
-            ],
-            msg=&quot;Failed: {} {}&quot;.format(rrule, items,),
-        )
</del><ins>+        recur.parse(&quot;FREQ=DAILY&quot;)
</ins><span class="cx"> 
</span><del>-
-    def testChineseMonthlyByMonthDay30SkipBackward(self):
-
-        rrule = &quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=30;SKIP=BACKWARD&quot;
-        recur = Recurrence()
-        recur.parse(rrule)
-        start = DateTime(2014, 1, 30, 12, 0, 0)
-        end = DateTime(2015, 1, 1, 0, 0, 0)
-        items = []
</del><ins>+        start = DateTime(2013, 1, 1, 0, 0, 0)
+        end = DateTime(2017, 1, 1, 0, 0, 0)
</ins><span class="cx">         range = Period(start, end)
</span><ins>+        items = []
</ins><span class="cx">         recur.expand(start, range, items)
</span><del>-        self.assertEqual(
-            items,
-            [
-                DateTime(2014, 1, 30, 12, 0, 0),
-                DateTime(2014, 2, 28, 12, 0, 0),
-                DateTime(2014, 3, 30, 12, 0, 0),
-                DateTime(2014, 4, 28, 12, 0, 0),
-                DateTime(2014, 5, 28, 12, 0, 0),
-                DateTime(2014, 6, 26, 12, 0, 0),
-                DateTime(2014, 7, 26, 12, 0, 0),
-                DateTime(2014, 8, 24, 12, 0, 0),
-                DateTime(2014, 9, 23, 12, 0, 0),
-                DateTime(2014, 10, 23, 12, 0, 0),
-                DateTime(2014, 11, 21, 12, 0, 0),
-                DateTime(2014, 12, 21, 12, 0, 0),
-            ],
-            msg=&quot;Failed: {} {}&quot;.format(rrule, items,),
-        )
</del><ins>+        self.assertTrue(recur.mCached)
+        self.assertTrue(len(items) &gt; 100)
</ins><span class="cx"> 
</span><del>-
-    def testChineseMonthlyByMonthDay30SkipForward(self):
-
-        rrule = &quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=30;SKIP=FORWARD&quot;
-        recur = Recurrence()
-        recur.parse(rrule)
-        start = DateTime(2014, 1, 30, 12, 0, 0)
-        end = DateTime(2015, 1, 1, 0, 0, 0)
</del><ins>+        recur.setUseCount(True)
+        recur.setCount(10)
+        self.assertFalse(recur.mCached)
</ins><span class="cx">         items = []
</span><del>-        range = Period(start, end)
</del><span class="cx">         recur.expand(start, range, items)
</span><del>-        self.assertEqual(
-            items,
-            [
-                DateTime(2014, 1, 30, 12, 0, 0),
-                DateTime(2014, 3, 1, 12, 0, 0),
-                DateTime(2014, 3, 30, 12, 0, 0),
-                DateTime(2014, 4, 29, 12, 0, 0),
-                DateTime(2014, 5, 28, 12, 0, 0),
-                DateTime(2014, 6, 27, 12, 0, 0),
-                DateTime(2014, 7, 26, 12, 0, 0),
-                DateTime(2014, 8, 25, 12, 0, 0),
-                DateTime(2014, 9, 23, 12, 0, 0),
-                DateTime(2014, 10, 23, 12, 0, 0),
-                DateTime(2014, 11, 22, 12, 0, 0),
-                DateTime(2014, 12, 21, 12, 0, 0),
-            ],
-            msg=&quot;Failed: {} {}&quot;.format(rrule, items,),
-        )
</del><ins>+        self.assertEqual(len(items), 10)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def testChineseMonthlyByMonthDayMinus30SkipYes(self):
</del><span class="cx"> 
</span><del>-        rrule = &quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=-30;SKIP=YES&quot;
-        recur = Recurrence()
-        recur.parse(rrule)
-        start = DateTime(2014, 1, 30, 12, 0, 0)
-        end = DateTime(2015, 1, 1, 0, 0, 0)
-        items = []
-        range = Period(start, end)
-        recur.expand(start, range, items)
-        self.assertEqual(
-            items,
-            [
-                DateTime(2014, 3, 1, 12, 0, 0),
-                DateTime(2014, 4, 29, 12, 0, 0),
-                DateTime(2014, 6, 27, 12, 0, 0),
-                DateTime(2014, 8, 25, 12, 0, 0),
-                DateTime(2014, 9, 24, 12, 0, 0),
-                DateTime(2014, 11, 22, 12, 0, 0),
-            ],
-            msg=&quot;Failed: {} {}&quot;.format(rrule, items,),
-        )
</del><ins>+class TestRecurrenceRscale(unittest.TestCase):
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def testChineseMonthlyByMonthDayMinus30SkipBackward(self):
</del><ins>+    def testExampleRules(self):
</ins><span class="cx"> 
</span><del>-        rrule = &quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=-30;SKIP=BACKWARD&quot;
-        recur = Recurrence()
-        recur.parse(rrule)
-        start = DateTime(2014, 1, 30, 12, 0, 0)
-        end = DateTime(2015, 1, 1, 0, 0, 0)
-        items = []
-        range = Period(start, end)
-        recur.expand(start, range, items)
-        self.assertEqual(
-            items,
-            [
-                DateTime(2014, 1, 30, 12, 0, 0),
-                DateTime(2014, 3, 1, 12, 0, 0),
-                DateTime(2014, 3, 30, 12, 0, 0),
-                DateTime(2014, 4, 29, 12, 0, 0),
-                DateTime(2014, 5, 28, 12, 0, 0),
-                DateTime(2014, 6, 27, 12, 0, 0),
-                DateTime(2014, 7, 26, 12, 0, 0),
-                DateTime(2014, 8, 25, 12, 0, 0),
-                DateTime(2014, 9, 24, 12, 0, 0),
-                DateTime(2014, 10, 23, 12, 0, 0),
-                DateTime(2014, 11, 22, 12, 0, 0),
-                DateTime(2014, 12, 21, 12, 0, 0),
-            ],
-            msg=&quot;Failed: {} {}&quot;.format(rrule, items,),
-        )
</del><ins>+        examples = os.path.join(os.path.dirname(__file__), &quot;rscale_examples.json&quot;)
+        with open(examples) as f:
+            examples = json.loads(f.read())
</ins><span class="cx"> 
</span><ins>+        for ctr, i in enumerate(examples):
</ins><span class="cx"> 
</span><del>-    def testChineseMonthlyByMonthDayMinus30SkipForward(self):
</del><ins>+            for rule in i[&quot;rule&quot;]:
+                recur = Recurrence()
+                recur.parse(rule)
+                start = DateTime.parseText(i[&quot;start&quot;])
+                end = DateTime.parseText(i[&quot;end&quot;])
+                results = map(DateTime.parseText, i[&quot;results&quot;])
</ins><span class="cx"> 
</span><del>-        rrule = &quot;RSCALE=CHINESE;FREQ=MONTHLY;BYMONTHDAY=-30;SKIP=FORWARD&quot;
-        recur = Recurrence()
-        recur.parse(rrule)
-        start = DateTime(2014, 1, 30, 12, 0, 0)
-        end = DateTime(2015, 1, 1, 0, 0, 0)
-        items = []
-        range = Period(start, end)
-        recur.expand(start, range, items)
-        self.assertEqual(
-            items,
-            [
-                DateTime(2014, 1, 31, 12, 0, 0),
-                DateTime(2014, 3, 1, 12, 0, 0),
-                DateTime(2014, 3, 31, 12, 0, 0),
-                DateTime(2014, 4, 29, 12, 0, 0),
-                DateTime(2014, 5, 29, 12, 0, 0),
-                DateTime(2014, 6, 27, 12, 0, 0),
-                DateTime(2014, 7, 27, 12, 0, 0),
-                DateTime(2014, 8, 25, 12, 0, 0),
-                DateTime(2014, 9, 24, 12, 0, 0),
-                DateTime(2014, 10, 24, 12, 0, 0),
-                DateTime(2014, 11, 22, 12, 0, 0),
-                DateTime(2014, 12, 22, 12, 0, 0),
-            ],
-            msg=&quot;Failed: {} {}&quot;.format(rrule, items,),
-        )
</del><ins>+                items = []
+                range = Period(start, end)
+                recur.expand(start, range, items)
+                self.assertEqual(
+                    items,
+                    results,
+                    msg=&quot;Failed rule: #{} {}&quot;.format(ctr + 1, rule)
+                )
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarteststest_vpollpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_vpoll.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_vpoll.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/tests/test_vpoll.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2015 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> #    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
</span><span class="cx"> #    you may not use this file except in compliance with the License.
</span><span class="lines">@@ -32,8 +32,16 @@
</span><span class="cx"> ORGANIZER:mailto:user01@example.com
</span><span class="cx"> POLL-MODE:BASIC
</span><span class="cx"> POLL-PROPERTIES:DTSTART,DTEND
</span><ins>+BEGIN:VVOTER
</ins><span class="cx"> VOTER;CN=User 02:mailto:user02@example.com
</span><ins>+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:100
+END:VOTE
+END:VVOTER
+BEGIN:VVOTER
</ins><span class="cx"> VOTER;CN=User 03:mailto:user03@example.com
</span><ins>+END:VVOTER
</ins><span class="cx"> BEGIN:VEVENT
</span><span class="cx"> UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
</span><span class="cx"> DTSTART;VALUE=DATE:20130101
</span><span class="lines">@@ -63,11 +71,21 @@
</span><span class="cx"> UID:A979D282-2CDB-484F-BD63-3972094DFFC0
</span><span class="cx"> DTSTAMP:20020101T000000Z
</span><span class="cx"> ORGANIZER:mailto:user01@example.com
</span><del>-POLL-ITEM-ID;PUBLIC-COMMENT=Not ideal;RESPONSE=50:1
-POLL-ITEM-ID;PUBLIC-COMMENT=Perfect;RESPONSE=100:2
</del><span class="cx"> POLL-MODE:BASIC
</span><span class="cx"> POLL-PROPERTIES:DTSTART,DTEND
</span><ins>+BEGIN:VVOTER
</ins><span class="cx"> VOTER;CN=User 02:mailto:user02@example.com
</span><ins>+BEGIN:VOTE
+POLL-ITEM-ID:1
+RESPONSE:50
+COMMENT:Not ideal
+END:VOTE
+BEGIN:VOTE
+POLL-ITEM-ID:2
+RESPONSE:100
+COMMENT:Perfect
+END:VOTE
+END:VVOTER
</ins><span class="cx"> END:VPOLL
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarvotepyfromrev15020PyCalendartrunksrcpycalendaricalendarvotepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/branches/rscale/src/pycalendar/icalendar/vote.py (from rev 15020, PyCalendar/trunk/src/pycalendar/icalendar/vote.py) (0 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/vote.py                                (rev 0)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/vote.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+##
+#    Copyright (c) 2011-2015 Cyrus Daboo. All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+##
+
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class Vote(Component):
+
+    propertyCardinality_1 = (
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_POLL_ITEM_ID,
+        definitions.cICalProperty_RESPONSE,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None):
+        super(Vote, self).__init__(parent=parent)
+
+
+    def duplicate(self, parent=None):
+        return super(Vote, self).duplicate(parent=parent)
+
+
+    def getType(self):
+        return definitions.cICalComponent_VOTE
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_POLL_ITEM_ID,
+            definitions.cICalProperty_RESPONSE,
+        )
+
+Component.registerComponent(definitions.cICalComponent_VOTE, Vote)
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarvpollpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/icalendar/vpoll.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/vpoll.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/vpoll.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2015 Cyrus Daboo. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> #    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
</span><span class="cx"> #    you may not use this file except in compliance with the License.
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx">         definitions.cICalProperty_LAST_MODIFIED,
</span><span class="cx">         definitions.cICalProperty_POLL_MODE,
</span><span class="cx">         definitions.cICalProperty_POLL_PROPERTIES,
</span><ins>+        definitions.cICalProperty_POLL_WINNER,
</ins><span class="cx">         definitions.cICalProperty_PRIORITY,
</span><span class="cx">         definitions.cICalProperty_SEQUENCE,
</span><span class="cx">         definitions.cICalProperty_STATUS,
</span><span class="lines">@@ -67,13 +68,18 @@
</span><span class="cx"> 
</span><span class="cx">     def sortedComponents(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        Also take POLL-ID into account
</del><ins>+        Also take VVOTER and POLL-ID into account
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         components = self.mComponents[:]
</span><span class="cx"> 
</span><del>-        # Write out the remainder sorted by name, sortKey
-        return sorted(components, key=lambda x: (x.getType().upper(), x.loadValueString(definitions.cICalProperty_POLL_ITEM_ID),))
</del><ins>+        # VVOTER sorts above components with POLL-ITEM-ID
+        def _sortKey(subcomponent):
+            if subcomponent.getType().upper() == definitions.cICalComponent_VVOTER:
+                return (&quot;0&quot;, subcomponent.loadValueString(definitions.cICalProperty_VOTER),)
+            else:
+                return (subcomponent.getType().upper(), subcomponent.loadValueInteger(definitions.cICalProperty_POLL_ITEM_ID),)
+        return sorted(components, key=_sortKey)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> Component.registerComponent(definitions.cICalComponent_VPOLL, VPoll)
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendaricalendarvvoterpyfromrev15020PyCalendartrunksrcpycalendaricalendarvvoterpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/branches/rscale/src/pycalendar/icalendar/vvoter.py (from rev 15020, PyCalendar/trunk/src/pycalendar/icalendar/vvoter.py) (0 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/icalendar/vvoter.py                                (rev 0)
+++ PyCalendar/branches/rscale/src/pycalendar/icalendar/vvoter.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -0,0 +1,71 @@
</span><ins>+##
+#    Copyright (c) 2011-2015 Cyrus Daboo. All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+##
+
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VVoter(Component):
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_VOTER,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_CREATED,
+        definitions.cICalProperty_DESCRIPTION,
+        definitions.cICalProperty_LAST_MODIFIED,
+        definitions.cICalProperty_SUMMARY,
+        definitions.cICalProperty_URL,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None):
+        super(VVoter, self).__init__(parent=parent)
+
+
+    def duplicate(self, parent=None):
+        return super(VVoter, self).duplicate(parent=parent)
+
+
+    def getType(self):
+        return definitions.cICalComponent_VVOTER
+
+
+    def addComponent(self, comp):
+        # We can embed the available components only
+        if comp.getType() == definitions.cICalComponent_VOTE:
+            super(VVoter, self).addComponent(comp)
+        else:
+            raise ValueError
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_VOTER,
+        )
+
+
+    def sortedComponents(self):
+        &quot;&quot;&quot;
+        Also take POLL-ITEM-ID into account
+        &quot;&quot;&quot;
+
+        components = self.mComponents[:]
+        return sorted(components, key=lambda x: x.loadValueInteger(definitions.cICalProperty_POLL_ITEM_ID))
+
+Component.registerComponent(definitions.cICalComponent_VVOTER, VVoter)
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendarparserpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/parser.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/parser.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/parser.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -61,6 +61,9 @@
</span><span class="cx">     # Remove \-escaping in URI values when parsing - only PARSER_FIX or PARSER_ALLOW
</span><span class="cx">     BACKSLASH_IN_URI_VALUE = PARSER_FIX
</span><span class="cx"> 
</span><ins>+    # Remove \-escaping in GEO values when parsing - only PARSER_FIX
+    BACKSLASH_IN_GEO_VALUE = PARSER_FIX
+
</ins><span class="cx">     @staticmethod
</span><span class="cx">     def allRaise():
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -75,4 +78,5 @@
</span><span class="cx">         ParserContext.INVALID_ADR_N_VALUES = ParserContext.PARSER_RAISE
</span><span class="cx">         ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_RAISE
</span><span class="cx">         ParserContext.BACKSLASH_IN_URI_VALUE = ParserContext.PARSER_RAISE
</span><ins>+        ParserContext.BACKSLASH_IN_GEO_VALUE = ParserContext.PARSER_RAISE
</ins><span class="cx">         ParserContext.INVALID_REQUEST_STATUS = ParserContext.PARSER_RAISE
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendarperiodpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/period.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/period.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/period.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -28,26 +28,28 @@
</span><span class="cx"> 
</span><span class="cx">         if end is not None:
</span><span class="cx">             self.mEnd = end
</span><del>-            self.mDuration = self.mEnd - self.mStart
</del><ins>+            self.mDuration = None
</ins><span class="cx">             self.mUseDuration = False
</span><span class="cx">         elif duration is not None:
</span><span class="cx">             self.mDuration = duration
</span><del>-            self.mEnd = self.mStart + self.mDuration
</del><ins>+            self.mEnd = None
</ins><span class="cx">             self.mUseDuration = True
</span><span class="cx">         else:
</span><span class="cx">             self.mEnd = self.mStart.duplicate()
</span><del>-            self.mDuration = Duration()
</del><ins>+            self.mDuration = None
</ins><span class="cx">             self.mUseDuration = False
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def duplicate(self):
</span><del>-        other = Period(start=self.mStart.duplicate(), end=self.mEnd.duplicate())
-        other.mUseDuration = self.mUseDuration
</del><ins>+        if self.mUseDuration:
+            other = Period(start=self.mStart.duplicate(), duration=self.mDuration.duplicate())
+        else:
+            other = Period(start=self.mStart.duplicate(), end=self.mEnd.duplicate())
</ins><span class="cx">         return other
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __hash__(self):
</span><del>-        return hash((self.mStart, self.mEnd,))
</del><ins>+        return hash((self.mStart, self.getEnd(),))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __repr__(self):
</span><span class="lines">@@ -59,7 +61,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __eq__(self, comp):
</span><del>-        return self.mStart == comp.mStart and self.mEnd == comp.mEnd
</del><ins>+        return self.mStart == comp.mStart and self.getEnd() == comp.getEnd()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __gt__(self, comp):
</span><span class="lines">@@ -68,7 +70,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __lt__(self, comp):
</span><span class="cx">         return self.mStart &lt; comp.mStart  \
</span><del>-            or (self.mStart == comp.mStart) and self.mEnd &lt; comp.mEnd
</del><ins>+            or (self.mStart == comp.mStart) and self.getEnd() &lt; comp.getEnd()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><span class="lines">@@ -79,21 +81,24 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def parse(self, data, fullISO=False):
</span><del>-        splits = data.split('/', 1)
-        if len(splits) == 2:
-            start = splits[0]
-            end = splits[1]
</del><ins>+        try:
+            splits = data.split('/', 1)
+            if len(splits) == 2:
+                start = splits[0]
+                end = splits[1]
</ins><span class="cx"> 
</span><del>-            self.mStart.parse(start, fullISO)
-            if end[0] == 'P':
-                self.mDuration.parse(end)
-                self.mUseDuration = True
-                self.mEnd = self.mStart + self.mDuration
</del><ins>+                self.mStart.parse(start, fullISO)
+                if end[0] == 'P':
+                    self.mDuration = Duration.parseText(end)
+                    self.mUseDuration = True
+                    self.mEnd = None
+                else:
+                    self.mEnd.parse(end, fullISO)
+                    self.mUseDuration = False
+                    self.mDuration = None
</ins><span class="cx">             else:
</span><del>-                self.mEnd.parse(end, fullISO)
-                self.mUseDuration = False
-                self.mDuration = self.mEnd - self.mStart
-        else:
</del><ins>+                raise ValueError
+        except IndexError:
</ins><span class="cx">             raise ValueError
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -146,10 +151,14 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getEnd(self):
</span><ins>+        if self.mEnd is None:
+            self.mEnd = self.mStart + self.mDuration
</ins><span class="cx">         return self.mEnd
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getDuration(self):
</span><ins>+        if self.mDuration is None:
+            self.mDuration = self.mEnd - self.mStart
</ins><span class="cx">         return self.mDuration
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -159,11 +168,15 @@
</span><span class="cx"> 
</span><span class="cx">     def setUseDuration(self, use):
</span><span class="cx">         self.mUseDuration = use
</span><ins>+        if self.mUseDuration and self.mDuration is None:
+            self.getDuration()
+        elif not self.mUseDuration and self.mEnd is None:
+            self.getEnd()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def isDateWithinPeriod(self, dt):
</span><span class="cx">         # Inclusive start, exclusive end
</span><del>-        return dt &gt;= self.mStart and dt &lt; self.mEnd
</del><ins>+        return dt &gt;= self.mStart and dt &lt; self.getEnd()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def isDateBeforePeriod(self, dt):
</span><span class="lines">@@ -173,17 +186,17 @@
</span><span class="cx"> 
</span><span class="cx">     def isDateAfterPeriod(self, dt):
</span><span class="cx">         # Exclusive end
</span><del>-        return dt &gt;= self.mEnd
</del><ins>+        return dt &gt;= self.getEnd()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def isPeriodOverlap(self, p):
</span><span class="cx">         # Inclusive start, exclusive end
</span><del>-        return not (self.mStart &gt;= p.mEnd or self.mEnd &lt;= p.mStart)
</del><ins>+        return not (self.mStart &gt;= p.getEnd() or self.getEnd() &lt;= p.mStart)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def adjustToUTC(self):
</span><span class="cx">         self.mStart.adjustToUTC()
</span><del>-        self.mEnd.adjustToUTC()
</del><ins>+        self.getEnd().adjustToUTC()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def describeDuration(self):
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendarplaintextvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/plaintextvalue.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/plaintextvalue.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/plaintextvalue.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def parseJSONValue(self, jobject):
</span><del>-        self.mValue = str(jobject)
</del><ins>+        self.mValue = jobject.encode(&quot;utf-8&quot;)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def writeJSONValue(self, jobject):
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendarpropertypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/property.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/property.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/property.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -472,21 +472,21 @@
</span><span class="cx">             prop = cls()
</span><span class="cx"> 
</span><span class="cx">             # Get the name
</span><del>-            prop.mName = jobject[0].upper()
</del><ins>+            prop.mName = jobject[0].encode(&quot;utf-8&quot;).upper()
</ins><span class="cx"> 
</span><span class="cx">             # Get the parameters
</span><span class="cx">             if jobject[1]:
</span><span class="cx">                 for name, value in jobject[1].items():
</span><span class="cx">                     # Now add parameter value
</span><span class="cx">                     name = name.upper()
</span><del>-                    attrvalue = Parameter(name=name, value=value)
</del><ins>+                    attrvalue = Parameter(name=name.encode(&quot;utf-8&quot;), value=value.encode(&quot;utf-8&quot;))
</ins><span class="cx">                     prop.mParameters.setdefault(name, []).append(attrvalue)
</span><span class="cx"> 
</span><span class="cx">             # Get default value type from property name and insert a VALUE parameter if current value type is not default
</span><span class="cx">             value_type = cls.sValueTypeMap.get(jobject[2].upper(), Value.VALUETYPE_UNKNOWN)
</span><span class="cx">             default_type = cls.sDefaultValueTypeMap.get(prop.mName.upper(), Value.VALUETYPE_UNKNOWN)
</span><span class="cx">             if default_type != value_type:
</span><del>-                attrvalue = Parameter(name=cls.sValue, value=jobject[2].upper())
</del><ins>+                attrvalue = Parameter(name=cls.sValue, value=jobject[2].encode(&quot;utf-8&quot;).upper())
</ins><span class="cx">                 prop.mParameters.setdefault(cls.sValue, []).append(attrvalue)
</span><span class="cx"> 
</span><span class="cx">             # Get value type from property name
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendarteststest_geovaluepyfromrev15020PyCalendartrunksrcpycalendarteststest_geovaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/branches/rscale/src/pycalendar/tests/test_geovalue.py (from rev 15020, PyCalendar/trunk/src/pycalendar/tests/test_geovalue.py) (0 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/tests/test_geovalue.py                                (rev 0)
+++ PyCalendar/branches/rscale/src/pycalendar/tests/test_geovalue.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+##
+#    Copyright (c) 2012-2013 Cyrus Daboo. All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+##
+
+from pycalendar.geovalue import GeoValue
+from pycalendar.icalendar.property import Property
+import unittest
+
+class TestURIValue(unittest.TestCase):
+
+    def testParseValue(self):
+
+        items = (
+            (&quot;-12.345;67.890&quot;, &quot;-12.345;67.89&quot;),
+            (&quot;-12.345\\;67.890&quot;, &quot;-12.345;67.89&quot;),
+        )
+
+        for item, result in items:
+            req = GeoValue()
+            req.parse(item, &quot;icalendar&quot;)
+            test = req.getText()
+            self.assertEqual(test, result, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
+
+
+    def testParseProperty(self):
+
+        items = (
+            (&quot;GEO:-12.345;67.890&quot;, &quot;GEO:-12.345;67.89&quot;),
+            (&quot;GEO:-12.345\\;67.890&quot;, &quot;GEO:-12.345;67.89&quot;),
+        )
+
+        for item, result in items:
+            prop = Property.parseText(item)
+            test = prop.getText()
+            self.assertEqual(test, result + &quot;\r\n&quot;, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendarteststest_periodpyfromrev15020PyCalendartrunksrcpycalendarteststest_periodpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/branches/rscale/src/pycalendar/tests/test_period.py (from rev 15020, PyCalendar/trunk/src/pycalendar/tests/test_period.py) (0 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/tests/test_period.py                                (rev 0)
+++ PyCalendar/branches/rscale/src/pycalendar/tests/test_period.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -0,0 +1,64 @@
</span><ins>+##
+#    Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+##
+
+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
+from pycalendar.period import Period
+import unittest
+
+class TestPeriod(unittest.TestCase):
+
+    test_data = (
+        &quot;20000101T000000Z/20000101T010000Z&quot;,
+        &quot;20000101T000000Z/PT1H&quot;,
+    )
+
+    def testParseGenerate(self):
+
+        for result in TestPeriod.test_data:
+            period = Period.parseText(result)
+            self.assertEqual(period.getText(), result)
+
+
+    def testParseBad(self):
+
+        test_bad_data = (
+            &quot;&quot;,
+            &quot;ABC&quot;,
+            &quot;20000101T000000Z&quot;,
+            &quot;20000101T000000Z/&quot;,
+            &quot;20000101T000000Z/P&quot;,
+            &quot;20000101T000000Z/2000&quot;,
+        )
+        for data in test_bad_data:
+            self.assertRaises(ValueError, Period.parseText, data)
+
+
+    def testSetUseDuration(self):
+
+        p1 = Period(
+            start=DateTime(2000, 1, 1, 0, 0, 0),
+            end=DateTime(2000, 1, 1, 1, 0, 0),
+        )
+        p1.setUseDuration(True)
+        self.assertTrue(p1.getText(), &quot;20000101T000000/PT1H&quot;)
+
+        p2 = Period(
+            start=DateTime(2000, 1, 1, 0, 0, 0),
+            duration=Duration(hours=1),
+        )
+        p2.setUseDuration(False)
+        self.assertTrue(p2.getText(), &quot;20000101T000000/20000101T010000&quot;)
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendartimezonepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/timezone.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/timezone.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/timezone.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     sDefaultTimezone = None
</span><ins>+    UTCTimezone = None
</ins><span class="cx"> 
</span><span class="cx">     def __init__(self, utc=None, tzid=None):
</span><span class="cx"> 
</span><span class="lines">@@ -127,3 +128,4 @@
</span><span class="cx">             return TimezoneDatabase.getTimezoneDescriptor(self.mTimezone, dt)
</span><span class="cx"> 
</span><span class="cx"> Timezone.sDefaultTimezone = Timezone()
</span><ins>+Timezone.UTCTimezone = Timezone(utc=True)
</ins></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendartimezonedbpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/timezonedb.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/timezonedb.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/timezonedb.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -127,7 +127,8 @@
</span><span class="cx">         tzpath = os.path.normpath(tzpath)
</span><span class="cx">         if tzpath.startswith(self.dbpath) and os.path.isfile(tzpath):
</span><span class="cx">             try:
</span><del>-                self.calendar.parseComponent(open(tzpath))
</del><ins>+                with open(tzpath) as f:
+                    self.calendar.parseComponent(f)
</ins><span class="cx">             except (IOError, InvalidData):
</span><span class="cx">                 raise NoTimezoneInDatabase(self.dbpath, tzid)
</span><span class="cx">         else:
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendarvalidatorpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/validator.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/validator.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/validator.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -27,7 +27,8 @@
</span><span class="cx">     Check whether the contents of the specified file is valid iCalendar or vCard data.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    data = open(fname).read()
</del><ins>+    with open(fname) as f:
+        data = f.read()
</ins><span class="cx"> 
</span><span class="cx">     ParserContext.allRaise()
</span><span class="cx"> 
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendarvcardadrpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/vcard/adr.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/vcard/adr.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/vcard/adr.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -120,7 +120,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def parseJSON(self, jobject):
</span><del>-        self.mValue = tuple(jobject)
</del><ins>+        self.mValue = tuple(map(lambda x: x.encode(&quot;utf-8&quot;), jobject))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def writeJSON(self, jobject):
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendarvcardnpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/vcard/n.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/vcard/n.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/vcard/n.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -117,7 +117,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def parseJSON(self, jobject):
</span><del>-        self.mValue = tuple(jobject)
</del><ins>+        self.mValue = tuple(map(lambda x: x.encode(&quot;utf-8&quot;), jobject))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def writeJSON(self, jobject):
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrcpycalendarvcardorgvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/pycalendar/vcard/orgvalue.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/pycalendar/vcard/orgvalue.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/pycalendar/vcard/orgvalue.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def parseJSONValue(self, jobject):
</span><del>-        self.mValue = tuple(jobject)
</del><ins>+        self.mValue = tuple(map(lambda x: x.encode(&quot;utf-8&quot;), jobject))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def writeJSONValue(self, jobject):
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrczonaltzconvertpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/zonal/tzconvert.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/zonal/tzconvert.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/zonal/tzconvert.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -53,28 +53,28 @@
</span><span class="cx"> 
</span><span class="cx">     def parse(self, file):
</span><span class="cx">         try:
</span><del>-            f = open(file, &quot;r&quot;)
-            ctr = 0
-            for line in f:
-                ctr += 1
-                line = line[:-1]
-                while True:
-                    if line.startswith(&quot;#&quot;) or len(line) == 0:
-                        break
-                    elif line.startswith(&quot;Rule&quot;):
-                        self.parseRule(line)
-                        break
-                    elif line.startswith(&quot;Zone&quot;):
-                        line = self.parseZone(line, f)
-                        if line is None:
</del><ins>+            with open(file, &quot;r&quot;) as f:
+                ctr = 0
+                for line in f:
+                    ctr += 1
+                    line = line[:-1]
+                    while True:
+                        if line.startswith(&quot;#&quot;) or len(line) == 0:
</ins><span class="cx">                             break
</span><del>-                    elif line.startswith(&quot;Link&quot;):
-                        self.parseLink(line)
-                        break
-                    elif len(line.strip()) != 0:
-                        assert False, &quot;Could not parse line %d from tzconvert file: '%s'&quot; % (ctr, line,)
-                    else:
-                        break
</del><ins>+                        elif line.startswith(&quot;Rule&quot;):
+                            self.parseRule(line)
+                            break
+                        elif line.startswith(&quot;Zone&quot;):
+                            line = self.parseZone(line, f)
+                            if line is None:
+                                break
+                        elif line.startswith(&quot;Link&quot;):
+                            self.parseLink(line)
+                            break
+                        elif len(line.strip()) != 0:
+                            assert False, &quot;Could not parse line %d from tzconvert file: '%s'&quot; % (ctr, line,)
+                        else:
+                            break
</ins><span class="cx">         except:
</span><span class="cx">             print(&quot;Failed to parse file %s&quot; % (file,))
</span><span class="cx">             raise
</span><span class="lines">@@ -119,8 +119,8 @@
</span><span class="cx">     def parseWindowsAliases(self, aliases):
</span><span class="cx"> 
</span><span class="cx">         try:
</span><del>-            xmlfile = open(aliases)
-            xmlroot = XML.ElementTree(file=xmlfile).getroot()
</del><ins>+            with open(aliases) as xmlfile:
+                xmlroot = XML.ElementTree(file=xmlfile).getroot()
</ins><span class="cx">         except (IOError, XMLParseError):
</span><span class="cx">             raise ValueError(&quot;Unable to open or read windows alias file: {}&quot;.format(aliases))
</span><span class="cx"> 
</span><span class="lines">@@ -217,7 +217,8 @@
</span><span class="cx"> 
</span><span class="cx">             # Generate link mapping file
</span><span class="cx">             linkPath = os.path.join(outputdir, &quot;links.txt&quot;)
</span><del>-            open(linkPath, &quot;w&quot;).write(&quot;\n&quot;.join(link_list))
</del><ins>+            with open(linkPath, &quot;w&quot;) as f:
+                f.write(&quot;\n&quot;.join(link_list))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrczonaltzdumppy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/zonal/tzdump.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/zonal/tzdump.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/zonal/tzdump.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -27,12 +27,12 @@
</span><span class="cx">     cal = Calendar()
</span><span class="cx">     if verbose:
</span><span class="cx">         print &quot;Parsing calendar data: %s&quot; % (file,)
</span><del>-    fin = open(file, &quot;r&quot;)
-    try:
-        cal.parse(fin)
-    except InvalidData, e:
-        print &quot;Failed to parse bad data: %s&quot; % (e.mData,)
-        raise
</del><ins>+    with open(file, &quot;r&quot;) as fin:
+        try:
+            cal.parse(fin)
+        except InvalidData, e:
+            print &quot;Failed to parse bad data: %s&quot; % (e.mData,)
+            raise
</ins><span class="cx">     return cal
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="PyCalendarbranchesrscalesrczonaltzverifypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/branches/rscale/src/zonal/tzverify.py (15126 => 15127)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/branches/rscale/src/zonal/tzverify.py        2015-09-11 17:35:39 UTC (rev 15126)
+++ PyCalendar/branches/rscale/src/zonal/tzverify.py        2015-09-14 16:49:28 UTC (rev 15127)
</span><span class="lines">@@ -63,12 +63,12 @@
</span><span class="cx">     for file in files:
</span><span class="cx">         if verbose:
</span><span class="cx">             print &quot;Parsing calendar data: %s&quot; % (file,)
</span><del>-        fin = open(file, &quot;r&quot;)
-        try:
-            cal.parse(fin)
-        except InvalidData, e:
-            print &quot;Failed to parse bad data: %s&quot; % (e.mData,)
-            raise
</del><ins>+        with open(file, &quot;r&quot;) as fin:
+            try:
+                cal.parse(fin)
+            except InvalidData, e:
+                print &quot;Failed to parse bad data: %s&quot; % (e.mData,)
+                raise
</ins><span class="cx">     return CalendarZonesWrapper(calendar=cal)
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>