<!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>[11914] PyCalendar/trunk</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/11914">11914</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2013-11-08 12:35:58 -0800 (Fri, 08 Nov 2013)</dd>
</dl>

<h3>Log Message</h3>
<pre>Major refactor to support JSON encoded iCalendar data. Module was re-organized and various naming issues cleaned up. This change is
NOT backwards compatible. Most code using PyCalendar will need to be updated.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#PyCalendartrunkpydevproject">PyCalendar/trunk/.pydevproject</a></li>
<li><a href="#PyCalendartrunksetuppy">PyCalendar/trunk/setup.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendar__init__py">PyCalendar/trunk/src/pycalendar/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarbinaryvaluepy">PyCalendar/trunk/src/pycalendar/binaryvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcaladdressvaluepy">PyCalendar/trunk/src/pycalendar/caladdressvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcomponentbasepy">PyCalendar/trunk/src/pycalendar/componentbase.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendardatetimepy">PyCalendar/trunk/src/pycalendar/datetime.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendardatetimevaluepy">PyCalendar/trunk/src/pycalendar/datetimevalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendardurationpy">PyCalendar/trunk/src/pycalendar/duration.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendardurationvaluepy">PyCalendar/trunk/src/pycalendar/durationvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarexceptionspy">PyCalendar/trunk/src/pycalendar/exceptions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendar__init__py">PyCalendar/trunk/src/pycalendar/icalendar/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendartests__init__py">PyCalendar/trunk/src/pycalendar/icalendar/tests/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_validationpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvalidationpy">PyCalendar/trunk/src/pycalendar/icalendar/validation.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarintegervaluepy">PyCalendar/trunk/src/pycalendar/integervalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarlocalepy">PyCalendar/trunk/src/pycalendar/locale.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarmanagerpy">PyCalendar/trunk/src/pycalendar/manager.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarmultivaluepy">PyCalendar/trunk/src/pycalendar/multivalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaroutputfilterpy">PyCalendar/trunk/src/pycalendar/outputfilter.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarperiodpy">PyCalendar/trunk/src/pycalendar/period.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarperiodvaluepy">PyCalendar/trunk/src/pycalendar/periodvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarplaintextvaluepy">PyCalendar/trunk/src/pycalendar/plaintextvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarpropertypy">PyCalendar/trunk/src/pycalendar/property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarstringutilspy">PyCalendar/trunk/src/pycalendar/stringutils.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendartests__init__py">PyCalendar/trunk/src/pycalendar/tests/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_datetimepy">PyCalendar/trunk/src/pycalendar/tests/test_datetime.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_durationpy">PyCalendar/trunk/src/pycalendar/tests/test_duration.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_multivaluepy">PyCalendar/trunk/src/pycalendar/tests/test_multivalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_urivaluepy">PyCalendar/trunk/src/pycalendar/tests/test_urivalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_utilspy">PyCalendar/trunk/src/pycalendar/tests/test_utils.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_validationpy">PyCalendar/trunk/src/pycalendar/tests/test_validation.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendartextvaluepy">PyCalendar/trunk/src/pycalendar/textvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendartimezonepy">PyCalendar/trunk/src/pycalendar/timezone.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendartimezonedbpy">PyCalendar/trunk/src/pycalendar/timezonedb.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarunknownvaluepy">PyCalendar/trunk/src/pycalendar/unknownvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarurivaluepy">PyCalendar/trunk/src/pycalendar/urivalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarutcoffsetvaluepy">PyCalendar/trunk/src/pycalendar/utcoffsetvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarutilspy">PyCalendar/trunk/src/pycalendar/utils.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvalidationpy">PyCalendar/trunk/src/pycalendar/validation.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvalidatorpy">PyCalendar/trunk/src/pycalendar/validator.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvaluepy">PyCalendar/trunk/src/pycalendar/value.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvalueutilspy">PyCalendar/trunk/src/pycalendar/valueutils.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcard__init__py">PyCalendar/trunk/src/pycalendar/vcard/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardcardpy">PyCalendar/trunk/src/pycalendar/vcard/card.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcarddefinitionspy">PyCalendar/trunk/src/pycalendar/vcard/definitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardpropertypy">PyCalendar/trunk/src/pycalendar/vcard/property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardtests__init__py">PyCalendar/trunk/src/pycalendar/vcard/tests/__init__.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_cardpy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_card.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_propertypy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_validationpy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_validation.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardvalidationpy">PyCalendar/trunk/src/pycalendar/vcard/validation.py</a></li>
<li><a href="#PyCalendartrunksrczonal__init__py">PyCalendar/trunk/src/zonal/__init__.py</a></li>
<li><a href="#PyCalendartrunksrczonalrulepy">PyCalendar/trunk/src/zonal/rule.py</a></li>
<li><a href="#PyCalendartrunksrczonaltests__init__py">PyCalendar/trunk/src/zonal/tests/__init__.py</a></li>
<li><a href="#PyCalendartrunksrczonalteststest_rulepy">PyCalendar/trunk/src/zonal/tests/test_rule.py</a></li>
<li><a href="#PyCalendartrunksrczonalteststest_zonepy">PyCalendar/trunk/src/zonal/tests/test_zone.py</a></li>
<li><a href="#PyCalendartrunksrczonaltzconvertpy">PyCalendar/trunk/src/zonal/tzconvert.py</a></li>
<li><a href="#PyCalendartrunksrczonaltzdumppy">PyCalendar/trunk/src/zonal/tzdump.py</a></li>
<li><a href="#PyCalendartrunksrczonaltzverifypy">PyCalendar/trunk/src/zonal/tzverify.py</a></li>
<li><a href="#PyCalendartrunksrczonalutilspy">PyCalendar/trunk/src/zonal/utils.py</a></li>
<li><a href="#PyCalendartrunksrczonalzonepy">PyCalendar/trunk/src/zonal/zone.py</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#PyCalendartrunksrcpycalendarcontainerbasepy">PyCalendar/trunk/src/pycalendar/containerbase.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarfloatvaluepy">PyCalendar/trunk/src/pycalendar/floatvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendargeovaluepy">PyCalendar/trunk/src/pycalendar/geovalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendaravailablepy">PyCalendar/trunk/src/pycalendar/icalendar/available.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarcalendarpy">PyCalendar/trunk/src/pycalendar/icalendar/calendar.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarcomponentpy">PyCalendar/trunk/src/pycalendar/icalendar/component.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarcomponentexpandedpy">PyCalendar/trunk/src/pycalendar/icalendar/componentexpanded.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarcomponentrecurpy">PyCalendar/trunk/src/pycalendar/icalendar/componentrecur.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendardefinitionspy">PyCalendar/trunk/src/pycalendar/icalendar/definitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarfreebusypy">PyCalendar/trunk/src/pycalendar/icalendar/freebusy.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendaritipdefinitionspy">PyCalendar/trunk/src/pycalendar/icalendar/itipdefinitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarpropertypy">PyCalendar/trunk/src/pycalendar/icalendar/property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarrecurrencepy">PyCalendar/trunk/src/pycalendar/icalendar/recurrence.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarrecurrencesetpy">PyCalendar/trunk/src/pycalendar/icalendar/recurrenceset.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarrecurrencevaluepy">PyCalendar/trunk/src/pycalendar/icalendar/recurrencevalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarrequeststatusvaluepy">PyCalendar/trunk/src/pycalendar/icalendar/requeststatusvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_calendarpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_calendar.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_componentrecurpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_componentrecur.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_i18npy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_i18n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_jsonpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_json.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_propertypy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_recurrencepy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_recurrence.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_requeststatuspy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_requeststatus.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_timezonepy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_timezone.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_vpollpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_vpoll.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarteststest_xmlpy">PyCalendar/trunk/src/pycalendar/icalendar/tests/test_xml.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvalarmpy">PyCalendar/trunk/src/pycalendar/icalendar/valarm.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvavailabilitypy">PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarveventpy">PyCalendar/trunk/src/pycalendar/icalendar/vevent.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvfreebusypy">PyCalendar/trunk/src/pycalendar/icalendar/vfreebusy.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvjournalpy">PyCalendar/trunk/src/pycalendar/icalendar/vjournal.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvpollpy">PyCalendar/trunk/src/pycalendar/icalendar/vpoll.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvtimezonepy">PyCalendar/trunk/src/pycalendar/icalendar/vtimezone.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvtimezonedaylightpy">PyCalendar/trunk/src/pycalendar/icalendar/vtimezonedaylight.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvtimezoneelementpy">PyCalendar/trunk/src/pycalendar/icalendar/vtimezoneelement.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvtimezonestandardpy">PyCalendar/trunk/src/pycalendar/icalendar/vtimezonestandard.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvtodopy">PyCalendar/trunk/src/pycalendar/icalendar/vtodo.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarvunknownpy">PyCalendar/trunk/src/pycalendar/icalendar/vunknown.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaricalendarxmldefinitionspy">PyCalendar/trunk/src/pycalendar/icalendar/xmldefinitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarparameterpy">PyCalendar/trunk/src/pycalendar/parameter.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardadrpy">PyCalendar/trunk/src/pycalendar/vcard/adr.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardadrvaluepy">PyCalendar/trunk/src/pycalendar/vcard/adrvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardnpy">PyCalendar/trunk/src/pycalendar/vcard/n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardnvaluepy">PyCalendar/trunk/src/pycalendar/vcard/nvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardorgvaluepy">PyCalendar/trunk/src/pycalendar/vcard/orgvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_adrpy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_adr.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_adrvaluepy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_adrvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_npy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_nvaluepy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_nvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardteststest_orgvaluepy">PyCalendar/trunk/src/pycalendar/vcard/tests/test_orgvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvcardxmldefinitionspy">PyCalendar/trunk/src/pycalendar/vcard/xmldefinitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarxmldefinitionspy">PyCalendar/trunk/src/pycalendar/xmldefinitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarxmlutilspy">PyCalendar/trunk/src/pycalendar/xmlutils.py</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#PyCalendartrunksrcpycalendaradrpy">PyCalendar/trunk/src/pycalendar/adr.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaradrvaluepy">PyCalendar/trunk/src/pycalendar/adrvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarattributepy">PyCalendar/trunk/src/pycalendar/attribute.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaravailablepy">PyCalendar/trunk/src/pycalendar/available.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcalendarpy">PyCalendar/trunk/src/pycalendar/calendar.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcomponentpy">PyCalendar/trunk/src/pycalendar/component.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcomponentexpandedpy">PyCalendar/trunk/src/pycalendar/componentexpanded.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarcomponentrecurpy">PyCalendar/trunk/src/pycalendar/componentrecur.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendardefinitionspy">PyCalendar/trunk/src/pycalendar/definitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarfreebusypy">PyCalendar/trunk/src/pycalendar/freebusy.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendaritipdefinitionspy">PyCalendar/trunk/src/pycalendar/itipdefinitions.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarnpy">PyCalendar/trunk/src/pycalendar/n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarnvaluepy">PyCalendar/trunk/src/pycalendar/nvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarorgvaluepy">PyCalendar/trunk/src/pycalendar/orgvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarrecurrencepy">PyCalendar/trunk/src/pycalendar/recurrence.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarrecurrencesetpy">PyCalendar/trunk/src/pycalendar/recurrenceset.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarrecurrencevaluepy">PyCalendar/trunk/src/pycalendar/recurrencevalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarrequeststatusvaluepy">PyCalendar/trunk/src/pycalendar/requeststatusvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_adrpy">PyCalendar/trunk/src/pycalendar/tests/test_adr.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_adrvaluepy">PyCalendar/trunk/src/pycalendar/tests/test_adrvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_calendarpy">PyCalendar/trunk/src/pycalendar/tests/test_calendar.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_componentrecurpy">PyCalendar/trunk/src/pycalendar/tests/test_componentrecur.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_i18npy">PyCalendar/trunk/src/pycalendar/tests/test_i18n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_npy">PyCalendar/trunk/src/pycalendar/tests/test_n.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_nvaluepy">PyCalendar/trunk/src/pycalendar/tests/test_nvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_orgvaluepy">PyCalendar/trunk/src/pycalendar/tests/test_orgvalue.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_propertypy">PyCalendar/trunk/src/pycalendar/tests/test_property.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_recurrencepy">PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_requeststatuspy">PyCalendar/trunk/src/pycalendar/tests/test_requeststatus.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_timezonepy">PyCalendar/trunk/src/pycalendar/tests/test_timezone.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarteststest_xmlpy">PyCalendar/trunk/src/pycalendar/tests/test_xml.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvalarmpy">PyCalendar/trunk/src/pycalendar/valarm.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvavailabilitypy">PyCalendar/trunk/src/pycalendar/vavailability.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarveventpy">PyCalendar/trunk/src/pycalendar/vevent.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvfreebusypy">PyCalendar/trunk/src/pycalendar/vfreebusy.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvjournalpy">PyCalendar/trunk/src/pycalendar/vjournal.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvtimezonepy">PyCalendar/trunk/src/pycalendar/vtimezone.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvtimezonedaylightpy">PyCalendar/trunk/src/pycalendar/vtimezonedaylight.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvtimezoneelementpy">PyCalendar/trunk/src/pycalendar/vtimezoneelement.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvtimezonestandardpy">PyCalendar/trunk/src/pycalendar/vtimezonestandard.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvtodopy">PyCalendar/trunk/src/pycalendar/vtodo.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarvunknownpy">PyCalendar/trunk/src/pycalendar/vunknown.py</a></li>
<li><a href="#PyCalendartrunksrcpycalendarxmldefspy">PyCalendar/trunk/src/pycalendar/xmldefs.py</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#PyCalendartrunk">PyCalendar/trunk/</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="PyCalendartrunk"></a>
<div class="propset"><h4>Property changes: PyCalendar/trunk</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/revised-api-126:10457-10463
</span><span class="cx">/PyCalendar/branches/server:10466-10553
</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><a id="PyCalendartrunkpydevproject"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/.pydevproject (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/.pydevproject        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/.pydevproject        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,8 +1,6 @@
</span><span class="cx"> &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
</span><del>-&lt;?eclipse-pydev version=&quot;1.0&quot;?&gt;
-
-&lt;pydev_project&gt;
-&lt;pydev_property name=&quot;org.python.pydev.PYTHON_PROJECT_VERSION&quot;&gt;python 2.5&lt;/pydev_property&gt;
</del><ins>+&lt;?eclipse-pydev version=&quot;1.0&quot;?&gt;&lt;pydev_project&gt;
+&lt;pydev_property name=&quot;org.python.pydev.PYTHON_PROJECT_VERSION&quot;&gt;python 2.7&lt;/pydev_property&gt;
</ins><span class="cx"> &lt;pydev_pathproperty name=&quot;org.python.pydev.PROJECT_SOURCE_PATH&quot;&gt;
</span><span class="cx"> &lt;path&gt;/PyCalendar/src&lt;/path&gt;
</span><span class="cx"> &lt;/pydev_pathproperty&gt;
</span></span></pre></div>
<a id="PyCalendartrunksetuppy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/setup.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/setup.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/setup.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,12 +1,12 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2011 Cyrus Daboo. All rights reserved.
-#    
</del><ins>+#    Copyright (c) 2007-2013 Cyrus Daboo. All rights reserved.
+#
</ins><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="cx"> #    You may obtain a copy of the License at
</span><del>-#    
</del><ins>+#
</ins><span class="cx"> #        http://www.apache.org/licenses/LICENSE-2.0
</span><del>-#    
</del><ins>+#
</ins><span class="cx"> #    Unless required by applicable law or agreed to in writing, software
</span><span class="cx"> #    distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
</span><span class="cx"> #    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
</span><span class="lines">@@ -17,13 +17,13 @@
</span><span class="cx"> from distutils.core import setup, Extension
</span><span class="cx"> 
</span><span class="cx"> setup (
</span><del>-    name = &quot;pycalendar&quot;,
-    version = &quot;2.0&quot;,
-    description = &quot;iCalendar/vCard Library&quot;,
-    license = &quot;Apache 2.0&quot;,
-    platforms = [&quot;any&quot;],
</del><ins>+    name=&quot;pycalendar&quot;,
+    version=&quot;2.1&quot;,
+    description=&quot;iCalendar/vCard Library&quot;,
+    license=&quot;Apache 2.0&quot;,
+    platforms=[&quot;any&quot;],
</ins><span class="cx">     package_dir={'': 'src'},
</span><del>-    packages = [
</del><ins>+    packages=[
</ins><span class="cx">         'pycalendar',
</span><span class="cx">         'pycalendar.icalendar',
</span><span class="cx">         'pycalendar.vcard',
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendar__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,62 +14,38 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-__all__ = [
-    &quot;attribute&quot;,
-    &quot;available&quot;,
-    &quot;binaryvalue&quot;,
-    &quot;caladdressvalue&quot;,
-    &quot;calendar&quot;,
-    &quot;datetime&quot;,
-    &quot;datetimevalue&quot;,
-    &quot;definitions&quot;,
-    &quot;duration&quot;,
-    &quot;durationvalue&quot;,
-    &quot;exceptions&quot;,
-    &quot;freebusy&quot;,
-    &quot;integervalue&quot;,
-    &quot;locale&quot;,
-    &quot;manager&quot;,
-    &quot;multivalue&quot;,
-    &quot;period&quot;,
-    &quot;periodvalue&quot;,
-    &quot;plaintextvalue&quot;,
-    &quot;property&quot;,
-    &quot;recurrence&quot;,
-    &quot;recurrencevalue&quot;,
-    &quot;requeststatusvalue&quot;,
-    &quot;textvalue&quot;,
-    &quot;timezone&quot;,
-    &quot;timezonedb&quot;,
-    &quot;unknownvalue&quot;,
-    &quot;urivalue&quot;,
-    &quot;utcoffsetvalue&quot;,
-    &quot;valarm&quot;,
-    &quot;value&quot;,
-    &quot;vevent&quot;,
-    &quot;vfreebusy&quot;,
-    &quot;vjournal&quot;,
-    &quot;vtimezone&quot;,
-    &quot;vtimezonedaylight&quot;,
-    &quot;vtimezonestandard&quot;,
-    &quot;vtodo&quot;,
-    &quot;vunknown&quot;,
-]
-
</del><span class="cx"> # Import these to register the values
</span><ins>+
</ins><span class="cx"> import binaryvalue
</span><span class="cx"> import caladdressvalue
</span><span class="cx"> import datetimevalue
</span><span class="cx"> import durationvalue
</span><ins>+import floatvalue
+import geovalue
+import icalendar.recurrencevalue
+import icalendar.requeststatusvalue
</ins><span class="cx"> import integervalue
</span><span class="cx"> import multivalue
</span><span class="cx"> import periodvalue
</span><del>-import recurrencevalue
-import requeststatusvalue
</del><span class="cx"> import textvalue
</span><span class="cx"> import unknownvalue
</span><span class="cx"> import urivalue
</span><span class="cx"> import utcoffsetvalue
</span><ins>+import vcard.adrvalue
+import vcard.nvalue
+import vcard.orgvalue
</ins><span class="cx"> 
</span><del>-# Import these to force static initialisation
-import property
</del><ins>+# Import these to register the components
+
+import icalendar.available
+import icalendar.valarm
+import icalendar.vavailability
+import icalendar.vevent
+import icalendar.vfreebusy
+import icalendar.vjournal
+import icalendar.vpoll
+import icalendar.vtimezone
+import icalendar.vtimezonedaylight
+import icalendar.vtimezonestandard
+import icalendar.vtodo
+import icalendar.vunknown
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaradrpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/adr.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/adr.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/adr.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,127 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.
-##
-
-# vCard ADR value
-
-from pycalendar import utils
-from pycalendar.valueutils import ValueMixin
-
-class Adr(ValueMixin):
-    &quot;&quot;&quot;
-    mValue is a tuple of seven str or tuples of str
-    &quot;&quot;&quot;
-
-    (
-        POBOX,
-        EXTENDED,
-        STREET,
-        LOCALITY,
-        REGION,
-        POSTALCODE,
-        COUNTRY,
-        MAXITEMS
-    ) = range(8)
-
-    def __init__(self, pobox=&quot;&quot;, extended=&quot;&quot;, street=&quot;&quot;, locality=&quot;&quot;, region=&quot;&quot;, postalcode=&quot;&quot;, country=&quot;&quot;):
-        self.mValue = (pobox, extended, street, locality, region, postalcode, country)
-
-
-    def duplicate(self):
-        return Adr(*self.mValue)
-
-
-    def __hash__(self):
-        return hash(self.mValue)
-
-
-    def __repr__(self):
-        return &quot;ADR %s&quot; % (self.getText(),)
-
-
-    def __eq__(self, comp):
-        return self.mValue == comp.mValue
-
-
-    def getPobox(self):
-        return self.mValue[Adr.POBOX]
-
-
-    def setPobox(self, value):
-        self.mValue[Adr.POBOX] = value
-
-
-    def getExtended(self):
-        return self.mValue[Adr.EXTENDED]
-
-
-    def setExtended(self, value):
-        self.mValue[Adr.EXTENDED] = value
-
-
-    def getStreet(self):
-        return self.mValue[Adr.STREET]
-
-
-    def setStreet(self, value):
-        self.mValue[Adr.STREET] = value
-
-
-    def getLocality(self):
-        return self.mValue[Adr.LOCALITY]
-
-
-    def setLocality(self, value):
-        self.mValue[Adr.LOCALITY] = value
-
-
-    def getRegion(self):
-        return self.mValue[Adr.REGION]
-
-
-    def setRegion(self, value):
-        self.mValue[Adr.REGION] = value
-
-
-    def getPostalCode(self):
-        return self.mValue[Adr.POSTALCODE]
-
-
-    def setPostalCode(self, value):
-        self.mValue[Adr.POSTALCODE] = value
-
-
-    def getCountry(self):
-        return self.mValue[Adr.COUNTRY]
-
-
-    def setCountry(self, value):
-        self.mValue[Adr.COUNTRY] = value
-
-
-    def parse(self, data):
-        self.mValue = utils.parseDoubleNestedList(data, Adr.MAXITEMS)
-
-
-    def generate(self, os):
-        utils.generateDoubleNestedList(os, self.mValue)
-
-
-    def getValue(self):
-        return self.mValue
-
-
-    def setValue(self, value):
-        self.mValue = value
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendaradrvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/adrvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/adrvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/adrvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,51 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.
-##
-
-# vCard ADR value
-
-from pycalendar.adr import Adr
-from pycalendar.value import PyCalendarValue
-
-class AdrValue(PyCalendarValue):
-
-    def __init__(self, value=None):
-        self.mValue = value if value is not None else Adr()
-
-
-    def duplicate(self):
-        return AdrValue(self.mValue.duplicate())
-
-
-    def getType(self):
-        return PyCalendarValue.VALUETYPE_ADR
-
-
-    def parse(self, data):
-        self.mValue.parse(data)
-
-
-    def generate(self, os):
-        self.mValue.generate(os)
-
-
-    def getValue(self):
-        return self.mValue
-
-
-    def setValue(self, value):
-        self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_ADR, AdrValue, None)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarattributepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/attribute.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/attribute.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/attribute.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,128 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.
-##
-
-&quot;&quot;&quot;
-ICalendar attribute.
-
-The attribute can consist of one or more values, all string.
-&quot;&quot;&quot;
-
-from pycalendar import xmldefs
-from pycalendar.utils import encodeParameterValue
-import xml.etree.cElementTree as XML
-
-class PyCalendarAttribute(object):
-
-    def __init__(self, name, value=None):
-        self.mName = name
-        if value is None:
-            self.mValues = []
-        elif isinstance(value, basestring):
-            self.mValues = [value]
-        else:
-            self.mValues = value
-
-
-    def duplicate(self):
-        other = PyCalendarAttribute(self.mName)
-        other.mValues = self.mValues[:]
-        return other
-
-
-    def __hash__(self):
-        return hash((self.mName.upper(), tuple(self.mValues)))
-
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-
-    def __eq__(self, other):
-        if not isinstance(other, PyCalendarAttribute):
-            return False
-        return self.mName.upper() == other.mName.upper() and self.mValues == other.mValues
-
-
-    def getName(self):
-        return self.mName
-
-
-    def setName(self, name):
-        self.mName = name
-
-
-    def getFirstValue(self):
-        return self.mValues[0]
-
-
-    def getValues(self):
-        return self.mValues
-
-
-    def setValues(self, values):
-        self.mValues = values
-
-
-    def addValue(self, value):
-        self.mValues.append(value)
-
-
-    def removeValue(self, value):
-        self.mValues.remove(value)
-        return len(self.mValues)
-
-
-    def generate(self, os):
-        try:
-            os.write(self.mName)
-
-            # To support vCard 2.1 syntax we allow parameters without values
-            if self.mValues:
-                os.write(&quot;=&quot;)
-
-                first = True
-                for s in self.mValues:
-                    if first:
-                        first = False
-                    else:
-                        os.write(&quot;,&quot;)
-
-                    # Write with quotation if required
-                    self.generateValue(os, s)
-
-        except:
-            # We ignore errors
-            pass
-
-
-    def generateValue(self, os, str):
-
-        # ^-escaping
-        str = encodeParameterValue(str)
-
-        # Look for quoting
-        if str.find(&quot;:&quot;) != -1 or str.find(&quot;;&quot;) != -1 or str.find(&quot;,&quot;) != -1:
-            os.write(&quot;\&quot;%s\&quot;&quot; % (str,))
-        else:
-            os.write(str)
-
-
-    def writeXML(self, node, namespace):
-        param = XML.SubElement(node, xmldefs.makeTag(namespace, self.getName()))
-        for value in self.getValues():
-            # TODO: need to figure out proper value types
-            text = XML.SubElement(param, xmldefs.makeTag(namespace, xmldefs.value_text))
-            text.text = value
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendaravailablepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/available.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/available.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/available.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,90 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-2012 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 import definitions
-from pycalendar.componentrecur import PyCalendarComponentRecur
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-
-class PyCalendarAvailable(PyCalendarComponentRecur):
-
-    propertyCardinality_1 = (
-        definitions.cICalProperty_DTSTAMP,
-        definitions.cICalProperty_DTSTART,
-        definitions.cICalProperty_UID,
-    )
-
-    propertyCardinality_0_1 = (
-        definitions.cICalProperty_CREATED,
-        definitions.cICalProperty_DESCRIPTION,
-        definitions.cICalProperty_GEO,
-        definitions.cICalProperty_LAST_MODIFIED,
-        definitions.cICalProperty_LOCATION,
-        definitions.cICalProperty_RECURRENCE_ID,
-        definitions.cICalProperty_RRULE,
-        definitions.cICalProperty_SEQUENCE,
-        definitions.cICalProperty_SUMMARY,
-        definitions.cICalProperty_DTEND,
-        definitions.cICalProperty_DURATION,
-    )
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    def __init__(self, parent=None):
-        super(PyCalendarAvailable, self).__init__(parent=parent)
-
-
-    def duplicate(self, parent=None):
-        return super(PyCalendarAvailable, self).duplicate(parent=parent)
-
-
-    def getType(self):
-        return definitions.cICalComponent_AVAILABLE
-
-
-    def validate(self, doFix=False):
-        &quot;&quot;&quot;
-        Validate the data in this component and optionally fix any problems, else raise. If
-        loggedProblems is not None it must be a C{list} and problem descriptions are appended
-        to that.
-        &quot;&quot;&quot;
-
-        fixed, unfixed = super(PyCalendarAvailable, self).validate(doFix)
-
-        # Extra constraint: only one of DTEND or DURATION
-        if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
-            # Fix by removing the DTEND
-            logProblem = &quot;[%s] Properties must not both be present: %s, %s&quot; % (
-                self.getType(),
-                definitions.cICalProperty_DTEND,
-                definitions.cICalProperty_DURATION,
-            )
-            if doFix:
-                self.removeProperties(definitions.cICalProperty_DTEND)
-                fixed.append(logProblem)
-            else:
-                unfixed.append(logProblem)
-
-        return fixed, unfixed
-
-
-    def sortedPropertyKeyOrder(self):
-        return (
-            definitions.cICalProperty_UID,
-            definitions.cICalProperty_RECURRENCE_ID,
-            definitions.cICalProperty_DTSTART,
-            definitions.cICalProperty_DURATION,
-            definitions.cICalProperty_DTEND,
-        )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarbinaryvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/binaryvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/binaryvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/binaryvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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">@@ -16,13 +16,13 @@
</span><span class="cx"> 
</span><span class="cx"> # iCalendar Binary value
</span><span class="cx"> 
</span><del>-from pycalendar import xmldefs
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.value import Value
</ins><span class="cx"> 
</span><del>-class PyCalendarBinaryValue(PyCalendarPlainTextValue):
</del><ins>+class BinaryValue(PlainTextValue):
</ins><span class="cx"> 
</span><span class="cx">     def getType(self):
</span><del>-        return PyCalendarValue.VALUETYPE_BINARY
</del><ins>+        return Value.VALUETYPE_BINARY
</ins><span class="cx"> 
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_BINARY, PyCalendarBinaryValue, xmldefs.value_binary)
</del><ins>+Value.registerType(Value.VALUETYPE_BINARY, BinaryValue, xmldefinitions.value_binary)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcaladdressvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/caladdressvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/caladdressvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/caladdressvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -16,13 +16,13 @@
</span><span class="cx"> 
</span><span class="cx"> # iCalendar UTC Offset value
</span><span class="cx"> 
</span><del>-from pycalendar import xmldefs
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.value import Value
</ins><span class="cx"> 
</span><del>-class PyCalendarCalAddressValue(PyCalendarPlainTextValue):
</del><ins>+class CalAddressValue(PlainTextValue):
</ins><span class="cx"> 
</span><span class="cx">     def getType(self):
</span><del>-        return PyCalendarValue.VALUETYPE_CALADDRESS
</del><ins>+        return Value.VALUETYPE_CALADDRESS
</ins><span class="cx"> 
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_CALADDRESS, PyCalendarCalAddressValue, xmldefs.value_cal_address)
</del><ins>+Value.registerType(Value.VALUETYPE_CALADDRESS, CalAddressValue, xmldefinitions.value_cal_address)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcalendarpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/calendar.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/calendar.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/calendar.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,754 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 cStringIO import StringIO
-from pycalendar import definitions, xmldefs
-from pycalendar.available import PyCalendarAvailable
-from pycalendar.componentbase import PyCalendarComponentBase
-from pycalendar.componentexpanded import PyCalendarComponentExpanded
-from pycalendar.componentrecur import PyCalendarComponentRecur
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.exceptions import PyCalendarInvalidData, \
-    PyCalendarValidationError
-from pycalendar.freebusy import PyCalendarFreeBusy
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.parser import ParserContext
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.property import PyCalendarProperty
-from pycalendar.utils import readFoldedLine
-from pycalendar.valarm import PyCalendarVAlarm
-from pycalendar.vavailability import PyCalendarVAvailability
-from pycalendar.vevent import PyCalendarVEvent
-from pycalendar.vfreebusy import PyCalendarVFreeBusy
-from pycalendar.vjournal import PyCalendarVJournal
-from pycalendar.vtimezone import PyCalendarVTimezone
-from pycalendar.vtimezonedaylight import PyCalendarVTimezoneDaylight
-from pycalendar.vtimezonestandard import PyCalendarVTimezoneStandard
-from pycalendar.vtodo import PyCalendarVToDo
-from pycalendar.vunknown import PyCalendarUnknownComponent
-import collections
-import xml.etree.cElementTree as XML
-
-class PyCalendar(PyCalendarComponentBase):
-
-    REMOVE_ALL = 0
-    REMOVE_ONLY_THIS = 1
-    REMOVE_THIS_AND_FUTURE = 2
-
-    FIND_EXACT = 0
-    FIND_MASTER = 1
-
-    sProdID = &quot;-//mulberrymail.com//Mulberry v4.0//EN&quot;
-    sDomain = &quot;mulberrymail.com&quot;
-
-    @staticmethod
-    def setPRODID(prodid):
-        PyCalendar.sProdID = prodid
-
-
-    @staticmethod
-    def setDomain(domain):
-        PyCalendar.sDomain = domain
-
-    propertyCardinality_1 = (
-        definitions.cICalProperty_PRODID,
-        definitions.cICalProperty_VERSION,
-    )
-
-    propertyCardinality_0_1 = (
-        definitions.cICalProperty_CALSCALE,
-        definitions.cICalProperty_METHOD,
-    )
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    def __init__(self, parent=None, add_defaults=True):
-        super(PyCalendar, self).__init__(None)
-
-        self.mName = &quot;&quot;
-        self.mDescription = &quot;&quot;
-        self.mMasterComponentsByTypeAndUID = collections.defaultdict(lambda: collections.defaultdict(list))
-        self.mOverriddenComponentsByUID = collections.defaultdict(list)
-
-        if add_defaults:
-            self.addDefaultProperties()
-
-
-    def duplicate(self):
-        other = super(PyCalendar, self).duplicate()
-        other.mName = self.mName
-        other.mDescription = self.mDescription
-        return other
-
-
-    def getType(self):
-        return definitions.cICalComponent_VCALENDAR
-
-
-    def getName(self):
-        return self.mName
-
-
-    def setName(self, name):
-        self.mName = name
-
-
-    def editName(self, name):
-        if self.mName != name:
-            # Updated cached value
-            self.mName = name
-
-            # Remove existing items
-            self.removeProperties(definitions.cICalProperty_XWRCALNAME)
-
-            # Now create properties
-            if len(name):
-                self.ddProperty(PyCalendarProperty(definitions.cICalProperty_XWRCALNAME, name))
-
-
-    def getDescription(self):
-        return self.mDescription
-
-
-    def setDescription(self, description):
-        self.mDescription = description
-
-
-    def editDescription(self, description):
-        if self.mDescription != description:
-            # Updated cached value
-            self.mDescription = description
-
-            # Remove existing items
-            self.removeProperties(definitions.cICalProperty_XWRCALDESC)
-
-            # Now create properties
-            if len(description):
-                self.addProperty(PyCalendarProperty(definitions.cICalProperty_XWRCALDESC, description))
-
-
-    def getMethod(self):
-        result = &quot;&quot;
-        if self.hasProperty(definitions.cICalProperty_METHOD):
-            result = self.loadValueString(definitions.cICalProperty_METHOD)
-        return result
-
-
-    def changeUID(self, oldUID, newUID):
-        &quot;&quot;&quot;
-        Change the UID of all components with a matching UID to a new value. We need to
-        do this at the calendar level because this object maintains mappings based on UID
-        which need to be updated whenever the UID changes.
-
-        @param oldUID: the old value to match
-        @type oldUID: C{str}
-        @param newUID: the new value to match
-        @type newUID: C{str}
-        &quot;&quot;&quot;
-
-        # Each component
-        for component in self.mComponents:
-            if component.getUID() == oldUID:
-                component.setUID(newUID)
-
-        # Maps
-        if oldUID in self.mOverriddenComponentsByUID:
-            self.mOverriddenComponentsByUID[newUID] = self.mOverriddenComponentsByUID[oldUID]
-            del self.mOverriddenComponentsByUID[oldUID]
-        for ctype in self.mMasterComponentsByTypeAndUID:
-            if oldUID in self.mMasterComponentsByTypeAndUID[ctype]:
-                self.mMasterComponentsByTypeAndUID[ctype][newUID] = self.mMasterComponentsByTypeAndUID[ctype][oldUID]
-                del self.mMasterComponentsByTypeAndUID[ctype][oldUID]
-
-
-    def finalise(self):
-        # Get calendar name if present
-
-        # Get X-WR-CALNAME
-        temps = self.loadValueString(definitions.cICalProperty_XWRCALNAME)
-        if temps is not None:
-            self.mName = temps
-
-        # Get X-WR-CALDESC
-        temps = self.loadValueString(definitions.cICalProperty_XWRCALDESC)
-        if temps is not None:
-            self.mDescription = temps
-
-
-    def validate(self, doFix=False, doRaise=False):
-        &quot;&quot;&quot;
-        Validate the data in this component and optionally fix any problems. Return
-        a tuple containing two lists: the first describes problems that were fixed, the
-        second problems that were not fixed. Caller can then decide what to do with unfixed
-        issues.
-        &quot;&quot;&quot;
-
-        # Optional raise behavior
-        fixed, unfixed = super(PyCalendar, self).validate(doFix)
-        if doRaise and unfixed:
-            raise PyCalendarValidationError(&quot;;&quot;.join(unfixed))
-        return fixed, unfixed
-
-
-    def sortedComponentNames(self):
-        return (
-            definitions.cICalComponent_VTIMEZONE,
-            definitions.cICalComponent_VEVENT,
-            definitions.cICalComponent_VTODO,
-            definitions.cICalComponent_VJOURNAL,
-            definitions.cICalComponent_VFREEBUSY,
-            definitions.cICalComponent_VAVAILABILITY,
-        )
-
-
-    def sortedPropertyKeyOrder(self):
-        return (
-            definitions.cICalProperty_VERSION,
-            definitions.cICalProperty_CALSCALE,
-            definitions.cICalProperty_METHOD,
-            definitions.cICalProperty_PRODID,
-        )
-
-
-    @staticmethod
-    def parseText(data):
-
-        cal = PyCalendar(add_defaults=False)
-        if cal.parse(StringIO(data)):
-            return cal
-        else:
-            return None
-
-
-    def parse(self, ins):
-
-        result = False
-
-        self.setProperties({})
-
-        LOOK_FOR_VCALENDAR = 0
-        GET_PROPERTY_OR_COMPONENT = 1
-
-        state = LOOK_FOR_VCALENDAR
-
-        # Get lines looking for start of calendar
-        lines = [None, None]
-        comp = self
-        compend = None
-        componentstack = []
-
-        while readFoldedLine(ins, lines):
-
-            line = lines[0]
-
-            if state == LOOK_FOR_VCALENDAR:
-
-                # Look for start
-                if line == self.getBeginDelimiter():
-                    # Next state
-                    state = GET_PROPERTY_OR_COMPONENT
-
-                    # Indicate success at this point
-                    result = True
-
-                # Handle blank line
-                elif len(line) == 0:
-                    # Raise if requested, otherwise just ignore
-                    if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
-                        raise PyCalendarInvalidData(&quot;iCalendar data has blank lines&quot;)
-
-                # Unrecognized data
-                else:
-                    raise PyCalendarInvalidData(&quot;iCalendar data not recognized&quot;, line)
-
-            elif state == GET_PROPERTY_OR_COMPONENT:
-
-                # Parse property or look for start of component
-                if line.startswith(&quot;BEGIN:&quot;):
-
-                    # Push previous details to stack
-                    componentstack.append((comp, compend,))
-
-                    # Start a new component
-                    comp = PyCalendar.makeComponent(line[6:], comp)
-                    compend = comp.getEndDelimiter()
-
-                # Look for end of object
-                elif line == self.getEndDelimiter():
-
-                    # Finalise the current calendar
-                    self.finalise()
-
-                    # Change state
-                    state = LOOK_FOR_VCALENDAR
-
-                # Look for end of current component
-                elif line == compend:
-
-                    # Finalise the component (this caches data from the properties)
-                    comp.finalise()
-
-                    # Embed component in parent and reset to use parent
-                    componentstack[-1][0].addComponent(comp)
-                    comp, compend = componentstack.pop()
-
-                # Blank line
-                elif len(line) == 0:
-                    # Raise if requested, otherwise just ignore
-                    if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
-                        raise PyCalendarInvalidData(&quot;iCalendar data has blank lines&quot;)
-
-                # Must be a property
-                else:
-
-                    # Parse attribute/value for top-level calendar item
-                    prop = PyCalendarProperty()
-                    if prop.parse(line):
-
-                        # Check for valid property
-                        if comp is self:
-                            if not comp.validProperty(prop):
-                                raise PyCalendarInvalidData(&quot;Invalid property&quot;, str(prop))
-                            elif not comp.ignoreProperty(prop):
-                                comp.addProperty(prop)
-                        else:
-                            comp.addProperty(prop)
-
-        # Check for truncated data
-        if state != LOOK_FOR_VCALENDAR:
-            raise PyCalendarInvalidData(&quot;iCalendar data not complete&quot;)
-
-        # We need to store all timezones in the static object so they can be accessed by any date object
-        from timezonedb import PyCalendarTimezoneDatabase
-        PyCalendarTimezoneDatabase.mergeTimezones(self, self.getComponents(definitions.cICalComponent_VTIMEZONE))
-
-        # Validate some things
-        if result and not self.hasProperty(&quot;VERSION&quot;):
-            raise PyCalendarInvalidData(&quot;iCalendar missing VERSION&quot;)
-
-        return result
-
-
-    def parseComponent(self, ins):
-
-        result = None
-
-        LOOK_FOR_VCALENDAR = 0
-        GET_PROPERTY_OR_COMPONENT = 1
-        GOT_VCALENDAR = 4
-
-        state = LOOK_FOR_VCALENDAR
-
-        # Get lines looking for start of calendar
-        lines = [None, None]
-        comp = self
-        compend = None
-        componentstack = []
-        got_timezone = False
-
-        while readFoldedLine(ins, lines):
-
-            if state == LOOK_FOR_VCALENDAR:
-
-                # Look for start
-                if lines[0] == self.getBeginDelimiter():
-                    # Next state
-                    state = GET_PROPERTY_OR_COMPONENT
-
-                # Handle blank line
-                elif len(lines[0]) == 0:
-                    # Raise if requested, otherwise just ignore
-                    if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
-                        raise PyCalendarInvalidData(&quot;iCalendar data has blank lines&quot;)
-
-                # Unrecognized data
-                else:
-                    raise PyCalendarInvalidData(&quot;iCalendar data not recognized&quot;, lines[0])
-
-            elif state == GET_PROPERTY_OR_COMPONENT:
-
-                # Parse property or look for start of component
-                if lines[0].startswith(&quot;BEGIN:&quot;):
-
-                    # Push previous details to stack
-                    componentstack.append((comp, compend,))
-
-                    # Start a new component
-                    comp = PyCalendar.makeComponent(lines[0][6:], comp)
-                    compend = comp.getEndDelimiter()
-
-                    # Cache as result - but only the first one, we ignore the rest
-                    if result is None:
-                        result = comp
-
-                    # Look for timezone component to trigger timezone merge only if one is present
-                    if comp.getType() == definitions.cICalComponent_VTIMEZONE:
-                        got_timezone = True
-
-                elif lines[0] == self.getEndDelimiter():
-
-                    # Change state
-                    state = GOT_VCALENDAR
-
-                # Look for end of current component
-                elif lines[0] == compend:
-
-                    # Finalise the component (this caches data from the properties)
-                    comp.finalise()
-
-                    # Embed component in parent and reset to use parent
-                    componentstack[-1][0].addComponent(comp)
-                    comp, compend = componentstack.pop()
-
-                # Blank line
-                elif len(lines[0]) == 0:
-                    # Raise if requested, otherwise just ignore
-                    if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
-                        raise PyCalendarInvalidData(&quot;iCalendar data has blank lines&quot;)
-
-                # Ignore top-level items
-                elif comp is self:
-                    pass
-
-                # Must be a property
-                else:
-
-                    # Parse attribute/value for top-level calendar item
-                    prop = PyCalendarProperty()
-                    if prop.parse(lines[0]):
-
-                        # Check for valid property
-                        if comp is not self:
-                            comp.addProperty(prop)
-
-            # Exit if we have one - ignore all the rest
-            if state == GOT_VCALENDAR:
-                break
-
-        # We need to store all timezones in the static object so they can be accessed by any date object
-        # Only do this if we read in a timezone
-        if got_timezone:
-            from timezonedb import PyCalendarTimezoneDatabase
-            PyCalendarTimezoneDatabase.mergeTimezones(self, self.getComponents(definitions.cICalComponent_VTIMEZONE))
-
-        return result
-
-
-    def addComponent(self, component):
-        &quot;&quot;&quot;
-        Override to track components by UID.
-        &quot;&quot;&quot;
-        super(PyCalendar, self).addComponent(component)
-
-        if isinstance(component, PyCalendarComponentRecur):
-            uid = component.getUID()
-            rid = component.getRecurrenceID()
-            if rid:
-                self.mOverriddenComponentsByUID[uid].append(component)
-            else:
-                self.mMasterComponentsByTypeAndUID[component.getType()][uid] = component
-
-
-    def removeComponent(self, component):
-        &quot;&quot;&quot;
-        Override to track components by UID.
-        &quot;&quot;&quot;
-        super(PyCalendar, self).removeComponent(component)
-
-        if isinstance(component, PyCalendarComponentRecur):
-            uid = component.getUID()
-            rid = component.getRecurrenceID()
-            if rid:
-                self.mOverriddenComponentsByUID[uid].remove(component)
-            else:
-                del self.mMasterComponentsByTypeAndUID[component.getType()][uid]
-
-
-    def getText(self, includeTimezones=False):
-        s = StringIO()
-        self.generate(s, includeTimezones=includeTimezones)
-        return s.getvalue()
-
-
-    def generate(self, os, includeTimezones=False):
-        # Make sure all required timezones are in this object
-        if includeTimezones:
-            self.includeTimezones()
-        super(PyCalendar, self).generate(os)
-
-
-    def getTextXML(self, includeTimezones=False):
-        node = self.writeXML(includeTimezones)
-        return xmldefs.toString(node)
-
-
-    def writeXML(self, includeTimezones=False):
-        # Make sure all required timezones are in this object
-        if includeTimezones:
-            self.includeTimezones()
-
-        # Root node structure
-        root = XML.Element(xmldefs.makeTag(xmldefs.iCalendar20_namespace, xmldefs.icalendar))
-        super(PyCalendar, self).writeXML(root, xmldefs.iCalendar20_namespace)
-        return root
-
-
-    # Get expanded components
-    def getVEvents(self, period, list, all_day_at_top=True):
-        # Look at each VEvent
-        for vevent in self.getComponents(definitions.cICalComponent_VEVENT):
-            vevent.expandPeriod(period, list)
-
-        if (all_day_at_top):
-            list.sort(PyCalendarComponentExpanded.sort_by_dtstart_allday)
-        else:
-            list.sort(PyCalendarComponentExpanded.sort_by_dtstart)
-
-
-    def getVToDos(self, only_due, all_dates, upto_due_date, list):
-        # Get current date-time less one day to test for completed events during the last day
-        minusoneday = PyCalendarDateTime()
-        minusoneday.setNowUTC()
-        minusoneday.offsetDay(-1)
-
-        today = PyCalendarDateTime()
-        today.setToday()
-
-        # Look at each VToDo
-        for vtodo in self.getComponents(definitions.cICalComponent_VTODO):
-
-            # Filter out done (that were complted more than a day ago) or cancelled to dos if required
-            if only_due:
-                if vtodo.getStatus() == definitions.eStatus_VToDo_Cancelled:
-                    continue
-                elif ((vtodo.getStatus() == definitions.eStatus_VToDo_Completed) and
-                            (not vtodo.hasCompleted() or (vtodo.getCompleted() &lt; minusoneday))):
-                    continue
-
-            # Filter out those with end after chosen date if required
-            if not all_dates:
-                if vtodo.hasEnd() and (vtodo.getEnd() &gt; upto_due_date):
-                    continue
-                elif not vtodo.hasEnd() and (today &gt; upto_due_date):
-                    continue
-
-            # TODO: fix this
-            #list.append(PyCalendarComponentExpandedShared(PyCalendarComponentExpanded(vtodo, None)))
-
-
-    def getRecurrenceInstancesItems(self, type, uid, items):
-        # Get instances from list
-        items.extend(self.mOverriddenComponentsByUID.get(uid, ()))
-
-
-    def getRecurrenceInstancesIds(self, type, uid, ids):
-        # Get instances from list
-        ids.extend([comp.getRecurrenceID() for comp in self.mOverriddenComponentsByUID.get(uid, ())])
-
-
-    # Freebusy generation
-    def getVFreeBusyList(self, period, list):
-        # Look at each VFreeBusy
-        for vfreebusy in self.getComponents(definitions.cICalComponent_VFREEBUSY):
-            vfreebusy.expandPeriod(period, list)
-
-
-    def getVFreeBusyFB(self, period, fb):
-        # First create expanded set
-        # TODO: fix this
-        #list = PyCalendarExpandedComponents()
-        self.getVEvents(period, list)
-        if len(list) == 0:
-            return
-
-        # Get start/end list for each non-all-day expanded components
-        dtstart = []
-        dtend = []
-        for dt in list:
-
-            # Ignore if all-day
-            if dt.getInstanceStart().isDateOnly():
-                continue
-
-            # Ignore if transparent to free-busy
-            transp = &quot;&quot;
-            if dt.getOwner().getProperty(definitions.cICalProperty_TRANSP, transp) and (transp == definitions.cICalProperty_TRANSPARENT):
-                continue
-
-            # Add start/end to list
-            dtstart.append(dt.getInstanceStart())
-            dtend.append(dt.getInstanceEnd())
-
-        # No longer need the expanded items
-        list.clear()
-
-        # Create non-overlapping periods as properties in the freebusy component
-        temp = PyCalendarPeriod(dtstart.front(), dtend.front())
-        dtstart_iter = dtstart.iter()
-        dtstart_iter.next()
-        dtend_iter = dtend.iter()
-        dtend_iter.next()
-        for i in i:
-
-            # Check for non-overlap
-            if dtstart_iter &gt; temp.getEnd():
-
-                # Current period is complete
-                fb.addProperty(PyCalendarProperty(definitions.cICalProperty_FREEBUSY, temp))
-
-                # Reset period to new range
-                temp = PyCalendarPeriod(dtstart_iter, dtend_iter)
-
-            # They overlap - check for extended end
-            if dtend_iter &gt; temp.getEnd():
-
-                # Extend the end
-                temp = PyCalendarPeriod(temp.getStart(), dtend_iter)
-
-        # Add remaining period as property
-        fb.addProperty(PyCalendarProperty(definitions.cICalProperty_FREEBUSY, temp))
-
-
-    def getFreeBusy(self, period, fb):
-        # First create expanded set
-
-        list = []
-        self.getVEvents(period, list)
-
-        # Get start/end list for each non-all-day expanded components
-        for comp in list:
-
-            # Ignore if all-day
-            if comp.getInstanceStart().isDateOnly():
-                continue
-
-            # Ignore if transparent to free-busy
-            transp = &quot;&quot;
-            if comp.getOwner().getProperty(definitions.cICalProperty_TRANSP, transp) and (transp == definitions.cICalProperty_TRANSPARENT):
-                continue
-
-            # Add free busy item to list
-            status = comp.getMaster().getStatus()
-            if status in (definitions.eStatus_VEvent_None, definitions.eStatus_VEvent_Confirmed):
-                fb.append(PyCalendarFreeBusy(PyCalendarFreeBusy.BUSY, PyCalendarPeriod(comp.getInstanceStart(), comp.getInstanceEnd())))
-            elif status == definitions.eStatus_VEvent_Tentative:
-                fb.append(PyCalendarFreeBusy(PyCalendarFreeBusy.BUSYTENTATIVE, PyCalendarPeriod(comp.getInstanceStart(), comp.getInstanceEnd())))
-                break
-            elif status == definitions.eStatus_VEvent_Cancelled:
-                # Cancelled =&gt; does not contribute to busy time
-                pass
-
-        # Now get the VFREEBUSY info
-        list2 = []
-        self.getVFreeBusy(period, list2)
-
-        # Get start/end list for each free-busy
-        for comp in list2:
-
-            # Expand component and add free busy info to list
-            comp.expandPeriod(period, fb)
-
-        # Add remaining period as property
-        PyCalendarFreeBusy.resolveOverlaps(fb)
-
-
-    def getTimezoneOffsetSeconds(self, tzid, dt):
-        # Find timezone that matches the name (which is the same as the map key)
-        timezone = self.getTimezone(tzid)
-        return timezone.getTimezoneOffsetSeconds(dt) if timezone else 0
-
-
-    def getTimezoneDescriptor(self, tzid, dt):
-        # Find timezone that matches the name (which is the same as the map key)
-        timezone = self.getTimezone(tzid)
-        return timezone.getTimezoneDescriptor(dt) if timezone else &quot;&quot;
-
-
-    def getTimezone(self, tzid):
-        # Find timezone that matches the name (which is the same as the map key)
-        for timezone in self.getComponents(definitions.cICalComponent_VTIMEZONE):
-            if timezone.getID() == tzid:
-                return timezone
-        else:
-            return None
-
-
-    def addDefaultProperties(self):
-        self.addProperty(PyCalendarProperty(definitions.cICalProperty_PRODID, PyCalendar.sProdID))
-        self.addProperty(PyCalendarProperty(definitions.cICalProperty_VERSION, &quot;2.0&quot;))
-        self.addProperty(PyCalendarProperty(definitions.cICalProperty_CALSCALE, &quot;GREGORIAN&quot;))
-
-
-    def validProperty(self, prop):
-        if prop.getName() == definitions.cICalProperty_VERSION:
-
-            tvalue = prop.getTextValue()
-            if ((tvalue is None) or (tvalue.getValue() != &quot;2.0&quot;)):
-                return False
-
-        elif prop.getName() == definitions.cICalProperty_CALSCALE:
-
-            tvalue = prop.getTextValue()
-            if ((tvalue is None) or (tvalue.getValue() != &quot;GREGORIAN&quot;)):
-                return False
-
-        return True
-
-
-    def ignoreProperty(self, prop):
-        return False #prop.getName() in (definitions.cICalProperty_VERSION, definitions.cICalProperty_CALSCALE, definitions.cICalProperty_PRODID)
-
-
-    def includeTimezones(self):
-        # Get timezone names from each component
-        tzids = set()
-        for component in self.mComponents:
-            if component.getType() != definitions.cICalComponent_VTIMEZONE:
-                component.getTimezones(tzids)
-
-        # Make sure each timezone is in current calendar
-        from timezonedb import PyCalendarTimezoneDatabase
-        for tzid in tzids:
-            tz = self.getTimezone(tzid)
-            if tz is None:
-                # Find it in the static object
-                tz = PyCalendarTimezoneDatabase.getTimezone(tzid)
-                if tz is not None:
-                    dup = tz.duplicate()
-                    self.addComponent(dup)
-
-
-    @staticmethod
-    def makeComponent(compname, parent):
-
-        mapper = {
-            definitions.cICalComponent_VEVENT: PyCalendarVEvent,
-            definitions.cICalComponent_VTODO: PyCalendarVToDo,
-            definitions.cICalComponent_VJOURNAL: PyCalendarVJournal,
-            definitions.cICalComponent_VFREEBUSY: PyCalendarVFreeBusy,
-            definitions.cICalComponent_VTIMEZONE: PyCalendarVTimezone,
-            definitions.cICalComponent_VAVAILABILITY: PyCalendarVAvailability,
-            definitions.cICalComponent_VALARM: PyCalendarVAlarm,
-            definitions.cICalComponent_AVAILABLE: PyCalendarAvailable,
-            definitions.cICalComponent_STANDARD: PyCalendarVTimezoneStandard,
-            definitions.cICalComponent_DAYLIGHT: PyCalendarVTimezoneDaylight,
-        }
-
-        try:
-            cls = mapper[compname]
-            return cls(parent=parent)
-        except KeyError:
-            return PyCalendarUnknownComponent(parent=parent, comptype=compname)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcomponentpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/component.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/component.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/component.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,192 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from pycalendar import stringutils
-from pycalendar.componentbase import PyCalendarComponentBase
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.property import PyCalendarProperty
-import os
-import time
-import uuid
-
-class PyCalendarComponent(PyCalendarComponentBase):
-
-    uid_ctr = 1
-
-    def __init__(self, parent=None):
-
-        super(PyCalendarComponent, self).__init__(parent)
-        self.mUID = &quot;&quot;
-        self.mSeq = 0
-        self.mOriginalSeq = 0
-        self.mChanged = False
-
-
-    def duplicate(self, parent=None, **args):
-
-        other = super(PyCalendarComponent, self).duplicate(parent=parent, **args)
-        other.mUID = self.mUID
-        other.mSeq = self.mSeq
-        other.mOriginalSeq = self.mOriginalSeq
-
-        other.mChanged = self.mChanged
-
-        return other
-
-
-    def __repr__(self):
-        return &quot;%s: UID: %s&quot; % (self.getType(), self.getMapKey(),)
-
-
-    def getMimeComponentName(self):
-        raise NotImplementedError
-
-
-    def getMapKey(self):
-        if hasattr(self, &quot;mMapKey&quot;):
-            return self.mMapKey
-        elif self.mUID:
-            return self.mUID
-        else:
-            self.mMapKey = str(uuid.uuid4())
-            return self.mMapKey
-
-
-    def getSortKey(self):
-        return self.getMapKey()
-
-
-    def getMasterKey(self):
-        return self.mUID
-
-
-    def getUID(self):
-        return self.mUID
-
-
-    def setUID(self, uid):
-        if uid:
-            self.mUID = uid
-        else:
-            # Get left-side of UID (first 24 chars of MD5 digest of time, pid
-            # and ctr)
-            lhs_txt = &quot;&quot;
-            lhs_txt += str(time.time())
-            lhs_txt += &quot;.&quot;
-            lhs_txt += str(os.getpid())
-            lhs_txt += &quot;.&quot;
-            lhs_txt += str(PyCalendarComponent.uid_ctr)
-            PyCalendarComponent.uid_ctr += 1
-            lhs = stringutils.md5digest(lhs_txt)
-
-            # Get right side (domain) of message-id
-            rhs = None
-
-            # Use app name
-            from pycalendar.calendar import PyCalendar
-            domain = PyCalendar.sDomain
-            domain += str(PyCalendarComponent.uid_ctr)
-
-            # Use first 24 chars of MD5 digest of the domain as the
-            # right-side of message-id
-            rhs = stringutils.md5digest(domain)
-
-            # Generate the UID string
-            new_uid = lhs
-            new_uid += &quot;@&quot;
-            new_uid += rhs
-
-            self.mUID = new_uid
-
-        self.removeProperties(definitions.cICalProperty_UID)
-
-        prop = PyCalendarProperty(definitions.cICalProperty_UID, self.mUID)
-        self.addProperty(prop)
-
-
-    def getSeq(self):
-        return self.mSeq
-
-
-    def setSeq(self, seq):
-        self.mSeq = seq
-
-        self.removeProperties(definitions.cICalProperty_SEQUENCE)
-
-        prop = PyCalendarProperty(definitions.cICalProperty_SEQUENCE, self.mSeq)
-        self.addProperty(prop)
-
-
-    def getOriginalSeq(self):
-        return self.mOriginalSeq
-
-
-    def getChanged(self):
-        return self.mChanged
-
-
-    def setChanged(self, changed):
-        self.mChanged = changed
-
-
-    def initDTSTAMP(self):
-        self.removeProperties(definitions.cICalProperty_DTSTAMP)
-
-        prop = PyCalendarProperty(definitions.cICalProperty_DTSTAMP,
-                                  PyCalendarDateTime.getNowUTC())
-        self.addProperty(prop)
-
-
-    def updateLastModified(self):
-        self.removeProperties(definitions.cICalProperty_LAST_MODIFIED)
-
-        prop = PyCalendarProperty(definitions.cICalProperty_LAST_MODIFIED,
-                                  PyCalendarDateTime.getNowUTC())
-        self.addProperty(prop)
-
-
-    def finalise(self):
-        # Get UID
-        temps = self.loadValueString(definitions.cICalProperty_UID)
-        if temps is not None:
-            self.mUID = temps
-
-        # Get SEQ
-        temp = self.loadValueInteger(definitions.cICalProperty_SEQUENCE)
-        if temp is not None:
-            self.mSeq = temp
-
-        # Cache the original sequence when the component is read in.
-        # This will be used to synchronise changes between two instances of the
-        # same calendar
-        self.mOriginalSeq = self.mSeq
-
-
-    def canGenerateInstance(self):
-        return True
-
-
-    def getTimezones(self, tzids):
-        # Look for all date-time properties
-        for props in self.mProperties.itervalues():
-            for prop in props:
-                # Try to get a date-time value from the property
-                dtv = prop.getDateTimeValue()
-                if dtv is not None:
-                    # Add timezone id if appropriate
-                    if dtv.getValue().getTimezoneID():
-                        tzids.add(dtv.getValue().getTimezoneID())
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcomponentbasepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/componentbase.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/componentbase.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/componentbase.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -15,14 +15,14 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> from cStringIO import StringIO
</span><del>-from pycalendar import xmldefs
-from pycalendar.datetimevalue import PyCalendarDateTimeValue
-from pycalendar.periodvalue import PyCalendarPeriodValue
-from pycalendar.property import PyCalendarProperty
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions, xmlutils
+from pycalendar.datetimevalue import DateTimeValue
+from pycalendar.periodvalue import PeriodValue
+from pycalendar.value import Value
</ins><span class="cx"> import xml.etree.cElementTree as XML
</span><ins>+from pycalendar.exceptions import InvalidComponent, ErrorBase
</ins><span class="cx"> 
</span><del>-class PyCalendarComponentBase(object):
</del><ins>+class ComponentBase(object):
</ins><span class="cx"> 
</span><span class="cx">     # These are class attributes for sets of properties for testing cardinality constraints. The sets
</span><span class="cx">     # must contain property names.
</span><span class="lines">@@ -35,6 +35,9 @@
</span><span class="cx"> 
</span><span class="cx">     sortSubComponents = True
</span><span class="cx"> 
</span><ins>+    sComponentType = None
+    sPropertyType = None
+
</ins><span class="cx">     def __init__(self, parent=None):
</span><span class="cx">         self.mParentComponent = parent
</span><span class="cx">         self.mComponents = []
</span><span class="lines">@@ -70,7 +73,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __eq__(self, other):
</span><del>-        if not isinstance(other, PyCalendarComponentBase):
</del><ins>+        if not isinstance(other, ComponentBase):
</ins><span class="cx">             return False
</span><span class="cx">         return self.getType() == other.getType() and self.compareProperties(other) and self.compareComponents(other)
</span><span class="cx"> 
</span><span class="lines">@@ -276,7 +279,7 @@
</span><span class="cx">             elif self.countProperty(propname) == 0: # Possibly fix by adding empty property
</span><span class="cx">                 logProblem = &quot;[%s] Missing required property: %s&quot; % (self.getType(), propname)
</span><span class="cx">                 if doFix:
</span><del>-                    self.addProperty(PyCalendarProperty(propname, &quot;&quot;))
</del><ins>+                    self.addProperty(self.sPropertyType(propname, &quot;&quot;))
</ins><span class="cx">                     fixed.append(logProblem)
</span><span class="cx">                 else:
</span><span class="cx">                     unfixed.append(logProblem)
</span><span class="lines">@@ -337,7 +340,7 @@
</span><span class="cx">     def writeXML(self, node, namespace):
</span><span class="cx"> 
</span><span class="cx">         # Component element
</span><del>-        comp = XML.SubElement(node, xmldefs.makeTag(namespace, self.getType()))
</del><ins>+        comp = XML.SubElement(node, xmlutils.makeTag(namespace, self.getType()))
</ins><span class="cx"> 
</span><span class="cx">         # Each property
</span><span class="cx">         self.writePropertiesXML(comp, namespace)
</span><span class="lines">@@ -348,7 +351,7 @@
</span><span class="cx"> 
</span><span class="cx">     def writeXMLFiltered(self, node, namespace, filter):
</span><span class="cx">         # Component element
</span><del>-        comp = XML.SubElement(node, xmldefs.makeTag(namespace, self.getType()))
</del><ins>+        comp = XML.SubElement(node, xmlutils.makeTag(namespace, self.getType()))
</ins><span class="cx"> 
</span><span class="cx">         # Each property
</span><span class="cx">         self.writePropertiesFilteredXML(comp, namespace, filter)
</span><span class="lines">@@ -357,6 +360,60 @@
</span><span class="cx">         self.writeComponentsFilteredXML(comp, namespace, filter)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    @classmethod
+    def parseJSON(cls, jobject, parent, comp=None):
+        &quot;&quot;&quot;
+        Parse the JSON object which has the form:
+
+        [name, properties, subcomponents]
+
+        @param jobject: a JSON array
+        @type jobject: C{list}
+        &quot;&quot;&quot;
+        # [name, properties, subcomponents]
+
+        try:
+            if comp is None:
+                comp = cls.sComponentType.makeComponent(jobject[0].upper(), parent)
+            for prop in jobject[1]:
+                comp.addProperty(cls.sPropertyType.parseJSON(prop))
+            for subcomp in jobject[2]:
+                comp.addComponent(cls.sComponentType.parseJSON(subcomp, comp))
+            comp.finalise()
+            return comp
+        except ErrorBase:
+            raise
+        except Exception:
+            raise InvalidComponent(&quot;Invalid component&quot;, jobject)
+
+
+    def writeJSON(self, jobject):
+
+        # Component element
+        comp = [self.getType().lower(), [], []]
+
+        # Each property
+        self.writePropertiesJSON(comp[1])
+
+        # Each component
+        self.writeComponentsJSON(comp[2])
+
+        jobject.append(comp)
+
+
+    def writeJSONFiltered(self, jobject, filter):
+        # Component element
+        comp = [self.getType().lower(), [], []]
+
+        # Each property
+        self.writePropertiesFilteredJSON(comp[1], filter)
+
+        # Each component
+        self.writeComponentsFilteredJSON(comp[2], filter)
+
+        jobject.append(comp)
+
+
</ins><span class="cx">     def sortedComponents(self):
</span><span class="cx"> 
</span><span class="cx">         components = self.mComponents[:]
</span><span class="lines">@@ -407,7 +464,7 @@
</span><span class="cx">     def writeComponentsXML(self, node, namespace):
</span><span class="cx"> 
</span><span class="cx">         if self.mComponents:
</span><del>-            comps = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.components))
</del><ins>+            comps = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.components))
</ins><span class="cx"> 
</span><span class="cx">             # Write out the remainder
</span><span class="cx">             for component in self.sortedComponents():
</span><span class="lines">@@ -417,7 +474,7 @@
</span><span class="cx">     def writeComponentsFilteredXML(self, node, namespace, filter):
</span><span class="cx"> 
</span><span class="cx">         if self.mComponents:
</span><del>-            comps = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.components))
</del><ins>+            comps = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.components))
</ins><span class="cx"> 
</span><span class="cx">             # Shortcut for all sub-components
</span><span class="cx">             if filter.isAllSubComponents():
</span><span class="lines">@@ -426,9 +483,30 @@
</span><span class="cx">                 for subcomp in self.sortedcomponents():
</span><span class="cx">                     subfilter = filter.getSubComponentFilter(subcomp.getType())
</span><span class="cx">                     if subfilter is not None:
</span><del>-                        subcomp.writeFilteredXML(comps, namespace, subfilter)
</del><ins>+                        subcomp.writeXMLFiltered(comps, namespace, subfilter)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def writeComponentsJSON(self, jobject):
+
+        if self.mComponents:
+            # Write out the remainder
+            for component in self.sortedComponents():
+                component.writeJSON(jobject)
+
+
+    def writeComponentsFilteredJSON(self, jobject, filter):
+
+        if self.mComponents:
+            # Shortcut for all sub-components
+            if filter.isAllSubComponents():
+                self.writeJSON(jobject)
+            elif filter.hasSubComponentFilters():
+                for subcomp in self.sortedcomponents():
+                    subfilter = filter.getSubComponentFilter(subcomp.getType())
+                    if subfilter is not None:
+                        subcomp.writeJSONFiltered(jobject, subfilter)
+
+
</ins><span class="cx">     def loadValue(self, value_name):
</span><span class="cx">         if self.hasProperty(value_name):
</span><span class="cx">             return self.findFirstProperty(value_name)
</span><span class="lines">@@ -439,18 +517,18 @@
</span><span class="cx">     def loadValueInteger(self, value_name, type=None):
</span><span class="cx">         if type:
</span><span class="cx">             if self.hasProperty(value_name):
</span><del>-                if type == PyCalendarValue.VALUETYPE_INTEGER:
</del><ins>+                if type == Value.VALUETYPE_INTEGER:
</ins><span class="cx">                     ivalue = self.findFirstProperty(value_name).getIntegerValue()
</span><span class="cx">                     if ivalue is not None:
</span><span class="cx">                         return ivalue.getValue()
</span><del>-                elif type == PyCalendarValue.VALUETYPE_UTC_OFFSET:
</del><ins>+                elif type == Value.VALUETYPE_UTC_OFFSET:
</ins><span class="cx">                     uvalue = self.findFirstProperty(value_name).getUTCOffsetValue()
</span><span class="cx">                     if (uvalue is not None):
</span><span class="cx">                         return uvalue.getValue()
</span><span class="cx"> 
</span><span class="cx">             return None
</span><span class="cx">         else:
</span><del>-            return self.loadValueInteger(value_name, PyCalendarValue.VALUETYPE_INTEGER)
</del><ins>+            return self.loadValueInteger(value_name, Value.VALUETYPE_INTEGER)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def loadValueString(self, value_name):
</span><span class="lines">@@ -513,12 +591,12 @@
</span><span class="cx">                 if (mvalue is not None):
</span><span class="cx">                     for obj in mvalue.getValues():
</span><span class="cx">                         # cast to date-time
</span><del>-                        if isinstance(obj, PyCalendarDateTimeValue):
</del><ins>+                        if isinstance(obj, DateTimeValue):
</ins><span class="cx">                             if add:
</span><span class="cx">                                 value.addDT(obj.getValue())
</span><span class="cx">                             else:
</span><span class="cx">                                 value.subtractDT(obj.getValue())
</span><del>-                        elif isinstance(obj, PyCalendarPeriodValue):
</del><ins>+                        elif isinstance(obj, PeriodValue):
</ins><span class="cx">                             if add:
</span><span class="cx">                                 value.addPeriod(obj.getValue().getStart())
</span><span class="cx">                             else:
</span><span class="lines">@@ -573,7 +651,7 @@
</span><span class="cx"> 
</span><span class="cx">     def writePropertiesXML(self, node, namespace):
</span><span class="cx"> 
</span><del>-        properties = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.properties))
</del><ins>+        properties = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.properties))
</ins><span class="cx"> 
</span><span class="cx">         # Sort properties by name
</span><span class="cx">         keys = self.sortedPropertyKeys()
</span><span class="lines">@@ -585,7 +663,7 @@
</span><span class="cx"> 
</span><span class="cx">     def writePropertiesFilteredXML(self, node, namespace, filter):
</span><span class="cx"> 
</span><del>-        props = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.properties))
</del><ins>+        props = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.properties))
</ins><span class="cx"> 
</span><span class="cx">         # Sort properties by name
</span><span class="cx">         keys = self.sortedPropertyKeys()
</span><span class="lines">@@ -598,9 +676,35 @@
</span><span class="cx">         elif filter.hasPropertyFilters():
</span><span class="cx">             for key in keys:
</span><span class="cx">                 for prop in self.getProperties(key):
</span><del>-                    prop.writeFilteredXML(props, namespace, filter)
</del><ins>+                    prop.writeXMLFiltered(props, namespace, filter)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def writePropertiesJSON(self, jobject):
+
+        # Sort properties by name
+        keys = self.sortedPropertyKeys()
+        for key in keys:
+            props = self.mProperties[key]
+            for prop in props:
+                prop.writeJSON(jobject)
+
+
+    def writePropertiesFilteredJSON(self, jobject, filter):
+
+        # Sort properties by name
+        keys = self.sortedPropertyKeys()
+
+        # Shortcut for all properties
+        if filter.isAllProperties():
+            for key in keys:
+                for prop in self.getProperties(key):
+                    prop.writeJSON(jobject)
+        elif filter.hasPropertyFilters():
+            for key in keys:
+                for prop in self.getProperties(key):
+                    prop.writeJSONFiltered(jobject, filter)
+
+
</ins><span class="cx">     def loadPrivateValue(self, value_name):
</span><span class="cx">         # Read it in from properties list and then delete the property from the
</span><span class="cx">         # main list
</span><span class="lines">@@ -611,7 +715,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def writePrivateProperty(self, os, key, value):
</span><del>-        prop = PyCalendarProperty(name=key, value=value)
</del><ins>+        prop = self.sPropertyType(name=key, value=value)
</ins><span class="cx">         prop.generate(os)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -622,4 +726,4 @@
</span><span class="cx"> 
</span><span class="cx">         # Now create properties
</span><span class="cx">         if propvalue:
</span><del>-            self.addProperty(PyCalendarProperty(name=propname, value=propvalue))
</del><ins>+            self.addProperty(self.sPropertyType(name=propname, value=propvalue))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcomponentexpandedpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/componentexpanded.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/componentexpanded.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/componentexpanded.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,158 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 PyCalendarDateTime
-
-class PyCalendarComponentExpanded(object):
-
-    @staticmethod
-    def sort_by_dtstart_allday(e1, e2):
-
-        if e1.mInstanceStart.isDateOnly() and e2.mInstanceStart.isDateOnly():
-            return e1.mInstanceStart &lt; e2.mInstanceStart
-        elif e1.mInstanceStart.isDateOnly():
-            return True
-        elif e2.mInstanceStart.isDateOnly():
-            return False
-        elif e1.mInstanceStart == e2.mInstanceStart:
-            if e1.mInstanceEnd == e2.mInstanceEnd:
-                # Put ones created earlier in earlier columns in day view
-                return e1.getOwner().getStamp() &lt; e2.getOwner().getStamp()
-            else:
-                # Put ones that end later in earlier columns in day view
-                return e1.mInstanceEnd &gt; e2.mInstanceEnd
-        else:
-            return e1.mInstanceStart &lt; e2.mInstanceStart
-
-
-    @staticmethod
-    def sort_by_dtstart(e1, e2):
-        if e1.mInstanceStart == e2.mInstanceStart:
-            if (e1.mInstanceStart.isDateOnly() and not e2.mInstanceStart.isDateOnly() or
-                not e1.mInstanceStart.isDateOnly() and e2.mInstanceStart.isDateOnly()):
-                return e1.mInstanceStart.isDateOnly()
-            else:
-                return False
-        else:
-            return e1.mInstanceStart &lt; e2.mInstanceStart
-
-
-    def __init__(self, owner, rid):
-
-        self.mOwner = owner
-        self.initFromOwner(rid)
-
-
-    def duplicate(self):
-        other = PyCalendarComponentExpanded(self.mOwner, None)
-        other.mInstanceStart = self.mInstanceStart.duplicate()
-        other.mInstanceEnd = self.mInstanceEnd.duplicate()
-        other.mRecurring = self.mRecurring
-        return other
-
-
-    def close(self):
-        # Clean-up
-        self.mOwner = None
-
-
-    def getOwner(self):
-        return self.mOwner
-
-
-    def getMaster(self):
-        return self.mOwner
-
-
-    def getTrueMaster(self):
-        return self.mOwner.getMaster()
-
-
-    def getInstanceStart(self):
-        return self.mInstanceStart
-
-
-    def getInstanceEnd(self):
-        return self.mInstanceEnd
-
-
-    def recurring(self):
-        return self.mRecurring
-
-
-    def isNow(self):
-        # Check instance start/end against current date-time
-        now = PyCalendarDateTime.getNowUTC()
-        return self.mInstanceStart &lt;= now and self.mInstanceEnd &gt; now
-
-
-    def initFromOwner(self, rid):
-        # There are four possibilities here:
-        #
-        # 1: this instance is the instance for the master component
-        #
-        # 2: this instance is an expanded instance derived directly from the
-        # master component
-        #
-        # 3: This instance is the instance for a slave (overridden recurrence
-        # instance)
-        #
-        # 4: This instance is the expanded instance for a slave with a RANGE
-        # parameter
-        #
-
-        # rid is not set if the owner is the master (case 1)
-        if rid is None:
-            # Just get start/end from owner
-            self.mInstanceStart = self.mOwner.getStart()
-            self.mInstanceEnd = self.mOwner.getEnd()
-            self.mRecurring = False
-
-        # If the owner is not a recurrence instance then it is case 2
-        elif not self.mOwner.isRecurrenceInstance():
-            # Derive start/end from rid and duration of master
-
-            # Start of the recurrence instance is the recurrence id
-            self.mInstanceStart = rid
-
-            # End is based on original events settings
-            if self.mOwner.hasEnd():
-                self.mInstanceEnd = self.mInstanceStart + (self.mOwner.getEnd() - self.mOwner.getStart())
-            else:
-                self.mInstanceEnd = self.mInstanceStart.duplicate()
-
-            self.mRecurring = True
-
-        # If the owner is a recurrence item and the passed in rid is the same
-        # as the component rid we have case 3
-        elif rid == self.mOwner.getRecurrenceID():
-            # Derive start/end directly from the owner
-            self.mInstanceStart = self.mOwner.getStart()
-            self.mInstanceEnd = self.mOwner.getEnd()
-
-            self.mRecurring = True
-
-        # case 4 - the complicated one!
-        else:
-            # We need to use the rid as the starting point, but adjust it by
-            # the offset between the slave's
-            # rid and its start
-            self.mInstanceStart = rid + (self.mOwner.getStart() - self.mOwner.getRecurrenceID())
-
-            # End is based on duration of owner
-            self.mInstanceEnd = self.mInstanceStart + (self.mOwner.getEnd() - self.mOwner.getStart())
-
-            self.mRecurring = True
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcomponentrecurpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/componentrecur.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/componentrecur.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/componentrecur.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,714 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.componentexpanded import PyCalendarComponentExpanded
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.property import PyCalendarProperty
-from pycalendar.recurrenceset import PyCalendarRecurrenceSet
-from pycalendar.timezone import PyCalendarTimezone
-from pycalendar.utils import set_difference
-import uuid
-
-class PyCalendarComponentRecur(PyCalendarComponent):
-
-    propertyCardinality_STATUS_Fix = (
-        definitions.cICalProperty_STATUS,
-    )
-
-    @staticmethod
-    def mapKey(uid, rid=None):
-        if uid:
-            result = &quot;u:&quot; + uid
-            if rid is not None:
-                result += rid
-            return result
-        else:
-            return None
-
-
-    @staticmethod
-    def sort_by_dtstart_allday(e1, e2):
-
-        if e1.self.mStart.isDateOnly() and e2.self.mStart.isDateOnly():
-            return e1.self.mStart &lt; e2.self.mStart
-        elif e1.self.mStart.isDateOnly():
-            return True
-        elif (e2.self.mStart.isDateOnly()):
-            return False
-        elif e1.self.mStart == e2.self.mStart:
-            if e1.self.mEnd == e2.self.mEnd:
-                # Put ones created earlier in earlier columns in day view
-                return e1.self.mStamp &lt; e2.self.mStamp
-            else:
-                # Put ones that end later in earlier columns in day view
-                return e1.self.mEnd &gt; e2.self.mEnd
-        else:
-            return e1.self.mStart &lt; e2.self.mStart
-
-
-    @staticmethod
-    def sort_by_dtstart(e1, e2):
-        if e1.self.mStart == e2.self.mStart:
-            if (e1.self.mStart.isDateOnly() and e2.self.mStart.isDateOnly() or
-                not e1.self.mStart.isDateOnly() and not e2.self.mStart.isDateOnly()):
-                return False
-            else:
-                return e1.self.mStart.isDateOnly()
-        else:
-            return e1.self.mStart &lt; e2.self.mStart
-
-
-    def __init__(self, parent=None):
-        super(PyCalendarComponentRecur, self).__init__(parent=parent)
-        self.mMaster = self
-        self.mMapKey = None
-        self.mSummary = None
-        self.mStamp = PyCalendarDateTime()
-        self.mHasStamp = False
-        self.mStart = PyCalendarDateTime()
-        self.mHasStart = False
-        self.mEnd = PyCalendarDateTime()
-        self.mHasEnd = False
-        self.mDuration = False
-        self.mHasRecurrenceID = False
-        self.mAdjustFuture = False
-        self.mAdjustPrior = False
-        self.mRecurrenceID = None
-        self.mRecurrences = None
-
-        # This is a special check we do only for STATUS due to a calendarserver bug
-        self.cardinalityChecks += (
-            self.check_cardinality_STATUS_Fix,
-        )
-
-
-    def duplicate(self, parent=None):
-        other = super(PyCalendarComponentRecur, self).duplicate(parent=parent)
-
-        # Special determination of master
-        other.mMaster = self.mMaster if self.recurring() else self
-
-        other.mMapKey = self.mMapKey
-
-        other.mSummary = self.mSummary
-
-        if (self.mStamp is not None):
-            other.mStamp = self.mStamp.duplicate()
-        other.mHasStamp = self.mHasStamp
-
-        other.mStart = self.mStart.duplicate()
-        other.mHasStart = self.mHasStart
-        other.mEnd = self.mEnd.duplicate()
-        other.mHasEnd = self.mHasEnd
-        other.mDuration = self.mDuration
-
-        other.mHasRecurrenceID = self.mHasRecurrenceID
-        other.mAdjustFuture = self.mAdjustFuture
-        other.mAdjustPrior = self.mAdjustPrior
-        if self.mRecurrenceID is not None:
-            other.mRecurrenceID = self.mRecurrenceID.duplicate()
-
-        other._resetRecurrenceSet()
-
-        return other
-
-
-    def canGenerateInstance(self):
-        return not self.mHasRecurrenceID
-
-
-    def recurring(self):
-        return (self.mMaster is not None) and (self.mMaster is not self)
-
-
-    def setMaster(self, master):
-        self.mMaster = master
-        self.initFromMaster()
-
-
-    def getMaster(self):
-        return self.mMaster
-
-
-    def getMapKey(self):
-
-        if self.mMapKey is None:
-            self.mMapKey = str(uuid.uuid4())
-        return self.mMapKey
-
-
-    def getMasterKey(self):
-        return PyCalendarComponentRecur.mapKey(self.mUID)
-
-
-    def initDTSTAMP(self):
-        # Save new one
-        super(PyCalendarComponentRecur, self).initDTSTAMP()
-
-        # Get the new one
-        temp = self.loadValueDateTime(definitions.cICalProperty_DTSTAMP)
-        self.mHasStamp = temp is not None
-        if self.mHasStamp:
-            self.mStamp = temp
-
-
-    def getStamp(self):
-        return self.mStamp
-
-
-    def hasStamp(self):
-        return self.mHasStamp
-
-
-    def getStart(self):
-        return self.mStart
-
-
-    def hasStart(self):
-        return self.mHasStart
-
-
-    def getEnd(self):
-        return self.mEnd
-
-
-    def hasEnd(self):
-        return self.mHasEnd
-
-
-    def useDuration(self):
-        return self.mDuration
-
-
-    def isRecurrenceInstance(self):
-        return self.mHasRecurrenceID
-
-
-    def isAdjustFuture(self):
-        return self.mAdjustFuture
-
-
-    def isAdjustPrior(self):
-        return self.mAdjustPrior
-
-
-    def getRecurrenceID(self):
-        return self.mRecurrenceID
-
-
-    def isRecurring(self):
-        return (self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()
-
-
-    def getRecurrenceSet(self):
-        return self.mRecurrences
-
-
-    def setUID(self, uid):
-        super(PyCalendarComponentRecur, self).setUID(uid)
-
-        # Update the map key
-        if self.mHasRecurrenceID:
-            self.mMapKey = self.mapKey(self.mUID, self.mRecurrenceID.getText())
-        else:
-            self.mMapKey = self.mapKey(self.mUID)
-
-
-    def getSummary(self):
-        return self.mSummary
-
-
-    def setSummary(self, summary):
-        self.mSummary = summary
-
-
-    def getDescription(self):
-        # Get DESCRIPTION
-        txt = self.loadValueString(definitions.cICalProperty_DESCRIPTION)
-        if txt is not None:
-            return txt
-        else:
-            return &quot;&quot;
-
-
-    def getLocation(self):
-        # Get LOCATION
-        txt = self.loadValueString(definitions.cICalProperty_LOCATION)
-        if txt is not None:
-            return txt
-        else:
-            return &quot;&quot;
-
-
-    def finalise(self):
-        super(PyCalendarComponentRecur, self).finalise()
-
-        # Get DTSTAMP
-        temp = self.loadValueDateTime(definitions.cICalProperty_DTSTAMP)
-        self.mHasStamp = temp is not None
-        if self.mHasStamp:
-            self.mStamp = temp
-
-        # Get DTSTART
-        temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
-        self.mHasStart = temp is not None
-        if self.mHasStart:
-            self.mStart = temp
-
-        # Get DTEND
-        temp = self.loadValueDateTime(definitions.cICalProperty_DTEND)
-        if temp is None:
-            # Try DURATION instead
-            temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
-            if temp is not None:
-                self.mHasEnd = False
-                self.mEnd = self.mStart + temp
-                self.mDuration = True
-            else:
-                # If no end or duration then use the start
-                self.mHasEnd = False
-                self.mEnd = self.mStart.duplicate()
-                self.mDuration = False
-        else:
-            self.mHasEnd = True
-            self.mEnd = temp
-            self.mDuration = False
-
-        # Get SUMMARY
-        temp = self.loadValueString(definitions.cICalProperty_SUMMARY)
-        if temp is not None:
-            self.mSummary = temp
-
-        # Get RECURRENCE-ID
-        self.mHasRecurrenceID = (self.countProperty(definitions.cICalProperty_RECURRENCE_ID) != 0)
-        if self.mHasRecurrenceID:
-            self.mRecurrenceID = self.loadValueDateTime(definitions.cICalProperty_RECURRENCE_ID)
-
-        # Update the map key
-        if self.mHasRecurrenceID:
-            self.mMapKey = self.mapKey(self.mUID, self.mRecurrenceID.getText())
-
-            # Also get the RANGE attribute
-            attrs = self.findFirstProperty(definitions.cICalProperty_RECURRENCE_ID).getAttributes()
-            if definitions.cICalAttribute_RANGE in attrs:
-                self.mAdjustFuture = (attrs[definitions.cICalAttribute_RANGE][0].getFirstValue() == definitions.cICalAttribute_RANGE_THISANDFUTURE)
-                self.mAdjustPrior = (attrs[definitions.cICalAttribute_RANGE][0].getFirstValue() == definitions.cICalAttribute_RANGE_THISANDPRIOR)
-            else:
-                self.mAdjustFuture = False
-                self.mAdjustPrior = False
-        else:
-            self.mMapKey = self.mapKey(self.mUID)
-
-        self._resetRecurrenceSet()
-
-
-    def validate(self, doFix=False):
-        &quot;&quot;&quot;
-        Validate the data in this component and optionally fix any problems. Return
-        a tuple containing two lists: the first describes problems that were fixed, the
-        second problems that were not fixed. Caller can then decide what to do with unfixed
-        issues.
-        &quot;&quot;&quot;
-
-        # Do normal checks
-        fixed, unfixed = super(PyCalendarComponentRecur, self).validate(doFix)
-
-        # Check that any UNTIL value matches that for DTSTART
-        if self.mHasStart and self.mRecurrences:
-            dtutc = self.mStart.duplicateAsUTC()
-            for rrule in self.mRecurrences.getRules():
-                if rrule.getUseUntil():
-                    if rrule.getUntil().isDateOnly() ^ self.mStart.isDateOnly():
-                        logProblem = &quot;[%s] Value types must match: %s, %s&quot; % (
-                            self.getType(),
-                            definitions.cICalProperty_DTSTART,
-                            definitions.cICalValue_RECUR_UNTIL,
-                        )
-                        if doFix:
-                            rrule.getUntil().setDateOnly(self.mStart.isDateOnly())
-                            if not self.mStart.isDateOnly():
-                                rrule.getUntil().setHHMMSS(dtutc.getHours(), dtutc.getMinutes(), dtutc.getSeconds())
-                                rrule.getUntil().setTimezone(PyCalendarTimezone(utc=True))
-                            self.mRecurrences.changed()
-                            fixed.append(logProblem)
-                        else:
-                            unfixed.append(logProblem)
-
-        return fixed, unfixed
-
-
-    def check_cardinality_STATUS_Fix(self, fixed, unfixed, doFix):
-        &quot;&quot;&quot;
-        Special for bug with STATUS where STATUS:CANCELLED is added alongside
-        another STATUS. In this case we want STATUS:CANCELLED to win.
-        &quot;&quot;&quot;
-        for propname in self.propertyCardinality_STATUS_Fix:
-            if self.countProperty(propname) &gt; 1:
-                logProblem = &quot;[%s] Too many properties: %s&quot; % (self.getType(), propname)
-                if doFix:
-                    # Check that one of them is STATUS:CANCELLED
-                    for prop in self.getProperties(propname):
-                        if prop.getTextValue().getValue().upper() == definitions.cICalProperty_STATUS_CANCELLED:
-                            self.removeProperties(propname)
-                            self.addProperty(PyCalendarProperty(propname, definitions.cICalProperty_STATUS_CANCELLED))
-                            fixed.append(logProblem)
-                            break
-                    else:
-                        unfixed.append(logProblem)
-                else:
-                    unfixed.append(logProblem)
-
-
-    def _resetRecurrenceSet(self):
-        # May need to create items
-        self.mRecurrences = None
-        if ((self.countProperty(definitions.cICalProperty_RRULE) != 0) or
-            (self.countProperty(definitions.cICalProperty_RDATE) != 0) or
-            (self.countProperty(definitions.cICalProperty_EXRULE) != 0) or
-            (self.countProperty(definitions.cICalProperty_EXDATE) != 0)):
-
-            self.mRecurrences = PyCalendarRecurrenceSet()
-
-            # Get RRULEs
-            self.loadValueRRULE(definitions.cICalProperty_RRULE, self.mRecurrences, True)
-
-            # Get RDATEs
-            self.loadValueRDATE(definitions.cICalProperty_RDATE, self.mRecurrences, True)
-
-            # Get EXRULEs
-            self.loadValueRRULE(definitions.cICalProperty_EXRULE, self.mRecurrences, False)
-
-            # Get EXDATEs
-            self.loadValueRDATE(definitions.cICalProperty_EXDATE, self.mRecurrences, False)
-
-
-    def FixStartEnd(self):
-        # End is always greater than start if start exists
-        if self.mHasStart and self.mEnd &lt;= self.mStart:
-            # Use the start
-            self.mEnd = self.mStart.duplicate()
-            self.mDuration = False
-
-            # Adjust to approriate non-inclusive end point
-            if self.mStart.isDateOnly():
-                self.mEnd.offsetDay(1)
-
-                # For all day events it makes sense to use duration
-                self.mDuration = True
-            else:
-                # Use end of current day
-                self.mEnd.offsetDay(1)
-                self.mEnd.setHHMMSS(0, 0, 0)
-
-
-    def expandPeriod(self, period, results):
-        # Check for recurrence and True master
-        if ((self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()
-                and not self.isRecurrenceInstance()):
-            # Expand recurrences within the range
-            items = []
-            self.mRecurrences.expand(self.mStart, period, items)
-
-            # Look for overridden recurrence items
-            cal = self.mParentComponent
-            if cal is not None:
-                # Remove recurrence instances from the list of items
-                recurs = []
-                cal.getRecurrenceInstancesIds(definitions.cICalComponent_VEVENT, self.getUID(), recurs)
-                recurs.sort()
-                if len(recurs) != 0:
-                    temp = []
-                    temp = set_difference(items, recurs)
-                    items = temp
-
-                    # Now get actual instances
-                    instances = []
-                    cal.getRecurrenceInstancesItems(definitions.cICalComponent_VEVENT, self.getUID(), instances)
-
-                    # Get list of each ones with RANGE
-                    prior = []
-                    future = []
-                    for iter in instances:
-                        if iter.isAdjustPrior():
-                            prior.append(iter)
-                        if iter.isAdjustFuture():
-                            future.append(iter)
-
-                    # Check for special behaviour
-                    if len(prior) + len(future) == 0:
-                        # Add each expanded item
-                        for iter in items:
-                            results.append(self.createExpanded(self, iter))
-                    else:
-                        # Sort each list first
-                        prior.sort(self.sort_by_dtstart)
-                        future.sort(self.sort_by_dtstart)
-
-                        # Add each expanded item
-                        for iter1 in items:
-
-                            # Now step through each using the slave item
-                            # instead of the master as appropriate
-                            slave = None
-
-                            # Find most appropriate THISANDPRIOR item
-                            for i in range(len(prior) - 1, 0, -1):
-                                riter2 = prior[i]
-                                if riter2.getStart() &gt; iter1:
-                                    slave = riter2
-                                    break
-
-                            # Find most appropriate THISANDFUTURE item
-                            for i in range(len(future) - 1, 0, -1):
-                                riter2 = future.elementAt(i)
-                                if riter2.getStart() &lt; iter1:
-                                    slave = riter2
-                                    break
-
-                            if slave is None:
-                                slave = self
-                            results.append(self.createExpanded(slave, iter1))
-                else:
-                    # Add each expanded item
-                    for iter in items:
-                        results.append(self.createExpanded(self, iter))
-
-        elif self.withinPeriod(period):
-            if self.isRecurrenceInstance():
-                rid = self.mRecurrenceID
-            else:
-                rid = None
-            results.append(PyCalendarComponentExpanded(self, rid))
-
-
-    def withinPeriod(self, period):
-        # Check for recurrence
-        if ((self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()):
-            items = []
-            self.mRecurrences.expand(self.mStart, period, items)
-            return len(items) != 0
-        else:
-            # Does event span the period (assume self.mEnd &gt; self.mStart)
-            # Check start (inclusive) and end (exclusive)
-            if self.mEnd &lt;= period.getStart() or self.mStart &gt;= period.getEnd():
-                return False
-            else:
-                return True
-
-
-    def changedRecurrence(self):
-        # Clear cached values
-        if self.mRecurrences is not None:
-            self.mRecurrences.changed()
-
-
-    # Editing
-    def editSummary(self, summary):
-        # Updated cached value
-        self.mSummary = summary
-
-        # Remove existing items
-        self.editProperty(definitions.cICalProperty_SUMMARY, summary)
-
-
-    def editDetails(self, description, location):
-
-        # Edit existing items
-        self.editProperty(definitions.cICalProperty_DESCRIPTION, description)
-        self.editProperty(definitions.cICalProperty_LOCATION, location)
-
-
-    def editTiming(self):
-        # Updated cached values
-        self.mHasStart = False
-        self.mHasEnd = False
-        self.mDuration = False
-        self.mStart.setToday()
-        self.mEnd.setToday()
-
-        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
-        self.removeProperties(definitions.cICalProperty_DTSTART)
-        self.removeProperties(definitions.cICalProperty_DTEND)
-        self.removeProperties(definitions.cICalProperty_DURATION)
-        self.removeProperties(definitions.cICalProperty_DUE)
-
-
-    def editTimingDue(self, due):
-        # Updated cached values
-        self.mHasStart = False
-        self.mHasEnd = True
-        self.mDuration = False
-        self.mStart = due
-        self.mEnd = due
-
-        # Remove existing DUE &amp; DTSTART &amp; DTEND &amp; DURATION items
-        self.removeProperties(definitions.cICalProperty_DUE)
-        self.removeProperties(definitions.cICalProperty_DTSTART)
-        self.removeProperties(definitions.cICalProperty_DTEND)
-        self.removeProperties(definitions.cICalProperty_DURATION)
-
-        # Now create properties
-        prop = PyCalendarProperty(definitions.cICalProperty_DUE, due)
-        self.addProperty(prop)
-
-
-    def editTimingStartEnd(self, start, end):
-        # Updated cached values
-        self.mHasStart = self.mHasEnd = True
-        self.mStart = start
-        self.mEnd = end
-        self.mDuration = False
-        self.FixStartEnd()
-        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
-        self.removeProperties(definitions.cICalProperty_DTSTART)
-        self.removeProperties(definitions.cICalProperty_DTEND)
-        self.removeProperties(definitions.cICalProperty_DURATION)
-        self.removeProperties(definitions.cICalProperty_DUE)
-
-        # Now create properties
-        prop = PyCalendarProperty(definitions.cICalProperty_DTSTART, start)
-        self.addProperty(prop)
-
-        # If its an all day event and the end one day after the start, ignore it
-        temp = start.duplicate()
-        temp.offsetDay(1)
-        if not start.isDateOnly() or end != temp:
-            prop = PyCalendarProperty(definitions.cICalProperty_DTEND, end)
-            self.addProperty(prop)
-
-
-    def editTimingStartDuration(self, start, duration):
-        # Updated cached values
-        self.mHasStart = True
-        self.mHasEnd = False
-        self.mStart = start
-        self.mEnd = start + duration
-        self.mDuration = True
-
-        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
-        self.removeProperties(definitions.cICalProperty_DTSTART)
-        self.removeProperties(definitions.cICalProperty_DTEND)
-        self.removeProperties(definitions.cICalProperty_DURATION)
-        self.removeProperties(definitions.cICalProperty_DUE)
-
-        # Now create properties
-        prop = PyCalendarProperty(definitions.cICalProperty_DTSTART, start)
-        self.addProperty(prop)
-
-        # If its an all day event and the duration is one day, ignore it
-        if (not start.isDateOnly() or (duration.getWeeks() != 0)
-                or (duration.getDays() &gt; 1)):
-            prop = PyCalendarProperty(definitions.cICalProperty_DURATION, duration)
-            self.addProperty(prop)
-
-
-    def editRecurrenceSet(self, recurs):
-        # Must have items
-        if self.mRecurrences is None:
-            self.mRecurrences = PyCalendarRecurrenceSet()
-
-        # Updated cached values
-        self.mRecurrences = recurs
-
-        # Remove existing RRULE, EXRULE, RDATE &amp; EXDATE
-        self.removeProperties(definitions.cICalProperty_RRULE)
-        self.removeProperties(definitions.cICalProperty_EXRULE)
-        self.removeProperties(definitions.cICalProperty_RDATE)
-        self.removeProperties(definitions.cICalProperty_EXDATE)
-
-        # Now create properties
-        for iter in self.mRecurrences.getRules():
-            prop = PyCalendarProperty(definitions.cICalProperty_RRULE, iter)
-            self.addProperty(prop)
-        for iter in self.getExrules():
-            prop = PyCalendarProperty(definitions.cICalProperty_EXRULE, iter)
-            self.addProperty(prop)
-        for iter in self.mRecurrences.getDates():
-            prop = PyCalendarProperty(definitions.cICalProperty_RDATE, iter)
-            self.addProperty(prop)
-        for iter in self.mRecurrences.getExdates():
-            prop = PyCalendarProperty(definitions.cICalProperty_EXDATE, iter)
-            self.addProperty(prop)
-
-
-    def excludeRecurrence(self, start):
-        # Must have items
-        if self.mRecurrences is None:
-            return
-
-        # Add to recurrence set and clear cache
-        self.mRecurrences.subtract(start)
-
-        # Add property
-        prop = PyCalendarProperty(definitions.cICalProperty_EXDATE, start)
-        self.addProperty(prop)
-
-
-    def excludeFutureRecurrence(self, start):
-        # Must have items
-        if self.mRecurrences is None:
-            return
-
-        # Adjust RRULES to end before start
-        self.mRecurrences.excludeFutureRecurrence(start)
-
-        # Remove existing RRULE &amp; RDATE
-        self.removeProperties(definitions.cICalProperty_RRULE)
-        self.removeProperties(definitions.cICalProperty_RDATE)
-
-        # Now create properties
-        for iter in self.mRecurrences.getRules():
-            prop = PyCalendarProperty(definitions.cICalProperty_RRULE, iter)
-            self.addProperty(prop)
-        for iter in  self.mRecurrences.getDates():
-            prop = PyCalendarProperty(definitions.cICalProperty_RDATE, iter)
-            self.addProperty(prop)
-
-
-    def initFromMaster(self):
-        # Only if not master
-        if self.recurring():
-            # Redo this to get cached values from master
-            self.finalise()
-
-            # If this component does not have its own start property, use the
-            # recurrence id
-            # i.e. the start time of this instance has not changed - something
-            # else has
-            if not self.hasProperty(definitions.cICalProperty_DTSTART):
-                self.mStart = self.mRecurrenceID
-
-            # If this component does not have its own end/duration property,
-            # the determine
-            # the end from the master duration
-            if (not self.hasProperty(definitions.cICalProperty_DTEND) and
-                not self.hasProperty(definitions.cICalProperty_DURATION)):
-                # End is based on original events settings
-                self.mEnd = self.mStart + (self.mMaster.getEnd() - self.mMaster.getStart())
-
-            # If this instance has a duration, but no start of its own, then we
-            # need to readjust the end
-            # to account for the start being changed to the recurrence id
-            elif (self.hasProperty(definitions.cICalProperty_DURATION) and
-                  not self.hasProperty(definitions.cICalProperty_DTSTART)):
-                temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
-                self.mEnd = self.mStart + temp
-
-
-    def createExpanded(self, master, recurid):
-        return PyCalendarComponentExpanded(master, recurid)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarcontainerbasepyfromrev11912PyCalendarbranchesjson2srcpycalendarcontainerbasepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/containerbase.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/containerbase.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/containerbase.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/containerbase.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,257 @@
</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 cStringIO import StringIO
+from pycalendar.componentbase import ComponentBase
+from pycalendar.exceptions import InvalidData, ValidationError
+from pycalendar.parser import ParserContext
+from pycalendar.utils import readFoldedLine
+import json
+
+class ContainerBase(ComponentBase):
+    &quot;&quot;&quot;
+    Represents the top-level component (i.e., VCALENDAR or vCARD)
+    &quot;&quot;&quot;
+
+    sProdID = &quot;-//calendarserver.org//PyCalendar v1//EN&quot;
+    sDomain = &quot;calendarserver.org&quot;
+
+    # These must be set by derived classes
+    sContainerDescriptor = None
+    sComponentType = None
+    sPropertyType = None
+
+    sFormatText = None
+    sFormatJSON = None
+
+    @classmethod
+    def setPRODID(cls, prodid):
+        cls.sProdID = prodid
+
+
+    @classmethod
+    def setDomain(cls, domain):
+        cls.sDomain = domain
+
+
+    def __init__(self, add_defaults=True):
+        super(ContainerBase, self).__init__()
+
+        if add_defaults:
+            self.addDefaultProperties()
+
+
+    def duplicate(self):
+        return super(ContainerBase, self).duplicate()
+
+
+    def getType(self):
+        raise NotImplementedError
+
+
+    def finalise(self):
+        pass
+
+
+    def validate(self, doFix=False, doRaise=False):
+        &quot;&quot;&quot;
+        Validate the data in this component and optionally fix any problems. Return
+        a tuple containing two lists: the first describes problems that were fixed, the
+        second problems that were not fixed. Caller can then decide what to do with unfixed
+        issues.
+        &quot;&quot;&quot;
+
+        # Optional raise behavior
+        fixed, unfixed = super(ContainerBase, self).validate(doFix)
+        if doRaise and unfixed:
+            raise ValidationError(&quot;;&quot;.join(unfixed))
+        return fixed, unfixed
+
+
+    @classmethod
+    def parseData(cls, data, format=None):
+        &quot;&quot;&quot;
+        Parse a source of data that can either be a stream (file like object) or a string. Also,
+        it can be in text or json formats.
+
+        @param data: the data to parse
+        @type data: C{str} or C{File-like}
+        @param format: format (MIME media type) of data.
+        @type format: C{str}
+        &quot;&quot;&quot;
+
+        if format is None or format == cls.sFormatText:
+            return cls.parseTextData(data)
+
+        elif format == cls.sFormatJSON:
+            return cls.parseJSONData(data)
+
+
+    @classmethod
+    def parseText(cls, data):
+        return cls.parseTextData(data)
+
+
+    @classmethod
+    def parseTextData(cls, data):
+        if isinstance(data, str):
+            data = StringIO(data)
+        cal = cls(add_defaults=False)
+        if cal.parse(data):
+            return cal
+        else:
+            return None
+
+
+    def parse(self, ins):
+
+        result = False
+
+        self.setProperties({})
+
+        LOOK_FOR_CONTAINER = 0
+        GET_PROPERTY_OR_COMPONENT = 1
+
+        state = LOOK_FOR_CONTAINER
+
+        # Get lines looking for start of calendar
+        lines = [None, None]
+        comp = self
+        compend = None
+        componentstack = []
+
+        while readFoldedLine(ins, lines):
+
+            line = lines[0]
+
+            if state == LOOK_FOR_CONTAINER:
+
+                # Look for start
+                if line == self.getBeginDelimiter():
+                    # Next state
+                    state = GET_PROPERTY_OR_COMPONENT
+
+                    # Indicate success at this point
+                    result = True
+
+                # Handle blank line
+                elif len(line) == 0:
+                    # Raise if requested, otherwise just ignore
+                    if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
+                        raise InvalidData(&quot;%s data has blank lines&quot; % (self.sContainerDescriptor,))
+
+                # Unrecognized data
+                else:
+                    raise InvalidData(&quot;%s data not recognized&quot; % (self.sContainerDescriptor,), line)
+
+            elif state == GET_PROPERTY_OR_COMPONENT:
+
+                # Parse property or look for start of component
+                if line.startswith(&quot;BEGIN:&quot;) and self.sComponentType is not None:
+
+                    # Push previous details to stack
+                    componentstack.append((comp, compend,))
+
+                    # Start a new component
+                    comp = self.sComponentType.makeComponent(line[6:], comp)
+                    compend = comp.getEndDelimiter()
+
+                # Look for end of object
+                elif line == self.getEndDelimiter():
+
+                    # Finalise the current calendar
+                    self.finalise()
+
+                    # Change state
+                    state = LOOK_FOR_CONTAINER
+
+                # Look for end of current component
+                elif line == compend:
+
+                    # Finalise the component (this caches data from the properties)
+                    comp.finalise()
+
+                    # Embed component in parent and reset to use parent
+                    componentstack[-1][0].addComponent(comp)
+                    comp, compend = componentstack.pop()
+
+                # Blank line
+                elif len(line) == 0:
+                    # Raise if requested, otherwise just ignore
+                    if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
+                        raise InvalidData(&quot;%s data has blank lines&quot; % (self.sContainerDescriptor,))
+
+                # Must be a property
+                else:
+
+                    # Parse parameter/value for top-level calendar item
+                    prop = self.sPropertyType.parseText(line)
+
+                    # Check for valid property
+                    if comp is self:
+                        if not comp.validProperty(prop):
+                            raise InvalidData(&quot;Invalid property&quot;, str(prop))
+                        else:
+                            comp.addProperty(prop)
+                    else:
+                        comp.addProperty(prop)
+
+        # Check for truncated data
+        if state != LOOK_FOR_CONTAINER:
+            raise InvalidData(&quot;%s data not complete&quot; % (self.sContainerDescriptor,))
+
+        # Validate some things
+        if result and not self.hasProperty(&quot;VERSION&quot;):
+            raise InvalidData(&quot;%s missing VERSION&quot; % (self.sContainerDescriptor,))
+
+        return result
+
+
+    @classmethod
+    def parseJSONData(cls, data):
+        if not isinstance(data, str):
+            data = data.read()
+        try:
+            jobject = json.loads(data)
+        except ValueError, e:
+            raise InvalidData(e, data)
+        return cls.parseJSON(jobject, None, cls(add_defaults=False))
+
+
+    def getText(self, format=None):
+
+        if format is None or format == self.sFormatText:
+            s = StringIO()
+            self.generate(s)
+            return s.getvalue()
+        elif format == self.sFormatJSON:
+            return self.getTextJSON()
+        else:
+            return None
+
+
+    def getTextJSON(self):
+        jobject = []
+        self.writeJSON(jobject)
+        return json.dumps(jobject[0], indent=2, separators=(',', ':'))
+
+
+    def addDefaultProperties(self):
+        raise NotImplementedError
+
+
+    def validProperty(self, prop):
+        raise NotImplementedError
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendardatetimepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/datetime.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/datetime.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/datetime.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,18 +14,17 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar import definitions
-from pycalendar import locale
</del><ins>+from pycalendar import locale, xmldefinitions, xmlutils
</ins><span class="cx"> from pycalendar import utils
</span><del>-from pycalendar import xmldefs
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.duration import Duration
+from pycalendar.icalendar import definitions
+from pycalendar.timezone import Timezone
</ins><span class="cx"> from pycalendar.valueutils import ValueMixin
</span><span class="cx"> import cStringIO as StringIO
</span><span class="cx"> import time
</span><span class="cx"> import xml.etree.cElementTree as XML
</span><span class="cx"> 
</span><del>-class PyCalendarDateTime(ValueMixin):
</del><ins>+class DateTime(ValueMixin):
</ins><span class="cx"> 
</span><span class="cx">     SUNDAY = 0
</span><span class="cx">     MONDAY = 1
</span><span class="lines">@@ -83,7 +82,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def duplicate(self):
</span><del>-        other = PyCalendarDateTime(self.mYear, self.mMonth, self.mDay, self.mHours, self.mMinutes, self.mSeconds)
</del><ins>+        other = DateTime(self.mYear, self.mMonth, self.mDay, self.mHours, self.mMinutes, self.mSeconds)
</ins><span class="cx"> 
</span><span class="cx">         other.mDateOnly = self.mDateOnly
</span><span class="cx"> 
</span><span class="lines">@@ -104,7 +103,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __repr__(self):
</span><del>-        return &quot;PyCalendarDateTime: %s&quot; % (self.getText(),)
</del><ins>+        return &quot;DateTime: %s&quot; % (self.getText(),)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __hash__(self):
</span><span class="lines">@@ -122,7 +121,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __sub__(self, dateorduration):
</span><span class="cx"> 
</span><del>-        if isinstance(dateorduration, PyCalendarDateTime):
</del><ins>+        if isinstance(dateorduration, DateTime):
</ins><span class="cx"> 
</span><span class="cx">             date = dateorduration
</span><span class="cx"> 
</span><span class="lines">@@ -151,9 +150,9 @@
</span><span class="cx">             else:
</span><span class="cx">                 # Do diff of date-time in seconds
</span><span class="cx">                 diff = self.getPosixTime() - date.getPosixTime()
</span><del>-                return PyCalendarDuration(duration=diff)
</del><ins>+                return Duration(duration=diff)
</ins><span class="cx"> 
</span><del>-        elif isinstance(dateorduration, PyCalendarDuration):
</del><ins>+        elif isinstance(dateorduration, Duration):
</ins><span class="cx"> 
</span><span class="cx">             duration = dateorduration
</span><span class="cx">             result = self.duplicate()
</span><span class="lines">@@ -216,7 +215,7 @@
</span><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><del>-        elif (PyCalendarTimezone.same(self.mTZUTC, self.mTZID, comp.mTZUTC, comp.mTZID)):
</del><ins>+        elif (Timezone.same(self.mTZUTC, self.mTZID, comp.mTZUTC, comp.mTZID)):
</ins><span class="cx">             if self.mYear == comp.mYear:
</span><span class="cx">                 if self.mMonth == comp.mMonth:
</span><span class="cx">                     if self.mDay == comp.mDay:
</span><span class="lines">@@ -301,6 +300,14 @@
</span><span class="cx">         self.changed()
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def setYYMMDD(self, year, month, days):
+        if (self.mYear != year) or (self.mMonth != month) or (self.mDay != days):
+            self.mYear = year
+            self.mMonth = month
+            self.mDay = days
+            self.changed()
+
+
</ins><span class="cx">     def getYear(self):
</span><span class="cx">         return self.mYear
</span><span class="cx"> 
</span><span class="lines">@@ -426,14 +433,14 @@
</span><span class="cx">             return
</span><span class="cx"> 
</span><span class="cx">         # What day does the current year start on, and diff that with the current day
</span><del>-        temp = PyCalendarDateTime(year=self.mYear, month=1, day=1)
</del><ins>+        temp = DateTime(year=self.mYear, month=1, day=1)
</ins><span class="cx">         first_day = temp.getDayOfWeek()
</span><span class="cx">         current_day = self.getDayOfWeek()
</span><span class="cx"> 
</span><span class="cx">         # Calculate and set yearday for start of week. The first week is the one that contains at least
</span><span class="cx">         # four days (with week start defaulting to MONDAY), so that means the 1st of January would fall
</span><span class="cx">         # on MO, TU, WE, TH.
</span><del>-        if first_day in (PyCalendarDateTime.MONDAY, PyCalendarDateTime.TUESDAY, PyCalendarDateTime.WEDNESDAY, PyCalendarDateTime.THURSDAY):
</del><ins>+        if first_day in (DateTime.MONDAY, DateTime.TUESDAY, DateTime.WEDNESDAY, DateTime.THURSDAY):
</ins><span class="cx">             year_day = (weekno - 1) * 7 + current_day - first_day
</span><span class="cx">         else:
</span><span class="cx">             year_day = weekno * 7 + current_day - first_day
</span><span class="lines">@@ -453,7 +460,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # What day does the current year start on
</span><del>-        temp = PyCalendarDateTime(year=self.mYear, month=1, day=1)
</del><ins>+        temp = DateTime(year=self.mYear, month=1, day=1)
</ins><span class="cx">         first_day = temp.getDayOfWeek()
</span><span class="cx">         if first_day == 0:
</span><span class="cx">             first_day = 7
</span><span class="lines">@@ -467,13 +474,13 @@
</span><span class="cx">         # Might need to adjust forward/backwards based on year boundaries
</span><span class="cx">         if week_no == 0:
</span><span class="cx">             # Last week of previous year
</span><del>-            temp = PyCalendarDateTime(year=self.mYear - 1, month=12, day=31)
</del><ins>+            temp = DateTime(year=self.mYear - 1, month=12, day=31)
</ins><span class="cx">             week_no = temp.getWeekNo()
</span><span class="cx">         elif week_no == 53:
</span><span class="cx">             # Might be first week of next year
</span><del>-            temp = PyCalendarDateTime(year=self.mYear + 1, month=1, day=1)
</del><ins>+            temp = DateTime(year=self.mYear + 1, month=1, day=1)
</ins><span class="cx">             first_day = temp.getDayOfWeek()
</span><del>-            if first_day in (PyCalendarDateTime.MONDAY, PyCalendarDateTime.TUESDAY, PyCalendarDateTime.WEDNESDAY, PyCalendarDateTime.THURSDAY):
</del><ins>+            if first_day in (DateTime.MONDAY, DateTime.TUESDAY, DateTime.WEDNESDAY, DateTime.THURSDAY):
</ins><span class="cx">                 week_no = 1
</span><span class="cx"> 
</span><span class="cx">         return week_no
</span><span class="lines">@@ -579,7 +586,7 @@
</span><span class="cx"> 
</span><span class="cx">     def getDayOfWeek(self):
</span><span class="cx">         # Count days since 01-Jan-1970 which was a Thursday
</span><del>-        result = PyCalendarDateTime.THURSDAY + self.daysSince1970()
</del><ins>+        result = DateTime.THURSDAY + self.daysSince1970()
</ins><span class="cx">         result %= 7
</span><span class="cx">         if result &lt; 0:
</span><span class="cx">             result += 7
</span><span class="lines">@@ -686,7 +693,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getTimezone(self):
</span><del>-        return PyCalendarTimezone(utc=self.mTZUTC, tzid=self.mTZID)
</del><ins>+        return Timezone(utc=self.mTZUTC, tzid=self.mTZID)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def setTimezone(self, tzid):
</span><span class="lines">@@ -711,7 +718,7 @@
</span><span class="cx">             # Cache and restore and adjust the posix value to avoid a recalc since it won't change during this adjust
</span><span class="cx">             tempPosix = self.mPosixTime if self.mPosixTimeCached else None
</span><span class="cx"> 
</span><del>-            utc = PyCalendarTimezone(utc=True)
</del><ins>+            utc = Timezone(utc=True)
</ins><span class="cx"> 
</span><span class="cx">             offset_from = self.timeZoneSecondsOffset()
</span><span class="cx">             self.setTimezone(utc)
</span><span class="lines">@@ -735,7 +742,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def setToday(self):
</span><del>-        tz = PyCalendarTimezone(utc=self.mTZUTC, tzid=self.mTZID)
</del><ins>+        tz = Timezone(utc=self.mTZUTC, tzid=self.mTZID)
</ins><span class="cx">         self.copy_ICalendarDateTime(self.getToday(tz))
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -745,24 +752,24 @@
</span><span class="cx">         now = time.time()
</span><span class="cx">         now_tm = time.localtime(now)
</span><span class="cx"> 
</span><del>-        temp = PyCalendarDateTime(year=now_tm.tm_year, month=now_tm.tm_mon, day=now_tm.tm_mday, tzid=tzid)
</del><ins>+        temp = DateTime(year=now_tm.tm_year, month=now_tm.tm_mon, day=now_tm.tm_mday, tzid=tzid)
</ins><span class="cx">         return temp
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def setNow(self):
</span><del>-        tz = PyCalendarTimezone(utc=self.mTZUTC, tzid=self.mTZID)
</del><ins>+        tz = Timezone(utc=self.mTZUTC, tzid=self.mTZID)
</ins><span class="cx">         self.copy_ICalendarDateTime(self.getNow(tz))
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="cx">     def getNow(tzid):
</span><del>-        utc = PyCalendarDateTime.getNowUTC()
-        utc.adjustTimezone(tzid if tzid is not None else PyCalendarTimezone())
</del><ins>+        utc = DateTime.getNowUTC()
+        utc.adjustTimezone(tzid if tzid is not None else Timezone())
</ins><span class="cx">         return utc
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def setNowUTC(self):
</span><del>-        self.copy_PyCalendarDateTime(self.getNowUTC())
</del><ins>+        self.copy_DateTime(self.getNowUTC())
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="lines">@@ -770,9 +777,9 @@
</span><span class="cx">         # Get from posix time
</span><span class="cx">         now = time.time()
</span><span class="cx">         now_tm = time.gmtime(now)
</span><del>-        tzid = PyCalendarTimezone(utc=True)
</del><ins>+        tzid = Timezone(utc=True)
</ins><span class="cx"> 
</span><del>-        return PyCalendarDateTime(year=now_tm.tm_year, month=now_tm.tm_mon, day=now_tm.tm_mday, hours=now_tm.tm_hour, minutes=now_tm.tm_min, seconds=now_tm.tm_sec, tzid=tzid)
</del><ins>+        return DateTime(year=now_tm.tm_year, month=now_tm.tm_mon, day=now_tm.tm_mday, hours=now_tm.tm_hour, minutes=now_tm.tm_min, seconds=now_tm.tm_sec, tzid=tzid)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def recur(self, freq, interval):
</span><span class="lines">@@ -809,7 +816,7 @@
</span><span class="cx"> 
</span><span class="cx">         buf = StringIO.StringIO()
</span><span class="cx"> 
</span><del>-        if locale == PyCalendarDateTime.FULLDATE:
</del><ins>+        if locale == 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">@@ -817,7 +824,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 == PyCalendarDateTime.ABBREVDATE:
</del><ins>+        elif locale == 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">@@ -825,25 +832,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 == PyCalendarDateTime.NUMERICDATE:
</del><ins>+        elif locale == 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 == PyCalendarDateTime.FULLDATENOYEAR:
</del><ins>+        elif locale == 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 == PyCalendarDateTime.ABBREVDATENOYEAR:
</del><ins>+        elif locale == 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 == PyCalendarDateTime.NUMERICDATENOYEAR:
</del><ins>+        elif locale == 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 class="lines">@@ -935,6 +942,7 @@
</span><span class="cx">             else:
</span><span class="cx">                 return &quot;%04d-%02d-%02dT%02d:%02d:%02d&quot; % (self.mYear, self.mMonth, self.mDay, self.mHours, self.mMinutes, self.mSeconds)
</span><span class="cx"> 
</span><ins>+    getJSONText = getXMLText
</ins><span class="cx"> 
</span><span class="cx">     @classmethod
</span><span class="cx">     def parseText(cls, data, fullISO=False):
</span><span class="lines">@@ -1031,7 +1039,7 @@
</span><span class="cx"> 
</span><span class="cx">         # iCalendar:
</span><span class="cx">         #   parse format YYYYMMDD[THHMMSS[Z]]
</span><del>-        # vCard (fullISO)
</del><ins>+        # vCard (fullISO), jCal
</ins><span class="cx">         #   parse format YYYY[-]MM[-]DD[THH[:]MM[:]SS[(Z/(+/-)HHMM]]
</span><span class="cx"> 
</span><span class="cx">         try:
</span><span class="lines">@@ -1086,13 +1094,21 @@
</span><span class="cx">     def writeXML(self, node, namespace):
</span><span class="cx">         value = XML.SubElement(
</span><span class="cx">             node,
</span><del>-            xmldefs.makeTag(
</del><ins>+            xmlutils.makeTag(
</ins><span class="cx">                 namespace,
</span><del>-                xmldefs.value_date if self.isDateOnly() else xmldefs.value_date_time
</del><ins>+                xmldefinitions.value_date if self.isDateOnly() else xmldefinitions.value_date_time
</ins><span class="cx">         ))
</span><span class="cx">         value.text = self.getXMLText()
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def parseJSON(self, jobject):
+        self.parse(str(jobject), True)
+
+
+    def writeJSON(self, jobject):
+        jobject.append(self.getJSONText())
+
+
</ins><span class="cx">     def normalise(self):
</span><span class="cx">         # Normalise seconds
</span><span class="cx">         normalised_secs = self.mSeconds % 60
</span><span class="lines">@@ -1160,13 +1176,13 @@
</span><span class="cx">         if self.mTZUTC:
</span><span class="cx">             return 0
</span><span class="cx">         if self.mTZOffset is None:
</span><del>-            tz = PyCalendarTimezone(utc=self.mTZUTC, tzid=self.mTZID)
</del><ins>+            tz = Timezone(utc=self.mTZUTC, tzid=self.mTZID)
</ins><span class="cx">             self.mTZOffset = tz.timeZoneSecondsOffset(self)
</span><span class="cx">         return self.mTZOffset
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def timeZoneDescriptor(self):
</span><del>-        tz = PyCalendarTimezone(utc=self.mTZUTC, tzid=self.mTZID)
</del><ins>+        tz = Timezone(utc=self.mTZUTC, tzid=self.mTZID)
</ins><span class="cx">         return tz.timeZoneDescriptor(self)
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendardatetimevaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/datetimevalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/datetimevalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/datetimevalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,42 +14,26 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar import xmldefs
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.datetime import DateTime
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
</ins><span class="cx"> 
</span><del>-class PyCalendarDateTimeValue(PyCalendarValue):
</del><ins>+class DateTimeValue(WrapperValue, Value):
</ins><span class="cx"> 
</span><del>-    def __init__(self, value=None):
-        self.mValue = value if value is not None else PyCalendarDateTime()
</del><ins>+    _wrappedClass = DateTime
+    _wrappedType = None # Depends on actual value
</ins><span class="cx"> 
</span><del>-
-    def duplicate(self):
-        return PyCalendarDateTimeValue(self.mValue.duplicate())
-
-
</del><span class="cx">     def getType(self):
</span><del>-        return  (PyCalendarValue.VALUETYPE_DATETIME, PyCalendarValue.VALUETYPE_DATE)[self.mValue.isDateOnly()]
</del><ins>+        return  (Value.VALUETYPE_DATETIME, Value.VALUETYPE_DATE)[self.mValue.isDateOnly()]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def parse(self, data, fullISO=False):
-        self.mValue.parse(data, fullISO)
</del><ins>+    def parse(self, data, variant):
+        self.mValue.parse(data, fullISO=(variant == &quot;vcard&quot;))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def generate(self, os):
-        self.mValue.generate(os)
-
-
</del><span class="cx">     def writeXML(self, node, namespace):
</span><span class="cx">         self.mValue.writeXML(node, namespace)
</span><span class="cx"> 
</span><del>-
-    def getValue(self):
-        return self.mValue
-
-
-    def setValue(self, value):
-        self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_DATE, PyCalendarDateTimeValue, xmldefs.value_date)
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_DATETIME, PyCalendarDateTimeValue, xmldefs.value_date_time)
</del><ins>+Value.registerType(Value.VALUETYPE_DATE, DateTimeValue, xmldefinitions.value_date)
+Value.registerType(Value.VALUETYPE_DATETIME, DateTimeValue, xmldefinitions.value_date_time)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendardefinitionspy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/definitions.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/definitions.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/definitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,349 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.
-##
-
-#     5545 Components
-
-cICalComponent_VCALENDAR = &quot;VCALENDAR&quot;
-cICalComponent_VEVENT = &quot;VEVENT&quot;
-cICalComponent_VTODO = &quot;VTODO&quot;
-cICalComponent_VJOURNAL = &quot;VJOURNAL&quot;
-cICalComponent_VFREEBUSY = &quot;VFREEBUSY&quot;
-cICalComponent_VTIMEZONE = &quot;VTIMEZONE&quot;
-cICalComponent_VALARM = &quot;VALARM&quot;
-cICalComponent_STANDARD = &quot;STANDARD&quot;
-cICalComponent_DAYLIGHT = &quot;DAYLIGHT&quot;
-
-#     5545 Calendar Property Attributes
-
-#     5545 Section 3.2
-cICalAttribute_ALTREP = &quot;ALTREP&quot;
-cICalAttribute_CN = &quot;CN&quot;
-cICalAttribute_CUTYPE = &quot;CUTYPE&quot;
-cICalAttribute_DELEGATED_FROM = &quot;DELEGATED-FROM&quot;
-cICalAttribute_DELEGATED_TO = &quot;DELEGATED-TO&quot;
-cICalAttribute_DIR = &quot;DIR&quot;
-cICalAttribute_ENCODING = &quot;ENCODING&quot;
-cICalAttribute_FMTTYPE = &quot;FMTTYPE&quot;
-cICalAttribute_FBTYPE = &quot;FBTYPE&quot;
-cICalAttribute_LANGUAGE = &quot;LANGUAGE&quot;
-cICalAttribute_MEMBER = &quot;MEMBER&quot;
-cICalAttribute_PARTSTAT = &quot;PARTSTAT&quot;
-cICalAttribute_RANGE = &quot;RANGE&quot;
-cICalAttribute_RELATED = &quot;RELATED&quot;
-cICalAttribute_RELTYPE = &quot;RELTYPE&quot;
-cICalAttribute_ROLE = &quot;ROLE&quot;
-cICalAttribute_RSVP = &quot;RSVP&quot;
-cICalAttribute_RSVP_TRUE = &quot;TRUE&quot;
-cICalAttribute_RSVP_FALSE = &quot;FALSE&quot;
-cICalAttribute_SENT_BY = &quot;SENT-BY&quot;
-cICalAttribute_TZID = &quot;TZID&quot;
-cICalAttribute_VALUE = &quot;VALUE&quot;
-
-#     5545 Section 3.2.9
-cICalAttribute_FBTYPE_FREE = &quot;FREE&quot;
-cICalAttribute_FBTYPE_BUSY = &quot;BUSY&quot;
-cICalAttribute_FBTYPE_BUSYUNAVAILABLE = &quot;BUSY-UNAVAILABLE&quot;
-cICalAttribute_FBTYPE_BUSYTENTATIVE = &quot;BUSY-TENTATIVE&quot;
-
-#     5545 Section 3.2.12
-ePartStat_NeedsAction = 0
-ePartStat_Accepted = 1
-ePartStat_Declined = 2
-ePartStat_Tentative = 3
-ePartStat_Delegated = 4
-ePartStat_Completed = 5
-ePartStat_InProcess = 6
-
-cICalAttribute_PARTSTAT_NEEDSACTION = &quot;NEEDS-ACTION&quot;
-cICalAttribute_PARTSTAT_ACCEPTED = &quot;ACCEPTED&quot;
-cICalAttribute_PARTSTAT_DECLINED = &quot;DECLINED&quot;
-cICalAttribute_PARTSTAT_TENTATIVE = &quot;TENTATIVE&quot;
-cICalAttribute_PARTSTAT_DELEGATED = &quot;DELEGATED&quot;
-cICalAttribute_PARTSTAT_COMPLETED = &quot;COMPLETE&quot;
-cICalAttribute_PARTSTAT_INPROCESS = &quot;IN-PROCESS&quot;
-
-#     5545 Section 3.2.13
-cICalAttribute_RANGE_THISANDFUTURE = &quot;THISANDFUTURE&quot;
-cICalAttribute_RANGE_THISANDPRIOR = &quot;THISANDPRIOR&quot;      # 2445 only
-
-#     5545 Section 3.2.14
-cICalAttribute_RELATED_START = &quot;START&quot;
-cICalAttribute_RELATED_END = &quot;END&quot;
-
-#     5545 Section 3.2.16
-ePartRole_Chair = 0
-ePartRole_Required = 1
-ePartRole_Optional = 2
-ePartRole_Non = 3
-
-cICalAttribute_ROLE_CHAIR = &quot;CHAIR&quot;
-cICalAttribute_ROLE_REQ_PART = &quot;REQ-PARTICIPANT&quot;
-cICalAttribute_ROLE_OPT_PART = &quot;OPT-PARTICIPANT&quot;
-cICalAttribute_ROLE_NON_PART = &quot;NON-PARTICIPANT&quot;
-
-#     5545 Section 3.2.3
-eCutype_Individual = 0
-eCutype_Group = 1
-eCutype_Resource = 2
-eCutype_Room = 3
-eCutype_Unknown = 4
-
-cICalAttribute_CUTYPE_INDIVIDUAL = &quot;INDIVIDUAL&quot;
-cICalAttribute_CUTYPE_GROUP = &quot;GROUP&quot;
-cICalAttribute_CUTYPE_RESOURCE = &quot;RESOURCE&quot;
-cICalAttribute_CUTYPE_ROOM = &quot;ROOM&quot;
-cICalAttribute_CUTYPE_UNKNOWN = &quot;UNKNOWN&quot;
-
-#     5545 Value types
-
-#     5545 Section 3.3
-cICalValue_BINARY = &quot;BINARY&quot;
-cICalValue_BOOLEAN = &quot;BOOLEAN&quot;
-cICalValue_CAL_ADDRESS = &quot;CAL-ADDRESS&quot;
-cICalValue_DATE = &quot;DATE&quot;
-cICalValue_DATE_TIME = &quot;DATE-TIME&quot;
-cICalValue_DURATION = &quot;DURATION&quot;
-cICalValue_FLOAT = &quot;FLOAT&quot;
-cICalValue_INTEGER = &quot;INTEGER&quot;
-cICalValue_PERIOD = &quot;PERIOD&quot;
-cICalValue_RECUR = &quot;RECUR&quot;
-cICalValue_TEXT = &quot;TEXT&quot;
-cICalValue_TIME = &quot;TIME&quot;
-cICalValue_URI = &quot;URI&quot;
-cICalValue_UTC_OFFSET = &quot;UTC-OFFSET&quot;
-
-#     5545 Calendar Properties
-
-#     5545 Section  3.7
-
-cICalProperty_CALSCALE = &quot;CALSCALE&quot;
-cICalProperty_METHOD = &quot;METHOD&quot;
-cICalProperty_PRODID = &quot;PRODID&quot;
-cICalProperty_VERSION = &quot;VERSION&quot;
-
-#     Apple Extensions
-cICalProperty_XWRCALNAME = &quot;X-WR-CALNAME&quot;
-cICalProperty_XWRCALDESC = &quot;X-WR-CALDESC&quot;
-cICalProperty_XWRALARMUID = &quot;X-WR-ALARMUID&quot;
-
-#     5545 Component Property names
-
-#     5545 Section 3.8.1
-cICalProperty_ATTACH = &quot;ATTACH&quot;
-cICalProperty_CATEGORIES = &quot;CATEGORIES&quot;
-cICalProperty_CLASS = &quot;CLASS&quot;
-cICalProperty_COMMENT = &quot;COMMENT&quot;
-cICalProperty_DESCRIPTION = &quot;DESCRIPTION&quot;
-cICalProperty_GEO = &quot;GEO&quot;
-cICalProperty_LOCATION = &quot;LOCATION&quot;
-cICalProperty_PERCENT_COMPLETE = &quot;PERCENT-COMPLETE&quot;
-cICalProperty_PRIORITY = &quot;PRIORITY&quot;
-cICalProperty_RESOURCES = &quot;RESOURCES&quot;
-cICalProperty_STATUS = &quot;STATUS&quot;
-cICalProperty_SUMMARY = &quot;SUMMARY&quot;
-
-#     5545 Section 3.8.2
-cICalProperty_COMPLETED = &quot;COMPLETED&quot;
-cICalProperty_DTEND = &quot;DTEND&quot;
-cICalProperty_DUE = &quot;DUE&quot;
-cICalProperty_DTSTART = &quot;DTSTART&quot;
-cICalProperty_DURATION = &quot;DURATION&quot;
-cICalProperty_FREEBUSY = &quot;FREEBUSY&quot;
-cICalProperty_TRANSP = &quot;TRANSP&quot;
-cICalProperty_OPAQUE = &quot;OPAQUE&quot;
-cICalProperty_TRANSPARENT = &quot;TRANSPARENT&quot;
-
-#     5545 Section 3.8.3
-cICalProperty_TZID = &quot;TZID&quot;
-cICalProperty_TZNAME = &quot;TZNAME&quot;
-cICalProperty_TZOFFSETFROM = &quot;TZOFFSETFROM&quot;
-cICalProperty_TZOFFSETTO = &quot;TZOFFSETTO&quot;
-cICalProperty_TZURL = &quot;TZURL&quot;
-
-#     5545 Section 3.8.4
-cICalProperty_ATTENDEE = &quot;ATTENDEE&quot;
-cICalProperty_CONTACT = &quot;CONTACT&quot;
-cICalProperty_ORGANIZER = &quot;ORGANIZER&quot;
-cICalProperty_RECURRENCE_ID = &quot;RECURRENCE-ID&quot;
-cICalProperty_RELATED_TO = &quot;RELATED-TO&quot;
-cICalProperty_URL = &quot;URL&quot;
-cICalProperty_UID = &quot;UID&quot;
-
-#     5545 Section 3.8.5
-cICalProperty_EXDATE = &quot;EXDATE&quot;
-cICalProperty_EXRULE = &quot;EXRULE&quot;     # 2445 only
-cICalProperty_RDATE = &quot;RDATE&quot;
-cICalProperty_RRULE = &quot;RRULE&quot;
-
-#     5545 Section 3.8.6
-cICalProperty_ACTION = &quot;ACTION&quot;
-cICalProperty_REPEAT = &quot;REPEAT&quot;
-cICalProperty_TRIGGER = &quot;TRIGGER&quot;
-
-#     5545 Section 3.8.7
-cICalProperty_CREATED = &quot;CREATED&quot;
-cICalProperty_DTSTAMP = &quot;DTSTAMP&quot;
-cICalProperty_LAST_MODIFIED = &quot;LAST-MODIFIED&quot;
-cICalProperty_SEQUENCE = &quot;SEQUENCE&quot;
-
-#     5545 Section 3.8.8.3
-cICalProperty_REQUEST_STATUS = &quot;REQUEST-STATUS&quot;
-
-#     Enums
-#     Use ascending order for sensible sorting
-
-#     5545 Section 3.3.10
-
-eRecurrence_SECONDLY = 0
-eRecurrence_MINUTELY = 1
-eRecurrence_HOURLY = 2
-eRecurrence_DAILY = 3
-eRecurrence_WEEKLY = 4
-eRecurrence_MONTHLY = 5
-eRecurrence_YEARLY = 6
-
-eRecurrence_FREQ = 0
-eRecurrence_UNTIL = 1
-eRecurrence_COUNT = 2
-eRecurrence_INTERVAL = 3
-eRecurrence_BYSECOND = 4
-eRecurrence_BYMINUTE = 5
-eRecurrence_BYHOUR = 6
-eRecurrence_BYDAY = 7
-eRecurrence_BYMONTHDAY = 8
-eRecurrence_BYYEARDAY = 9
-eRecurrence_BYWEEKNO = 10
-eRecurrence_BYMONTH = 11
-eRecurrence_BYSETPOS = 12
-eRecurrence_WKST = 13
-
-cICalValue_RECUR_FREQ = &quot;FREQ&quot;
-cICalValue_RECUR_FREQ_LEN = 5
-
-cICalValue_RECUR_SECONDLY = &quot;SECONDLY&quot;
-cICalValue_RECUR_MINUTELY = &quot;MINUTELY&quot;
-cICalValue_RECUR_HOURLY = &quot;HOURLY&quot;
-cICalValue_RECUR_DAILY = &quot;DAILY&quot;
-cICalValue_RECUR_WEEKLY = &quot;WEEKLY&quot;
-cICalValue_RECUR_MONTHLY = &quot;MONTHLY&quot;
-cICalValue_RECUR_YEARLY = &quot;YEARLY&quot;
-
-cICalValue_RECUR_UNTIL = &quot;UNTIL&quot;
-cICalValue_RECUR_COUNT = &quot;COUNT&quot;
-
-cICalValue_RECUR_INTERVAL = &quot;INTERVAL&quot;
-cICalValue_RECUR_BYSECOND = &quot;BYSECOND&quot;
-cICalValue_RECUR_BYMINUTE = &quot;BYMINUTE&quot;
-cICalValue_RECUR_BYHOUR = &quot;BYHOUR&quot;
-cICalValue_RECUR_BYDAY = &quot;BYDAY&quot;
-cICalValue_RECUR_BYMONTHDAY = &quot;BYMONTHDAY&quot;
-cICalValue_RECUR_BYYEARDAY = &quot;BYYEARDAY&quot;
-cICalValue_RECUR_BYWEEKNO = &quot;BYWEEKNO&quot;
-cICalValue_RECUR_BYMONTH = &quot;BYMONTH&quot;
-cICalValue_RECUR_BYSETPOS = &quot;BYSETPOS&quot;
-cICalValue_RECUR_WKST = &quot;WKST&quot;
-
-eRecurrence_WEEKDAY_SU = 0
-eRecurrence_WEEKDAY_MO = 1
-eRecurrence_WEEKDAY_TU = 2
-eRecurrence_WEEKDAY_WE = 3
-eRecurrence_WEEKDAY_TH = 4
-eRecurrence_WEEKDAY_FR = 5
-eRecurrence_WEEKDAY_SA = 6
-
-cICalValue_RECUR_WEEKDAY_SU = &quot;SU&quot;
-cICalValue_RECUR_WEEKDAY_MO = &quot;MO&quot;
-cICalValue_RECUR_WEEKDAY_TU = &quot;TU&quot;
-cICalValue_RECUR_WEEKDAY_WE = &quot;WE&quot;
-cICalValue_RECUR_WEEKDAY_TH = &quot;TH&quot;
-cICalValue_RECUR_WEEKDAY_FR = &quot;FR&quot;
-cICalValue_RECUR_WEEKDAY_SA = &quot;SA&quot;
-
-#     5545 Section 3.8.1.11
-eStatus_VEvent_None = 0
-eStatus_VEvent_Confirmed = 1
-eStatus_VEvent_Tentative = 2
-eStatus_VEvent_Cancelled = 3
-
-eStatus_VToDo_None = 0
-eStatus_VToDo_NeedsAction = 1
-eStatus_VToDo_InProcess = 2
-eStatus_VToDo_Completed = 3
-eStatus_VToDo_Cancelled = 4
-
-eStatus_VJournal_None = 0
-eStatus_VJournal_Final = 1
-eStatus_VJournal_Draft = 2
-eStatus_VJournal_Cancelled = 3
-
-cICalProperty_STATUS_TENTATIVE = &quot;TENTATIVE&quot;
-cICalProperty_STATUS_CONFIRMED = &quot;CONFIRMED&quot;
-cICalProperty_STATUS_CANCELLED = &quot;CANCELLED&quot;
-cICalProperty_STATUS_NEEDS_ACTION = &quot;NEEDS-ACTION&quot;
-cICalProperty_STATUS_COMPLETED = &quot;COMPLETED&quot;
-cICalProperty_STATUS_IN_PROCESS = &quot;IN-PROCESS&quot;
-cICalProperty_STATUS_DRAFT = &quot;DRAFT&quot;
-cICalProperty_STATUS_FINAL = &quot;FINAL&quot;
-
-#     5545 Section 3.8.6.1
-eAction_VAlarm_Audio = 0
-eAction_VAlarm_Display = 1
-eAction_VAlarm_Email = 2
-eAction_VAlarm_Procedure = 3
-eAction_VAlarm_Unknown = 4
-
-cICalProperty_ACTION_AUDIO = &quot;AUDIO&quot;
-cICalProperty_ACTION_DISPLAY = &quot;DISPLAY&quot;
-cICalProperty_ACTION_EMAIL = &quot;EMAIL&quot;
-cICalProperty_ACTION_PROCEDURE = &quot;PROCEDURE&quot;
-
-#     Extensions: draft-daboo-calendar-availability-02
-
-#     Section 3.1
-cICalComponent_VAVAILABILITY = &quot;VAVAILABILITY&quot;
-cICalComponent_AVAILABLE = &quot;AVAILABLE&quot;
-
-#     Section 3.2
-cICalProperty_BUSYTYPE = &quot;BUSYTYPE&quot;
-
-#     Extensions: draft-daboo-valarm-extensions-03
-
-#     Section 5
-eAction_VAlarm_URI = 5
-cICalProperty_ACTION_URI = &quot;URI&quot;
-
-#     Section 7.1
-cICalProperty_ACKNOWLEDGED = &quot;ACKNOWLEDGED&quot;
-
-eAction_VAlarm_None = 6
-cICalProperty_ACTION_NONE = &quot;NONE&quot;
-
-#     Mulberry extensions
-cICalProperty_ACTION_X_SPEAKTEXT = &quot;X-MULBERRY-SPEAK-TEXT&quot;
-cICalProperty_ALARM_X_LASTTRIGGER = &quot;X-MULBERRY-LAST-TRIGGER&quot;
-
-cICalProperty_ALARM_X_ALARMSTATUS = &quot;X-MULBERRY-ALARM-STATUS&quot;
-
-eAlarm_Status_Pending = 0
-eAlarm_Status_Completed = 1
-eAlarm_Status_Disabled = 2
-
-cICalProperty_ALARM_X_ALARMSTATUS_PENDING = &quot;PENDING&quot;
-cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED = &quot;COMPLETED&quot;
-cICalProperty_ALARM_X_ALARMSTATUS_DISABLED = &quot;DISABLED&quot;
-
-cICalAttribute_ORGANIZER_X_IDENTITY = &quot;X-MULBERRY-IDENTITY&quot;
-cICalAttribute_ATTENDEE_X_NEEDS_ITIP = &quot;X-MULBERRY-NEEDS-ITIP&quot;
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendardurationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/duration.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/duration.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/duration.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -18,7 +18,7 @@
</span><span class="cx"> from pycalendar.stringutils import strtoul
</span><span class="cx"> from pycalendar.valueutils import ValueMixin
</span><span class="cx"> 
</span><del>-class PyCalendarDuration(ValueMixin):
</del><ins>+class Duration(ValueMixin):
</ins><span class="cx"> 
</span><span class="cx">     def __init__(self, duration=None, weeks=0, days=0, hours=0, minutes=0, seconds=0):
</span><span class="cx">         self.mForward = True
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def duplicate(self):
</span><del>-        other = PyCalendarDuration(None)
</del><ins>+        other = Duration(None)
</ins><span class="cx">         other.mForward = self.mForward
</span><span class="cx"> 
</span><span class="cx">         other.mWeeks = self.mWeeks
</span><span class="lines">@@ -270,3 +270,11 @@
</span><span class="cx"> 
</span><span class="cx">     def writeXML(self, node, namespace):
</span><span class="cx">         node.text = self.getText()
</span><ins>+
+
+    def parseJSON(self, jobject):
+        self.parse(str(jobject))
+
+
+    def writeJSON(self, jobject):
+        jobject.append(self.getText())
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendardurationvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/durationvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/durationvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/durationvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,42 +14,14 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar import xmldefs
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.duration import Duration
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
</ins><span class="cx"> 
</span><del>-class PyCalendarDurationValue(PyCalendarValue):
</del><ins>+class DurationValue(WrapperValue, Value):
</ins><span class="cx"> 
</span><del>-    def __init__(self, value=None):
-        self.mValue = value if value is not None else PyCalendarDuration()
</del><ins>+    _wrappedClass = Duration
+    _wrappedType = Value.VALUETYPE_DURATION
</ins><span class="cx"> 
</span><del>-
-    def duplicate(self):
-        return PyCalendarDurationValue(self.mValue.duplicate())
-
-
-    def getType(self):
-        return PyCalendarValue.VALUETYPE_DURATION
-
-
-    def parse(self, data):
-        self.mValue.parse(data)
-
-
-    def generate(self, os):
-        self.mValue.generate(os)
-
-
-    def writeXML(self, node, namespace):
-        value = self.getXMLNode(node, namespace)
-        value.text = self.mValue.writeXML()
-
-
-    def getValue(self):
-        return self.mValue
-
-
-    def setValue(self, value):
-        self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_DURATION, PyCalendarDurationValue, xmldefs.value_duration)
</del><ins>+Value.registerType(Value.VALUETYPE_DURATION, DurationValue, xmldefinitions.value_duration)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarexceptionspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/exceptions.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/exceptions.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/exceptions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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">@@ -14,7 +14,7 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-class PyCalendarError(Exception):
</del><ins>+class ErrorBase(Exception):
</ins><span class="cx"> 
</span><span class="cx">     def __init__(self, reason, data=&quot;&quot;):
</span><span class="cx">         self.mReason = reason
</span><span class="lines">@@ -22,23 +22,28 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class PyCalendarInvalidData(PyCalendarError):
</del><ins>+class InvalidData(ErrorBase):
</ins><span class="cx">     pass
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class PyCalendarInvalidProperty(PyCalendarError):
</del><ins>+class InvalidComponent(ErrorBase):
</ins><span class="cx">     pass
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class PyCalendarValidationError(PyCalendarError):
</del><ins>+class InvalidProperty(ErrorBase):
</ins><span class="cx">     pass
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class PyCalendarNoTimezoneInDatabase(Exception):
</del><ins>+class ValidationError(ErrorBase):
+    pass
</ins><span class="cx"> 
</span><ins>+
+
+class NoTimezoneInDatabase(Exception):
+
</ins><span class="cx">     def __init__(self, dbpath, tzid):
</span><span class="cx">         self.mTZDBpath = dbpath
</span><span class="cx">         self.mTZID = tzid
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarfloatvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarfloatvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/floatvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/floatvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/floatvalue.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/floatvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,68 @@
</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.
+##
+
+# iCalendar float value
+
+from pycalendar import xmldefinitions
+from pycalendar.value import Value
+
+class FloatValue(Value):
+
+    def __init__(self, value=None):
+        self.mValue = value if value is not None else 0.0
+
+
+    def duplicate(self):
+        return FloatValue(self.mValue)
+
+
+    def getType(self):
+        return Value.VALUETYPE_FLOAT
+
+
+    def parse(self, data, variant):
+        self.mValue = float(data)
+
+
+    # os - StringIO object
+    def generate(self, os):
+        try:
+            os.write(str(self.mValue))
+        except:
+            pass
+
+
+    def writeXML(self, node, namespace):
+        value = self.getXMLNode(node, namespace)
+        value.text = str(self.mValue)
+
+
+    def parseJSONValue(self, jobject):
+        self.mValue = float(jobject)
+
+
+    def writeJSONValue(self, jobject):
+        jobject.append(self.mValue)
+
+
+    def getValue(self):
+        return self.mValue
+
+
+    def setValue(self, value):
+        self.mValue = value
+
+Value.registerType(Value.VALUETYPE_FLOAT, FloatValue, xmldefinitions.value_float)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarfreebusypy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/freebusy.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/freebusy.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/freebusy.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,56 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.
-##
-
-class PyCalendarFreeBusy(object):
-
-    FREE = 0
-    BUSYTENTATIVE = 1
-    BUSYUNAVAILABLE = 2
-    BUSY = 3
-
-    def __init__(self, type=None, period=None):
-
-        self.mType = type if type else PyCalendarFreeBusy.FREE
-        self.mPeriod = period.duplicate() if period is not None else None
-
-
-    def duplicate(self):
-        return PyCalendarFreeBusy(self.mType, self.mPeriod)
-
-
-    def setType(self, type):
-        self.mType = type
-
-
-    def getType(self):
-        return self.mType
-
-
-    def setPeriod(self, period):
-        self.mPeriod = period.duplicate()
-
-
-    def getPeriod(self):
-        return self.mPeriod
-
-
-    def isPeriodOverlap(self, period):
-        return self.mPeriod.isPeriodOverlap(period)
-
-
-    def resolveOverlaps(self, fb):
-        # TODO:
-        pass
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendargeovaluepyfromrev11912PyCalendarbranchesjson2srcpycalendargeovaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/geovalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/geovalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/geovalue.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/geovalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,88 @@
</span><ins>+##
+#    Copyright (c) 2011-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.
+##
+
+# iCalendar REQUEST-STATUS value
+
+from pycalendar import xmlutils
+from pycalendar.exceptions import InvalidData
+from pycalendar.icalendar import xmldefinitions
+from pycalendar.value import Value
+from pycalendar import xmldefinitions as xmldefinitions_top
+import xml.etree.cElementTree as XML
+
+class GeoValue(Value):
+    &quot;&quot;&quot;
+    The value is a list of 2 floats
+    &quot;&quot;&quot;
+
+    def __init__(self, value=None):
+        self.mValue = value if value is not None else [0.0, 0.0]
+
+
+    def __hash__(self):
+        return hash(tuple(self.mValue))
+
+
+    def duplicate(self):
+        return GeoValue(self.mValue[:])
+
+
+    def getType(self):
+        return Value.VALUETYPE_GEO
+
+
+    def parse(self, data, variant=&quot;icalendar&quot;):
+
+        splits = data.split(&quot;;&quot;)
+        if len(splits) != 2:
+            raise InvalidData(&quot;GEO value incorrect&quot;, data)
+        try:
+            self.mValue = [float(splits[0]), float(splits[1])]
+        except ValueError:
+            raise InvalidData(&quot;GEO value incorrect&quot;, data)
+
+
+    # os - StringIO object
+    def generate(self, os):
+        os.write(&quot;%s;%s&quot; % (self.mValue[0], self.mValue[1],))
+
+
+    def writeXML(self, node, namespace):
+        value = self.getXMLNode(node, namespace)
+
+        latitude = XML.SubElement(value, xmlutils.makeTag(namespace, xmldefinitions.geo_latitude))
+        latitude.text = self.mValue[0]
+
+        longitude = XML.SubElement(value, xmlutils.makeTag(namespace, xmldefinitions.geo_longitude))
+        longitude.text = self.mValue[1]
+
+
+    def parseJSONValue(self, jobject):
+        self.mValue = jobject
+
+
+    def writeJSONValue(self, jobject):
+        jobject.append(list(self.mValue))
+
+
+    def getValue(self):
+        return self.mValue
+
+
+    def setValue(self, value):
+        self.mValue = value
+
+Value.registerType(Value.VALUETYPE_GEO, GeoValue, xmldefinitions.geo, xmldefinitions_top.value_float)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendar__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/icalendar/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/icalendar/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> #
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendaravailablepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendaravailablepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/available.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/available.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/available.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/available.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,92 @@
</span><ins>+##
+#    Copyright (c) 2011-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.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentrecur import ComponentRecur
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class Available(ComponentRecur):
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_DTSTAMP,
+        definitions.cICalProperty_DTSTART,
+        definitions.cICalProperty_UID,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_CREATED,
+        definitions.cICalProperty_DESCRIPTION,
+        definitions.cICalProperty_GEO,
+        definitions.cICalProperty_LAST_MODIFIED,
+        definitions.cICalProperty_LOCATION,
+        definitions.cICalProperty_RECURRENCE_ID,
+        definitions.cICalProperty_RRULE,
+        definitions.cICalProperty_SEQUENCE,
+        definitions.cICalProperty_SUMMARY,
+        definitions.cICalProperty_DTEND,
+        definitions.cICalProperty_DURATION,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None):
+        super(Available, self).__init__(parent=parent)
+
+
+    def duplicate(self, parent=None):
+        return super(Available, self).duplicate(parent=parent)
+
+
+    def getType(self):
+        return definitions.cICalComponent_AVAILABLE
+
+
+    def validate(self, doFix=False):
+        &quot;&quot;&quot;
+        Validate the data in this component and optionally fix any problems, else raise. If
+        loggedProblems is not None it must be a C{list} and problem descriptions are appended
+        to that.
+        &quot;&quot;&quot;
+
+        fixed, unfixed = super(Available, self).validate(doFix)
+
+        # Extra constraint: only one of DTEND or DURATION
+        if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
+            # Fix by removing the DTEND
+            logProblem = &quot;[%s] Properties must not both be present: %s, %s&quot; % (
+                self.getType(),
+                definitions.cICalProperty_DTEND,
+                definitions.cICalProperty_DURATION,
+            )
+            if doFix:
+                self.removeProperties(definitions.cICalProperty_DTEND)
+                fixed.append(logProblem)
+            else:
+                unfixed.append(logProblem)
+
+        return fixed, unfixed
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_UID,
+            definitions.cICalProperty_RECURRENCE_ID,
+            definitions.cICalProperty_DTSTART,
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_DTEND,
+        )
+Component.registerComponent(definitions.cICalComponent_AVAILABLE, Available)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarcalendarpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarcalendarpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/calendar.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/calendar.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/calendar.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/calendar.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,607 @@
</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 cStringIO import StringIO
+from pycalendar import xmlutils
+from pycalendar.containerbase import ContainerBase
+from pycalendar.datetime import DateTime
+from pycalendar.exceptions import InvalidData
+from pycalendar.icalendar import definitions, xmldefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentexpanded import ComponentExpanded
+from pycalendar.icalendar.componentrecur import ComponentRecur
+from pycalendar.icalendar.freebusy import FreeBusy
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+from pycalendar.parser import ParserContext
+from pycalendar.period import Period
+from pycalendar.utils import readFoldedLine
+import collections
+import json
+import xml.etree.cElementTree as XML
+
+class Calendar(ContainerBase):
+
+    REMOVE_ALL = 0
+    REMOVE_ONLY_THIS = 1
+    REMOVE_THIS_AND_FUTURE = 2
+
+    FIND_EXACT = 0
+    FIND_MASTER = 1
+
+    sContainerDescriptor = &quot;iCalendar&quot;
+    sComponentType = Component
+    sPropertyType = Property
+
+    sFormatText = &quot;text/calendar&quot;
+    sFormatJSON = &quot;application/calendar+json&quot;
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_PRODID,
+        definitions.cICalProperty_VERSION,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_CALSCALE,
+        definitions.cICalProperty_METHOD,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None, add_defaults=True):
+        super(Calendar, self).__init__(add_defaults=add_defaults)
+
+        self.mName = &quot;&quot;
+        self.mDescription = &quot;&quot;
+        self.mMasterComponentsByTypeAndUID = collections.defaultdict(lambda: collections.defaultdict(list))
+        self.mOverriddenComponentsByUID = collections.defaultdict(list)
+
+
+    def duplicate(self):
+        other = super(Calendar, self).duplicate()
+        other.mName = self.mName
+        other.mDescription = self.mDescription
+        return other
+
+
+    def getType(self):
+        return definitions.cICalComponent_VCALENDAR
+
+
+    def getName(self):
+        return self.mName
+
+
+    def setName(self, name):
+        self.mName = name
+
+
+    def editName(self, name):
+        if self.mName != name:
+            # Updated cached value
+            self.mName = name
+
+            # Remove existing items
+            self.removeProperties(definitions.cICalProperty_XWRCALNAME)
+
+            # Now create properties
+            if len(name):
+                self.ddProperty(Property(definitions.cICalProperty_XWRCALNAME, name))
+
+
+    def getDescription(self):
+        return self.mDescription
+
+
+    def setDescription(self, description):
+        self.mDescription = description
+
+
+    def editDescription(self, description):
+        if self.mDescription != description:
+            # Updated cached value
+            self.mDescription = description
+
+            # Remove existing items
+            self.removeProperties(definitions.cICalProperty_XWRCALDESC)
+
+            # Now create properties
+            if len(description):
+                self.addProperty(Property(definitions.cICalProperty_XWRCALDESC, description))
+
+
+    def getMethod(self):
+        result = &quot;&quot;
+        if self.hasProperty(definitions.cICalProperty_METHOD):
+            result = self.loadValueString(definitions.cICalProperty_METHOD)
+        return result
+
+
+    def changeUID(self, oldUID, newUID):
+        &quot;&quot;&quot;
+        Change the UID of all components with a matching UID to a new value. We need to
+        do this at the calendar level because this object maintains mappings based on UID
+        which need to be updated whenever the UID changes.
+
+        @param oldUID: the old value to match
+        @type oldUID: C{str}
+        @param newUID: the new value to match
+        @type newUID: C{str}
+        &quot;&quot;&quot;
+
+        # Each component
+        for component in self.mComponents:
+            if component.getUID() == oldUID:
+                component.setUID(newUID)
+
+        # Maps
+        if oldUID in self.mOverriddenComponentsByUID:
+            self.mOverriddenComponentsByUID[newUID] = self.mOverriddenComponentsByUID[oldUID]
+            del self.mOverriddenComponentsByUID[oldUID]
+        for ctype in self.mMasterComponentsByTypeAndUID:
+            if oldUID in self.mMasterComponentsByTypeAndUID[ctype]:
+                self.mMasterComponentsByTypeAndUID[ctype][newUID] = self.mMasterComponentsByTypeAndUID[ctype][oldUID]
+                del self.mMasterComponentsByTypeAndUID[ctype][oldUID]
+
+
+    def finalise(self):
+        # Get calendar name if present
+
+        # Get X-WR-CALNAME
+        temps = self.loadValueString(definitions.cICalProperty_XWRCALNAME)
+        if temps is not None:
+            self.mName = temps
+
+        # Get X-WR-CALDESC
+        temps = self.loadValueString(definitions.cICalProperty_XWRCALDESC)
+        if temps is not None:
+            self.mDescription = temps
+
+
+    def sortedComponentNames(self):
+        return (
+            definitions.cICalComponent_VTIMEZONE,
+            definitions.cICalComponent_VEVENT,
+            definitions.cICalComponent_VTODO,
+            definitions.cICalComponent_VJOURNAL,
+            definitions.cICalComponent_VFREEBUSY,
+            definitions.cICalComponent_VAVAILABILITY,
+        )
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_VERSION,
+            definitions.cICalProperty_CALSCALE,
+            definitions.cICalProperty_METHOD,
+            definitions.cICalProperty_PRODID,
+        )
+
+
+    def parse(self, ins):
+
+        result = super(Calendar, self).parse(ins)
+
+        # We need to store all timezones in the static object so they can be accessed by any date object
+        from pycalendar.timezonedb import TimezoneDatabase
+        TimezoneDatabase.mergeTimezones(self, self.getComponents(definitions.cICalComponent_VTIMEZONE))
+
+        return result
+
+
+    def parseComponent(self, ins):
+
+        result = None
+
+        LOOK_FOR_VCALENDAR = 0
+        GET_PROPERTY_OR_COMPONENT = 1
+        GOT_VCALENDAR = 4
+
+        state = LOOK_FOR_VCALENDAR
+
+        # Get lines looking for start of calendar
+        lines = [None, None]
+        comp = self
+        compend = None
+        componentstack = []
+        got_timezone = False
+
+        while readFoldedLine(ins, lines):
+
+            line = lines[0]
+
+            if state == LOOK_FOR_VCALENDAR:
+
+                # Look for start
+                if line == self.getBeginDelimiter():
+                    # Next state
+                    state = GET_PROPERTY_OR_COMPONENT
+
+                # Handle blank line
+                elif len(line) == 0:
+                    # Raise if requested, otherwise just ignore
+                    if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
+                        raise InvalidData(&quot;iCalendar data has blank lines&quot;)
+
+                # Unrecognized data
+                else:
+                    raise InvalidData(&quot;iCalendar data not recognized&quot;, line)
+
+            elif state == GET_PROPERTY_OR_COMPONENT:
+
+                # Parse property or look for start of component
+                if line.startswith(&quot;BEGIN:&quot;):
+
+                    # Push previous details to stack
+                    componentstack.append((comp, compend,))
+
+                    # Start a new component
+                    comp = self.sComponentType.makeComponent(line[6:], comp)
+                    compend = comp.getEndDelimiter()
+
+                    # Cache as result - but only the first one, we ignore the rest
+                    if result is None:
+                        result = comp
+
+                    # Look for timezone component to trigger timezone merge only if one is present
+                    if comp.getType() == definitions.cICalComponent_VTIMEZONE:
+                        got_timezone = True
+
+                elif line == self.getEndDelimiter():
+
+                    # Change state
+                    state = GOT_VCALENDAR
+
+                # Look for end of current component
+                elif line == compend:
+
+                    # Finalise the component (this caches data from the properties)
+                    comp.finalise()
+
+                    # Embed component in parent and reset to use parent
+                    componentstack[-1][0].addComponent(comp)
+                    comp, compend = componentstack.pop()
+
+                # Blank line
+                elif len(line) == 0:
+                    # Raise if requested, otherwise just ignore
+                    if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
+                        raise InvalidData(&quot;iCalendar data has blank lines&quot;)
+
+                # Ignore top-level items
+                elif comp is self:
+                    pass
+
+                # Must be a property
+                else:
+
+                    # Parse parameter/value for top-level calendar item
+                    prop = self.sPropertyType.parseText(line)
+
+                    # Check for valid property
+                    if comp is not self:
+                        comp.addProperty(prop)
+
+            # Exit if we have one - ignore all the rest
+            if state == GOT_VCALENDAR:
+                break
+
+        # We need to store all timezones in the static object so they can be accessed by any date object
+        # Only do this if we read in a timezone
+        if got_timezone:
+            from pycalendar.timezonedb import TimezoneDatabase
+            TimezoneDatabase.mergeTimezones(self, self.getComponents(definitions.cICalComponent_VTIMEZONE))
+
+        return result
+
+
+    def addComponent(self, component):
+        &quot;&quot;&quot;
+        Override to track components by UID.
+        &quot;&quot;&quot;
+        super(Calendar, self).addComponent(component)
+
+        if isinstance(component, ComponentRecur):
+            uid = component.getUID()
+            rid = component.getRecurrenceID()
+            if rid:
+                self.mOverriddenComponentsByUID[uid].append(component)
+            else:
+                self.mMasterComponentsByTypeAndUID[component.getType()][uid] = component
+
+
+    def removeComponent(self, component):
+        &quot;&quot;&quot;
+        Override to track components by UID.
+        &quot;&quot;&quot;
+        super(Calendar, self).removeComponent(component)
+
+        if isinstance(component, ComponentRecur):
+            uid = component.getUID()
+            rid = component.getRecurrenceID()
+            if rid:
+                self.mOverriddenComponentsByUID[uid].remove(component)
+            else:
+                del self.mMasterComponentsByTypeAndUID[component.getType()][uid]
+
+
+    def getText(self, includeTimezones=False, format=None):
+
+        if format is None or format == self.sFormatText:
+            s = StringIO()
+            self.generate(s, includeTimezones=includeTimezones)
+            return s.getvalue()
+        elif format == self.sFormatJSON:
+            return self.getTextJSON(includeTimezones)
+
+
+    def generate(self, os, includeTimezones=False):
+        # Make sure all required timezones are in this object
+        if includeTimezones:
+            self.includeTimezones()
+        super(Calendar, self).generate(os)
+
+
+    def getTextXML(self, includeTimezones=False):
+        node = self.writeXML(includeTimezones)
+        return xmlutils.toString(node)
+
+
+    def writeXML(self, includeTimezones=False):
+        # Make sure all required timezones are in this object
+        if includeTimezones:
+            self.includeTimezones()
+
+        # Root node structure
+        root = XML.Element(xmlutils.makeTag(xmldefinitions.iCalendar20_namespace, xmldefinitions.icalendar))
+        super(Calendar, self).writeXML(root, xmldefinitions.iCalendar20_namespace)
+        return root
+
+
+    def getTextJSON(self, includeTimezones=False):
+        jobject = []
+        self.writeJSON(jobject, includeTimezones)
+        return json.dumps(jobject[0], indent=2, separators=(',', ':'))
+
+
+    def writeJSON(self, jobject, includeTimezones=False):
+        # Make sure all required timezones are in this object
+        if includeTimezones:
+            self.includeTimezones()
+
+        # Root node structure
+        super(Calendar, self).writeJSON(jobject)
+
+
+    # Get expanded components
+    def getVEvents(self, period, list, all_day_at_top=True):
+        # Look at each VEvent
+        for vevent in self.getComponents(definitions.cICalComponent_VEVENT):
+            vevent.expandPeriod(period, list)
+
+        if (all_day_at_top):
+            list.sort(ComponentExpanded.sort_by_dtstart_allday)
+        else:
+            list.sort(ComponentExpanded.sort_by_dtstart)
+
+
+    def getVToDos(self, only_due, all_dates, upto_due_date, list):
+        # Get current date-time less one day to test for completed events during the last day
+        minusoneday = DateTime()
+        minusoneday.setNowUTC()
+        minusoneday.offsetDay(-1)
+
+        today = DateTime()
+        today.setToday()
+
+        # Look at each VToDo
+        for vtodo in self.getComponents(definitions.cICalComponent_VTODO):
+
+            # Filter out done (that were complted more than a day ago) or cancelled to dos if required
+            if only_due:
+                if vtodo.getStatus() == definitions.eStatus_VToDo_Cancelled:
+                    continue
+                elif ((vtodo.getStatus() == definitions.eStatus_VToDo_Completed) and
+                            (not vtodo.hasCompleted() or (vtodo.getCompleted() &lt; minusoneday))):
+                    continue
+
+            # Filter out those with end after chosen date if required
+            if not all_dates:
+                if vtodo.hasEnd() and (vtodo.getEnd() &gt; upto_due_date):
+                    continue
+                elif not vtodo.hasEnd() and (today &gt; upto_due_date):
+                    continue
+
+            # TODO: fix this
+            #list.append(ComponentExpandedShared(ComponentExpanded(vtodo, None)))
+
+
+    def getRecurrenceInstancesItems(self, type, uid, items):
+        # Get instances from list
+        items.extend(self.mOverriddenComponentsByUID.get(uid, ()))
+
+
+    def getRecurrenceInstancesIds(self, type, uid, ids):
+        # Get instances from list
+        ids.extend([comp.getRecurrenceID() for comp in self.mOverriddenComponentsByUID.get(uid, ())])
+
+
+    # Freebusy generation
+    def getVFreeBusyList(self, period, list):
+        # Look at each VFreeBusy
+        for vfreebusy in self.getComponents(definitions.cICalComponent_VFREEBUSY):
+            vfreebusy.expandPeriod(period, list)
+
+
+    def getVFreeBusyFB(self, period, fb):
+        # First create expanded set
+        # TODO: fix this
+        #list = ExpandedComponents()
+        self.getVEvents(period, list)
+        if len(list) == 0:
+            return
+
+        # Get start/end list for each non-all-day expanded components
+        dtstart = []
+        dtend = []
+        for dt in list:
+
+            # Ignore if all-day
+            if dt.getInstanceStart().isDateOnly():
+                continue
+
+            # Ignore if transparent to free-busy
+            transp = &quot;&quot;
+            if dt.getOwner().getProperty(definitions.cICalProperty_TRANSP, transp) and (transp == definitions.cICalProperty_TRANSPARENT):
+                continue
+
+            # Add start/end to list
+            dtstart.append(dt.getInstanceStart())
+            dtend.append(dt.getInstanceEnd())
+
+        # No longer need the expanded items
+        list.clear()
+
+        # Create non-overlapping periods as properties in the freebusy component
+        temp = Period(dtstart.front(), dtend.front())
+        dtstart_iter = dtstart.iter()
+        dtstart_iter.next()
+        dtend_iter = dtend.iter()
+        dtend_iter.next()
+        for i in i:
+
+            # Check for non-overlap
+            if dtstart_iter &gt; temp.getEnd():
+
+                # Current period is complete
+                fb.addProperty(Property(definitions.cICalProperty_FREEBUSY, temp))
+
+                # Reset period to new range
+                temp = Period(dtstart_iter, dtend_iter)
+
+            # They overlap - check for extended end
+            if dtend_iter &gt; temp.getEnd():
+
+                # Extend the end
+                temp = Period(temp.getStart(), dtend_iter)
+
+        # Add remaining period as property
+        fb.addProperty(Property(definitions.cICalProperty_FREEBUSY, temp))
+
+
+    def getFreeBusy(self, period, fb):
+        # First create expanded set
+
+        list = []
+        self.getVEvents(period, list)
+
+        # Get start/end list for each non-all-day expanded components
+        for comp in list:
+
+            # Ignore if all-day
+            if comp.getInstanceStart().isDateOnly():
+                continue
+
+            # Ignore if transparent to free-busy
+            transp = &quot;&quot;
+            if comp.getOwner().getProperty(definitions.cICalProperty_TRANSP, transp) and (transp == definitions.cICalProperty_TRANSPARENT):
+                continue
+
+            # Add free busy item to list
+            status = comp.getMaster().getStatus()
+            if status in (definitions.eStatus_VEvent_None, definitions.eStatus_VEvent_Confirmed):
+                fb.append(FreeBusy(FreeBusy.BUSY, Period(comp.getInstanceStart(), comp.getInstanceEnd())))
+            elif status == definitions.eStatus_VEvent_Tentative:
+                fb.append(FreeBusy(FreeBusy.BUSYTENTATIVE, Period(comp.getInstanceStart(), comp.getInstanceEnd())))
+                break
+            elif status == definitions.eStatus_VEvent_Cancelled:
+                # Cancelled =&gt; does not contribute to busy time
+                pass
+
+        # Now get the VFREEBUSY info
+        list2 = []
+        self.getVFreeBusy(period, list2)
+
+        # Get start/end list for each free-busy
+        for comp in list2:
+
+            # Expand component and add free busy info to list
+            comp.expandPeriod(period, fb)
+
+        # Add remaining period as property
+        FreeBusy.resolveOverlaps(fb)
+
+
+    def getTimezoneOffsetSeconds(self, tzid, dt):
+        # Find timezone that matches the name (which is the same as the map key)
+        timezone = self.getTimezone(tzid)
+        return timezone.getTimezoneOffsetSeconds(dt) if timezone else 0
+
+
+    def getTimezoneDescriptor(self, tzid, dt):
+        # Find timezone that matches the name (which is the same as the map key)
+        timezone = self.getTimezone(tzid)
+        return timezone.getTimezoneDescriptor(dt) if timezone else &quot;&quot;
+
+
+    def getTimezone(self, tzid):
+        # Find timezone that matches the name (which is the same as the map key)
+        for timezone in self.getComponents(definitions.cICalComponent_VTIMEZONE):
+            if timezone.getID() == tzid:
+                return timezone
+        else:
+            return None
+
+
+    def addDefaultProperties(self):
+        self.addProperty(Property(definitions.cICalProperty_PRODID, Calendar.sProdID))
+        self.addProperty(Property(definitions.cICalProperty_VERSION, &quot;2.0&quot;))
+        self.addProperty(Property(definitions.cICalProperty_CALSCALE, &quot;GREGORIAN&quot;))
+
+
+    def validProperty(self, prop):
+        if prop.getName() == definitions.cICalProperty_VERSION:
+
+            tvalue = prop.getTextValue()
+            if ((tvalue is None) or (tvalue.getValue() != &quot;2.0&quot;)):
+                return False
+
+        elif prop.getName() == definitions.cICalProperty_CALSCALE:
+
+            tvalue = prop.getTextValue()
+            if ((tvalue is None) or (tvalue.getValue() != &quot;GREGORIAN&quot;)):
+                return False
+
+        return True
+
+
+    def includeTimezones(self):
+        # Get timezone names from each component
+        tzids = set()
+        for component in self.mComponents:
+            if component.getType() != definitions.cICalComponent_VTIMEZONE:
+                component.getTimezones(tzids)
+
+        # Make sure each timezone is in current calendar
+        from pycalendar.timezonedb import TimezoneDatabase
+        for tzid in tzids:
+            tz = self.getTimezone(tzid)
+            if tz is None:
+                # Find it in the static object
+                tz = TimezoneDatabase.getTimezone(tzid)
+                if tz is not None:
+                    dup = tz.duplicate()
+                    self.addComponent(dup)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarcomponentpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarcomponentpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/component.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/component.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/component.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/component.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,212 @@
</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 import stringutils
+from pycalendar.componentbase import ComponentBase
+from pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.property import Property
+import os
+import time
+import uuid
+
+class Component(ComponentBase):
+
+    uid_ctr = 1
+
+    mapper = {}
+
+    sComponentType = None
+    sPropertyType = Property
+
+    @classmethod
+    def registerComponent(cls, name, comptype):
+        cls.mapper[name] = comptype
+
+
+    @classmethod
+    def makeComponent(cls, compname, parent):
+        try:
+            return cls.mapper[compname](parent=parent)
+        except KeyError:
+            return cls.mapper[definitions.cICalComponent_UNKNOWN](parent=parent, comptype=compname)
+
+
+    def __init__(self, parent=None):
+
+        super(Component, self).__init__(parent)
+        self.mUID = &quot;&quot;
+        self.mSeq = 0
+        self.mOriginalSeq = 0
+        self.mChanged = False
+
+
+    def duplicate(self, parent=None, **args):
+
+        other = super(Component, self).duplicate(parent=parent, **args)
+        other.mUID = self.mUID
+        other.mSeq = self.mSeq
+        other.mOriginalSeq = self.mOriginalSeq
+
+        other.mChanged = self.mChanged
+
+        return other
+
+
+    def __repr__(self):
+        return &quot;%s: UID: %s&quot; % (self.getType(), self.getMapKey(),)
+
+
+    def getMimeComponentName(self):
+        raise NotImplementedError
+
+
+    def getMapKey(self):
+        if hasattr(self, &quot;mMapKey&quot;):
+            return self.mMapKey
+        elif self.mUID:
+            return self.mUID
+        else:
+            self.mMapKey = str(uuid.uuid4())
+            return self.mMapKey
+
+
+    def getSortKey(self):
+        return self.getMapKey()
+
+
+    def getMasterKey(self):
+        return self.mUID
+
+
+    def getUID(self):
+        return self.mUID
+
+
+    def setUID(self, uid):
+        if uid:
+            self.mUID = uid
+        else:
+            # Get left-side of UID (first 24 chars of MD5 digest of time, pid
+            # and ctr)
+            lhs_txt = &quot;&quot;
+            lhs_txt += str(time.time())
+            lhs_txt += &quot;.&quot;
+            lhs_txt += str(os.getpid())
+            lhs_txt += &quot;.&quot;
+            lhs_txt += str(Component.uid_ctr)
+            Component.uid_ctr += 1
+            lhs = stringutils.md5digest(lhs_txt)
+
+            # Get right side (domain) of message-id
+            rhs = None
+
+            # Use app name
+            from pycalendar.icalendar.calendar import Calendar
+            domain = Calendar.sDomain
+            domain += str(Component.uid_ctr)
+
+            # Use first 24 chars of MD5 digest of the domain as the
+            # right-side of message-id
+            rhs = stringutils.md5digest(domain)
+
+            # Generate the UID string
+            new_uid = lhs
+            new_uid += &quot;@&quot;
+            new_uid += rhs
+
+            self.mUID = new_uid
+
+        self.removeProperties(definitions.cICalProperty_UID)
+
+        prop = Property(definitions.cICalProperty_UID, self.mUID)
+        self.addProperty(prop)
+
+
+    def getSeq(self):
+        return self.mSeq
+
+
+    def setSeq(self, seq):
+        self.mSeq = seq
+
+        self.removeProperties(definitions.cICalProperty_SEQUENCE)
+
+        prop = Property(definitions.cICalProperty_SEQUENCE, self.mSeq)
+        self.addProperty(prop)
+
+
+    def getOriginalSeq(self):
+        return self.mOriginalSeq
+
+
+    def getChanged(self):
+        return self.mChanged
+
+
+    def setChanged(self, changed):
+        self.mChanged = changed
+
+
+    def initDTSTAMP(self):
+        self.removeProperties(definitions.cICalProperty_DTSTAMP)
+
+        prop = Property(definitions.cICalProperty_DTSTAMP,
+                                  DateTime.getNowUTC())
+        self.addProperty(prop)
+
+
+    def updateLastModified(self):
+        self.removeProperties(definitions.cICalProperty_LAST_MODIFIED)
+
+        prop = Property(definitions.cICalProperty_LAST_MODIFIED,
+                                  DateTime.getNowUTC())
+        self.addProperty(prop)
+
+
+    def finalise(self):
+        # Get UID
+        temps = self.loadValueString(definitions.cICalProperty_UID)
+        if temps is not None:
+            self.mUID = temps
+
+        # Get SEQ
+        temp = self.loadValueInteger(definitions.cICalProperty_SEQUENCE)
+        if temp is not None:
+            self.mSeq = temp
+
+        # Cache the original sequence when the component is read in.
+        # This will be used to synchronise changes between two instances of the
+        # same calendar
+        self.mOriginalSeq = self.mSeq
+
+
+    def canGenerateInstance(self):
+        return True
+
+
+    def getTimezones(self, tzids):
+        # Look for all date-time properties
+        for props in self.mProperties.itervalues():
+            for prop in props:
+                # Try to get a date-time value from the property
+                dtv = prop.getDateTimeValue()
+                if dtv is not None:
+                    # Add timezone id if appropriate
+                    if dtv.getValue().getTimezoneID():
+                        tzids.add(dtv.getValue().getTimezoneID())
+
+Component.sComponentType = Component
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarcomponentexpandedpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarcomponentexpandedpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/componentexpanded.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/componentexpanded.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/componentexpanded.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/componentexpanded.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,158 @@
</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
+
+class ComponentExpanded(object):
+
+    @staticmethod
+    def sort_by_dtstart_allday(e1, e2):
+
+        if e1.mInstanceStart.isDateOnly() and e2.mInstanceStart.isDateOnly():
+            return e1.mInstanceStart &lt; e2.mInstanceStart
+        elif e1.mInstanceStart.isDateOnly():
+            return True
+        elif e2.mInstanceStart.isDateOnly():
+            return False
+        elif e1.mInstanceStart == e2.mInstanceStart:
+            if e1.mInstanceEnd == e2.mInstanceEnd:
+                # Put ones created earlier in earlier columns in day view
+                return e1.getOwner().getStamp() &lt; e2.getOwner().getStamp()
+            else:
+                # Put ones that end later in earlier columns in day view
+                return e1.mInstanceEnd &gt; e2.mInstanceEnd
+        else:
+            return e1.mInstanceStart &lt; e2.mInstanceStart
+
+
+    @staticmethod
+    def sort_by_dtstart(e1, e2):
+        if e1.mInstanceStart == e2.mInstanceStart:
+            if (e1.mInstanceStart.isDateOnly() and not e2.mInstanceStart.isDateOnly() or
+                not e1.mInstanceStart.isDateOnly() and e2.mInstanceStart.isDateOnly()):
+                return e1.mInstanceStart.isDateOnly()
+            else:
+                return False
+        else:
+            return e1.mInstanceStart &lt; e2.mInstanceStart
+
+
+    def __init__(self, owner, rid):
+
+        self.mOwner = owner
+        self.initFromOwner(rid)
+
+
+    def duplicate(self):
+        other = ComponentExpanded(self.mOwner, None)
+        other.mInstanceStart = self.mInstanceStart.duplicate()
+        other.mInstanceEnd = self.mInstanceEnd.duplicate()
+        other.mRecurring = self.mRecurring
+        return other
+
+
+    def close(self):
+        # Clean-up
+        self.mOwner = None
+
+
+    def getOwner(self):
+        return self.mOwner
+
+
+    def getMaster(self):
+        return self.mOwner
+
+
+    def getTrueMaster(self):
+        return self.mOwner.getMaster()
+
+
+    def getInstanceStart(self):
+        return self.mInstanceStart
+
+
+    def getInstanceEnd(self):
+        return self.mInstanceEnd
+
+
+    def recurring(self):
+        return self.mRecurring
+
+
+    def isNow(self):
+        # Check instance start/end against current date-time
+        now = DateTime.getNowUTC()
+        return self.mInstanceStart &lt;= now and self.mInstanceEnd &gt; now
+
+
+    def initFromOwner(self, rid):
+        # There are four possibilities here:
+        #
+        # 1: this instance is the instance for the master component
+        #
+        # 2: this instance is an expanded instance derived directly from the
+        # master component
+        #
+        # 3: This instance is the instance for a slave (overridden recurrence
+        # instance)
+        #
+        # 4: This instance is the expanded instance for a slave with a RANGE
+        # parameter
+        #
+
+        # rid is not set if the owner is the master (case 1)
+        if rid is None:
+            # Just get start/end from owner
+            self.mInstanceStart = self.mOwner.getStart()
+            self.mInstanceEnd = self.mOwner.getEnd()
+            self.mRecurring = False
+
+        # If the owner is not a recurrence instance then it is case 2
+        elif not self.mOwner.isRecurrenceInstance():
+            # Derive start/end from rid and duration of master
+
+            # Start of the recurrence instance is the recurrence id
+            self.mInstanceStart = rid
+
+            # End is based on original events settings
+            if self.mOwner.hasEnd():
+                self.mInstanceEnd = self.mInstanceStart + (self.mOwner.getEnd() - self.mOwner.getStart())
+            else:
+                self.mInstanceEnd = self.mInstanceStart.duplicate()
+
+            self.mRecurring = True
+
+        # If the owner is a recurrence item and the passed in rid is the same
+        # as the component rid we have case 3
+        elif rid == self.mOwner.getRecurrenceID():
+            # Derive start/end directly from the owner
+            self.mInstanceStart = self.mOwner.getStart()
+            self.mInstanceEnd = self.mOwner.getEnd()
+
+            self.mRecurring = True
+
+        # case 4 - the complicated one!
+        else:
+            # We need to use the rid as the starting point, but adjust it by
+            # the offset between the slave's
+            # rid and its start
+            self.mInstanceStart = rid + (self.mOwner.getStart() - self.mOwner.getRecurrenceID())
+
+            # End is based on duration of owner
+            self.mInstanceEnd = self.mInstanceStart + (self.mOwner.getEnd() - self.mOwner.getStart())
+
+            self.mRecurring = True
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarcomponentrecurpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarcomponentrecurpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/componentrecur.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/componentrecur.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/componentrecur.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/componentrecur.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,717 @@
</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.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentexpanded import ComponentExpanded
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.recurrenceset import RecurrenceSet
+from pycalendar.timezone import Timezone
+from pycalendar.utils import set_difference
+import uuid
+
+class ComponentRecur(Component):
+
+    propertyCardinality_STATUS_Fix = (
+        definitions.cICalProperty_STATUS,
+    )
+
+    @staticmethod
+    def mapKey(uid, rid=None):
+        if uid:
+            result = &quot;u:&quot; + uid
+            if rid is not None:
+                result += rid
+            return result
+        else:
+            return None
+
+
+    @staticmethod
+    def sort_by_dtstart_allday(e1, e2):
+
+        if e1.self.mStart.isDateOnly() and e2.self.mStart.isDateOnly():
+            return e1.self.mStart &lt; e2.self.mStart
+        elif e1.self.mStart.isDateOnly():
+            return True
+        elif (e2.self.mStart.isDateOnly()):
+            return False
+        elif e1.self.mStart == e2.self.mStart:
+            if e1.self.mEnd == e2.self.mEnd:
+                # Put ones created earlier in earlier columns in day view
+                return e1.self.mStamp &lt; e2.self.mStamp
+            else:
+                # Put ones that end later in earlier columns in day view
+                return e1.self.mEnd &gt; e2.self.mEnd
+        else:
+            return e1.self.mStart &lt; e2.self.mStart
+
+
+    @staticmethod
+    def sort_by_dtstart(e1, e2):
+        if e1.self.mStart == e2.self.mStart:
+            if (e1.self.mStart.isDateOnly() and e2.self.mStart.isDateOnly() or
+                not e1.self.mStart.isDateOnly() and not e2.self.mStart.isDateOnly()):
+                return False
+            else:
+                return e1.self.mStart.isDateOnly()
+        else:
+            return e1.self.mStart &lt; e2.self.mStart
+
+
+    def __init__(self, parent=None):
+        super(ComponentRecur, self).__init__(parent=parent)
+        self.mMaster = self
+        self.mMapKey = None
+        self.mSummary = None
+        self.mStamp = DateTime()
+        self.mHasStamp = False
+        self.mStart = DateTime()
+        self.mHasStart = False
+        self.mEnd = DateTime()
+        self.mHasEnd = False
+        self.mDuration = False
+        self.mHasRecurrenceID = False
+        self.mAdjustFuture = False
+        self.mAdjustPrior = False
+        self.mRecurrenceID = None
+        self.mRecurrences = None
+
+        # This is a special check we do only for STATUS due to a calendarserver bug
+        self.cardinalityChecks += (
+            self.check_cardinality_STATUS_Fix,
+        )
+
+
+    def duplicate(self, parent=None):
+        other = super(ComponentRecur, self).duplicate(parent=parent)
+
+        # Special determination of master
+        other.mMaster = self.mMaster if self.recurring() else self
+
+        other.mMapKey = self.mMapKey
+
+        other.mSummary = self.mSummary
+
+        if (self.mStamp is not None):
+            other.mStamp = self.mStamp.duplicate()
+        other.mHasStamp = self.mHasStamp
+
+        other.mStart = self.mStart.duplicate()
+        other.mHasStart = self.mHasStart
+        other.mEnd = self.mEnd.duplicate()
+        other.mHasEnd = self.mHasEnd
+        other.mDuration = self.mDuration
+
+        other.mHasRecurrenceID = self.mHasRecurrenceID
+        other.mAdjustFuture = self.mAdjustFuture
+        other.mAdjustPrior = self.mAdjustPrior
+        if self.mRecurrenceID is not None:
+            other.mRecurrenceID = self.mRecurrenceID.duplicate()
+
+        other._resetRecurrenceSet()
+
+        return other
+
+
+    def canGenerateInstance(self):
+        return not self.mHasRecurrenceID
+
+
+    def recurring(self):
+        return (self.mMaster is not None) and (self.mMaster is not self)
+
+
+    def setMaster(self, master):
+        self.mMaster = master
+        self.initFromMaster()
+
+
+    def getMaster(self):
+        return self.mMaster
+
+
+    def getMapKey(self):
+
+        if self.mMapKey is None:
+            self.mMapKey = str(uuid.uuid4())
+        return self.mMapKey
+
+
+    def getMasterKey(self):
+        return ComponentRecur.mapKey(self.mUID)
+
+
+    def initDTSTAMP(self):
+        # Save new one
+        super(ComponentRecur, self).initDTSTAMP()
+
+        # Get the new one
+        temp = self.loadValueDateTime(definitions.cICalProperty_DTSTAMP)
+        self.mHasStamp = temp is not None
+        if self.mHasStamp:
+            self.mStamp = temp
+
+
+    def getStamp(self):
+        return self.mStamp
+
+
+    def hasStamp(self):
+        return self.mHasStamp
+
+
+    def getStart(self):
+        return self.mStart
+
+
+    def hasStart(self):
+        return self.mHasStart
+
+
+    def getEnd(self):
+        return self.mEnd
+
+
+    def hasEnd(self):
+        return self.mHasEnd
+
+
+    def useDuration(self):
+        return self.mDuration
+
+
+    def isRecurrenceInstance(self):
+        return self.mHasRecurrenceID
+
+
+    def isAdjustFuture(self):
+        return self.mAdjustFuture
+
+
+    def isAdjustPrior(self):
+        return self.mAdjustPrior
+
+
+    def getRecurrenceID(self):
+        return self.mRecurrenceID
+
+
+    def isRecurring(self):
+        return (self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()
+
+
+    def getRecurrenceSet(self):
+        return self.mRecurrences
+
+
+    def setUID(self, uid):
+        super(ComponentRecur, self).setUID(uid)
+
+        # Update the map key
+        if self.mHasRecurrenceID:
+            self.mMapKey = self.mapKey(self.mUID, self.mRecurrenceID.getText())
+        else:
+            self.mMapKey = self.mapKey(self.mUID)
+
+
+    def getSummary(self):
+        return self.mSummary
+
+
+    def setSummary(self, summary):
+        self.mSummary = summary
+
+
+    def getDescription(self):
+        # Get DESCRIPTION
+        txt = self.loadValueString(definitions.cICalProperty_DESCRIPTION)
+        if txt is not None:
+            return txt
+        else:
+            return &quot;&quot;
+
+
+    def getLocation(self):
+        # Get LOCATION
+        txt = self.loadValueString(definitions.cICalProperty_LOCATION)
+        if txt is not None:
+            return txt
+        else:
+            return &quot;&quot;
+
+
+    def finalise(self):
+        super(ComponentRecur, self).finalise()
+
+        # Get DTSTAMP
+        temp = self.loadValueDateTime(definitions.cICalProperty_DTSTAMP)
+        self.mHasStamp = temp is not None
+        if self.mHasStamp:
+            self.mStamp = temp
+
+        # Get DTSTART
+        temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
+        self.mHasStart = temp is not None
+        if self.mHasStart:
+            self.mStart = temp
+
+        # Get DTEND
+        temp = self.loadValueDateTime(definitions.cICalProperty_DTEND)
+        if temp is None:
+            # Try DURATION instead
+            temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
+            if temp is not None:
+                self.mHasEnd = False
+                self.mEnd = self.mStart + temp
+                self.mDuration = True
+            else:
+                # If no end or duration then use the start (bumped by one day for
+                # an all day event)
+                self.mHasEnd = False
+                self.mEnd = self.mStart.duplicate()
+                if self.mEnd.isDateOnly():
+                    self.mEnd.offsetDay(1)
+                self.mDuration = False
+        else:
+            self.mHasEnd = True
+            self.mEnd = temp
+            self.mDuration = False
+
+        # Get SUMMARY
+        temp = self.loadValueString(definitions.cICalProperty_SUMMARY)
+        if temp is not None:
+            self.mSummary = temp
+
+        # Get RECURRENCE-ID
+        self.mHasRecurrenceID = (self.countProperty(definitions.cICalProperty_RECURRENCE_ID) != 0)
+        if self.mHasRecurrenceID:
+            self.mRecurrenceID = self.loadValueDateTime(definitions.cICalProperty_RECURRENCE_ID)
+
+        # Update the map key
+        if self.mHasRecurrenceID:
+            self.mMapKey = self.mapKey(self.mUID, self.mRecurrenceID.getText())
+
+            # Also get the RANGE parameter
+            attrs = self.findFirstProperty(definitions.cICalProperty_RECURRENCE_ID).getParameters()
+            if definitions.cICalParameter_RANGE in attrs:
+                self.mAdjustFuture = (attrs[definitions.cICalParameter_RANGE][0].getFirstValue() == definitions.cICalParameter_RANGE_THISANDFUTURE)
+                self.mAdjustPrior = (attrs[definitions.cICalParameter_RANGE][0].getFirstValue() == definitions.cICalParameter_RANGE_THISANDPRIOR)
+            else:
+                self.mAdjustFuture = False
+                self.mAdjustPrior = False
+        else:
+            self.mMapKey = self.mapKey(self.mUID)
+
+        self._resetRecurrenceSet()
+
+
+    def validate(self, doFix=False):
+        &quot;&quot;&quot;
+        Validate the data in this component and optionally fix any problems. Return
+        a tuple containing two lists: the first describes problems that were fixed, the
+        second problems that were not fixed. Caller can then decide what to do with unfixed
+        issues.
+        &quot;&quot;&quot;
+
+        # Do normal checks
+        fixed, unfixed = super(ComponentRecur, self).validate(doFix)
+
+        # Check that any UNTIL value matches that for DTSTART
+        if self.mHasStart and self.mRecurrences:
+            dtutc = self.mStart.duplicateAsUTC()
+            for rrule in self.mRecurrences.getRules():
+                if rrule.getUseUntil():
+                    if rrule.getUntil().isDateOnly() ^ self.mStart.isDateOnly():
+                        logProblem = &quot;[%s] Value types must match: %s, %s&quot; % (
+                            self.getType(),
+                            definitions.cICalProperty_DTSTART,
+                            definitions.cICalValue_RECUR_UNTIL,
+                        )
+                        if doFix:
+                            rrule.getUntil().setDateOnly(self.mStart.isDateOnly())
+                            if not self.mStart.isDateOnly():
+                                rrule.getUntil().setHHMMSS(dtutc.getHours(), dtutc.getMinutes(), dtutc.getSeconds())
+                                rrule.getUntil().setTimezone(Timezone(utc=True))
+                            self.mRecurrences.changed()
+                            fixed.append(logProblem)
+                        else:
+                            unfixed.append(logProblem)
+
+        return fixed, unfixed
+
+
+    def check_cardinality_STATUS_Fix(self, fixed, unfixed, doFix):
+        &quot;&quot;&quot;
+        Special for bug with STATUS where STATUS:CANCELLED is added alongside
+        another STATUS. In this case we want STATUS:CANCELLED to win.
+        &quot;&quot;&quot;
+        for propname in self.propertyCardinality_STATUS_Fix:
+            if self.countProperty(propname) &gt; 1:
+                logProblem = &quot;[%s] Too many properties: %s&quot; % (self.getType(), propname)
+                if doFix:
+                    # Check that one of them is STATUS:CANCELLED
+                    for prop in self.getProperties(propname):
+                        if prop.getTextValue().getValue().upper() == definitions.cICalProperty_STATUS_CANCELLED:
+                            self.removeProperties(propname)
+                            self.addProperty(Property(propname, definitions.cICalProperty_STATUS_CANCELLED))
+                            fixed.append(logProblem)
+                            break
+                    else:
+                        unfixed.append(logProblem)
+                else:
+                    unfixed.append(logProblem)
+
+
+    def _resetRecurrenceSet(self):
+        # May need to create items
+        self.mRecurrences = None
+        if ((self.countProperty(definitions.cICalProperty_RRULE) != 0) or
+            (self.countProperty(definitions.cICalProperty_RDATE) != 0) or
+            (self.countProperty(definitions.cICalProperty_EXRULE) != 0) or
+            (self.countProperty(definitions.cICalProperty_EXDATE) != 0)):
+
+            self.mRecurrences = RecurrenceSet()
+
+            # Get RRULEs
+            self.loadValueRRULE(definitions.cICalProperty_RRULE, self.mRecurrences, True)
+
+            # Get RDATEs
+            self.loadValueRDATE(definitions.cICalProperty_RDATE, self.mRecurrences, True)
+
+            # Get EXRULEs
+            self.loadValueRRULE(definitions.cICalProperty_EXRULE, self.mRecurrences, False)
+
+            # Get EXDATEs
+            self.loadValueRDATE(definitions.cICalProperty_EXDATE, self.mRecurrences, False)
+
+
+    def FixStartEnd(self):
+        # End is always greater than start if start exists
+        if self.mHasStart and self.mEnd &lt;= self.mStart:
+            # Use the start
+            self.mEnd = self.mStart.duplicate()
+            self.mDuration = False
+
+            # Adjust to approriate non-inclusive end point
+            if self.mStart.isDateOnly():
+                self.mEnd.offsetDay(1)
+
+                # For all day events it makes sense to use duration
+                self.mDuration = True
+            else:
+                # Use end of current day
+                self.mEnd.offsetDay(1)
+                self.mEnd.setHHMMSS(0, 0, 0)
+
+
+    def expandPeriod(self, period, results):
+        # Check for recurrence and True master
+        if ((self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()
+                and not self.isRecurrenceInstance()):
+            # Expand recurrences within the range
+            items = []
+            self.mRecurrences.expand(self.mStart, period, items)
+
+            # Look for overridden recurrence items
+            cal = self.mParentComponent
+            if cal is not None:
+                # Remove recurrence instances from the list of items
+                recurs = []
+                cal.getRecurrenceInstancesIds(definitions.cICalComponent_VEVENT, self.getUID(), recurs)
+                recurs.sort()
+                if len(recurs) != 0:
+                    temp = []
+                    temp = set_difference(items, recurs)
+                    items = temp
+
+                    # Now get actual instances
+                    instances = []
+                    cal.getRecurrenceInstancesItems(definitions.cICalComponent_VEVENT, self.getUID(), instances)
+
+                    # Get list of each ones with RANGE
+                    prior = []
+                    future = []
+                    for iter in instances:
+                        if iter.isAdjustPrior():
+                            prior.append(iter)
+                        if iter.isAdjustFuture():
+                            future.append(iter)
+
+                    # Check for special behaviour
+                    if len(prior) + len(future) == 0:
+                        # Add each expanded item
+                        for iter in items:
+                            results.append(self.createExpanded(self, iter))
+                    else:
+                        # Sort each list first
+                        prior.sort(self.sort_by_dtstart)
+                        future.sort(self.sort_by_dtstart)
+
+                        # Add each expanded item
+                        for iter1 in items:
+
+                            # Now step through each using the slave item
+                            # instead of the master as appropriate
+                            slave = None
+
+                            # Find most appropriate THISANDPRIOR item
+                            for i in range(len(prior) - 1, 0, -1):
+                                riter2 = prior[i]
+                                if riter2.getStart() &gt; iter1:
+                                    slave = riter2
+                                    break
+
+                            # Find most appropriate THISANDFUTURE item
+                            for i in range(len(future) - 1, 0, -1):
+                                riter2 = future.elementAt(i)
+                                if riter2.getStart() &lt; iter1:
+                                    slave = riter2
+                                    break
+
+                            if slave is None:
+                                slave = self
+                            results.append(self.createExpanded(slave, iter1))
+                else:
+                    # Add each expanded item
+                    for iter in items:
+                        results.append(self.createExpanded(self, iter))
+
+        elif self.withinPeriod(period):
+            if self.isRecurrenceInstance():
+                rid = self.mRecurrenceID
+            else:
+                rid = None
+            results.append(ComponentExpanded(self, rid))
+
+
+    def withinPeriod(self, period):
+        # Check for recurrence
+        if ((self.mRecurrences is not None) and self.mRecurrences.hasRecurrence()):
+            items = []
+            self.mRecurrences.expand(self.mStart, period, items)
+            return len(items) != 0
+        else:
+            # Does event span the period (assume self.mEnd &gt; self.mStart)
+            # Check start (inclusive) and end (exclusive)
+            if self.mEnd &lt;= period.getStart() or self.mStart &gt;= period.getEnd():
+                return False
+            else:
+                return True
+
+
+    def changedRecurrence(self):
+        # Clear cached values
+        if self.mRecurrences is not None:
+            self.mRecurrences.changed()
+
+
+    # Editing
+    def editSummary(self, summary):
+        # Updated cached value
+        self.mSummary = summary
+
+        # Remove existing items
+        self.editProperty(definitions.cICalProperty_SUMMARY, summary)
+
+
+    def editDetails(self, description, location):
+
+        # Edit existing items
+        self.editProperty(definitions.cICalProperty_DESCRIPTION, description)
+        self.editProperty(definitions.cICalProperty_LOCATION, location)
+
+
+    def editTiming(self):
+        # Updated cached values
+        self.mHasStart = False
+        self.mHasEnd = False
+        self.mDuration = False
+        self.mStart.setToday()
+        self.mEnd.setToday()
+
+        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
+        self.removeProperties(definitions.cICalProperty_DTSTART)
+        self.removeProperties(definitions.cICalProperty_DTEND)
+        self.removeProperties(definitions.cICalProperty_DURATION)
+        self.removeProperties(definitions.cICalProperty_DUE)
+
+
+    def editTimingDue(self, due):
+        # Updated cached values
+        self.mHasStart = False
+        self.mHasEnd = True
+        self.mDuration = False
+        self.mStart = due
+        self.mEnd = due
+
+        # Remove existing DUE &amp; DTSTART &amp; DTEND &amp; DURATION items
+        self.removeProperties(definitions.cICalProperty_DUE)
+        self.removeProperties(definitions.cICalProperty_DTSTART)
+        self.removeProperties(definitions.cICalProperty_DTEND)
+        self.removeProperties(definitions.cICalProperty_DURATION)
+
+        # Now create properties
+        prop = Property(definitions.cICalProperty_DUE, due)
+        self.addProperty(prop)
+
+
+    def editTimingStartEnd(self, start, end):
+        # Updated cached values
+        self.mHasStart = self.mHasEnd = True
+        self.mStart = start
+        self.mEnd = end
+        self.mDuration = False
+        self.FixStartEnd()
+        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
+        self.removeProperties(definitions.cICalProperty_DTSTART)
+        self.removeProperties(definitions.cICalProperty_DTEND)
+        self.removeProperties(definitions.cICalProperty_DURATION)
+        self.removeProperties(definitions.cICalProperty_DUE)
+
+        # Now create properties
+        prop = Property(definitions.cICalProperty_DTSTART, start)
+        self.addProperty(prop)
+
+        # If its an all day event and the end one day after the start, ignore it
+        temp = start.duplicate()
+        temp.offsetDay(1)
+        if not start.isDateOnly() or end != temp:
+            prop = Property(definitions.cICalProperty_DTEND, end)
+            self.addProperty(prop)
+
+
+    def editTimingStartDuration(self, start, duration):
+        # Updated cached values
+        self.mHasStart = True
+        self.mHasEnd = False
+        self.mStart = start
+        self.mEnd = start + duration
+        self.mDuration = True
+
+        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
+        self.removeProperties(definitions.cICalProperty_DTSTART)
+        self.removeProperties(definitions.cICalProperty_DTEND)
+        self.removeProperties(definitions.cICalProperty_DURATION)
+        self.removeProperties(definitions.cICalProperty_DUE)
+
+        # Now create properties
+        prop = Property(definitions.cICalProperty_DTSTART, start)
+        self.addProperty(prop)
+
+        # If its an all day event and the duration is one day, ignore it
+        if (not start.isDateOnly() or (duration.getWeeks() != 0)
+                or (duration.getDays() &gt; 1)):
+            prop = Property(definitions.cICalProperty_DURATION, duration)
+            self.addProperty(prop)
+
+
+    def editRecurrenceSet(self, recurs):
+        # Must have items
+        if self.mRecurrences is None:
+            self.mRecurrences = RecurrenceSet()
+
+        # Updated cached values
+        self.mRecurrences = recurs
+
+        # Remove existing RRULE, EXRULE, RDATE &amp; EXDATE
+        self.removeProperties(definitions.cICalProperty_RRULE)
+        self.removeProperties(definitions.cICalProperty_EXRULE)
+        self.removeProperties(definitions.cICalProperty_RDATE)
+        self.removeProperties(definitions.cICalProperty_EXDATE)
+
+        # Now create properties
+        for iter in self.mRecurrences.getRules():
+            prop = Property(definitions.cICalProperty_RRULE, iter)
+            self.addProperty(prop)
+        for iter in self.getExrules():
+            prop = Property(definitions.cICalProperty_EXRULE, iter)
+            self.addProperty(prop)
+        for iter in self.mRecurrences.getDates():
+            prop = Property(definitions.cICalProperty_RDATE, iter)
+            self.addProperty(prop)
+        for iter in self.mRecurrences.getExdates():
+            prop = Property(definitions.cICalProperty_EXDATE, iter)
+            self.addProperty(prop)
+
+
+    def excludeRecurrence(self, start):
+        # Must have items
+        if self.mRecurrences is None:
+            return
+
+        # Add to recurrence set and clear cache
+        self.mRecurrences.subtract(start)
+
+        # Add property
+        prop = Property(definitions.cICalProperty_EXDATE, start)
+        self.addProperty(prop)
+
+
+    def excludeFutureRecurrence(self, start):
+        # Must have items
+        if self.mRecurrences is None:
+            return
+
+        # Adjust RRULES to end before start
+        self.mRecurrences.excludeFutureRecurrence(start)
+
+        # Remove existing RRULE &amp; RDATE
+        self.removeProperties(definitions.cICalProperty_RRULE)
+        self.removeProperties(definitions.cICalProperty_RDATE)
+
+        # Now create properties
+        for iter in self.mRecurrences.getRules():
+            prop = Property(definitions.cICalProperty_RRULE, iter)
+            self.addProperty(prop)
+        for iter in  self.mRecurrences.getDates():
+            prop = Property(definitions.cICalProperty_RDATE, iter)
+            self.addProperty(prop)
+
+
+    def initFromMaster(self):
+        # Only if not master
+        if self.recurring():
+            # Redo this to get cached values from master
+            self.finalise()
+
+            # If this component does not have its own start property, use the
+            # recurrence id
+            # i.e. the start time of this instance has not changed - something
+            # else has
+            if not self.hasProperty(definitions.cICalProperty_DTSTART):
+                self.mStart = self.mRecurrenceID
+
+            # If this component does not have its own end/duration property,
+            # the determine
+            # the end from the master duration
+            if (not self.hasProperty(definitions.cICalProperty_DTEND) and
+                not self.hasProperty(definitions.cICalProperty_DURATION)):
+                # End is based on original events settings
+                self.mEnd = self.mStart + (self.mMaster.getEnd() - self.mMaster.getStart())
+
+            # If this instance has a duration, but no start of its own, then we
+            # need to readjust the end
+            # to account for the start being changed to the recurrence id
+            elif (self.hasProperty(definitions.cICalProperty_DURATION) and
+                  not self.hasProperty(definitions.cICalProperty_DTSTART)):
+                temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
+                self.mEnd = self.mStart + temp
+
+
+    def createExpanded(self, master, recurid):
+        return ComponentExpanded(master, recurid)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendardefinitionspyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendardefinitionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/definitions.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/definitions.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/definitions.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/definitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,372 @@
</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.
+##
+
+#     5545 Components
+
+cICalComponent_VCALENDAR = &quot;VCALENDAR&quot;
+cICalComponent_VEVENT = &quot;VEVENT&quot;
+cICalComponent_VTODO = &quot;VTODO&quot;
+cICalComponent_VJOURNAL = &quot;VJOURNAL&quot;
+cICalComponent_VFREEBUSY = &quot;VFREEBUSY&quot;
+cICalComponent_VTIMEZONE = &quot;VTIMEZONE&quot;
+cICalComponent_VALARM = &quot;VALARM&quot;
+cICalComponent_STANDARD = &quot;STANDARD&quot;
+cICalComponent_DAYLIGHT = &quot;DAYLIGHT&quot;
+cICalComponent_UNKNOWN = &quot;UNKNOWN&quot;
+
+#     5545 Calendar Property Parameters
+
+#     5545 Section 3.2
+cICalParameter_ALTREP = &quot;ALTREP&quot;
+cICalParameter_CN = &quot;CN&quot;
+cICalParameter_CUTYPE = &quot;CUTYPE&quot;
+cICalParameter_DELEGATED_FROM = &quot;DELEGATED-FROM&quot;
+cICalParameter_DELEGATED_TO = &quot;DELEGATED-TO&quot;
+cICalParameter_DIR = &quot;DIR&quot;
+cICalParameter_ENCODING = &quot;ENCODING&quot;
+cICalParameter_FMTTYPE = &quot;FMTTYPE&quot;
+cICalParameter_FBTYPE = &quot;FBTYPE&quot;
+cICalParameter_LANGUAGE = &quot;LANGUAGE&quot;
+cICalParameter_MEMBER = &quot;MEMBER&quot;
+cICalParameter_PARTSTAT = &quot;PARTSTAT&quot;
+cICalParameter_RANGE = &quot;RANGE&quot;
+cICalParameter_RELATED = &quot;RELATED&quot;
+cICalParameter_RELTYPE = &quot;RELTYPE&quot;
+cICalParameter_ROLE = &quot;ROLE&quot;
+cICalParameter_RSVP = &quot;RSVP&quot;
+cICalParameter_RSVP_TRUE = &quot;TRUE&quot;
+cICalParameter_RSVP_FALSE = &quot;FALSE&quot;
+cICalParameter_SENT_BY = &quot;SENT-BY&quot;
+cICalParameter_TZID = &quot;TZID&quot;
+cICalParameter_VALUE = &quot;VALUE&quot;
+
+#     5545 Section 3.2.9
+cICalParameter_FBTYPE_FREE = &quot;FREE&quot;
+cICalParameter_FBTYPE_BUSY = &quot;BUSY&quot;
+cICalParameter_FBTYPE_BUSYUNAVAILABLE = &quot;BUSY-UNAVAILABLE&quot;
+cICalParameter_FBTYPE_BUSYTENTATIVE = &quot;BUSY-TENTATIVE&quot;
+
+#     5545 Section 3.2.12
+ePartStat_NeedsAction = 0
+ePartStat_Accepted = 1
+ePartStat_Declined = 2
+ePartStat_Tentative = 3
+ePartStat_Delegated = 4
+ePartStat_Completed = 5
+ePartStat_InProcess = 6
+
+cICalParameter_PARTSTAT_NEEDSACTION = &quot;NEEDS-ACTION&quot;
+cICalParameter_PARTSTAT_ACCEPTED = &quot;ACCEPTED&quot;
+cICalParameter_PARTSTAT_DECLINED = &quot;DECLINED&quot;
+cICalParameter_PARTSTAT_TENTATIVE = &quot;TENTATIVE&quot;
+cICalParameter_PARTSTAT_DELEGATED = &quot;DELEGATED&quot;
+cICalParameter_PARTSTAT_COMPLETED = &quot;COMPLETE&quot;
+cICalParameter_PARTSTAT_INPROCESS = &quot;IN-PROCESS&quot;
+
+#     5545 Section 3.2.13
+cICalParameter_RANGE_THISANDFUTURE = &quot;THISANDFUTURE&quot;
+cICalParameter_RANGE_THISANDPRIOR = &quot;THISANDPRIOR&quot;      # 2445 only
+
+#     5545 Section 3.2.14
+cICalParameter_RELATED_START = &quot;START&quot;
+cICalParameter_RELATED_END = &quot;END&quot;
+
+#     5545 Section 3.2.16
+ePartRole_Chair = 0
+ePartRole_Required = 1
+ePartRole_Optional = 2
+ePartRole_Non = 3
+
+cICalParameter_ROLE_CHAIR = &quot;CHAIR&quot;
+cICalParameter_ROLE_REQ_PART = &quot;REQ-PARTICIPANT&quot;
+cICalParameter_ROLE_OPT_PART = &quot;OPT-PARTICIPANT&quot;
+cICalParameter_ROLE_NON_PART = &quot;NON-PARTICIPANT&quot;
+
+#     5545 Section 3.2.3
+eCutype_Individual = 0
+eCutype_Group = 1
+eCutype_Resource = 2
+eCutype_Room = 3
+eCutype_Unknown = 4
+
+cICalParameter_CUTYPE_INDIVIDUAL = &quot;INDIVIDUAL&quot;
+cICalParameter_CUTYPE_GROUP = &quot;GROUP&quot;
+cICalParameter_CUTYPE_RESOURCE = &quot;RESOURCE&quot;
+cICalParameter_CUTYPE_ROOM = &quot;ROOM&quot;
+cICalParameter_CUTYPE_UNKNOWN = &quot;UNKNOWN&quot;
+
+#     5545 Value types
+
+#     5545 Section 3.3
+cICalValue_BINARY = &quot;BINARY&quot;
+cICalValue_BOOLEAN = &quot;BOOLEAN&quot;
+cICalValue_CAL_ADDRESS = &quot;CAL-ADDRESS&quot;
+cICalValue_DATE = &quot;DATE&quot;
+cICalValue_DATE_TIME = &quot;DATE-TIME&quot;
+cICalValue_DURATION = &quot;DURATION&quot;
+cICalValue_FLOAT = &quot;FLOAT&quot;
+cICalValue_INTEGER = &quot;INTEGER&quot;
+cICalValue_PERIOD = &quot;PERIOD&quot;
+cICalValue_RECUR = &quot;RECUR&quot;
+cICalValue_TEXT = &quot;TEXT&quot;
+cICalValue_TIME = &quot;TIME&quot;
+cICalValue_URI = &quot;URI&quot;
+cICalValue_UTC_OFFSET = &quot;UTC-OFFSET&quot;
+
+#     5545 Calendar Properties
+
+#     5545 Section  3.7
+
+cICalProperty_CALSCALE = &quot;CALSCALE&quot;
+cICalProperty_METHOD = &quot;METHOD&quot;
+cICalProperty_PRODID = &quot;PRODID&quot;
+cICalProperty_VERSION = &quot;VERSION&quot;
+
+#     Apple Extensions
+cICalProperty_XWRCALNAME = &quot;X-WR-CALNAME&quot;
+cICalProperty_XWRCALDESC = &quot;X-WR-CALDESC&quot;
+cICalProperty_XWRALARMUID = &quot;X-WR-ALARMUID&quot;
+
+#     5545 Component Property names
+
+#     5545 Section 3.8.1
+cICalProperty_ATTACH = &quot;ATTACH&quot;
+cICalProperty_CATEGORIES = &quot;CATEGORIES&quot;
+cICalProperty_CLASS = &quot;CLASS&quot;
+cICalProperty_COMMENT = &quot;COMMENT&quot;
+cICalProperty_DESCRIPTION = &quot;DESCRIPTION&quot;
+cICalProperty_GEO = &quot;GEO&quot;
+cICalProperty_LOCATION = &quot;LOCATION&quot;
+cICalProperty_PERCENT_COMPLETE = &quot;PERCENT-COMPLETE&quot;
+cICalProperty_PRIORITY = &quot;PRIORITY&quot;
+cICalProperty_RESOURCES = &quot;RESOURCES&quot;
+cICalProperty_STATUS = &quot;STATUS&quot;
+cICalProperty_SUMMARY = &quot;SUMMARY&quot;
+
+#     5545 Section 3.8.2
+cICalProperty_COMPLETED = &quot;COMPLETED&quot;
+cICalProperty_DTEND = &quot;DTEND&quot;
+cICalProperty_DUE = &quot;DUE&quot;
+cICalProperty_DTSTART = &quot;DTSTART&quot;
+cICalProperty_DURATION = &quot;DURATION&quot;
+cICalProperty_FREEBUSY = &quot;FREEBUSY&quot;
+cICalProperty_TRANSP = &quot;TRANSP&quot;
+cICalProperty_OPAQUE = &quot;OPAQUE&quot;
+cICalProperty_TRANSPARENT = &quot;TRANSPARENT&quot;
+
+#     5545 Section 3.8.3
+cICalProperty_TZID = &quot;TZID&quot;
+cICalProperty_TZNAME = &quot;TZNAME&quot;
+cICalProperty_TZOFFSETFROM = &quot;TZOFFSETFROM&quot;
+cICalProperty_TZOFFSETTO = &quot;TZOFFSETTO&quot;
+cICalProperty_TZURL = &quot;TZURL&quot;
+
+#     5545 Section 3.8.4
+cICalProperty_ATTENDEE = &quot;ATTENDEE&quot;
+cICalProperty_CONTACT = &quot;CONTACT&quot;
+cICalProperty_ORGANIZER = &quot;ORGANIZER&quot;
+cICalProperty_RECURRENCE_ID = &quot;RECURRENCE-ID&quot;
+cICalProperty_RELATED_TO = &quot;RELATED-TO&quot;
+cICalProperty_URL = &quot;URL&quot;
+cICalProperty_UID = &quot;UID&quot;
+
+#     5545 Section 3.8.5
+cICalProperty_EXDATE = &quot;EXDATE&quot;
+cICalProperty_EXRULE = &quot;EXRULE&quot;     # 2445 only
+cICalProperty_RDATE = &quot;RDATE&quot;
+cICalProperty_RRULE = &quot;RRULE&quot;
+
+#     5545 Section 3.8.6
+cICalProperty_ACTION = &quot;ACTION&quot;
+cICalProperty_REPEAT = &quot;REPEAT&quot;
+cICalProperty_TRIGGER = &quot;TRIGGER&quot;
+
+#     5545 Section 3.8.7
+cICalProperty_CREATED = &quot;CREATED&quot;
+cICalProperty_DTSTAMP = &quot;DTSTAMP&quot;
+cICalProperty_LAST_MODIFIED = &quot;LAST-MODIFIED&quot;
+cICalProperty_SEQUENCE = &quot;SEQUENCE&quot;
+
+#     5545 Section 3.8.8.3
+cICalProperty_REQUEST_STATUS = &quot;REQUEST-STATUS&quot;
+
+#     Enums
+#     Use ascending order for sensible sorting
+
+#     5545 Section 3.3.10
+
+eRecurrence_SECONDLY = 0
+eRecurrence_MINUTELY = 1
+eRecurrence_HOURLY = 2
+eRecurrence_DAILY = 3
+eRecurrence_WEEKLY = 4
+eRecurrence_MONTHLY = 5
+eRecurrence_YEARLY = 6
+
+eRecurrence_FREQ = 0
+eRecurrence_UNTIL = 1
+eRecurrence_COUNT = 2
+eRecurrence_INTERVAL = 3
+eRecurrence_BYSECOND = 4
+eRecurrence_BYMINUTE = 5
+eRecurrence_BYHOUR = 6
+eRecurrence_BYDAY = 7
+eRecurrence_BYMONTHDAY = 8
+eRecurrence_BYYEARDAY = 9
+eRecurrence_BYWEEKNO = 10
+eRecurrence_BYMONTH = 11
+eRecurrence_BYSETPOS = 12
+eRecurrence_WKST = 13
+
+cICalValue_RECUR_FREQ = &quot;FREQ&quot;
+cICalValue_RECUR_FREQ_LEN = 5
+
+cICalValue_RECUR_SECONDLY = &quot;SECONDLY&quot;
+cICalValue_RECUR_MINUTELY = &quot;MINUTELY&quot;
+cICalValue_RECUR_HOURLY = &quot;HOURLY&quot;
+cICalValue_RECUR_DAILY = &quot;DAILY&quot;
+cICalValue_RECUR_WEEKLY = &quot;WEEKLY&quot;
+cICalValue_RECUR_MONTHLY = &quot;MONTHLY&quot;
+cICalValue_RECUR_YEARLY = &quot;YEARLY&quot;
+
+cICalValue_RECUR_UNTIL = &quot;UNTIL&quot;
+cICalValue_RECUR_COUNT = &quot;COUNT&quot;
+
+cICalValue_RECUR_INTERVAL = &quot;INTERVAL&quot;
+cICalValue_RECUR_BYSECOND = &quot;BYSECOND&quot;
+cICalValue_RECUR_BYMINUTE = &quot;BYMINUTE&quot;
+cICalValue_RECUR_BYHOUR = &quot;BYHOUR&quot;
+cICalValue_RECUR_BYDAY = &quot;BYDAY&quot;
+cICalValue_RECUR_BYMONTHDAY = &quot;BYMONTHDAY&quot;
+cICalValue_RECUR_BYYEARDAY = &quot;BYYEARDAY&quot;
+cICalValue_RECUR_BYWEEKNO = &quot;BYWEEKNO&quot;
+cICalValue_RECUR_BYMONTH = &quot;BYMONTH&quot;
+cICalValue_RECUR_BYSETPOS = &quot;BYSETPOS&quot;
+cICalValue_RECUR_WKST = &quot;WKST&quot;
+
+eRecurrence_WEEKDAY_SU = 0
+eRecurrence_WEEKDAY_MO = 1
+eRecurrence_WEEKDAY_TU = 2
+eRecurrence_WEEKDAY_WE = 3
+eRecurrence_WEEKDAY_TH = 4
+eRecurrence_WEEKDAY_FR = 5
+eRecurrence_WEEKDAY_SA = 6
+
+cICalValue_RECUR_WEEKDAY_SU = &quot;SU&quot;
+cICalValue_RECUR_WEEKDAY_MO = &quot;MO&quot;
+cICalValue_RECUR_WEEKDAY_TU = &quot;TU&quot;
+cICalValue_RECUR_WEEKDAY_WE = &quot;WE&quot;
+cICalValue_RECUR_WEEKDAY_TH = &quot;TH&quot;
+cICalValue_RECUR_WEEKDAY_FR = &quot;FR&quot;
+cICalValue_RECUR_WEEKDAY_SA = &quot;SA&quot;
+
+#     5545 Section 3.8.1.11
+eStatus_VEvent_None = 0
+eStatus_VEvent_Confirmed = 1
+eStatus_VEvent_Tentative = 2
+eStatus_VEvent_Cancelled = 3
+
+eStatus_VToDo_None = 0
+eStatus_VToDo_NeedsAction = 1
+eStatus_VToDo_InProcess = 2
+eStatus_VToDo_Completed = 3
+eStatus_VToDo_Cancelled = 4
+
+eStatus_VJournal_None = 0
+eStatus_VJournal_Final = 1
+eStatus_VJournal_Draft = 2
+eStatus_VJournal_Cancelled = 3
+
+cICalProperty_STATUS_TENTATIVE = &quot;TENTATIVE&quot;
+cICalProperty_STATUS_CONFIRMED = &quot;CONFIRMED&quot;
+cICalProperty_STATUS_CANCELLED = &quot;CANCELLED&quot;
+cICalProperty_STATUS_NEEDS_ACTION = &quot;NEEDS-ACTION&quot;
+cICalProperty_STATUS_COMPLETED = &quot;COMPLETED&quot;
+cICalProperty_STATUS_IN_PROCESS = &quot;IN-PROCESS&quot;
+cICalProperty_STATUS_DRAFT = &quot;DRAFT&quot;
+cICalProperty_STATUS_FINAL = &quot;FINAL&quot;
+
+#     5545 Section 3.8.6.1
+eAction_VAlarm_Audio = 0
+eAction_VAlarm_Display = 1
+eAction_VAlarm_Email = 2
+eAction_VAlarm_Procedure = 3
+eAction_VAlarm_Unknown = 4
+
+cICalProperty_ACTION_AUDIO = &quot;AUDIO&quot;
+cICalProperty_ACTION_DISPLAY = &quot;DISPLAY&quot;
+cICalProperty_ACTION_EMAIL = &quot;EMAIL&quot;
+cICalProperty_ACTION_PROCEDURE = &quot;PROCEDURE&quot;
+
+#     Extensions: draft-daboo-calendar-availability-02
+
+#     Section 3.1
+cICalComponent_VAVAILABILITY = &quot;VAVAILABILITY&quot;
+cICalComponent_AVAILABLE = &quot;AVAILABLE&quot;
+
+#     Section 3.2
+cICalProperty_BUSYTYPE = &quot;BUSYTYPE&quot;
+
+
+#     Extensions: draft-daboo-valarm-extensions-03
+
+#     Section 5
+eAction_VAlarm_URI = 5
+cICalProperty_ACTION_URI = &quot;URI&quot;
+
+#     Section 7.1
+cICalProperty_ACKNOWLEDGED = &quot;ACKNOWLEDGED&quot;
+
+eAction_VAlarm_None = 6
+cICalProperty_ACTION_NONE = &quot;NONE&quot;
+
+
+#    Extensions: draft-york-vpoll-00.txt
+
+#    Section 4.1
+cICalParamater_PUBLIC_COMMENT = &quot;PUBLIC-COMMENT&quot;
+cICalParamater_RESPONSE = &quot;RESPONSE&quot;
+cICalParamater_STAY_INFORMED = &quot;STAY-INFORMED&quot;
+
+#    Section 4.2
+cICalProperty_ACCEPT_RESPONSE = &quot;ACCEPT-RESPONSE&quot;
+cICalProperty_POLL_ITEM_ID = &quot;POLL-ITEM-ID&quot;
+cICalProperty_POLL_WINNER = &quot;POLL-WINNER&quot;
+cICalProperty_POLL_MODE = &quot;POLL-MODE&quot;
+cICalProperty_POLL_MODE_BASIC = &quot;BASIC&quot;
+cICalProperty_POLL_PROPERTIES = &quot;POLL-PROPERTIES&quot;
+cICalProperty_VOTER = &quot;VOTER&quot;
+
+#    Section 4.3
+cICalComponent_VPOLL = &quot;VPOLL&quot;
+
+
+#     Mulberry extensions
+cICalProperty_ACTION_X_SPEAKTEXT = &quot;X-MULBERRY-SPEAK-TEXT&quot;
+cICalProperty_ALARM_X_LASTTRIGGER = &quot;X-MULBERRY-LAST-TRIGGER&quot;
+
+cICalProperty_ALARM_X_ALARMSTATUS = &quot;X-MULBERRY-ALARM-STATUS&quot;
+
+eAlarm_Status_Pending = 0
+eAlarm_Status_Completed = 1
+eAlarm_Status_Disabled = 2
+
+cICalProperty_ALARM_X_ALARMSTATUS_PENDING = &quot;PENDING&quot;
+cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED = &quot;COMPLETED&quot;
+cICalProperty_ALARM_X_ALARMSTATUS_DISABLED = &quot;DISABLED&quot;
+
+cICalParameter_ORGANIZER_X_IDENTITY = &quot;X-MULBERRY-IDENTITY&quot;
+cICalParameter_ATTENDEE_X_NEEDS_ITIP = &quot;X-MULBERRY-NEEDS-ITIP&quot;
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarfreebusypyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarfreebusypy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/freebusy.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/freebusy.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/freebusy.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/freebusy.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,56 @@
</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.
+##
+
+class FreeBusy(object):
+
+    FREE = 0
+    BUSYTENTATIVE = 1
+    BUSYUNAVAILABLE = 2
+    BUSY = 3
+
+    def __init__(self, type=None, period=None):
+
+        self.mType = type if type else FreeBusy.FREE
+        self.mPeriod = period.duplicate() if period is not None else None
+
+
+    def duplicate(self):
+        return FreeBusy(self.mType, self.mPeriod)
+
+
+    def setType(self, type):
+        self.mType = type
+
+
+    def getType(self):
+        return self.mType
+
+
+    def setPeriod(self, period):
+        self.mPeriod = period.duplicate()
+
+
+    def getPeriod(self):
+        return self.mPeriod
+
+
+    def isPeriodOverlap(self, period):
+        return self.mPeriod.isPeriodOverlap(period)
+
+
+    def resolveOverlaps(self, fb):
+        # TODO:
+        pass
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendaritipdefinitionspyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendaritipdefinitionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/itipdefinitions.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/itipdefinitions.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/itipdefinitions.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/itipdefinitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,49 @@
</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.
+##
+
+#     2446 Section 3
+
+cICalMethod_PUBLISH = &quot;PUBLISH&quot;
+cICalMethod_REQUEST = &quot;REQUEST&quot;
+cICalMethod_REFRESH = &quot;REFRESH&quot;
+cICalMethod_CANCEL = &quot;CANCEL&quot;
+cICalMethod_ADD = &quot;ADD&quot;
+cICalMethod_REPLY = &quot;REPLY&quot;
+cICalMethod_COUNTER = &quot;COUNTER&quot;
+cICalMethod_DECLINECOUNTER = &quot;DECLINECOUNTER&quot;
+
+#     2447 Section 2.4
+cICalMIMEMethod_PUBLISH = &quot;publish&quot;
+cICalMIMEMethod_REQUEST = &quot;request&quot;
+cICalMIMEMethod_REFRESH = &quot;refresh&quot;
+cICalMIMEMethod_CANCEL = &quot;cancel&quot;
+cICalMIMEMethod_ADD = &quot;add&quot;
+cICalMIMEMethod_REPLY = &quot;reply&quot;
+cICalMIMEMethod_COUNTER = &quot;counter&quot;
+cICalMIMEMethod_DECLINECOUNTER = &quot;declinecounter&quot;
+
+cICalMIMEComponent_VEVENT = &quot;vevent&quot;
+cICalMIMEComponent_VTODO = &quot;vtodo&quot;
+cICalMIMEComponent_VJOURNAL = &quot;vjournal&quot;
+cICalMIMEComponent_VFREEBUSY = &quot;vfreebusy&quot;
+cICalMIMEComponent_VAVAILABILITY = &quot;vavailability&quot;
+
+# VPOLL extensions draft-york-vpoll-00.txt
+
+#    Section 6.1
+cICalMethod_POLLSTATUS = &quot;POLLSTATUS&quot;
+cICalMIMEMethod_POLLSTATUS = &quot;pollstatus&quot;
+cICalMIMEComponent_VPOLL = &quot;vpoll&quot;
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarpropertypyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarpropertypy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/property.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/property.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/property.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,358 @@
</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.parameter import Parameter
+from pycalendar.datetime import DateTime
+from pycalendar.datetimevalue import DateTimeValue
+from pycalendar.duration import Duration
+from pycalendar.durationvalue import DurationValue
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.recurrence import Recurrence
+from pycalendar.icalendar.recurrencevalue import RecurrenceValue
+from pycalendar.icalendar.requeststatusvalue import RequestStatusValue
+from pycalendar.multivalue import MultiValue
+from pycalendar.period import Period
+from pycalendar.periodvalue import PeriodValue
+from pycalendar.property import PropertyBase
+from pycalendar.utcoffsetvalue import UTCOffsetValue
+from pycalendar.value import Value
+
+class Property(PropertyBase):
+
+    sDefaultValueTypeMap = {
+
+        # 5545 Section 3.7
+        definitions.cICalProperty_CALSCALE         : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_METHOD           : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_PRODID           : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_VERSION          : Value.VALUETYPE_TEXT,
+
+        # 5545 Section 3.8.1
+        definitions.cICalProperty_ATTACH           : Value.VALUETYPE_URI,
+        definitions.cICalProperty_CATEGORIES       : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_CLASS            : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_COMMENT          : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_DESCRIPTION      : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_GEO              : Value.VALUETYPE_FLOAT,
+        definitions.cICalProperty_LOCATION         : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_PERCENT_COMPLETE : Value.VALUETYPE_INTEGER,
+        definitions.cICalProperty_PRIORITY         : Value.VALUETYPE_INTEGER,
+        definitions.cICalProperty_RESOURCES        : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_STATUS           : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_SUMMARY          : Value.VALUETYPE_TEXT,
+
+        # 5545 Section 3.8.2
+        definitions.cICalProperty_COMPLETED : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_DTEND     : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_DUE       : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_DTSTART   : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_DURATION  : Value.VALUETYPE_DURATION,
+        definitions.cICalProperty_FREEBUSY  : Value.VALUETYPE_PERIOD,
+        definitions.cICalProperty_TRANSP    : Value.VALUETYPE_TEXT,
+
+        # 5545 Section 3.8.3
+        definitions.cICalProperty_TZID         : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_TZNAME       : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_TZOFFSETFROM : Value.VALUETYPE_UTC_OFFSET,
+        definitions.cICalProperty_TZOFFSETTO   : Value.VALUETYPE_UTC_OFFSET,
+        definitions.cICalProperty_TZURL        : Value.VALUETYPE_URI,
+
+        # 5545 Section 3.8.4
+        definitions.cICalProperty_ATTENDEE      : Value.VALUETYPE_CALADDRESS,
+        definitions.cICalProperty_CONTACT       : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_ORGANIZER     : Value.VALUETYPE_CALADDRESS,
+        definitions.cICalProperty_RECURRENCE_ID : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_RELATED_TO    : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_URL           : Value.VALUETYPE_URI,
+        definitions.cICalProperty_UID           : Value.VALUETYPE_TEXT,
+
+        # 5545 Section 3.8.5
+        definitions.cICalProperty_EXDATE : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_EXRULE : Value.VALUETYPE_RECUR, # 2445 only
+        definitions.cICalProperty_RDATE  : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_RRULE  : Value.VALUETYPE_RECUR,
+
+        # 5545 Section 3.8.6
+        definitions.cICalProperty_ACTION  : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_REPEAT  : Value.VALUETYPE_INTEGER,
+        definitions.cICalProperty_TRIGGER : Value.VALUETYPE_DURATION,
+
+        # 5545 Section 3.8.7
+        definitions.cICalProperty_CREATED       : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_DTSTAMP       : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_LAST_MODIFIED : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_SEQUENCE      : Value.VALUETYPE_INTEGER,
+
+        # 5545 Section 3.8.8
+        definitions.cICalProperty_REQUEST_STATUS : Value.VALUETYPE_TEXT,
+
+        # Extensions: draft-daboo-valarm-extensions-03
+        definitions.cICalProperty_ACKNOWLEDGED   : Value.VALUETYPE_DATETIME,
+
+        # Extensions: draft-york-vpoll-00.txt
+        # Section 4.2
+        definitions.cICalProperty_ACCEPT_RESPONSE   : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_POLL_ITEM_ID      : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_POLL_WINNER       : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_POLL_MODE         : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_POLL_PROPERTIES   : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_VOTER             : Value.VALUETYPE_CALADDRESS,
+
+        # Apple Extensions
+        definitions.cICalProperty_XWRCALNAME  : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_XWRCALDESC  : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_XWRALARMUID : Value.VALUETYPE_TEXT,
+
+        # Mulberry extensions
+        definitions.cICalProperty_ACTION_X_SPEAKTEXT  : Value.VALUETYPE_TEXT,
+        definitions.cICalProperty_ALARM_X_LASTTRIGGER : Value.VALUETYPE_DATETIME,
+        definitions.cICalProperty_ALARM_X_ALARMSTATUS : Value.VALUETYPE_TEXT,
+    }
+
+    sValueTypeMap = {
+
+        # 5545 Section 3.3
+        definitions.cICalValue_BINARY      : Value.VALUETYPE_BINARY,
+        definitions.cICalValue_BOOLEAN     : Value.VALUETYPE_BOOLEAN,
+        definitions.cICalValue_CAL_ADDRESS : Value.VALUETYPE_CALADDRESS,
+        definitions.cICalValue_DATE        : Value.VALUETYPE_DATE,
+        definitions.cICalValue_DATE_TIME   : Value.VALUETYPE_DATETIME,
+        definitions.cICalValue_DURATION    : Value.VALUETYPE_DURATION,
+        definitions.cICalValue_FLOAT       : Value.VALUETYPE_FLOAT,
+        definitions.cICalValue_INTEGER     : Value.VALUETYPE_INTEGER,
+        definitions.cICalValue_PERIOD      : Value.VALUETYPE_PERIOD,
+        definitions.cICalValue_RECUR       : Value.VALUETYPE_RECUR,
+        definitions.cICalValue_TEXT        : Value.VALUETYPE_TEXT,
+        definitions.cICalValue_TIME        : Value.VALUETYPE_TIME,
+        definitions.cICalValue_URI         : Value.VALUETYPE_URI,
+        definitions.cICalValue_UTC_OFFSET  : Value.VALUETYPE_UTC_OFFSET,
+    }
+
+    sTypeValueMap = {
+
+        # 5545 Section 3.3
+        Value.VALUETYPE_BINARY         : definitions.cICalValue_BINARY,
+        Value.VALUETYPE_BOOLEAN        : definitions.cICalValue_BOOLEAN,
+        Value.VALUETYPE_CALADDRESS     : definitions.cICalValue_CAL_ADDRESS,
+        Value.VALUETYPE_DATE           : definitions.cICalValue_DATE,
+        Value.VALUETYPE_DATETIME       : definitions.cICalValue_DATE_TIME,
+        Value.VALUETYPE_DURATION       : definitions.cICalValue_DURATION,
+        Value.VALUETYPE_FLOAT          : definitions.cICalValue_FLOAT,
+        Value.VALUETYPE_GEO            : definitions.cICalValue_FLOAT,
+        Value.VALUETYPE_INTEGER        : definitions.cICalValue_INTEGER,
+        Value.VALUETYPE_PERIOD         : definitions.cICalValue_PERIOD,
+        Value.VALUETYPE_RECUR          : definitions.cICalValue_RECUR,
+        Value.VALUETYPE_TEXT           : definitions.cICalValue_TEXT,
+        Value.VALUETYPE_REQUEST_STATUS : definitions.cICalValue_TEXT,
+        Value.VALUETYPE_TIME           : definitions.cICalValue_TIME,
+        Value.VALUETYPE_URI            : definitions.cICalValue_URI,
+        Value.VALUETYPE_UTC_OFFSET     : definitions.cICalValue_UTC_OFFSET,
+    }
+
+    sMultiValues = set((
+        definitions.cICalProperty_CATEGORIES,
+        definitions.cICalProperty_RESOURCES,
+        definitions.cICalProperty_FREEBUSY,
+        definitions.cICalProperty_EXDATE,
+        definitions.cICalProperty_RDATE,
+        definitions.cICalProperty_POLL_PROPERTIES,
+    ))
+
+    sSpecialVariants = {
+        definitions.cICalProperty_GEO : Value.VALUETYPE_GEO,
+        definitions.cICalProperty_REQUEST_STATUS: Value.VALUETYPE_REQUEST_STATUS,
+    }
+
+    sVariant = &quot;ical&quot;
+
+    sValue = definitions.cICalParameter_VALUE
+    sText = definitions.cICalValue_TEXT
+
+    def __init__(self, name=None, value=None, valuetype=None):
+
+        super(Property, self).__init__(name, value, valuetype)
+
+        # The None check speeds up .duplicate()
+        if value is None:
+            pass
+
+        # Order these based on most likely occurrence to speed up this method
+        elif isinstance(value, str):
+            self._init_attr_value_text(value, valuetype if valuetype else self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_UNKNOWN))
+
+        elif isinstance(value, DateTime):
+            self._init_attr_value_datetime(value)
+
+        elif isinstance(value, Duration):
+            self._init_attr_value_duration(value)
+
+        elif isinstance(value, Recurrence):
+            self._init_attr_value_recur(value)
+
+        elif isinstance(value, Period):
+            self._init_attr_value_period(value)
+
+        elif isinstance(value, int):
+            self._init_attr_value_int(value)
+
+        elif isinstance(value, list):
+            if name.upper() == definitions.cICalProperty_REQUEST_STATUS:
+                self._init_attr_value_requeststatus(value)
+            else:
+                period_list = False
+                if len(value) != 0:
+                    period_list = isinstance(value[0], Period)
+                if period_list:
+                    self._init_attr_value_periodlist(value)
+                else:
+                    self._init_attr_value_datetimelist(value)
+
+        elif isinstance(value, UTCOffsetValue):
+            self._init_attr_value_utcoffset(value)
+
+
+    def duplicate(self):
+        other = Property(self.mName)
+        for attrname, attrs in self.mParameters.items():
+            other.mParameters[attrname] = [i.duplicate() for i in attrs]
+        other.mValue = self.mValue.duplicate()
+
+        return other
+
+
+    def __hash__(self):
+        return hash((
+            self.mName,
+            tuple([tuple(self.mParameters[attrname]) for attrname in sorted(self.mParameters.keys())]),
+            self.mValue,
+        ))
+
+
+    def __eq__(self, other):
+        if not isinstance(other, Property):
+            return False
+        return self.mName == other.mName and self.mValue == other.mValue and self.mParameters == other.mParameters
+
+
+    def getRecurrenceValue(self):
+
+        if isinstance(self.mValue, RecurrenceValue):
+            return self.mValue
+        else:
+            return None
+
+
+    def _postCreateValue(self, value_type):
+        &quot;&quot;&quot;
+        Do some extra work after creating a value in this property.
+
+        @param value_type: the iCalendar VALUE type for this property
+        @type value_type: C{str}
+        &quot;&quot;&quot;
+
+        # Look for TZID parameter
+        if value_type in (Value.VALUETYPE_TIME, Value.VALUETYPE_DATETIME) and self.hasParameter(definitions.cICalParameter_TZID):
+            tzid = self.getParameterValue(definitions.cICalParameter_TZID)
+
+            if isinstance(self.mValue, DateTimeValue):
+                self.mValue.getValue().setTimezoneID(tzid)
+
+            elif isinstance(self.mValue, MultiValue):
+                for item in self.mValue.getValues():
+                    if isinstance(item, DateTimeValue):
+                        item.getValue().setTimezoneID(tzid)
+
+
+    # Creation
+    def _init_attr_value_requeststatus(self, reqstatus):
+        # Value
+        self.mValue = RequestStatusValue(reqstatus)
+
+        # Parameters
+        self.setupValueParameter()
+
+
+    def _init_attr_value_datetime(self, dt):
+        # Value
+        self.mValue = DateTimeValue(value=dt)
+
+        # Parameters
+        self.setupValueParameter()
+
+        # Look for timezone
+        if not dt.isDateOnly() and dt.local():
+            if definitions.cICalParameter_TZID in self.mParameters:
+                del self.mParameters[definitions.cICalParameter_TZID]
+            self.mParameters.setdefault(definitions.cICalParameter_TZID, []).append(
+                    Parameter(name=definitions.cICalParameter_TZID, value=dt.getTimezoneID()))
+
+
+    def _init_attr_value_datetimelist(self, dtl):
+        # Value
+        date_only = (len(dtl) &gt; 0) and dtl[0].isDateOnly()
+        if date_only:
+            self.mValue = MultiValue(Value.VALUETYPE_DATE)
+        else:
+            self.mValue = MultiValue(Value.VALUETYPE_DATETIME)
+
+        for dt in dtl:
+            self.mValue.addValue(DateTimeValue(dt))
+
+        # Parameters
+        self.setupValueParameter()
+
+        # Look for timezone
+        if ((len(dtl) &gt; 0)
+                and not dtl[0].isDateOnly()
+                and dtl[0].local()):
+            if definitions.cICalParameter_TZID in self.mParameters:
+                del self.mParameters[definitions.cICalParameter_TZID]
+            self.mParameters.setdefault(definitions.cICalParameter_TZID, []).append(
+                    Parameter(name=definitions.cICalParameter_TZID, value=dtl[0].getTimezoneID()))
+
+
+    def _init_attr_value_periodlist(self, periodlist):
+        # Value
+        self.mValue = MultiValue(Value.VALUETYPE_PERIOD)
+        for period in periodlist:
+            self.mValue.addValue(PeriodValue(period))
+
+        # Parameters
+        self.setupValueParameter()
+
+
+    def _init_attr_value_duration(self, du):
+        # Value
+        self.mValue = DurationValue(value=du)
+
+        # Parameters
+        self.setupValueParameter()
+
+
+    def _init_attr_value_period(self, pe):
+        # Value
+        self.mValue = PeriodValue(value=pe)
+
+        # Parameters
+        self.setupValueParameter()
+
+
+    def _init_attr_value_recur(self, recur):
+        # Value
+        self.mValue = RecurrenceValue(value=recur)
+
+        # Parameters
+        self.setupValueParameter()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarrecurrencepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarrecurrencepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/recurrence.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/recurrence.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/recurrence.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/recurrence.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,1710 @@
</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 import xmlutils
+from pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions, xmldefinitions
+from pycalendar.period import Period
+from pycalendar.valueutils import ValueMixin
+import cStringIO as StringIO
+import xml.etree.cElementTree as XML
+
+def WeekDayNumCompare_compare(w1, w2):
+
+    if w1[0] &lt; w2[0]:
+        return -1
+    elif w1[0] &gt; w2[0]:
+        return 1
+    elif w1[1] &lt; w2[1]:
+        return -1
+    elif w1[1] &gt; w2[1]:
+        return 1
+    else:
+        return 0
+
+
+
+def WeekDayNumSort_less_than(w1, w2):
+
+    return (w1[0] &lt; w2[0]) or (w1[0] == w2[0]) and (w1[1] &lt; w2[1])
+
+
+
+class Recurrence(ValueMixin):
+
+    cFreqMap = {
+        definitions.cICalValue_RECUR_SECONDLY : definitions.eRecurrence_SECONDLY,
+        definitions.cICalValue_RECUR_MINUTELY : definitions.eRecurrence_MINUTELY,
+        definitions.cICalValue_RECUR_HOURLY   : definitions.eRecurrence_HOURLY,
+        definitions.cICalValue_RECUR_DAILY    : definitions.eRecurrence_DAILY,
+        definitions.cICalValue_RECUR_WEEKLY   : definitions.eRecurrence_WEEKLY,
+        definitions.cICalValue_RECUR_MONTHLY  : definitions.eRecurrence_MONTHLY,
+        definitions.cICalValue_RECUR_YEARLY   : definitions.eRecurrence_YEARLY,
+    }
+
+    cFreqToXMLMap = {
+        definitions.eRecurrence_SECONDLY: xmldefinitions.recur_freq_secondly,
+        definitions.eRecurrence_MINUTELY: xmldefinitions.recur_freq_minutely,
+        definitions.eRecurrence_HOURLY: xmldefinitions.recur_freq_hourly,
+        definitions.eRecurrence_DAILY: xmldefinitions.recur_freq_daily,
+        definitions.eRecurrence_WEEKLY: xmldefinitions.recur_freq_weekly,
+        definitions.eRecurrence_MONTHLY: xmldefinitions.recur_freq_monthly,
+        definitions.eRecurrence_YEARLY: xmldefinitions.recur_freq_yearly,
+    }
+
+    cRecurMap = {
+        definitions.cICalValue_RECUR_FREQ       : definitions.eRecurrence_FREQ,
+        definitions.cICalValue_RECUR_UNTIL      : definitions.eRecurrence_UNTIL,
+        definitions.cICalValue_RECUR_COUNT      : definitions.eRecurrence_COUNT,
+        definitions.cICalValue_RECUR_INTERVAL   : definitions.eRecurrence_INTERVAL,
+        definitions.cICalValue_RECUR_BYSECOND   : definitions.eRecurrence_BYSECOND,
+        definitions.cICalValue_RECUR_BYMINUTE   : definitions.eRecurrence_BYMINUTE,
+        definitions.cICalValue_RECUR_BYHOUR     : definitions.eRecurrence_BYHOUR,
+        definitions.cICalValue_RECUR_BYDAY      : definitions.eRecurrence_BYDAY,
+        definitions.cICalValue_RECUR_BYMONTHDAY : definitions.eRecurrence_BYMONTHDAY,
+        definitions.cICalValue_RECUR_BYYEARDAY  : definitions.eRecurrence_BYYEARDAY,
+        definitions.cICalValue_RECUR_BYWEEKNO   : definitions.eRecurrence_BYWEEKNO,
+        definitions.cICalValue_RECUR_BYMONTH    : definitions.eRecurrence_BYMONTH,
+        definitions.cICalValue_RECUR_BYSETPOS   : definitions.eRecurrence_BYSETPOS,
+        definitions.cICalValue_RECUR_WKST       : definitions.eRecurrence_WKST,
+    }
+
+    cWeekdayMap = {
+        definitions.cICalValue_RECUR_WEEKDAY_SU : definitions.eRecurrence_WEEKDAY_SU,
+        definitions.cICalValue_RECUR_WEEKDAY_MO : definitions.eRecurrence_WEEKDAY_MO,
+        definitions.cICalValue_RECUR_WEEKDAY_TU : definitions.eRecurrence_WEEKDAY_TU,
+        definitions.cICalValue_RECUR_WEEKDAY_WE : definitions.eRecurrence_WEEKDAY_WE,
+        definitions.cICalValue_RECUR_WEEKDAY_TH : definitions.eRecurrence_WEEKDAY_TH,
+        definitions.cICalValue_RECUR_WEEKDAY_FR : definitions.eRecurrence_WEEKDAY_FR,
+        definitions.cICalValue_RECUR_WEEKDAY_SA : definitions.eRecurrence_WEEKDAY_SA,
+    }
+
+    cWeekdayRecurMap = dict([(v, k) for k, v in cWeekdayMap.items()])
+
+    cUnknownIndex = -1
+
+    def __init__(self):
+        self.init_Recurrence()
+
+
+    def duplicate(self):
+        other = Recurrence()
+
+        other.mFreq = self.mFreq
+
+        other.mUseCount = self.mUseCount
+        other.mCount = self.mCount
+        other.mUseUntil = self.mUseUntil
+        if other.mUseUntil:
+            other.mUntil = self.mUntil.duplicate()
+
+        other.mInterval = self.mInterval
+        if self.mBySeconds is not None:
+            other.mBySeconds = self.mBySeconds[:]
+        if self.mByMinutes is not None:
+            other.mByMinutes = self.mByMinutes[:]
+        if self.mByHours is not None:
+            other.mByHours = self.mByHours[:]
+        if self.mByDay is not None:
+            other.mByDay = self.mByDay[:]
+        if self.mByMonthDay is not None:
+            other.mByMonthDay = self.mByMonthDay[:]
+        if self.mByYearDay is not None:
+            other.mByYearDay = self.mByYearDay[:]
+        if self.mByWeekNo is not None:
+            other.mByWeekNo = self.mByWeekNo[:]
+        if self.mByMonth is not None:
+            other.mByMonth = self.mByMonth[:]
+        if self.mBySetPos is not None:
+            other.mBySetPos = self.mBySetPos[:]
+        other.mWeekstart = self.mWeekstart
+
+        other.mCached = self.mCached
+        if self.mCacheStart:
+            other.mCacheStart = self.mCacheStart.duplicate()
+        if self.mCacheUpto:
+            other.mCacheUpto = self.mCacheUpto.duplicate()
+        other.mFullyCached = self.mFullyCached
+        if self.mRecurrences:
+            other.mRecurrences = self.mRecurrences[:]
+
+        return other
+
+
+    def init_Recurrence(self):
+        self.mFreq = definitions.eRecurrence_YEARLY
+
+        self.mUseCount = False
+        self.mCount = 0
+
+        self.mUseUntil = False
+        self.mUntil = None
+
+        self.mInterval = 1
+        self.mBySeconds = None
+        self.mByMinutes = None
+        self.mByHours = None
+        self.mByDay = None
+        self.mByMonthDay = None
+        self.mByYearDay = None
+        self.mByWeekNo = None
+        self.mByMonth = None
+        self.mBySetPos = None
+        self.mWeekstart = definitions.eRecurrence_WEEKDAY_MO
+
+        self.mCached = False
+        self.mCacheStart = None
+        self.mCacheUpto = None
+        self.mFullyCached = False
+        self.mRecurrences = None
+
+
+    def __hash__(self):
+        return hash((
+            self.mFreq,
+            self.mUseCount,
+            self.mCount,
+            self.mUseUntil,
+            self.mUntil,
+            self.mInterval,
+            tuple(self.mBySeconds) if self.mBySeconds else None,
+            tuple(self.mByMinutes) if self.mByMinutes else None,
+            tuple(self.mByHours) if self.mByHours else None,
+            tuple(self.mByDay) if self.mByDay else None,
+            tuple(self.mByMonthDay) if self.mByMonthDay else None,
+            tuple(self.mByYearDay) if self.mByYearDay else None,
+            tuple(self.mByWeekNo) if self.mByWeekNo else None,
+            tuple(self.mByMonth) if self.mByMonth else None,
+            tuple(self.mBySetPos) if self.mBySetPos else None,
+            self.mWeekstart,
+        ))
+
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+
+    def __eq__(self, other):
+        if not isinstance(other, Recurrence):
+            return False
+        return self.equals(other)
+
+
+    def equals(self, comp):
+        return (self.mFreq == comp.mFreq) \
+                and (self.mUseCount == comp.mUseCount) and (self.mCount == comp.mCount) \
+                and (self.mUseUntil == comp.mUseUntil) and (self.mUntil == comp.mUntil) \
+                and (self.mInterval == comp.mInterval) \
+                and self.equalsNum(self.mBySeconds, comp.mBySeconds) \
+                and self.equalsNum(self.mByMinutes, comp.mByMinutes) \
+                and self.equalsNum(self.mByHours, comp.mByHours) \
+                and self.equalsDayNum(self.mByDay, comp.mByDay) \
+                and self.equalsNum(self.mByMonthDay, comp.mByMonthDay) \
+                and self.equalsNum(self.mByYearDay, comp.mByYearDay) \
+                and self.equalsNum(self.mByWeekNo, comp.mByWeekNo) \
+                and self.equalsNum(self.mByMonth, comp.mByMonth) \
+                and self.equalsNum(self.mBySetPos, comp.mBySetPos) \
+                and (self.mWeekstart == comp.mWeekstart)
+
+
+    def equalsNum(self, items1, items2):
+        # Check sizes first
+        if items1 is None:
+            items1 = []
+        if items2 is None:
+            items2 = []
+        if len(items1) != len(items2):
+            return False
+        elif len(items1) == 0:
+            return True
+
+        # Copy and sort each one for comparison
+        temp1 = items1[:]
+        temp2 = items2[:]
+        temp1.sort()
+        temp2.sort()
+
+        for i in range(0, len(temp1)):
+            if temp1[i] != temp2[i]:
+                return False
+        return True
+
+
+    def equalsDayNum(self, items1, items2):
+        # Check sizes first
+        if items1 is None:
+            items1 = []
+        if items2 is None:
+            items2 = []
+        if len(items1) != len(items2):
+            return False
+        elif len(items1) == 0:
+            return True
+
+        # Copy and sort each one for comparison
+        temp1 = items1[:]
+        temp2 = items2[:]
+        temp1.sort()
+        temp2.sort()
+
+        for i in range(0, len(temp1)):
+            if temp1[i] != temp2[i]:
+                return False
+        return True
+
+
+    def _setAndclearIfChanged(self, attr, value):
+        if getattr(self, attr) != value:
+            self.clear()
+            setattr(self, attr, value)
+
+
+    def getFreq(self):
+        return self.mFreq
+
+
+    def setFreq(self, freq):
+        self._setAndclearIfChanged(&quot;mFreq&quot;, freq)
+
+
+    def getUseUntil(self):
+        return self.mUseUntil
+
+
+    def setUseUntil(self, use_until):
+        self._setAndclearIfChanged(&quot;mUseUntil&quot;, use_until)
+
+
+    def getUntil(self):
+        return self.mUntil
+
+
+    def setUntil(self, until):
+        self._setAndclearIfChanged(&quot;mUntil&quot;, until)
+
+
+    def getUseCount(self):
+        return self.mUseCount
+
+
+    def setUseCount(self, use_count):
+        self._setAndclearIfChanged(&quot;mUseCount&quot;, use_count)
+
+
+    def getCount(self):
+        return self.mCount
+
+
+    def setCount(self, count):
+        self._setAndclearIfChanged(&quot;mCount&quot;, count)
+
+
+    def getInterval(self):
+        return self.mInterval
+
+
+    def setInterval(self, interval):
+        self._setAndclearIfChanged(&quot;mInterval&quot;, interval)
+
+
+    def getByMonth(self):
+        return self.mByMonth
+
+
+    def setByMonth(self, by):
+        self._setAndclearIfChanged(&quot;mByMonth&quot;, by[:])
+
+
+    def getByMonthDay(self):
+        return self.mByMonthDay
+
+
+    def setByMonthDay(self, by):
+        self._setAndclearIfChanged(&quot;mByMonthDay&quot;, by[:])
+
+
+    def getByYearDay(self):
+        return self.mByYearDay
+
+
+    def setByYearDay(self, by):
+        self._setAndclearIfChanged(&quot;mByYearDay&quot;, by[:])
+
+
+    def getByDay(self):
+        return self.mByDay
+
+
+    def setByDay(self, by):
+        self._setAndclearIfChanged(&quot;mByDay&quot;, by[:])
+
+
+    def getBySetPos(self):
+        return self.mBySetPos
+
+
+    def setBySetPos(self, by):
+        self._setAndclearIfChanged(&quot;mBySetPos&quot;, by[:])
+
+
+    def parse(self, data):
+        self.init_Recurrence()
+
+        # Tokenise using ''
+        tokens = data.split(&quot;;&quot;)
+        tokens.reverse()
+
+        if len(tokens) == 0:
+            raise ValueError(&quot;Recurrence: Invalid recurrence rule value&quot;)
+
+        while len(tokens) != 0:
+            # Get next token
+            token = tokens.pop()
+            try:
+                tname, tvalue = token.split(&quot;=&quot;)
+            except ValueError:
+                raise ValueError(&quot;Recurrence: Invalid token '%s'&quot; % (token,))
+
+            # Determine token type
+            index = Recurrence.cRecurMap.get(tname, Recurrence.cUnknownIndex)
+            if index == Recurrence.cUnknownIndex:
+                raise ValueError(&quot;Recurrence: Invalid token '%s'&quot; % (tname,))
+
+            # Parse remainder based on index
+            if index == definitions.eRecurrence_FREQ:
+                # Get the FREQ value
+                index = Recurrence.cFreqMap.get(tvalue, Recurrence.cUnknownIndex)
+                if index == Recurrence.cUnknownIndex:
+                    raise ValueError(&quot;Recurrence: Invalid FREQ value&quot;)
+                self.mFreq = index
+
+            elif index == definitions.eRecurrence_UNTIL:
+                if self.mUseCount:
+                    raise ValueError(&quot;Recurrence: Can't have both UNTIL and COUNT&quot;)
+                self.mUseUntil = True
+                if self.mUntil is None:
+                    self.mUntil = DateTime()
+                try:
+                    self.mUntil.parse(tvalue)
+                except ValueError:
+                    raise ValueError(&quot;Recurrence: Invalid UNTIL value&quot;)
+
+            elif index == definitions.eRecurrence_COUNT:
+                if self.mUseUntil:
+                    raise ValueError(&quot;Recurrence: Can't have both UNTIL and COUNT&quot;)
+                self.mUseCount = True
+                try:
+                    self.mCount = int(tvalue)
+                except ValueError:
+                    raise ValueError(&quot;Recurrence: Invalid COUNT value&quot;)
+
+                # Must not be less than one
+                if self.mCount &lt; 1:
+                    raise ValueError(&quot;Recurrence: Invalid COUNT value&quot;)
+
+            elif index == definitions.eRecurrence_INTERVAL:
+                try:
+                    self.mInterval = int(tvalue)
+                except ValueError:
+                    raise ValueError(&quot;Recurrence: Invalid INTERVAL value&quot;)
+
+                # Must NOT be less than one
+                if self.mInterval &lt; 1:
+                    raise ValueError(&quot;Recurrence: Invalid INTERVAL value&quot;)
+
+            elif index == definitions.eRecurrence_BYSECOND:
+                if self.mBySeconds is not None:
+                    raise ValueError(&quot;Recurrence: Only one BYSECOND allowed&quot;)
+                self.mBySeconds = []
+                self.parseList(tvalue, self.mBySeconds, 0, 60, errmsg=&quot;Recurrence: Invalid BYSECOND value&quot;)
+
+            elif index == definitions.eRecurrence_BYMINUTE:
+                if self.mByMinutes is not None:
+                    raise ValueError(&quot;Recurrence: Only one BYMINUTE allowed&quot;)
+                self.mByMinutes = []
+                self.parseList(tvalue, self.mByMinutes, 0, 59, errmsg=&quot;Recurrence: Invalid BYMINUTE value&quot;)
+
+            elif index == definitions.eRecurrence_BYHOUR:
+                if self.mByHours is not None:
+                    raise ValueError(&quot;Recurrence: Only one BYHOUR allowed&quot;)
+                self.mByHours = []
+                self.parseList(tvalue, self.mByHours, 0, 23, errmsg=&quot;Recurrence: Invalid BYHOUR value&quot;)
+
+            elif index == definitions.eRecurrence_BYDAY:
+                if self.mByDay is not None:
+                    raise ValueError(&quot;Recurrence: Only one BYDAY allowed&quot;)
+                self.mByDay = []
+                self.parseListDW(tvalue, self.mByDay, errmsg=&quot;Recurrence: Invalid BYDAY value&quot;)
+
+            elif index == definitions.eRecurrence_BYMONTHDAY:
+                if self.mByMonthDay is not None:
+                    raise ValueError(&quot;Recurrence: Only one BYMONTHDAY allowed&quot;)
+                self.mByMonthDay = []
+                self.parseList(tvalue, self.mByMonthDay, 1, 31, True, errmsg=&quot;Recurrence: Invalid BYMONTHDAY value&quot;)
+
+            elif index == definitions.eRecurrence_BYYEARDAY:
+                if self.mByYearDay is not None:
+                    raise ValueError(&quot;Recurrence: Only one BYYEARDAY allowed&quot;)
+                self.mByYearDay = []
+                self.parseList(tvalue, self.mByYearDay, 1, 366, True, errmsg=&quot;Recurrence: Invalid BYYEARDAY value&quot;)
+
+            elif index == definitions.eRecurrence_BYWEEKNO:
+                if self.mByWeekNo is not None:
+                    raise ValueError(&quot;Recurrence: Only one BYWEEKNO allowed&quot;)
+                self.mByWeekNo = []
+                self.parseList(tvalue, self.mByWeekNo, 1, 53, True, errmsg=&quot;Recurrence: Invalid BYWEEKNO value&quot;)
+
+            elif index == definitions.eRecurrence_BYMONTH:
+                if self.mByMonth is not None:
+                    raise ValueError(&quot;Recurrence: Only one BYMONTH allowed&quot;)
+                self.mByMonth = []
+                self.parseList(tvalue, self.mByMonth, 1, 12, errmsg=&quot;Recurrence: Invalid BYMONTH value&quot;)
+
+            elif index == definitions.eRecurrence_BYSETPOS:
+                if self.mBySetPos is not None:
+                    raise ValueError(&quot;Recurrence: Only one BYSETPOS allowed&quot;)
+                self.mBySetPos = []
+                self.parseList(tvalue, self.mBySetPos, allowNegative=True, errmsg=&quot;Recurrence: Invalid BYSETPOS value&quot;)
+
+            elif index == definitions.eRecurrence_WKST:
+                index = Recurrence.cWeekdayMap.get(tvalue, Recurrence.cUnknownIndex)
+                if (index == Recurrence.cUnknownIndex):
+                    raise ValueError(&quot;Recurrence: Invalid WKST value&quot;)
+                self.mWeekstart = index
+
+
+    def parseList(self, txt, list, min=None, max=None, allowNegative=False, errmsg=&quot;&quot;):
+
+        if &quot;,&quot; in txt:
+            tokens = txt.split(&quot;,&quot;)
+        else:
+            tokens = (txt,)
+
+        for token in tokens:
+            value = int(token)
+            if not allowNegative and value &lt; 0:
+                raise ValueError(errmsg)
+            avalue = abs(value)
+            if min is not None and avalue &lt; min:
+                raise ValueError(errmsg)
+            if max is not None  and avalue &gt; max:
+                raise ValueError(errmsg)
+            list.append(value)
+
+
+    def parseListDW(self, txt, list, errmsg=&quot;&quot;):
+
+        if &quot;,&quot; in txt:
+            tokens = txt.split(&quot;,&quot;)
+        else:
+            tokens = (txt,)
+
+        for token in tokens:
+            # Get number if present
+            num = 0
+            if (len(token) &gt; 0) and token[0] in &quot;+-1234567890&quot;:
+                offset = 0
+                while (offset &lt; len(token)) and token[offset] in &quot;+-1234567890&quot;:
+                    offset += 1
+
+                num = int(token[0:offset])
+                token = token[offset:]
+
+                anum = abs(num)
+                if anum &lt; 1:
+                    raise ValueError(errmsg)
+                if anum &gt; 53:
+                    raise ValueError(errmsg)
+
+            # Get day
+            index = Recurrence.cWeekdayMap.get(token, Recurrence.cUnknownIndex)
+            if (index == Recurrence.cUnknownIndex):
+                raise ValueError(errmsg)
+            wday = index
+
+            list.append((num, wday))
+
+
+    def generate(self, os):
+        try:
+            os.write(definitions.cICalValue_RECUR_FREQ)
+            os.write(&quot;=&quot;)
+
+            if self.mFreq == definitions.eRecurrence_SECONDLY:
+                os.write(definitions.cICalValue_RECUR_SECONDLY)
+
+            elif self.mFreq == definitions.eRecurrence_MINUTELY:
+                os.write(definitions.cICalValue_RECUR_MINUTELY)
+
+            elif self.mFreq == definitions.eRecurrence_HOURLY:
+                os.write(definitions.cICalValue_RECUR_HOURLY)
+
+            elif self.mFreq == definitions.eRecurrence_DAILY:
+                os.write(definitions.cICalValue_RECUR_DAILY)
+
+            elif self.mFreq == definitions.eRecurrence_WEEKLY:
+                os.write(definitions.cICalValue_RECUR_WEEKLY)
+
+            elif self.mFreq == definitions.eRecurrence_MONTHLY:
+                os.write(definitions.cICalValue_RECUR_MONTHLY)
+
+            elif self.mFreq == definitions.eRecurrence_YEARLY:
+                os.write(definitions.cICalValue_RECUR_YEARLY)
+
+            if self.mUseCount:
+                os.write(&quot;;&quot;)
+                os.write(definitions.cICalValue_RECUR_COUNT)
+                os.write(&quot;=&quot;)
+                os.write(str(self.mCount))
+            elif self.mUseUntil:
+                os.write(&quot;;&quot;)
+                os.write(definitions.cICalValue_RECUR_UNTIL)
+                os.write(&quot;=&quot;)
+                self.mUntil.generate(os)
+
+            if self.mInterval &gt; 1:
+                os.write(&quot;;&quot;)
+                os.write(definitions.cICalValue_RECUR_INTERVAL)
+                os.write(&quot;=&quot;)
+                os.write(str(self.mInterval))
+
+            self.generateList(os, definitions.cICalValue_RECUR_BYSECOND, self.mBySeconds)
+            self.generateList(os, definitions.cICalValue_RECUR_BYMINUTE, self.mByMinutes)
+            self.generateList(os, definitions.cICalValue_RECUR_BYHOUR, self.mByHours)
+
+            if (self.mByDay is not None) and (len(self.mByDay) != 0):
+                os.write(&quot;;&quot;)
+                os.write(definitions.cICalValue_RECUR_BYDAY)
+                os.write(&quot;=&quot;)
+                comma = False
+                for iter in self.mByDay:
+                    if comma:
+                        os.write(&quot;,&quot;)
+                    comma = True
+
+                    if iter[0] != 0:
+                        os.write(str(iter[0]))
+
+                    if iter[1] == definitions.eRecurrence_WEEKDAY_SU:
+                        os.write(definitions.cICalValue_RECUR_WEEKDAY_SU)
+
+                    elif iter[1] == definitions.eRecurrence_WEEKDAY_MO:
+                        os.write(definitions.cICalValue_RECUR_WEEKDAY_MO)
+
+                    elif iter[1] == definitions.eRecurrence_WEEKDAY_TU:
+                        os.write(definitions.cICalValue_RECUR_WEEKDAY_TU)
+
+                    elif iter[1] == definitions.eRecurrence_WEEKDAY_WE:
+                        os.write(definitions.cICalValue_RECUR_WEEKDAY_WE)
+
+                    elif iter[1] == definitions.eRecurrence_WEEKDAY_TH:
+                        os.write(definitions.cICalValue_RECUR_WEEKDAY_TH)
+
+                    elif iter[1] == definitions.eRecurrence_WEEKDAY_FR:
+                        os.write(definitions.cICalValue_RECUR_WEEKDAY_FR)
+
+                    elif iter[1] == definitions.eRecurrence_WEEKDAY_SA:
+                        os.write(definitions.cICalValue_RECUR_WEEKDAY_SA)
+
+            self.generateList(os, definitions.cICalValue_RECUR_BYMONTHDAY, self.mByMonthDay)
+            self.generateList(os, definitions.cICalValue_RECUR_BYYEARDAY, self.mByYearDay)
+            self.generateList(os, definitions.cICalValue_RECUR_BYWEEKNO, self.mByWeekNo)
+            self.generateList(os, definitions.cICalValue_RECUR_BYMONTH, self.mByMonth)
+            self.generateList(os, definitions.cICalValue_RECUR_BYSETPOS, self.mBySetPos)
+
+            # MO is the default so we do not need it
+            if self.mWeekstart != definitions.eRecurrence_WEEKDAY_MO:
+                os.write(&quot;;&quot;)
+                os.write(definitions.cICalValue_RECUR_WKST)
+                os.write(&quot;=&quot;)
+
+                if self.mWeekstart == definitions.eRecurrence_WEEKDAY_SU:
+                    os.write(definitions.cICalValue_RECUR_WEEKDAY_SU)
+
+                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_MO:
+                    os.write(definitions.cICalValue_RECUR_WEEKDAY_MO)
+
+                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_TU:
+                    os.write(definitions.cICalValue_RECUR_WEEKDAY_TU)
+
+                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_WE:
+                    os.write(definitions.cICalValue_RECUR_WEEKDAY_WE)
+
+                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_TH:
+                    os.write(definitions.cICalValue_RECUR_WEEKDAY_TH)
+
+                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_FR:
+                    os.write(definitions.cICalValue_RECUR_WEEKDAY_FR)
+
+                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_SA:
+                    os.write(definitions.cICalValue_RECUR_WEEKDAY_SA)
+
+        except:
+            pass
+
+
+    def generateList(self, os, title, items):
+
+        if (items is not None) and (len(items) != 0):
+            os.write(&quot;;&quot;)
+            os.write(title)
+            os.write(&quot;=&quot;)
+            comma = False
+            for e in items:
+                if comma:
+                    os.write(&quot;,&quot;)
+                comma = True
+                os.write(str(e))
+
+
+    def writeXML(self, node, namespace):
+
+        recur = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.value_recur))
+
+        freq = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_freq))
+        freq.text = self.cFreqToXMLMap[self.mFreq]
+
+        if self.mUseCount:
+            count = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_count))
+            count.text = str(self.mCount)
+        elif self.mUseUntil:
+            until = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_until))
+            self.mUntil.writeXML(until, namespace)
+
+        if self.mInterval &gt; 1:
+            interval = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_interval))
+            interval.text = str(self.mInterval)
+
+        self.writeXMLList(recur, namespace, xmldefinitions.recur_bysecond, self.mBySeconds)
+        self.writeXMLList(recur, namespace, xmldefinitions.recur_byminute, self.mByMinutes)
+        self.writeXMLList(recur, namespace, xmldefinitions.recur_byhour, self.mByHours)
+
+        if self.mByDay is not None and len(self.mByDay) != 0:
+            for iter in self.mByDay:
+                byday = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_byday))
+                data = &quot;&quot;
+                if iter[0] != 0:
+                    data = str(iter[0])
+                data += self.cWeekdayRecurMap.get(iter[1], &quot;&quot;)
+                byday.text = data
+
+        self.writeXMLList(recur, namespace, xmldefinitions.recur_bymonthday, self.mByMonthDay)
+        self.writeXMLList(recur, namespace, xmldefinitions.recur_byyearday, self.mByYearDay)
+        self.writeXMLList(recur, namespace, xmldefinitions.recur_byweekno, self.mByWeekNo)
+        self.writeXMLList(recur, namespace, xmldefinitions.recur_bymonth, self.mByMonth)
+        self.writeXMLList(recur, namespace, xmldefinitions.recur_bysetpos, self.mBySetPos)
+
+        # MO is the default so we do not need it
+        if self.mWeekstart != definitions.eRecurrence_WEEKDAY_MO:
+            wkst = XML.SubElement(recur, xmlutils.makeTag(namespace, xmldefinitions.recur_wkst))
+            wkst.text = self.cWeekdayRecurMap.get(self.mWeekstart, definitions.cICalValue_RECUR_WEEKDAY_MO)
+
+
+    def writeXMLList(self, node, namespace, name, items):
+        if items is not None and len(items) != 0:
+            for item in items:
+                child = XML.SubElement(node, xmlutils.makeTag(namespace, name))
+                child.text = str(item)
+
+
+    def parseJSON(self, jobject):
+        &quot;&quot;&quot;
+        jCal splits the value into components. We need to convert that back to the
+        iCalendar string format, then parse it.
+        &quot;&quot;&quot;
+
+        items = []
+        for name, value in jobject.items():
+            if name in (
+                &quot;bysecond&quot;, &quot;byminute&quot;, &quot;byhour&quot;,
+                &quot;bymonthday&quot;, &quot;byyearday&quot;, &quot;byweekno&quot;,
+                &quot;bymonth&quot;, &quot;bysetpos&quot;, &quot;byday&quot;,
+            ):
+                if not isinstance(value, str) and not isinstance(value, unicode) and not isinstance(value, int):
+                    value = &quot;,&quot;.join(map(str, value))
+            elif name == &quot;until&quot;:
+                value = value.replace(&quot;-&quot;, &quot;&quot;).replace(&quot;:&quot;, &quot;&quot;)
+            items.append(&quot;%s=%s&quot; % (name.upper(), value,))
+        self.parse(&quot;;&quot;.join(items))
+
+
+    def writeJSON(self, jobject):
+        &quot;&quot;&quot;
+        jCal splits the value into components. We need to convert that back to the
+        iCalendar string format, then parse it.
+        &quot;&quot;&quot;
+        jdict = {}
+
+        jdict[xmldefinitions.recur_freq] = self.cFreqToXMLMap[self.mFreq]
+
+        if self.mUseCount:
+            jdict[xmldefinitions.recur_count] = self.mCount
+        elif self.mUseUntil:
+            jdict[xmldefinitions.recur_until] = self.mUntil.getXMLText()
+
+        if self.mInterval &gt; 1:
+            jdict[xmldefinitions.recur_interval] = self.mInterval
+
+        if self.mBySeconds:
+            jdict[xmldefinitions.recur_bysecond] = self.mBySeconds
+        if self.mByMinutes:
+            jdict[xmldefinitions.recur_byminute] = self.mByMinutes
+        if self.mByHours:
+            jdict[xmldefinitions.recur_byhour] = self.mByHours
+
+        if self.mByDay is not None and len(self.mByDay) != 0:
+            items = []
+            for iter in self.mByDay:
+                data = &quot;&quot;
+                if iter[0] != 0:
+                    data = str(iter[0])
+                data += self.cWeekdayRecurMap.get(iter[1], &quot;&quot;)
+                items.append(data)
+            jdict[xmldefinitions.recur_byday] = items
+
+        if self.mByMonthDay:
+            jdict[xmldefinitions.recur_bymonthday] = self.mByMonthDay
+        if self.mByYearDay:
+            jdict[xmldefinitions.recur_byyearday] = self.mByYearDay
+        if self.mByWeekNo:
+            jdict[xmldefinitions.recur_byweekno] = self.mByWeekNo
+        if self.mByMonth:
+            jdict[xmldefinitions.recur_bymonth] = self.mByMonth
+        if self.mBySetPos:
+            jdict[xmldefinitions.recur_bysetpos] = self.mBySetPos
+
+        # MO is the default so we do not need it
+        if self.mWeekstart != definitions.eRecurrence_WEEKDAY_MO:
+            jdict[xmldefinitions.recur_wkst] = self.cWeekdayRecurMap.get(self.mWeekstart, definitions.cICalValue_RECUR_WEEKDAY_MO)
+
+        jobject.append(jdict)
+
+
+    def hasBy(self):
+        return (self.mBySeconds is not None) and (len(self.mBySeconds) != 0) \
+                or (self.mByMinutes is not None) and (len(self.mByMinutes) != 0) \
+                or (self.mByHours is not None) and (len(self.mByHours) != 0) \
+                or (self.mByDay is not None) and (len(self.mByDay) != 0) \
+                or (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0) \
+                or (self.mByYearDay is not None) and (len(self.mByYearDay) != 0) \
+                or (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0) \
+                or (self.mByMonth is not None) and (len(self.mByMonth) != 0) \
+                or (self.mBySetPos is not None) and (len(self.mBySetPos) != 0)
+
+
+    def isSimpleRule(self):
+        # One that has no BYxxx rules
+        return not self.hasBy()
+
+
+    def isAdvancedRule(self):
+        # One that has BYMONTH,
+        # BYMONTHDAY (with no negative value),
+        # BYDAY (with multiple unnumbered, or numbered with all the same number
+        # (1..4, -2, -1)
+        # BYSETPOS with +1, or -1 only
+        # no others
+
+        # First checks the ones we do not handle at all
+        if ((self.mBySeconds is not None) and (len(self.mBySeconds) != 0) \
+                or (self.mByMinutes is not None) and (len(self.mByMinutes) != 0) \
+                or (self.mByHours is not None) and (len(self.mByHours) != 0) \
+                or (self.mByYearDay is not None) and (len(self.mByYearDay) != 0) \
+                or (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0)):
+            return False
+
+        # Check BYMONTHDAY numbers (we can handle -7...-1, 1..31)
+        if self.mByMonthDay is not None:
+            for iter in self.mByMonthDay:
+                if (iter &lt; -7) or (iter &gt; 31) or (iter == 0):
+                    return False
+
+        # Check BYDAY numbers
+        if self.mByDay is not None:
+            number = 0
+            first = True
+            for iter in self.mByDay:
+
+                # Get the first number
+                if (first):
+                    number = iter[0]
+                    first = False
+
+                    # Check number range
+                    if (number &gt; 4) or (number &lt; -2):
+                        return False
+
+                # If current differs from last, then we have an error
+                elif number != iter[0]:
+                    return False
+
+        # Check BYSETPOS numbers
+        if self.mBySetPos is not None:
+            if len(self.mBySetPos) &gt; 1:
+                return False
+            if (len(self.mBySetPos) == 1) and (self.mBySetPos[0] != -1) and (self.mBySetPos[0] != 1):
+                return False
+
+        # If we get here it must be OK
+        return True
+
+
+    def getUIDescription(self):
+        try:
+            # For now just use iCal item
+            sout = StringIO()
+            self.generate(sout)
+            result = sout.getvalue()
+        except:
+            result = &quot;&quot;
+
+        return result
+
+
+    def expand(self, start, range, items, float_offset=0):
+
+        # Must have recurrence list at this point
+        if self.mRecurrences is None:
+            self.mRecurrences = []
+
+        # Wipe cache if start is different
+        if self.mCached and (start != self.mCacheStart):
+            self.mCached = False
+            self.mFullyCached = False
+            self.mRecurrences = []
+
+        # Is the current cache complete or does it extend past the requested
+        # range end
+        if not self.mCached or not self.mFullyCached \
+                and (self.mCacheUpto is None or self.mCacheUpto &lt; range.getEnd()):
+            cache_range = range.duplicate()
+
+            # If partially cached just cache from previous cache end up to new
+            # end
+            if self.mCached:
+                cache_range = Period(self.mCacheUpto, range.getEnd())
+
+            # Simple expansion is one where there is no BYXXX rule part
+            if not self.hasBy():
+                self.mFullyCached = self.simpleExpand(start, cache_range, self.mRecurrences, float_offset)
+            else:
+                self.mFullyCached = self.complexExpand(start, cache_range, self.mRecurrences, float_offset)
+
+            # Set cache values
+            self.mCached = True
+            self.mCacheStart = start
+            self.mCacheUpto = range.getEnd()
+
+        # Just return the cached items in the requested range
+        limited = not self.mFullyCached
+        for iter in self.mRecurrences:
+            if range.isDateWithinPeriod(iter):
+                items.append(iter)
+            else:
+                limited = True
+        return limited
+
+
+    def simpleExpand(self, start, range, items, float_offset):
+        start_iter = start.duplicate()
+        ctr = 0
+
+        if self.mUseUntil:
+            float_until = self.mUntil.duplicate()
+            if start.floating():
+                float_until.setTimezoneID(0)
+                float_until.offsetSeconds(float_offset)
+
+        while True:
+            # Exit if after period we want
+            if range.isDateAfterPeriod(start_iter):
+                return False
+
+            # Add current one to list
+            items.append(start_iter.duplicate())
+
+            # Get next item
+            start_iter.recur(self.mFreq, self.mInterval)
+
+            # Check limits
+            if self.mUseCount:
+                # Bump counter and exit if over
+                ctr += 1
+                if ctr &gt;= self.mCount:
+                    return True
+            elif self.mUseUntil:
+                # Exit if next item is after until (its OK if its the same as
+                # UNTIL as UNTIL is inclusive)
+                if start_iter &gt; float_until:
+                    return True
+
+
+    def complexExpand(self, start, range, items, float_offset):
+        start_iter = start.duplicate()
+        ctr = 0
+
+        if self.mUseUntil:
+            float_until = self.mUntil.duplicate()
+            if start.floating():
+                float_until.setTimezoneID(None)
+                float_until.offsetSeconds(float_offset)
+
+        # Always add the initial instance DTSTART
+        if self.mUseCount:
+            # Bump counter and exit if over
+            ctr += 1
+            if ctr &gt;= self.mCount:
+                return True
+
+        # Need to re-initialise start based on BYxxx rules
+        while True:
+            # Behaviour is based on frequency
+            set_items = []
+
+            if self.mFreq == definitions.eRecurrence_SECONDLY:
+                self.generateSecondlySet(start_iter, set_items)
+
+            elif self.mFreq == definitions.eRecurrence_MINUTELY:
+                self.generateMinutelySet(start_iter, set_items)
+
+            elif self.mFreq == definitions.eRecurrence_HOURLY:
+                self.generateHourlySet(start_iter, set_items)
+
+            elif self.mFreq == definitions.eRecurrence_DAILY:
+                self.generateDailySet(start_iter, set_items)
+
+            elif self.mFreq == definitions.eRecurrence_WEEKLY:
+                self.generateWeeklySet(start_iter, set_items)
+
+            elif self.mFreq == definitions.eRecurrence_MONTHLY:
+                self.generateMonthlySet(start_iter, set_items)
+
+            elif self.mFreq == definitions.eRecurrence_YEARLY:
+                self.generateYearlySet(start_iter, set_items)
+
+            # Always sort the set as BYxxx rules may not be sorted
+            #set_items.sort(cmp=DateTime.sort)
+            set_items.sort(key=lambda x: x.getPosixTime())
+
+            # Process each one in the generated set
+            for iter in set_items:
+
+                # Ignore if it is before the actual start - we need this
+                # because the expansion
+                # can go back in time from the real start, but we must exclude
+                # those when counting
+                # even if they are not within the requested range
+                if iter &lt; start:
+                    continue
+
+                # Exit if after period we want
+                if range.isDateAfterPeriod(iter):
+                    return False
+
+                # Exit if beyond the UNTIL limit
+                if self.mUseUntil:
+                    # Exit if next item is after until (its OK if its the same
+                    # as UNTIL as UNTIL is inclusive)
+                    if iter &gt; float_until:
+                        return True
+
+                # Special for start instance
+                if (ctr == 1) and (start == iter):
+                    continue
+
+                # Add current one to list
+                items.append(iter)
+
+                # Check limits
+                if self.mUseCount:
+                    # Bump counter and exit if over
+                    ctr += 1
+                    if ctr &gt;= self.mCount:
+                        return True
+
+            # Exit if after period we want
+            if range.isDateAfterPeriod(start_iter):
+                return False
+
+            # Get next item
+            start_iter.recur(self.mFreq, self.mInterval)
+
+
+    def clear(self):
+        self.mCached = False
+        self.mFullyCached = False
+        if self.mRecurrences is not None:
+            self.mRecurrences = []
+
+
+    # IMPORTANT ExcludeFutureRecurrence assumes mCacheStart is setup with the
+    # owning VEVENT's DTSTART
+    # Currently this method is only called when a recurrence is being removed
+    # so
+    # the recurrence data should be cached
+
+    # Exclude dates on or after the chosen one
+    def excludeFutureRecurrence(self, exclude):
+        # Expand the rule up to the exclude date
+        items = []
+        period = Period()
+        period.init(self.mCacheStart, exclude)
+        self.expand(self.mCacheStart, period, items)
+
+        # Adjust UNTIL or add one if no COUNT
+        if self.getUseUntil() or not self.getUseCount():
+            # The last one is just less than the exclude date
+            if len(items) != 0:
+                # Now use the data as the UNTIL
+                self.mUseUntil = True
+                self.mUntil = items[-1]
+
+        # Adjust COUNT
+        elif self.getUseCount():
+            # The last one is just less than the exclude date
+            self.mUseCount = True
+            self.mCount = len(items)
+
+        # Now clear out the cached set after making changes
+        self.clear()
+
+
+    def generateYearlySet(self, start, items):
+        # All possible BYxxx are valid, though some combinations are not
+
+        # Start with initial date-time
+        items.append(start.duplicate())
+
+        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+            items[:] = self.byMonthExpand(items)
+
+        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+            items[:] = self.byWeekNoExpand(items)
+
+        if (self.mByYearDay is not None) and (len(self.mByYearDay) != 0):
+            items[:] = self.byYearDayExpand(items)
+
+        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+            items[:] = self.byMonthDayExpand(items)
+
+        if (self.mByDay is not None) and (len(self.mByDay) != 0):
+            # BYDAY is complicated:
+            # if BYDAY is included with BYYEARDAY or BYMONTHDAY then it
+            # contracts the recurrence set
+            # else it expands it, but the expansion depends on the frequency
+            # and other BYxxx periodicities
+
+            if ((self.mByYearDay is not None) and (len(self.mByYearDay) != 0)) \
+                    or ((self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0)):
+                items[:] = self.byDayLimit(items)
+            elif (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+                items[:] = self.byDayExpandWeekly(items)
+            elif (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+                items[:] = self.byDayExpandMonthly(items)
+            else:
+                items[:] = self.byDayExpandYearly(items)
+
+        if (self.mByHours is not None) and (len(self.mByHours) != 0):
+            items[:] = self.byHourExpand(items)
+
+        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+            items[:] = self.byMinuteExpand(items)
+
+        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+            items[:] = self.bySecondExpand(items)
+
+        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+            items[:] = self.bySetPosLimit(items)
+
+
+    def generateMonthlySet(self, start, items):
+        # Cannot have BYYEARDAY and BYWEEKNO
+
+        # Start with initial date-time
+        items.append(start.duplicate())
+
+        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+            # BYMONTH limits the range of possible values
+            items[:] = self.byMonthLimit(items)
+            if (len(items) == 0):
+                return
+
+        # No BYWEEKNO
+
+        # No BYYEARDAY
+
+        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+            items[:] = self.byMonthDayExpand(items)
+
+        if (self.mByDay is not None) and (len(self.mByDay) != 0):
+            # BYDAY is complicated:
+            # if BYDAY is included with BYYEARDAY or BYMONTHDAY then it
+            # contracts the recurrence set
+            # else it expands it, but the expansion depends on the frequency
+            # and other BYxxx periodicities
+
+            if ((self.mByYearDay is not None) and (len(self.mByYearDay) != 0)) \
+                    or ((self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0)):
+                items[:] = self.byDayLimit(items)
+            else:
+                items[:] = self.byDayExpandMonthly(items)
+
+        if ((self.mByHours is not None) and (len(self.mByHours) != 0)):
+            items[:] = self.byHourExpand(items)
+
+        if ((self.mByMinutes is not None) and (len(self.mByMinutes) != 0)):
+            items[:] = self.byMinuteExpand(items)
+
+        if ((self.mBySeconds is not None) and (len(self.mBySeconds) != 0)):
+            items[:] = self.bySecondExpand(items)
+
+        if ((self.mBySetPos is not None) and (len(self.mBySetPos) != 0)):
+            items[:] = self.bySetPosLimit(items)
+
+
+    def generateWeeklySet(self, start, items):
+        # Cannot have BYYEARDAY and BYMONTHDAY
+
+        # Start with initial date-time
+        items.append(start.duplicate())
+
+        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+            # BYMONTH limits the range of possible values
+            items[:] = self.byMonthLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+            items[:] = self.byWeekNoLimit(items)
+            if (len(items) == 0):
+                return
+
+        # No BYYEARDAY
+
+        # No BYMONTHDAY
+
+        if (self.mByDay is not None) and (len(self.mByDay) != 0):
+            items[:] = self.byDayExpandWeekly(items)
+
+        if (self.mByHours is not None) and (len(self.mByHours) != 0):
+            items[:] = self.byHourExpand(items)
+
+        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+            items[:] = self.byMinuteExpand(items)
+
+        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+            items[:] = self.bySecondExpand(items)
+
+        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+            items[:] = self.bySetPosLimit(items)
+
+
+    def generateDailySet(self, start, items):
+        # Cannot have BYYEARDAY
+
+        # Start with initial date-time
+        items.append(start.duplicate())
+
+        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+            # BYMONTH limits the range of possible values
+            items[:] = self.byMonthLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+            items[:] = self.byWeekNoLimit(items)
+            if (len(items) == 0):
+                return
+
+        # No BYYEARDAY
+
+        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+            items[:] = self.byMonthDayLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByDay is not None) and (len(self.mByDay) != 0):
+            items[:] = self.byDayLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByHours is not None) and (len(self.mByHours) != 0):
+            items[:] = self.byHourExpand(items)
+
+        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+            items[:] = self.byMinuteExpand(items)
+
+        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+            items[:] = self.bySecondExpand(items)
+
+        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+            items[:] = self.bySetPosLimit(items)
+
+
+    def generateHourlySet(self, start, items):
+        # Cannot have BYYEARDAY
+
+        # Start with initial date-time
+        items.append(start.duplicate())
+
+        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+            # BYMONTH limits the range of possible values
+            items[:] = self.byMonthLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+            items[:] = self.byWeekNoLimit(items)
+            if (len(items) == 0):
+                return
+
+        # No BYYEARDAY
+
+        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+            items[:] = self.byMonthDayLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByDay is not None) and (len(self.mByDay) != 0):
+            items[:] = self.byDayLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByHours is not None) and (len(self.mByHours) != 0):
+            items[:] = self.byHourLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+            items[:] = self.byMinuteExpand(items)
+
+        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+            items[:] = self.bySecondExpand(items)
+
+        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+            items[:] = self.bySetPosLimit(items)
+
+
+    def generateMinutelySet(self, start, items):
+        # Cannot have BYYEARDAY
+
+        # Start with initial date-time
+        items.append(start.duplicate())
+
+        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+            # BYMONTH limits the range of possible values
+            items[:] = self.byMonthLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+            items[:] = self.byWeekNoLimit(items)
+            if (len(items) == 0):
+                return
+
+        # No BYYEARDAY
+
+        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+            items[:] = self.byMonthDayLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByDay is not None) and (len(self.mByDay) != 0):
+            items[:] = self.byDayLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByHours is not None) and (len(self.mByHours) != 0):
+            items[:] = self.byHourLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+            items[:] = self.byMinuteLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+            items[:] = self.bySecondExpand(items)
+
+        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+            items[:] = self.bySetPosLimit(items)
+
+
+    def generateSecondlySet(self, start, items):
+        # Cannot have BYYEARDAY
+
+        # Start with initial date-time
+        items.append(start.duplicate())
+
+        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
+            # BYMONTH limits the range of possible values
+            items[:] = self.byMonthLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
+            items[:] = self.byWeekNoLimit(items)
+            if (len(items) == 0):
+                return
+
+        # No BYYEARDAY
+
+        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
+            items[:] = self.byMonthDayLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByDay is not None) and (len(self.mByDay) != 0):
+            items[:] = self.byDayLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByHours is not None) and (len(self.mByHours) != 0):
+            items[:] = self.byHourLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
+            items[:] = self.byMinuteLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
+            items[:] = self.bySecondLimit(items)
+            if (len(items) == 0):
+                return
+
+        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
+            items[:] = self.bySetPosLimit(items)
+
+
+    def byMonthExpand(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYMONTH and generating a new date-time for it and
+            # insert into output
+            for iter2 in self.mByMonth:
+                temp = iter1.duplicate()
+                temp.setMonth(iter2)
+                output.append(temp)
+
+        return output
+
+
+    def byWeekNoExpand(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYWEEKNO and generating a new date-time for it and
+            # insert into output
+            for iter2 in self.mByWeekNo:
+                temp = iter1.duplicate()
+                temp.setWeekNo(iter2)
+                output.append(temp)
+
+        return output
+
+
+    def byYearDayExpand(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYYEARDAY and generating a new date-time for it
+            # and insert into output
+            for iter2 in self.mByYearDay:
+                temp = iter1.duplicate()
+                temp.setYearDay(iter2)
+                output.append(temp)
+
+        return output
+
+
+    def byMonthDayExpand(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYMONTHDAY and generating a new date-time for it
+            # and insert into output
+            for iter2 in self.mByMonthDay:
+                temp = iter1.duplicate()
+                temp.setMonthDay(iter2)
+                output.append(temp)
+
+        return output
+
+
+    def byDayExpandYearly(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYDAY and generating a new date-time for it and
+            # insert into output
+            for iter2 in self.mByDay:
+                # Numeric value means specific instance
+                if iter2[0] != 0:
+                    temp = iter1.duplicate()
+                    temp.setDayOfWeekInYear(iter2[0], iter2[1])
+                    output.append(temp)
+                else:
+                    # Every matching day in the year
+                    for  i in range(1, 54):
+                        temp = iter1.duplicate()
+                        temp.setDayOfWeekInYear(i, iter2[1])
+                        if temp.getYear() == (iter1).getYear():
+                            output.append(temp)
+
+        return output
+
+
+    def byDayExpandMonthly(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYDAY and generating a new date-time for it and
+            # insert into output
+            for iter2 in self.mByDay:
+                # Numeric value means specific instance
+                if iter2[0] != 0:
+                    temp = iter1.duplicate()
+                    temp.setDayOfWeekInMonth(iter2[0], iter2[1])
+                    output.append(temp)
+                else:
+                    # Every matching day in the month
+                    for i in range(1, 7):
+                        temp = iter1.duplicate()
+                        temp.setDayOfWeekInMonth(i, iter2[1])
+                        if temp.getMonth() == iter1.getMonth():
+                            output.append(temp)
+
+        return output
+
+
+    def byDayExpandWeekly(self, dates):
+        # Must take into account the WKST value
+
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYDAY and generating a new date-time for it and
+            # insert into output
+            for iter2 in self.mByDay:
+                # Numeric values are meaningless so ignore them
+                if iter2[0] == 0:
+                    temp = iter1.duplicate()
+
+                    # Determine amount of offset to apply to temp to shift it
+                    # to the start of the week (backwards)
+                    week_start_offset = self.mWeekstart - temp.getDayOfWeek()
+                    if week_start_offset &gt; 0:
+                        week_start_offset -= 7
+
+                    # Determine amount of offset from the start of the week to
+                    # the day we want (forwards)
+                    day_in_week_offset = iter2[1] - self.mWeekstart
+                    if day_in_week_offset &lt; 0:
+                        day_in_week_offset += 7
+
+                    # Apply offsets
+                    temp.offsetDay(week_start_offset + day_in_week_offset)
+                    output.append(temp)
+
+        return output
+
+
+    def byHourExpand(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYHOUR and generating a new date-time for it and
+            # insert into output
+            for iter2 in self.mByHours:
+                temp = iter1.duplicate()
+                temp.setHours(iter2)
+                output.append(temp)
+
+        return output
+
+
+    def byMinuteExpand(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYMINUTE and generating a new date-time for it and
+            # insert into output
+            for iter2 in self.mByMinutes:
+                temp = iter1.duplicate()
+                temp.setMinutes(iter2)
+                output.append(temp)
+
+        return output
+
+
+    def bySecondExpand(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYSECOND and generating a new date-time for it and
+            # insert into output
+            for iter2 in self.mBySeconds:
+                temp = iter1.duplicate()
+                temp.setSeconds(iter2)
+                output.append(temp)
+
+        return output
+
+
+    def byMonthLimit(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYMONTH and indicate keep if input month matches
+            keep = False
+            for iter2 in self.mByMonth:
+                keep = (iter1.getMonth() == iter2)
+                if keep:
+                    break
+
+            if keep:
+                output.append(iter1)
+
+        return output
+
+
+    def byWeekNoLimit(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYWEEKNO and indicate keep if input month matches
+            keep = False
+            for iter2 in self.mByWeekNo:
+                keep = iter1.isWeekNo(iter2)
+                if keep:
+                    break
+
+            if keep:
+                output.append(iter1)
+
+        return output
+
+
+    def byMonthDayLimit(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYMONTHDAY and indicate keep if input month
+            # matches
+            keep = False
+            for iter2 in self.mByMonthDay:
+                keep = iter1.isMonthDay(iter2)
+                if keep:
+                    break
+
+            if keep:
+                output.append(iter1)
+
+        return output
+
+
+    def byDayLimit(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYDAY and indicate keep if input month matches
+            keep = False
+            for iter2 in self.mByDay:
+                keep = iter1.isDayOfWeekInMonth(iter2[0], iter2[1])
+                if keep:
+                    break
+
+            if keep:
+                output.append(iter1)
+
+        return output
+
+
+    def byHourLimit(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYHOUR and indicate keep if input hour matches
+            keep = False
+            for iter2 in self.mByHours:
+                keep = (iter1.getHours() == iter2)
+                if keep:
+                    break
+
+            if keep:
+                output.append(iter1)
+
+        return output
+
+
+    def byMinuteLimit(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYMINUTE and indicate keep if input minute matches
+            keep = False
+            for iter2 in self.mByMinutes:
+                keep = (iter1.getMinutes() == iter2)
+                if keep:
+                    break
+
+            if keep:
+                output.append(iter1)
+
+        return output
+
+
+    def bySecondLimit(self, dates):
+        # Loop over all input items
+        output = []
+        for iter1 in dates:
+            # Loop over each BYSECOND and indicate keep if input second matches
+            keep = False
+            for iter2 in self.mBySeconds:
+                keep = (iter1.getSeconds() == iter2)
+                if keep:
+                    break
+
+            if keep:
+                output.append(iter1)
+
+        return output
+
+
+    def bySetPosLimit(self, dates):
+        # The input dates MUST be sorted in order for this to work properly
+        #dates.sort(cmp=DateTime.sort)
+        dates.sort(key=lambda x: x.getPosixTime())
+
+        # Loop over each BYSETPOS and extract the relevant component from the
+        # input array and add to the output
+        output = []
+        input_size = len(dates)
+        for iter in self.mBySetPos:
+            if iter &gt; 0:
+                # Positive values are offset from the start
+                if iter &lt;= input_size:
+                    output.append(dates[iter - 1])
+            elif iter &lt; 0:
+                # Negative values are offset from the end
+                if -iter &lt;= input_size:
+                    output.append(dates[input_size + iter])
+
+        return output
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarrecurrencesetpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarrecurrencesetpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/recurrenceset.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/recurrenceset.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/recurrenceset.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/recurrenceset.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,312 @@
</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.utils import set_difference
+
+class RecurrenceSet(object):
+
+    def __init__(self):
+        self.mRrules = []
+        self.mExrules = []
+        self.mRdates = []
+        self.mExdates = []
+        self.mRperiods = []
+        self.mExperiods = []
+
+
+    def duplicate(self):
+        other = RecurrenceSet()
+        other.mRrules = [i.duplicate() for i in self.mRrules]
+        other.mExrules = [i.duplicate() for i in self.mExrules]
+        other.mRdates = [i.duplicate() for i in self.mRdates]
+        other.mExdates = [i.duplicate() for i in self.mExdates]
+        other.mRperiods = [i.duplicate() for i in self.mRperiods]
+        other.mExperiods = [i.duplicate() for i in self.mExperiods]
+        return other
+
+
+    def hasRecurrence(self):
+        return ((len(self.mRrules) != 0) or (len(self.mRdates) != 0) or (len(self.mRperiods) != 0)
+                    or (len(self.mExrules) != 0) or (len(self.mExdates) != 0)
+                    or (len(self.mExperiods) != 0))
+
+
+    def equals(self, comp):
+        # Look at RRULEs
+        if not self.equalsRules(self.mRrules, comp.self.mRrules):
+            return False
+
+        # Look at EXRULEs
+        if not self.equalsRules(self.mExrules, comp.self.mExrules):
+            return False
+
+        # Look at RDATEs
+        if not self.equalsDates(self.mRdates, comp.self.mRdates):
+            return False
+        if not self.equalsPeriods(self.mRperiods, comp.self.mRperiods):
+            return False
+
+        # Look at EXDATEs
+        if not self.equalsDates(self.mExdates, comp.self.mExdates):
+            return False
+        if not self.equalsPeriods(self.mExperiods, comp.self.mExperiods):
+            return False
+
+        # If we get here they match
+        return True
+
+
+    def equalsRules(self, rules1, rules2):
+        # Check sizes first
+        if len(rules1) != len(rules2):
+            return False
+        elif len(rules1) == 0:
+            return True
+
+        # Do sledge hammer O(n^2) approach as its not easy to sort these things
+        # for a smarter test.
+        # In most cases there will only be one rule anyway, so this should not
+        # be too painful.
+
+        temp2 = rules2[:]
+
+        for r1 in rules1:
+            found = False
+            for r2 in temp2:
+                if r1.equals(r2):
+                    # Remove the one found so it is not tested again
+                    temp2.remove(r2)
+                    found = True
+                    break
+
+            if not found:
+                return False
+
+        return True
+
+
+    def equalsDates(self, dates1, dates2):
+        # Check sizes first
+        if len(dates1) != len(dates2):
+            return False
+        elif len(dates1) == 0:
+            return True
+
+        # Copy each and sort for comparison
+        dt1 = dates1[:]
+        dt2 = dates2[:]
+
+        dt1.sort(key=lambda x: x.getPosixTime())
+        dt2.sort(key=lambda x: x.getPosixTime())
+
+        return dt1.equal(dt2)
+
+
+    def equalsPeriods(self, periods1, periods2):
+        # Check sizes first
+        if len(periods1) != len(periods2):
+            return False
+        elif len(periods1) == 0:
+            return True
+
+        # Copy each and sort for comparison
+        p1 = periods1[:]
+        p2 = periods2[:]
+
+        p1.sort()
+        p2.sort()
+
+        return p1.equal(p2)
+
+
+    def addRule(self, rule):
+        self.mRrules.append(rule)
+
+
+    def subtractRule(self, rule):
+        self.mExrules.append(rule)
+
+
+    def addDT(self, dt):
+        self.mRdates.append(dt)
+
+
+    def subtractDT(self, dt):
+        self.mExdates.append(dt)
+
+
+    def addPeriod(self, p):
+        self.mRperiods.append(p)
+
+
+    def subtractPeriod(self, p):
+        self.mExperiods.append(p)
+
+
+    def getRules(self):
+        return self.mRrules
+
+
+    def getExrules(self):
+        return self.mExrules
+
+
+    def getDates(self):
+        return self.mRdates
+
+
+    def getExdates(self):
+        return self.mExdates
+
+
+    def getPeriods(self):
+        return self.mRperiods
+
+
+    def getExperiods(self):
+        return self.mExperiods
+
+
+    def expand(self, start, range, items, float_offset=0):
+        # Need to return whether the limit was applied or not
+        limited = False
+
+        # Now create list of items to include
+        include = []
+
+        # Always include the initial DTSTART if within the range
+        if range.isDateWithinPeriod(start):
+            include.append(start)
+        else:
+            limited = True
+
+        # RRULES
+        for iter in self.mRrules:
+            if iter.expand(start, range, include, float_offset=float_offset):
+                limited = True
+
+        # RDATES
+        for iter in self.mRdates:
+            if range.isDateWithinPeriod(iter):
+                include.append(iter)
+            else:
+                limited = True
+        for iter in self.mRperiods:
+            if range.isPeriodOverlap(iter):
+                include.append(iter.getStart())
+            else:
+                limited = True
+
+        # Make sure the list is unique
+        include = [x for x in set(include)]
+        include.sort(key=lambda x: x.getPosixTime())
+
+        # Now create list of items to exclude
+        exclude = []
+
+        # EXRULES
+        for iter in self.mExrules:
+            iter.expand(start, range, exclude, float_offset=float_offset)
+
+        # EXDATES
+        for iter in self.mExdates:
+            if range.isDateWithinPeriod(iter):
+                exclude.append(iter)
+        for iter in self.mExperiods:
+            if range.isPeriodOverlap(iter):
+                exclude.append(iter.getStart())
+
+        # Make sure the list is unique
+        exclude = [x for x in set(exclude)]
+        exclude.sort(key=lambda x: x.getPosixTime())
+
+        # Add difference between to the two sets (include - exclude) to the
+        # results
+        items.extend(set_difference(include, exclude))
+        return limited
+
+
+    def changed(self):
+        # RRULES
+        for iter in self.mRrules:
+            iter.clear()
+
+        # EXRULES
+        for iter in self.mExrules:
+            iter.clear()
+
+
+    def excludeFutureRecurrence(self, exclude):
+        # Adjust RRULES to end before start
+        for iter in self.mRrules:
+            iter.excludeFutureRecurrence(exclude)
+
+        # Remove RDATES on or after start
+        self.mRdates.removeOnOrAfter(exclude)
+        for iter in self.mRperiods:
+            if iter &gt; exclude:
+                self.mRperiods.remove(iter)
+
+
+    # UI operations
+    def isSimpleUI(self):
+        # Right now the Event dialog only handles a single RRULE (but we allow
+        # any number of EXDATES as deleted
+        # instances will appear as EXDATES)
+        if ((len(self.mRrules) &gt; 1) or (len(self.mExrules) &gt; 0)
+                or (len(self.mRdates) &gt; 0) or (len(self.mRperiods) &gt; 0)):
+            return False
+
+        # Also, check the rule iteself
+        elif len(self.mRrules) == 1:
+            return self.mRrules.firstElement().isSimpleRule()
+        else:
+            return True
+
+
+    def isAdvancedUI(self):
+        # Right now the Event dialog only handles a single RRULE
+        if ((len(self.mRrules) &gt; 1) or (len(self.mExrules) &gt; 0)
+                or (len(self.mRdates) &gt; 0) or (len(self.mRperiods) &gt; 0)):
+            return False
+
+        # Also, check the rule iteself
+        elif len(self.mRrules) == 1:
+            return self.mRrules.firstElement().isAdvancedRule()
+        else:
+            return True
+
+
+    def getUIRecurrence(self):
+        if len(self.mRrules) == 1:
+            return self.mRrules[0]
+        else:
+            return None
+
+
+    def getUIDescription(self):
+        # Check for anything
+        if not self.hasRecurrence():
+            return &quot;No Recurrence&quot;
+
+        # Look for a single RRULE and return its descriptor
+        if ((len(self.mRrules) == 1) and (len(self.mExrules) == 0) and (len(self.mRdates) == 0)
+                and (len(self.mExdates) == 0) and (len(self.mRperiods) == 0)
+                and (len(self.mExperiods) == 0)):
+            return self.mRrules.firstElement().getUIDescription()
+
+        # Indicate some form of complex recurrence
+        return &quot;Multiple recurrence rules, dates or exclusions&quot;
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarrecurrencevaluepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarrecurrencevaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/recurrencevalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/recurrencevalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/recurrencevalue.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/recurrencevalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,30 @@
</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.icalendar import xmldefinitions
+from pycalendar.icalendar.recurrence import Recurrence
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
+
+class RecurrenceValue(WrapperValue, Value):
+
+    _wrappedClass = Recurrence
+    _wrappedType = Value.VALUETYPE_RECUR
+
+    def writeXML(self, node, namespace):
+        self.mValue.writeXML(node, namespace)
+
+Value.registerType(Value.VALUETYPE_RECUR, RecurrenceValue, xmldefinitions.value_recur)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarrequeststatusvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarrequeststatusvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/requeststatusvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/requeststatusvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/requeststatusvalue.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/requeststatusvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,117 @@
</span><ins>+##
+#    Copyright (c) 2011-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.
+##
+
+# iCalendar REQUEST-STATUS value
+
+from pycalendar import utils, xmlutils
+from pycalendar.icalendar import xmldefinitions
+from pycalendar.parser import ParserContext
+from pycalendar.value import Value
+from pycalendar import xmldefinitions as xmldefinitions_top
+import xml.etree.cElementTree as XML
+
+class RequestStatusValue(Value):
+    &quot;&quot;&quot;
+    The value is a list of strings (either 2 or 3 items)
+    &quot;&quot;&quot;
+
+    def __init__(self, value=None):
+        self.mValue = value if value is not None else [&quot;2.0&quot;, &quot;Success&quot;]
+
+
+    def __hash__(self):
+        return hash(tuple(self.mValue))
+
+
+    def duplicate(self):
+        return RequestStatusValue(self.mValue[:])
+
+
+    def getType(self):
+        return Value.VALUETYPE_REQUEST_STATUS
+
+
+    def parse(self, data, variant=&quot;icalendar&quot;):
+
+        result = utils.parseTextList(data, always_list=True)
+        if len(result) == 1:
+            if ParserContext.INVALID_REQUEST_STATUS_VALUE != ParserContext.PARSER_RAISE:
+                if &quot;;&quot; in result[0]:
+                    code, desc = result[0].split(&quot;;&quot;, 1)
+                else:
+                    code = result[0]
+                    desc = &quot;&quot;
+                rest = None
+            else:
+                raise ValueError
+        elif len(result) == 2:
+            code, desc = result
+            rest = None
+        elif len(result) == 3:
+            code, desc, rest = result
+        else:
+            if ParserContext.INVALID_REQUEST_STATUS_VALUE != ParserContext.PARSER_RAISE:
+                code, desc, rest = result[:3]
+            else:
+                raise ValueError
+
+        if &quot;\\&quot; in code and ParserContext.INVALID_REQUEST_STATUS_VALUE in (ParserContext.PARSER_IGNORE, ParserContext.PARSER_FIX):
+            code = code.replace(&quot;\\&quot;, &quot;&quot;)
+        elif ParserContext.INVALID_REQUEST_STATUS_VALUE == ParserContext.PARSER_RAISE:
+            raise ValueError
+
+        # Decoding required
+        self.mValue = [code, desc, rest, ] if rest else [code, desc, ]
+
+
+    # os - StringIO object
+    def generate(self, os):
+        utils.generateTextList(os, self.mValue if len(self.mValue) &lt; 3 or self.mValue[2] else self.mValue[:2])
+
+
+    def writeXML(self, node, namespace):
+        value = self.getXMLNode(node, namespace)
+
+        code = XML.SubElement(value, xmlutils.makeTag(namespace, xmldefinitions.req_status_code))
+        code.text = self.mValue[0]
+
+        description = XML.SubElement(value, xmlutils.makeTag(namespace, xmldefinitions.req_status_description))
+        description.text = self.mValue[1]
+
+        if len(self.mValue) == 3 and self.mValue[2]:
+            data = XML.SubElement(value, xmlutils.makeTag(namespace, xmldefinitions.req_status_data))
+            data.text = self.mValue[2]
+
+
+    def parseJSONValue(self, jobject):
+        self.mValue = jobject
+
+
+    def writeJSONValue(self, jobject):
+        value = [self.mValue[0], self.mValue[1]]
+        if len(self.mValue) == 3:
+            value.append(self.mValue[2])
+        jobject.append(value)
+
+
+    def getValue(self):
+        return self.mValue
+
+
+    def setValue(self, value):
+        self.mValue = value
+
+Value.registerType(Value.VALUETYPE_REQUEST_STATUS, RequestStatusValue, None, xmldefinitions_top.value_text)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendartests__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/icalendar/tests/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> #
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_calendarpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_calendarpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_calendar.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_calendar.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_calendar.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_calendar.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,854 @@
</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.exceptions import InvalidData
+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.icalendar.property import Property
+from pycalendar.parser import ParserContext
+from pycalendar.period import Period
+import cStringIO as StringIO
+import difflib
+import unittest
+
+class TestCalendar(unittest.TestCase):
+
+    data = (
+&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+&quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+X-WR-CALNAME:PayDay
+BEGIN:VTIMEZONE
+TZID:US/Eastern
+LAST-MODIFIED:20040110T032845Z
+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
+UID:DC3D0301C7790B38631F1FBB@ninevah.local
+DTSTART;VALUE=DATE:20040227
+DTSTAMP:20050211T173501Z
+RRULE:FREQ=MONTHLY;BYDAY=-1MO,-1TU,-1WE,-1TH,-1FR;BYSETPOS=-1
+SUMMARY:PAY DAY
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:Alarm for Organizer!
+TRIGGER;RELATED=START:-PT15M
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+&quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2@example.com
+EXDATE:20081114T000000Z
+ORGANIZER:mailto:user1@example.com
+RRULE:FREQ=YEARLY
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+ATTACH:http://example.com/test.jpg
+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:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+ATTACH;ENCODING=BASE64;VALUE=BINARY:dGVzdA==
+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:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+BEGIN:VTIMEZONE
+TZID:America/Montreal
+LAST-MODIFIED:20040110T032845Z
+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:VAVAILABILITY
+UID:20061005T133225Z-00001-availability@example.com
+DTSTART;TZID=America/Montreal:20060101T000000
+DTEND;TZID=America/Montreal:20060108T000000
+DTSTAMP:20061005T133225Z
+ORGANIZER:mailto:bernard@example.com
+BEGIN:AVAILABLE
+UID:20061005T133225Z-00001-A-availability@example.com
+DTSTART;TZID=America/Montreal:20060102T090000
+DTEND;TZID=America/Montreal:20060102T120000
+DTSTAMP:20061005T133225Z
+RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR
+SUMMARY:Monday\\, Wednesday and Friday from 9:00 to 12:00
+END:AVAILABLE
+BEGIN:AVAILABLE
+UID:20061005T133225Z-00001-A-availability@example.com
+RECURRENCE-ID;TZID=America/Montreal:20060106T090000
+DTSTART;TZID=America/Montreal:20060106T120000
+DTEND;TZID=America/Montreal:20060106T170000
+DTSTAMP:20061005T133225Z
+SUMMARY:Friday override from 12:00 to 17:00
+END:AVAILABLE
+END:VAVAILABILITY
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+&quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+BEGIN:VTODO
+UID:event1@ninevah.local
+CREATED:20060101T150000Z
+DTSTAMP:20051222T205953Z
+SUMMARY:event 1
+END:VTODO
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+BEGIN:X-COMPONENT
+UID:1234
+END:X-COMPONENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+&quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:uid4
+DTSTART;TZID=US/Pacific:20100207T170000
+DTEND;TZID=US/Pacific:20100207T173000
+CREATED:20100203T013849Z
+DTSTAMP:20100203T013909Z
+SEQUENCE:3
+SUMMARY:New Event
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:AUDIO
+ATTACH:Basso
+TRIGGER:-PT20M
+X-WR-ALARMUID:1377CCC7-F85C-4610-8583-9513D4B364E1
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+ATTACH:http://example.com/test.jpg
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+X-APPLE-STRUCTURED-LOCATION:geo:123.123,123.123
+X-Test:Some\, text.
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+ATTACH:http://example.com/test.jpg
+DTSTAMP:20020101T000000Z
+SUMMARY:New Year's Day
+X-APPLE-STRUCTURED-LOCATION;VALUE=URI:geo:123.123,123.123
+X-Test:Some\, text.
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+)
+    data2 = (
+                (
+&quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2@example.com
+EXDATE:20081114T000000Z
+ORGANIZER:mailto:user1@example.com
+RRULE:FREQ=YEARLY
+END:VEVENT
+X-TEST:Testing
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+&quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+X-TEST:Testing
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2@example.com
+EXDATE:20081114T000000Z
+ORGANIZER:mailto:user1@example.com
+RRULE:FREQ=YEARLY
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                ),
+)
+
+
+    def testRoundtrip(self):
+
+
+        def _doRoundtrip(caldata, resultdata=None):
+            test1 = resultdata if resultdata is not None else caldata
+
+            cal = Calendar()
+            cal.parse(StringIO.StringIO(caldata))
+
+            s = StringIO.StringIO()
+            cal.generate(s)
+            test2 = s.getvalue()
+
+            self.assertEqual(
+                test1,
+                test2,
+                &quot;\n&quot;.join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+            )
+
+        for item in self.data:
+            _doRoundtrip(item)
+
+        for item1, item2 in self.data2:
+            _doRoundtrip(item1, item2)
+
+
+    def testRoundtripDuplicate(self):
+
+
+        def _doDuplicateRoundtrip(caldata):
+            cal = Calendar()
+            cal.parse(StringIO.StringIO(caldata))
+            cal = cal.duplicate()
+
+            s = StringIO.StringIO()
+            cal.generate(s)
+            self.assertEqual(caldata, s.getvalue())
+
+        for item in self.data:
+            _doDuplicateRoundtrip(item)
+
+
+    def testEquality(self):
+
+
+        def _doEquality(caldata):
+            cal1 = Calendar()
+            cal1.parse(StringIO.StringIO(caldata))
+
+            cal2 = Calendar()
+            cal2.parse(StringIO.StringIO(caldata))
+
+            self.assertEqual(cal1, cal2, &quot;%s\n\n%s&quot; % (cal1, cal2,))
+
+
+        def _doNonEquality(caldata):
+            cal1 = Calendar()
+            cal1.parse(StringIO.StringIO(caldata))
+
+            cal2 = Calendar()
+            cal2.parse(StringIO.StringIO(caldata))
+            cal2.addProperty(Property(&quot;X-FOO&quot;, &quot;BAR&quot;))
+
+            self.assertNotEqual(cal1, cal2)
+
+        for item in self.data:
+            _doEquality(item)
+            _doNonEquality(item)
+
+
+    def testParseComponent(self):
+
+        data1 = &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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;)
+
+        data2 = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Example Inc.//Example Calendar//EN
+BEGIN:VTIMEZONE
+TZID:America/Montreal
+LAST-MODIFIED:20040110T032845Z
+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
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;)
+
+        result = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VTIMEZONE
+TZID:America/Montreal
+LAST-MODIFIED:20040110T032845Z
+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
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;)
+
+        cal = Calendar()
+        cal.parse(StringIO.StringIO(data1))
+        cal.parseComponent(StringIO.StringIO(data2))
+        self.assertEqual(str(cal), result)
+
+
+    def testParseFail(self):
+
+        data = (
+&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+&quot;&quot;&quot;BEGIN:VCARD
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+VERSION:2.0
+END:VCARD
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+&quot;&quot;&quot;BOGUS
+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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+&quot;&quot;&quot;BOGUS
+
+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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+BOGUS
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+
+BOGUS
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+        )
+
+        for item in data:
+            self.assertRaises(InvalidData, Calendar.parseText, item)
+
+
+    def testParseBlank(self):
+
+        data = (
+&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+
+
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+        )
+
+        save = ParserContext.BLANK_LINES_IN_DATA
+        for item in data:
+            ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_RAISE
+            self.assertRaises(InvalidData, Calendar.parseText, item)
+
+            ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_IGNORE
+            lines = item.split(&quot;\r\n&quot;)
+            result = &quot;\r\n&quot;.join([line for line in lines if line]) + &quot;\r\n&quot;
+            self.assertEqual(str(Calendar.parseText(item)), result)
+
+        ParserContext.BLANK_LINES_IN_DATA = save
+
+
+    def testGetVEvents(self):
+
+        data = (
+            (
+                &quot;Non-recurring match&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;),
+                (DateTime(2011, 6, 1),),
+            ),
+            (
+                &quot;Non-recurring no-match&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:20110501
+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;Recurring match&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;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                (
+                    DateTime(2011, 6, 1),
+                    DateTime(2011, 6, 2),
+                ),
+            ),
+            (
+                &quot;Recurring no match&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:20110501
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                (),
+            ),
+            (
+                &quot;Recurring with override match&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:20110601T120000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110602T120000
+DTSTART;VALUE=DATE:20110602T130000
+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, 1, 12, 0, 0),
+                    DateTime(2011, 6, 2, 13, 0, 0),
+                ),
+            ),
+            (
+                &quot;Recurring with override no match&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:20110501T120000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110502T120000
+DTSTART;VALUE=DATE:20110502T130000
+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;Recurring partial match&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:20110531
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+                (
+                    DateTime(2011, 6, 1),
+                ),
+            ),
+            (
+                &quot;Recurring with override partial match&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:20110531T120000
+DURATION:P1D
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=DAILY;COUNT=2
+SUMMARY:New Year's Day
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+RECURRENCE-ID;VALUE=DATE:20110601T120000
+DTSTART;VALUE=DATE:20110601T130000
+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, 1, 13, 0, 0),
+                ),
+            ),
+        )
+
+        for title, caldata, result in data:
+            calendar = Calendar.parseText(caldata)
+            instances = []
+            calendar.getVEvents(
+                Period(
+                    start=DateTime(2011, 6, 1),
+                    end=DateTime(2011, 7, 1),
+                ),
+                instances
+            )
+            instances = tuple([instance.getInstanceStart() for instance in instances])
+            self.assertEqual(instances, result, &quot;Failed in %s: got %s, expected %s&quot; % (title, instances, result))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_componentrecurpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_componentrecurpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_componentrecur.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_componentrecur.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_componentrecur.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_componentrecur.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,66 @@
</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.icalendar.calendar import Calendar
+import cStringIO as StringIO
+import unittest
+
+class TestCalendar(unittest.TestCase):
+
+    def testDuplicateWithRecurrenceChange(self):
+
+        data = (
+&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;COUNT=400
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+)
+
+        cal1 = Calendar()
+        cal1.parse(StringIO.StringIO(data[0]))
+        cal2 = cal1.duplicate()
+        vevent = cal2.getComponents()[0]
+        rrules = vevent.getRecurrenceSet()
+        for rrule in rrules.getRules():
+            rrule.setUseCount(True)
+            rrule.setCount(400)
+            rrules.changed()
+
+        self.assertEqual(data[0], str(cal1))
+        self.assertEqual(data[1], str(cal2))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_i18npyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_i18npy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_i18n.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_i18n.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_i18n.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_i18n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+# coding: utf-8
+##
+#    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.parameter import Parameter
+from pycalendar.icalendar.calendar import Calendar
+import cStringIO as StringIO
+import unittest
+
+class TestCalendar(unittest.TestCase):
+
+    def testAddCN(self):
+
+        data = (
+&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+ORGANIZER:user01@example.com
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+    &quot;まだ&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:20020101
+DTEND;VALUE=DATE:20020102
+DTSTAMP:20020101T000000Z
+RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
+ORGANIZER;CN=まだ:user01@example.com
+SUMMARY:New Year's Day
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+        )
+
+        cal1 = Calendar()
+        cal1.parse(StringIO.StringIO(data[0]))
+
+        vevent = cal1.getComponents(&quot;VEVENT&quot;)[0]
+        organizer = vevent.getProperties(&quot;ORGANIZER&quot;)[0]
+        organizer.addParameter(Parameter(&quot;CN&quot;, data[1]))
+
+        cal2 = Calendar()
+        cal2.parse(StringIO.StringIO(data[2]))
+
+        self.assertEqual(str(cal1), str(cal2))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_jsonpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_jsonpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_json.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_json.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_json.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_json.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,676 @@
</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.icalendar.calendar import Calendar
+from pycalendar.icalendar.property import Property
+import difflib
+import unittest
+
+class TestJSON(unittest.TestCase):
+
+    data = (
+                (
+&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;,
+            ),
+        )
+
+    def testGenerateJSON(self):
+
+        def _doRoundtrip(caldata, resultdata):
+            test1 = resultdata
+
+            cal = Calendar.parseText(caldata)
+
+            test2 = cal.getTextJSON()
+            self.assertEqual(
+                test1,
+                test2,
+                &quot;\n&quot;.join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+            )
+
+        for item1, item2 in self.data:
+            _doRoundtrip(item1, item2)
+
+
+    def testParseJSON(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.data:
+            _doRoundtrip(item1, item2)
+
+
+    def testjCalExample1(self):
+
+        jcaldata = &quot;&quot;&quot;[&quot;vcalendar&quot;,
+  [
+    [&quot;calscale&quot;, {}, &quot;text&quot;, &quot;GREGORIAN&quot;],
+    [&quot;prodid&quot;, {}, &quot;text&quot;, &quot;-//Example Inc.//Example Calendar//EN&quot;],
+    [&quot;version&quot;, {}, &quot;text&quot;, &quot;2.0&quot;]
+  ],
+  [
+    [&quot;vevent&quot;,
+      [
+        [&quot;dtstamp&quot;, {}, &quot;date-time&quot;, &quot;2008-02-05T19:12:24Z&quot;],
+        [&quot;dtstart&quot;, {}, &quot;date&quot;, &quot;2008-10-06&quot;],
+        [&quot;summary&quot;, {}, &quot;text&quot;, &quot;Planning meeting&quot;],
+        [&quot;uid&quot;, {}, &quot;text&quot;, &quot;4088E990AD89CB3DBB484909&quot;]
+      ],
+      []
+    ]
+  ]
+]
+&quot;&quot;&quot;
+
+        icaldata = &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;)
+
+        cal1 = Calendar.parseText(icaldata)
+        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()))
+        )
+
+
+    def testjCalExample2(self):
+
+        jcaldata = &quot;&quot;&quot;[&quot;vcalendar&quot;,
+  [
+    [&quot;prodid&quot;, {}, &quot;text&quot;, &quot;-//Example Corp.//Example Client//EN&quot;],
+    [&quot;version&quot;, {}, &quot;text&quot;, &quot;2.0&quot;]
+  ],
+  [
+    [&quot;vtimezone&quot;,
+      [
+        [&quot;last-modified&quot;, {}, &quot;date-time&quot;, &quot;2004-01-10T03:28:45Z&quot;],
+        [&quot;tzid&quot;, {}, &quot;text&quot;, &quot;US/Eastern&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;freq&quot;: &quot;YEARLY&quot;,
+                &quot;byday&quot;: &quot;1SU&quot;,
+                &quot;bymonth&quot;: 4
+              }
+            ],
+            [&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;freq&quot;: &quot;YEARLY&quot;,
+                &quot;byday&quot;: &quot;-1SU&quot;,
+                &quot;bymonth&quot;: 10
+              }
+            ],
+            [&quot;tzname&quot;, {}, &quot;text&quot;, &quot;EST&quot;],
+            [&quot;tzoffsetfrom&quot;, {}, &quot;utc-offset&quot;, &quot;-04:00:00&quot;],
+            [&quot;tzoffsetto&quot;, {}, &quot;utc-offset&quot;, &quot;-05:00:00&quot;]
+          ],
+          []
+        ]
+      ]
+    ],
+    [&quot;vevent&quot;,
+      [
+        [&quot;dtstamp&quot;, {}, &quot;date-time&quot;, &quot;2006-02-06T00:11:21Z&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;rrule&quot;, {}, &quot;recur&quot;, { &quot;freq&quot;: &quot;DAILY&quot;, &quot;count&quot;: 5 } ],
+        [&quot;rdate&quot;,
+          { &quot;tzid&quot;: &quot;US/Eastern&quot; },
+          &quot;period&quot;,
+          [&quot;2006-01-02T15:00:00&quot;, &quot;PT2H&quot;]
+        ],
+        [&quot;summary&quot;, {}, &quot;text&quot;, &quot;Event #2&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;uid&quot;, {}, &quot;text&quot;, &quot;00959BC664CA650E933C892C@example.com&quot;]
+      ],
+      []
+    ],
+    [&quot;vevent&quot;,
+      [
+        [&quot;dtstamp&quot;, {}, &quot;date-time&quot;, &quot;2006-02-06T00:11:21Z&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;recurrence-id&quot;,
+          { &quot;tzid&quot;: &quot;US/Eastern&quot; },
+          &quot;date-time&quot;,
+          &quot;2006-01-04T12:00:00&quot;
+        ],
+        [&quot;summary&quot;, {}, &quot;text&quot;, &quot;Event #2 bis&quot;],
+        [&quot;uid&quot;, {}, &quot;text&quot;, &quot;00959BC664CA650E933C892C@example.com&quot;]
+      ],
+      []
+    ]
+  ]
+]
+&quot;&quot;&quot;
+
+        icaldata = &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
+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;)
+
+        cal1 = Calendar.parseText(icaldata)
+        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()))
+        )
+
+
+
+class TestJSONProperty(unittest.TestCase):
+
+    test_data = (
+        # Different value types
+        [&quot;attach&quot;, {}, &quot;binary&quot;, &quot;VGVzdA==&quot;],
+        [&quot;organizer&quot;, {}, &quot;cal-address&quot;, &quot;mailto:jdoe@example.com&quot;],
+        [&quot;dtstart&quot;, {&quot;tzid&quot;: &quot;US/Eastern&quot;}, &quot;date-time&quot;, &quot;2006-02-26T12:00:00&quot;],
+        [&quot;dtstart&quot;, {}, &quot;date&quot;, &quot;2006-02-26&quot;],
+        [&quot;dtstart&quot;, {}, &quot;date-time&quot;, &quot;2006-02-26T13:00:00Z&quot;],
+        [&quot;x-foo&quot;, {}, &quot;text&quot;, &quot;BAR&quot;],
+        [&quot;duration&quot;, {}, &quot;duration&quot;, &quot;PT10M&quot;],
+        [&quot;sequence&quot;, {}, &quot;integer&quot;, 1],
+        [&quot;rdate&quot;, {}, &quot;date-time&quot;, &quot;2006-02-26T12:00:00Z&quot;, &quot;2006-02-27T12:00:00Z&quot;],
+        [&quot;freebusy&quot;, {}, &quot;period&quot;, [&quot;2006-02-26T12:00:00Z&quot;, &quot;2006-02-27T12:00:00Z&quot;]],
+        [&quot;rrule&quot;, {}, &quot;recur&quot;, {&quot;freq&quot;:&quot;MONTHLY&quot;, &quot;count&quot;: 3, &quot;byday&quot;:[&quot;TU&quot;, &quot;WE&quot;, &quot;TH&quot;], &quot;bysetpos&quot;:[-1]}],
+        [&quot;request-status&quot;, {}, &quot;text&quot;, [&quot;2.0&quot;, &quot;Success&quot;]],
+        [&quot;geo&quot;, {}, &quot;float&quot;, [-2.1, 3.2]],
+        [&quot;uri&quot;, {}, &quot;uri&quot;, &quot;http://www.example.com&quot;],
+        [&quot;tzoffsetfrom&quot;, {}, &quot;utc-offset&quot;, &quot;-05:00&quot;],
+        [&quot;tzoffsetfrom&quot;, {}, &quot;utc-offset&quot;, &quot;-04:58:57&quot;],
+        [&quot;x-foo&quot;, {}, &quot;float&quot;, -1.23],
+        [&quot;x-test&quot;, {}, &quot;text&quot;, &quot;Some:, text.&quot;],
+        [&quot;x-apple-structured-location&quot;, {}, &quot;uri&quot;, &quot;geo:123.123,123.123&quot;],
+        [&quot;rrule&quot;, {}, &quot;recur&quot;, {&quot;freq&quot;:&quot;MONTHLY&quot;, &quot;until&quot;: &quot;2013-01-01T00:00:00Z&quot;}],
+        [&quot;categories&quot;, {}, &quot;text&quot;, &quot;A&quot;, &quot;B&quot;],
+
+        # Various parameters
+        [&quot;dtstart&quot;, {&quot;tzid&quot;: &quot;Somewhere, else&quot;}, &quot;date-time&quot;, &quot;2006-02-26T12:00:00&quot;],
+        [&quot;attendee&quot;, {&quot;partstat&quot;: &quot;ACCEPTED&quot;, &quot;role&quot;: &quot;CHAIR&quot;}, &quot;cal-address&quot;, &quot;mailto:jdoe@example.com&quot;],
+        [&quot;x-foo&quot;, {&quot;x-bar&quot;: &quot;Some\\ntext&quot;}, &quot;text&quot;, &quot;foobar&quot;],
+
+        # Parameter escaping
+        [&quot;attendee&quot;, {&quot;cn&quot;: &quot;My 'Test' Name&quot;, &quot;role&quot;: &quot;CHAIR&quot;}, &quot;cal-address&quot;, &quot;mailto:jdoe@example.com&quot;],
+    )
+
+
+    def testParseGenerate(self):
+
+        for data in TestJSONProperty.test_data:
+            prop = Property.parseJSON(data)
+            jobject = []
+            prop.writeJSON(jobject)
+            self.assertEqual(jobject[0], data, &quot;Failed parse/generate: %s to %s&quot; % (data, jobject[0],))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_propertypyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_propertypy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_property.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_property.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_property.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,181 @@
</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.parameter import Parameter
+from pycalendar.exceptions import InvalidProperty
+from pycalendar.icalendar.property import Property
+from pycalendar.parser import ParserContext
+from pycalendar.value import Value
+import unittest
+
+class TestProperty(unittest.TestCase):
+
+    test_data = (
+        # Different value types
+        &quot;ATTACH;VALUE=BINARY:VGVzdA==&quot;,
+        &quot;attach;VALUE=BINARY:VGVzdA==&quot;,
+        &quot;ORGANIZER:mailto:jdoe@example.com&quot;,
+        &quot;DTSTART;TZID=US/Eastern:20060226T120000&quot;,
+        &quot;DTSTART;VALUE=DATE:20060226&quot;,
+        &quot;DTSTART:20060226T130000Z&quot;,
+        &quot;X-FOO:BAR&quot;,
+        &quot;DURATION:PT10M&quot;,
+        &quot;duraTION:PT10M&quot;,
+        &quot;SEQUENCE:1&quot;,
+        &quot;RDATE:20060226T120000Z,20060227T120000Z&quot;,
+        &quot;FREEBUSY:20060226T120000Z/20060227T120000Z&quot;,
+        &quot;SUMMARY:Some \\ntext&quot;,
+        &quot;RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=-1&quot;,
+        &quot;REQUEST-STATUS:2.0;Success&quot;,
+        &quot;GEO:-2.1;3.2&quot;,
+        &quot;URI:http://www.example.com&quot;,
+        &quot;TZOFFSETFROM:-0500&quot;,
+        &quot;TZOFFSETFROM:-045857&quot;,
+        &quot;X-FOO;VALUE=FLOAT:-1.23&quot;,
+        &quot;X-Test:Some\, text.&quot;,
+        &quot;X-Test:Some:, text.&quot;,
+        &quot;X-APPLE-STRUCTURED-LOCATION;VALUE=URI:geo:123.123,123.123&quot;,
+        &quot;X-CALENDARSERVER-PRIVATE-COMMENT:This\\ntest\\nis\\, here.\\n&quot;,
+
+        # Various parameters
+        &quot;DTSTART;TZID=\&quot;Somewhere, else\&quot;:20060226T120000&quot;,
+        &quot;ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:jdoe@example.com&quot;,
+        &quot;X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-APPLE-ABUID=ab\\://Work;X-TITLE=\&quot;10\\n XX S. XXX Dr.\\nSuite XXX\\nXX XX XXXXX\\nUnited States\&quot;:\&quot;geo:11.111111,-11.111111\&quot;&quot;,
+
+        # Parameter escaping
+        &quot;ATTENDEE;CN=My ^'Test^' Name;ROLE=CHAIR:mailto:jdoe@example.com&quot;,
+    )
+
+
+    def testParseGenerate(self):
+
+        for data in TestProperty.test_data:
+            prop = Property.parseText(data)
+            propstr = str(prop).replace(&quot;\r\n &quot;, &quot;&quot;)
+            self.assertEqual(propstr[:-2], data, &quot;Failed parse/generate: %s to %s&quot; % (data, propstr,))
+
+
+    def testEquality(self):
+
+        for data in TestProperty.test_data:
+            prop1 = Property.parseText(data)
+            prop2 = Property.parseText(data)
+            self.assertEqual(prop1, prop2, &quot;Failed equality: %s&quot; % (data,))
+
+
+    def testParseBad(self):
+
+        test_bad_data = (
+            &quot;DTSTART;TZID=US/Eastern:abc&quot;,
+            &quot;DTSTART;VALUE=DATE:20060226T&quot;,
+            &quot;DTSTART:20060226T120000A&quot;,
+            &quot;X-FOO;:BAR&quot;,
+            &quot;DURATION:A&quot;,
+            &quot;SEQUENCE:b&quot;,
+            &quot;RDATE:20060226T120000Z;20060227T120000Z&quot;,
+            &quot;FREEBUSY:20060226T120000Z/ABC&quot;,
+            &quot;SUMMARY:Some \\qtext&quot;,
+            &quot;RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,VE;BYSETPOS=-1&quot;,
+            &quot;TZOFFSETFROM:-050&quot;,
+            &quot;&quot;&quot;ATTENDEE;CN=&quot;\\&quot;;CUTYPE=INDIVIDUAL;PARTSTAT=X-UNDELIVERABLE:invalid:nomai
+ l&quot;&quot;&quot;,
+        )
+        save = ParserContext.INVALID_ESCAPE_SEQUENCES
+        for data in test_bad_data:
+            ParserContext.INVALID_ESCAPE_SEQUENCES = ParserContext.PARSER_RAISE
+            self.assertRaises(InvalidProperty, Property.parseText, data)
+        ParserContext.INVALID_ESCAPE_SEQUENCES = save
+
+
+    def testHash(self):
+
+        hashes = []
+        for item in TestProperty.test_data:
+            prop = Property.parseText(item)
+            hashes.append(hash(prop))
+        hashes.sort()
+        for i in range(1, len(hashes)):
+            self.assertNotEqual(hashes[i - 1], hashes[i])
+
+
+    def testDefaultValueCreate(self):
+
+        test_data = (
+            (&quot;ATTENDEE&quot;, &quot;mailto:attendee@example.com&quot;, &quot;ATTENDEE:mailto:attendee@example.com\r\n&quot;),
+            (&quot;attendee&quot;, &quot;mailto:attendee@example.com&quot;, &quot;attendee:mailto:attendee@example.com\r\n&quot;),
+            (&quot;ORGANIZER&quot;, &quot;mailto:organizer@example.com&quot;, &quot;ORGANIZER:mailto:organizer@example.com\r\n&quot;),
+            (&quot;ORGANizer&quot;, &quot;mailto:organizer@example.com&quot;, &quot;ORGANizer:mailto:organizer@example.com\r\n&quot;),
+            (&quot;URL&quot;, &quot;http://example.com/tz1&quot;, &quot;URL:http://example.com/tz1\r\n&quot;),
+            (&quot;TZURL&quot;, &quot;http://example.com/tz2&quot;, &quot;TZURL:http://example.com/tz2\r\n&quot;),
+        )
+        for propname, propvalue, result in test_data:
+            prop = Property(name=propname, value=propvalue)
+            self.assertEqual(str(prop), result)
+
+
+    def testGEOValueRoundtrip(self):
+
+        data = &quot;GEO:123.456;789.101&quot;
+        prop = Property.parseText(data)
+        self.assertEqual(str(prop), data + &quot;\r\n&quot;)
+
+
+    def testUnknownValueRoundtrip(self):
+
+        data = &quot;X-FOO:Text, not escaped&quot;
+        prop = Property.parseText(data)
+        self.assertEqual(str(prop), data + &quot;\r\n&quot;)
+
+        prop = Property(&quot;X-FOO&quot;, &quot;Text, not escaped&quot;)
+        self.assertEqual(str(prop), data + &quot;\r\n&quot;)
+
+        data = &quot;X-FOO:Text\\, escaped\\n&quot;
+        prop = Property.parseText(data)
+        self.assertEqual(str(prop), data + &quot;\r\n&quot;)
+
+        prop = Property(&quot;X-FOO&quot;, &quot;Text\\, escaped\\n&quot;)
+        self.assertEqual(str(prop), data + &quot;\r\n&quot;)
+
+
+    def testNewRegistrationValueRoundtrip(self):
+
+        Property.registerDefaultValue(&quot;X-SPECIAL-REGISTRATION&quot;, Value.VALUETYPE_TEXT)
+
+        data = &quot;X-SPECIAL-REGISTRATION:Text\\, escaped\\n&quot;
+        prop = Property.parseText(data)
+        self.assertEqual(str(prop), &quot;X-SPECIAL-REGISTRATION:Text\\, escaped\\n\r\n&quot;)
+
+        prop = Property(&quot;X-SPECIAL-REGISTRATION&quot;, &quot;Text, escaped\n&quot;)
+        self.assertEqual(str(prop), &quot;X-SPECIAL-REGISTRATION:Text\\, escaped\\n\r\n&quot;)
+
+
+    def testParameterEncodingDecoding(self):
+
+        prop = Property(&quot;X-FOO&quot;, &quot;Test&quot;)
+        prop.addParameter(Parameter(&quot;X-BAR&quot;, &quot;\&quot;Check\&quot;&quot;))
+        self.assertEqual(str(prop), &quot;X-FOO;X-BAR=^'Check^':Test\r\n&quot;)
+
+        prop.addParameter(Parameter(&quot;X-BAR2&quot;, &quot;Check\nThis\tOut\n&quot;))
+        self.assertEqual(str(prop), &quot;X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test\r\n&quot;)
+
+        data = &quot;X-FOO;X-BAR=^'Check^':Test&quot;
+        prop = Property.parseText(data)
+        self.assertEqual(prop.getParameterValue(&quot;X-BAR&quot;), &quot;\&quot;Check\&quot;&quot;)
+
+        data = &quot;X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test&quot;
+        prop = Property.parseText(data)
+        self.assertEqual(prop.getParameterValue(&quot;X-BAR&quot;), &quot;\&quot;Check\&quot;&quot;)
+        self.assertEqual(prop.getParameterValue(&quot;X-BAR2&quot;), &quot;Check\nThis\tOut\n&quot;)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_recurrencepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_recurrencepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_recurrence.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_recurrence.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_recurrence.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_recurrence.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,160 @@
</span><ins>+##
+#    Copyright (c) 2011-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.period import Period
+from pycalendar.icalendar.recurrence import Recurrence
+import unittest
+
+class TestRecurrence(unittest.TestCase):
+
+    items = (
+        &quot;FREQ=DAILY&quot;,
+        &quot;FREQ=YEARLY;COUNT=400&quot;,
+        &quot;FREQ=MONTHLY;UNTIL=20110102&quot;,
+        &quot;FREQ=MONTHLY;UNTIL=20110102T090000&quot;,
+        &quot;FREQ=MONTHLY;UNTIL=20110102T100000Z&quot;,
+        &quot;FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=-1&quot;,
+
+        # These are from RFC5545 examples
+        &quot;FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1&quot;,
+        &quot;FREQ=YEARLY;UNTIL=19730429T070000Z;BYDAY=-1SU;BYMONTH=4&quot;,
+        &quot;FREQ=YEARLY;UNTIL=20060402T070000Z;BYDAY=1SU;BYMONTH=4&quot;,
+        &quot;FREQ=YEARLY;BYDAY=2SU;BYMONTH=3&quot;,
+        &quot;FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10&quot;,
+        &quot;FREQ=DAILY;INTERVAL=2&quot;,
+        &quot;FREQ=DAILY;COUNT=5;INTERVAL=10&quot;,
+        &quot;FREQ=DAILY;UNTIL=20000131T140000Z;BYMONTH=1&quot;,
+        &quot;FREQ=WEEKLY;INTERVAL=2;WKST=SU&quot;,
+        &quot;FREQ=WEEKLY;UNTIL=19971007T000000Z;BYDAY=TU,TH;WKST=SU&quot;,
+        &quot;FREQ=WEEKLY;COUNT=10;BYDAY=TU,TH;WKST=SU&quot;,
+        &quot;FREQ=WEEKLY;UNTIL=19971224T000000Z;INTERVAL=2;BYDAY=MO,WE,FR;WKST=SU&quot;,
+        &quot;FREQ=WEEKLY;COUNT=8;INTERVAL=2;BYDAY=TU,TH;WKST=SU&quot;,
+        &quot;FREQ=MONTHLY;BYMONTHDAY=-3&quot;,
+        &quot;FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1&quot;,
+        &quot;FREQ=MONTHLY;COUNT=10;INTERVAL=18;BYMONTHDAY=10,11,12,13,14,15&quot;,
+        &quot;FREQ=YEARLY;COUNT=10;INTERVAL=3;BYYEARDAY=1,100,200&quot;,
+        &quot;FREQ=YEARLY;BYDAY=MO;BYWEEKNO=20&quot;,
+        &quot;FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3&quot;,
+        &quot;FREQ=DAILY;BYMINUTE=0,20,40;BYHOUR=9,10,11,12,13,14,15,16&quot;,
+    )
+
+
+    def testParse(self):
+
+        for item in TestRecurrence.items:
+            recur = Recurrence()
+            recur.parse(item)
+            self.assertEqual(recur.getText(), item, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
+
+
+    def testParseInvalid(self):
+
+        items = (
+            &quot;&quot;,
+            &quot;FREQ=&quot;,
+            &quot;FREQ=MICROSECONDLY&quot;,
+            &quot;FREQ=YEARLY;COUNT=ABC&quot;,
+            &quot;FREQ=YEARLY;COUNT=123;UNTIL=20110102&quot;,
+            &quot;FREQ=MONTHLY;UNTIL=20110102T&quot;,
+            &quot;FREQ=MONTHLY;UNTIL=20110102t090000&quot;,
+            &quot;FREQ=MONTHLY;UNTIL=20110102T100000z&quot;,
+            &quot;FREQ=MONTHLY;UNTIL=20110102TAABBCCz&quot;,
+            &quot;FREQ=MONTHLY;BYDAY=A&quot;,
+            &quot;FREQ=MONTHLY;BYDAY=+1,3MO&quot;,
+            &quot;FREQ=MONTHLY;BYHOUR=A&quot;,
+            &quot;FREQ=MONTHLY;BYHOUR=54&quot;,
+        )
+
+        for item in items:
+            self.assertRaises(ValueError, Recurrence().parse, item)
+
+
+    def testEquality(self):
+
+        recur1 = Recurrence()
+        recur1.parse(&quot;FREQ=YEARLY;COUNT=400&quot;)
+        recur2 = Recurrence()
+        recur2.parse(&quot;COUNT=400;FREQ=YEARLY&quot;)
+
+        self.assertEqual(recur1, recur2)
+
+
+    def testInequality(self):
+
+        recur1 = Recurrence()
+        recur1.parse(&quot;FREQ=YEARLY;COUNT=400&quot;)
+        recur2 = Recurrence()
+        recur2.parse(&quot;COUNT=400;FREQ=YEARLY;BYMONTH=1&quot;)
+
+        self.assertNotEqual(recur1, recur2)
+
+
+    def testHash(self):
+
+        hashes = []
+        for item in TestRecurrence.items:
+            recur = Recurrence()
+            recur.parse(item)
+            hashes.append(hash(recur))
+        hashes.sort()
+        for i in range(1, len(hashes)):
+            self.assertNotEqual(hashes[i - 1], hashes[i])
+
+
+    def testByWeekNoExpand(self):
+
+        recur = Recurrence()
+        recur.parse(&quot;FREQ=YEARLY;BYWEEKNO=1,2&quot;)
+        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),
+            ],
+        )
+
+
+    def testClearOnChange(self):
+
+        recur = Recurrence()
+        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)
+        items = []
+        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)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_requeststatuspyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_requeststatuspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_requeststatus.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_requeststatus.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_requeststatus.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_requeststatus.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,94 @@
</span><ins>+##
+#    Copyright (c) 2011-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.parser import ParserContext
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.requeststatusvalue import RequestStatusValue
+import unittest
+
+class TestRequestStatus(unittest.TestCase):
+
+    def testParseValue(self):
+
+        items = (
+            &quot;2.0;Success&quot;,
+            &quot;2.0;Success\;here&quot;,
+            &quot;2.0;Success;Extra&quot;,
+            &quot;2.0;Success\;here;Extra&quot;,
+            &quot;2.0;Success;Extra\;here&quot;,
+            &quot;2.0;Success\;here;Extra\;here too&quot;,
+        )
+
+        for item in items:
+            req = RequestStatusValue()
+            req.parse(item, &quot;icalendar&quot;)
+            self.assertEqual(req.getText(), item, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
+
+
+    def testBadValue(self):
+
+        bad_value = &quot;2.0\;Success&quot;
+        ok_value = &quot;2.0;Success&quot;
+
+        # Fix the value
+        oldContext = ParserContext.INVALID_REQUEST_STATUS_VALUE
+        ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_FIX
+        req = RequestStatusValue()
+        req.parse(bad_value, &quot;icalendar&quot;)
+        self.assertEqual(req.getText(), ok_value, &quot;Failed to parse and re-generate '%s'&quot; % (bad_value,))
+
+        # Raise the value
+        ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_RAISE
+        req = RequestStatusValue()
+        self.assertRaises(ValueError, req.parse, bad_value)
+
+        ParserContext.INVALID_REQUEST_STATUS_VALUE = oldContext
+
+
+    def testTruncatedValue(self):
+
+        bad_value = &quot;2.0&quot;
+        ok_value = &quot;2.0;&quot;
+
+        # Fix the value
+        oldContext = ParserContext.INVALID_REQUEST_STATUS_VALUE
+        ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_FIX
+        req = RequestStatusValue()
+        req.parse(bad_value, &quot;icalendar&quot;)
+        self.assertEqual(req.getText(), ok_value, &quot;Failed to parse and re-generate '%s'&quot; % (bad_value,))
+
+        # Raise the value
+        ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_RAISE
+        req = RequestStatusValue()
+        self.assertRaises(ValueError, req.parse, bad_value)
+
+        ParserContext.INVALID_REQUEST_STATUS_VALUE = oldContext
+
+
+    def testParseProperty(self):
+
+        items = (
+            &quot;REQUEST-STATUS:2.0;Success&quot;,
+            &quot;REQUEST-STATUS:2.0;Success\;here&quot;,
+            &quot;REQUEST-STATUS:2.0;Success;Extra&quot;,
+            &quot;REQUEST-STATUS:2.0;Success\;here;Extra&quot;,
+            &quot;REQUEST-STATUS:2.0;Success;Extra\;here&quot;,
+            &quot;REQUEST-STATUS:2.0;Success\;here;Extra\;here too&quot;,
+        )
+
+        for item in items:
+            req = Property.parseText(item)
+            self.assertEqual(req.getText(), item + &quot;\r\n&quot;, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_timezonepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_timezonepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_timezone.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_timezone.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_timezone.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_timezone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,235 @@
</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.icalendar.calendar import Calendar
+import unittest
+
+class TestCalendar(unittest.TestCase):
+
+    def testOffsets(self):
+
+        data = (
+                    (&quot;&quot;&quot;BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//calendarserver.org//Zonal//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:America/New_York
+X-LIC-LOCATION:America/New_York
+BEGIN:STANDARD
+DTSTART:18831118T120358
+RDATE:18831118T120358
+TZNAME:EST
+TZOFFSETFROM:-045602
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19180331T020000
+RRULE:FREQ=YEARLY;UNTIL=19190330T070000Z;BYDAY=-1SU;BYMONTH=3
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19181027T020000
+RRULE:FREQ=YEARLY;UNTIL=19191026T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19200101T000000
+RDATE:19200101T000000
+RDATE:19420101T000000
+RDATE:19460101T000000
+RDATE:19670101T000000
+TZNAME:EST
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19200328T020000
+RDATE:19200328T020000
+RDATE:19740106T020000
+RDATE:19750223T020000
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19201031T020000
+RDATE:19201031T020000
+RDATE:19450930T020000
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19210424T020000
+RRULE:FREQ=YEARLY;UNTIL=19410427T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19210925T020000
+RRULE:FREQ=YEARLY;UNTIL=19410928T060000Z;BYDAY=-1SU;BYMONTH=9
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19420209T020000
+RDATE:19420209T020000
+TZNAME:EWT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19450814T190000
+RDATE:19450814T190000
+TZNAME:EPT
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19460428T020000
+RRULE:FREQ=YEARLY;UNTIL=19660424T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19460929T020000
+RRULE:FREQ=YEARLY;UNTIL=19540926T060000Z;BYDAY=-1SU;BYMONTH=9
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:STANDARD
+DTSTART:19551030T020000
+RRULE:FREQ=YEARLY;UNTIL=19661030T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19670430T020000
+RRULE:FREQ=YEARLY;UNTIL=19730429T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;UNTIL=20061029T060000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19760425T020000
+RRULE:FREQ=YEARLY;UNTIL=19860427T070000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;UNTIL=20060402T070000Z;BYDAY=1SU;BYMONTH=4
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
+TZNAME:EDT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
+TZNAME:EST
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+END:STANDARD
+END:VTIMEZONE
+END:VCALENDAR
+&quot;&quot;&quot;,
+                (
+                    (DateTime(1942, 2, 8), -5),
+                    (DateTime(1942, 2, 10), -4),
+                    (DateTime(2011, 1, 1), -5),
+                    (DateTime(2011, 4, 1), -4),
+                    (DateTime(2011, 10, 24), -4),
+                    (DateTime(2011, 11, 8), -5),
+                    (DateTime(2006, 1, 1), -5),
+                    (DateTime(2006, 4, 1), -5),
+                    (DateTime(2006, 5, 1), -4),
+                    (DateTime(2006, 10, 1), -4),
+                    (DateTime(2006, 10, 24), -4),
+                    (DateTime(2006, 11, 8), -5),
+                )
+            ),
+                    (&quot;&quot;&quot;BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+PRODID:-//calendarserver.org//Zonal//EN
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Etc/GMT+8
+X-LIC-LOCATION:Etc/GMT+8
+BEGIN:STANDARD
+DTSTART:18000101T000000
+RDATE:18000101T000000
+TZNAME:GMT+8
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+END:VCALENDAR
+&quot;&quot;&quot;,
+                (
+                    (DateTime(1942, 2, 8), -8),
+                    (DateTime(1942, 2, 10), -8),
+                    (DateTime(2011, 1, 1), -8),
+                    (DateTime(2011, 4, 1), -8),
+                )
+            ),
+        )
+
+        for tzdata, offsets in data:
+
+            cal = Calendar.parseText(tzdata.replace(&quot;\n&quot;, &quot;\r\n&quot;))
+            tz = cal.getComponents()[0]
+
+            for dt, offset in offsets:
+                tzoffset = tz.getTimezoneOffsetSeconds(dt)
+                self.assertEqual(tzoffset, offset * 60 * 60, &quot;Failed to match offset for %s at %s with caching&quot; % (tz.getID(), dt,))
+            for dt, offset in reversed(offsets):
+                tzoffset = tz.getTimezoneOffsetSeconds(dt)
+                self.assertEqual(tzoffset, offset * 60 * 60, &quot;Failed to match offset for %s at %s with caching, reversed&quot; % (tz.getID(), dt,))
+
+            for dt, offset in offsets:
+                tz.mCachedExpandAllMax = None
+                tzoffset = tz.getTimezoneOffsetSeconds(dt)
+                self.assertEqual(tzoffset, offset * 60 * 60, &quot;Failed to match offset for %s at %s without caching&quot; % (tz.getID(), dt,))
+            for dt, offset in reversed(offsets):
+                tz.mCachedExpandAllMax = None
+                tzoffset = tz.getTimezoneOffsetSeconds(dt)
+                self.assertEqual(tzoffset, offset * 60 * 60, &quot;Failed to match offset for %s at %s without caching, reversed&quot; % (tz.getID(), dt,))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_validationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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">@@ -14,8 +14,8 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.exceptions import PyCalendarValidationError
</del><ins>+from pycalendar.exceptions import ValidationError
+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> import unittest
</span><span class="cx"> 
</span><span class="cx"> class TestValidation(unittest.TestCase):
</span><span class="lines">@@ -65,7 +65,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, item, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(item)
</del><ins>+            cal = Calendar.parseText(item)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=False)
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(unfixed), test_unfixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -216,7 +216,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=False, doRaise=False)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -367,7 +367,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=True, doRaise=False)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -523,9 +523,9 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed, test_raises in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             if test_raises:
</span><del>-                self.assertRaises(PyCalendarValidationError, cal.validate, doFix=False, doRaise=True)
</del><ins>+                self.assertRaises(ValidationError, cal.validate, doFix=False, doRaise=True)
</ins><span class="cx">             else:
</span><span class="cx">                 try:
</span><span class="cx">                     fixed, unfixed = cal.validate(doFix=False, doRaise=False)
</span><span class="lines">@@ -685,9 +685,9 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed, test_raises in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             if test_raises:
</span><del>-                self.assertRaises(PyCalendarValidationError, cal.validate, doFix=False, doRaise=True)
</del><ins>+                self.assertRaises(ValidationError, cal.validate, doFix=False, doRaise=True)
</ins><span class="cx">             else:
</span><span class="cx">                 try:
</span><span class="cx">                     fixed, unfixed = cal.validate(doFix=True, doRaise=False)
</span><span class="lines">@@ -977,7 +977,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -1047,7 +1047,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -1115,7 +1115,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -1260,7 +1260,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -1482,7 +1482,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -1680,7 +1680,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -1874,7 +1874,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -2564,7 +2564,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -2713,7 +2713,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=True)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="lines">@@ -3182,7 +3182,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for title, test_old, test_new, test_doFix, test_fixed, test_unfixed in data:
</span><del>-            cal = PyCalendar.parseText(test_old)
</del><ins>+            cal = Calendar.parseText(test_old)
</ins><span class="cx">             fixed, unfixed = cal.validate(doFix=test_doFix)
</span><span class="cx">             self.assertEqual(str(cal), test_new, msg=&quot;Failed test: %s&quot; % (title,))
</span><span class="cx">             self.assertEqual(set(fixed), test_fixed, msg=&quot;Failed test: %s&quot; % (title,))
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_vpollpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_vpollpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_vpoll.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_vpoll.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_vpoll.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_vpoll.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,98 @@
</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.icalendar.calendar import Calendar
+import cStringIO as StringIO
+import difflib
+import unittest
+
+class TestCalendar(unittest.TestCase):
+
+    data = (
+&quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VPOLL
+UID:A979D282-2CDB-484F-BD63-3972094DFFC0
+DTSTAMP:20020101T000000Z
+ORGANIZER:mailto:user01@example.com
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+VOTER;CN=User 02:mailto:user02@example.com
+VOTER;CN=User 03:mailto:user03@example.com
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20130101
+DTEND;VALUE=DATE:20130102
+DTSTAMP:20020101T000000Z
+POLL-ITEM-ID:1
+SUMMARY:Party option #1
+END:VEVENT
+BEGIN:VEVENT
+UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
+DTSTART;VALUE=DATE:20130201
+DTEND;VALUE=DATE:20130202
+DTSTAMP:20020101T000000Z
+POLL-ITEM-ID:2
+SUMMARY:Party option #2
+END:VEVENT
+END:VPOLL
+END:VCALENDAR
+&quot;&quot;&quot;,
+
+&quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REPLY
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VPOLL
+UID:A979D282-2CDB-484F-BD63-3972094DFFC0
+DTSTAMP:20020101T000000Z
+ORGANIZER:mailto:user01@example.com
+POLL-ITEM-ID;PUBLIC-COMMENT=Not ideal;RESPONSE=50:1
+POLL-ITEM-ID;PUBLIC-COMMENT=Perfect;RESPONSE=100:2
+POLL-MODE:BASIC
+POLL-PROPERTIES:DTSTART,DTEND
+VOTER;CN=User 02:mailto:user02@example.com
+END:VPOLL
+END:VCALENDAR
+&quot;&quot;&quot;,
+
+)
+
+
+    def testRoundtrip(self):
+
+
+        def _doRoundtrip(caldata, resultdata=None):
+            test1 = resultdata if resultdata is not None else caldata
+
+            cal = Calendar()
+            cal.parse(StringIO.StringIO(caldata))
+
+            s = StringIO.StringIO()
+            cal.generate(s)
+            test2 = s.getvalue()
+
+            self.assertEqual(
+                test1,
+                test2,
+                &quot;\n&quot;.join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+            )
+
+        for item in self.data:
+            _doRoundtrip(item.replace(&quot;\n&quot;, &quot;\r\n&quot;))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarteststest_xmlpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarteststest_xmlpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/tests/test_xml.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/tests/test_xml.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/tests/test_xml.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/tests/test_xml.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,104 @@
</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.icalendar.calendar import Calendar
+import cStringIO as StringIO
+import difflib
+import unittest
+
+class TestXML(unittest.TestCase):
+
+    data = (
+                (
+&quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//mulberrymail.com//Mulberry v4.0//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2@example.com
+EXDATE:20081114T000000Z
+ORGANIZER:mailto:user1@example.com
+RRULE:FREQ=YEARLY
+END:VEVENT
+X-TEST:Testing
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
+
+&quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;ns0:icalendar xmlns:ns0=&quot;urn:ietf:params:xml:ns:icalendar-2.0&quot;&gt;
+  &lt;ns0:vcalendar&gt;
+    &lt;ns0:properties&gt;
+      &lt;ns0:version&gt;
+        &lt;ns0:text&gt;2.0&lt;/ns0:text&gt;
+      &lt;/ns0:version&gt;
+      &lt;ns0:prodid&gt;
+        &lt;ns0:text&gt;-//mulberrymail.com//Mulberry v4.0//EN&lt;/ns0:text&gt;
+      &lt;/ns0:prodid&gt;
+      &lt;ns0:x-test&gt;
+        &lt;ns0:unknown&gt;Testing&lt;/ns0:unknown&gt;
+      &lt;/ns0:x-test&gt;
+    &lt;/ns0:properties&gt;
+    &lt;ns0:components&gt;
+      &lt;ns0:vevent&gt;
+        &lt;ns0:properties&gt;
+          &lt;ns0:uid&gt;
+            &lt;ns0:text&gt;12345-67890-3&lt;/ns0:text&gt;
+          &lt;/ns0:uid&gt;
+          &lt;ns0:dtstart&gt;
+            &lt;ns0:date-time&gt;2007-11-14T00:00:00Z&lt;/ns0:date-time&gt;
+          &lt;/ns0:dtstart&gt;
+          &lt;ns0:attendee&gt;
+            &lt;ns0:cal-address&gt;mailto:user2@example.com&lt;/ns0:cal-address&gt;
+          &lt;/ns0:attendee&gt;
+          &lt;ns0:exdate&gt;
+            &lt;ns0:date-time&gt;2008-11-14T00:00:00Z&lt;/ns0:date-time&gt;
+          &lt;/ns0:exdate&gt;
+          &lt;ns0:organizer&gt;
+            &lt;ns0:cal-address&gt;mailto:user1@example.com&lt;/ns0:cal-address&gt;
+          &lt;/ns0:organizer&gt;
+          &lt;ns0:rrule&gt;
+            &lt;ns0:recur&gt;
+              &lt;ns0:freq&gt;YEARLY&lt;/ns0:freq&gt;
+            &lt;/ns0:recur&gt;
+          &lt;/ns0:rrule&gt;
+        &lt;/ns0:properties&gt;
+      &lt;/ns0:vevent&gt;
+    &lt;/ns0:components&gt;
+  &lt;/ns0:vcalendar&gt;
+&lt;/ns0:icalendar&gt;
+&quot;&quot;&quot;,
+                ),
+)
+
+    def testGenerateXML(self):
+
+        def _doRoundtrip(caldata, resultdata=None):
+            test1 = resultdata if resultdata is not None else caldata
+
+            cal = Calendar()
+            cal.parse(StringIO.StringIO(caldata))
+
+            test2 = cal.getTextXML()
+
+            self.assertEqual(
+                test1,
+                test2,
+                &quot;\n&quot;.join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
+            )
+
+        for item1, item2 in self.data:
+            _doRoundtrip(item1, item2)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvalarmpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvalarmpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/valarm.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/valarm.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/valarm.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/valarm.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,707 @@
</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.parameter import Parameter
+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+from pycalendar.value import Value
+
+class VAlarm(Component):
+
+    sActionMap = {
+        definitions.cICalProperty_ACTION_AUDIO: definitions.eAction_VAlarm_Audio,
+        definitions.cICalProperty_ACTION_DISPLAY: definitions.eAction_VAlarm_Display,
+        definitions.cICalProperty_ACTION_EMAIL: definitions.eAction_VAlarm_Email,
+        definitions.cICalProperty_ACTION_PROCEDURE: definitions.eAction_VAlarm_Procedure,
+        definitions.cICalProperty_ACTION_URI: definitions.eAction_VAlarm_URI,
+        definitions.cICalProperty_ACTION_NONE: definitions.eAction_VAlarm_None,
+    }
+
+    sActionValueMap = {
+        definitions.eAction_VAlarm_Audio: definitions.cICalProperty_ACTION_AUDIO,
+        definitions.eAction_VAlarm_Display: definitions.cICalProperty_ACTION_DISPLAY,
+        definitions.eAction_VAlarm_Email: definitions.cICalProperty_ACTION_EMAIL,
+        definitions.eAction_VAlarm_Procedure: definitions.cICalProperty_ACTION_PROCEDURE,
+        definitions.eAction_VAlarm_URI: definitions.cICalProperty_ACTION_URI,
+        definitions.eAction_VAlarm_None: definitions.cICalProperty_ACTION_NONE,
+    }
+
+    # Classes for each action encapsulating action-specific data
+    class VAlarmAction(object):
+
+        propertyCardinality_1 = ()
+        propertyCardinality_1_Fix_Empty = ()
+        propertyCardinality_0_1 = ()
+        propertyCardinality_1_More = ()
+
+        def __init__(self, type):
+            self.mType = type
+
+        def duplicate(self):
+            return VAlarm.VAlarmAction(self.mType)
+
+        def load(self, valarm):
+            pass
+
+        def add(self, valarm):
+            pass
+
+        def remove(self, valarm):
+            pass
+
+        def getType(self):
+            return self.mType
+
+
+    class VAlarmAudio(VAlarmAction):
+
+        propertyCardinality_1 = (
+            definitions.cICalProperty_ACTION,
+            definitions.cICalProperty_TRIGGER,
+        )
+
+        propertyCardinality_0_1 = (
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_REPEAT,
+            definitions.cICalProperty_ATTACH,
+            definitions.cICalProperty_ACKNOWLEDGED,
+        )
+
+        def __init__(self, speak=None):
+            super(VAlarm.VAlarmAudio, self).__init__(type=definitions.eAction_VAlarm_Audio)
+            self.mSpeakText = speak
+
+        def duplicate(self):
+            return VAlarm.VAlarmAudio(self.mSpeakText)
+
+        def load(self, valarm):
+            # Get properties
+            self.mSpeakText = valarm.loadValueString(definitions.cICalProperty_ACTION_X_SPEAKTEXT)
+
+        def add(self, valarm):
+            # Delete existing then add
+            self.remove(valarm)
+
+            prop = Property(definitions.cICalProperty_ACTION_X_SPEAKTEXT, self.mSpeakText)
+            valarm.addProperty(prop)
+
+        def remove(self, valarm):
+            valarm.removeProperties(definitions.cICalProperty_ACTION_X_SPEAKTEXT)
+
+        def isSpeakText(self):
+            return len(self.mSpeakText) != 0
+
+        def getSpeakText(self):
+            return self.mSpeakText
+
+
+    class VAlarmDisplay(VAlarmAction):
+
+        propertyCardinality_1 = (
+            definitions.cICalProperty_ACTION,
+            definitions.cICalProperty_TRIGGER,
+        )
+
+        propertyCardinality_1_Fix_Empty = (
+            definitions.cICalProperty_DESCRIPTION,
+        )
+
+        propertyCardinality_0_1 = (
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_REPEAT,
+            definitions.cICalProperty_ACKNOWLEDGED,
+        )
+
+        def __init__(self, description=None):
+            super(VAlarm.VAlarmDisplay, self).__init__(type=definitions.eAction_VAlarm_Display)
+            self.mDescription = description
+
+        def duplicate(self):
+            return VAlarm.VAlarmDisplay(self.mDescription)
+
+        def load(self, valarm):
+            # Get properties
+            self.mDescription = valarm.loadValueString(definitions.cICalProperty_DESCRIPTION)
+
+        def add(self, valarm):
+            # Delete existing then add
+            self.remove(valarm)
+
+            prop = Property(definitions.cICalProperty_DESCRIPTION, self.mDescription)
+            valarm.addProperty(prop)
+
+        def remove(self, valarm):
+            valarm.removeProperties(definitions.cICalProperty_DESCRIPTION)
+
+        def getDescription(self):
+            return self.mDescription
+
+
+    class VAlarmEmail(VAlarmAction):
+
+        propertyCardinality_1 = (
+            definitions.cICalProperty_ACTION,
+            definitions.cICalProperty_TRIGGER,
+        )
+
+        propertyCardinality_1_Fix_Empty = (
+            definitions.cICalProperty_DESCRIPTION,
+            definitions.cICalProperty_SUMMARY,
+        )
+
+        propertyCardinality_0_1 = (
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_REPEAT,
+            definitions.cICalProperty_ACKNOWLEDGED,
+        )
+
+        propertyCardinality_1_More = (
+            definitions.cICalProperty_ATTENDEE,
+        )
+
+        def __init__(self, description=None, summary=None, attendees=None):
+            super(VAlarm.VAlarmEmail, self).__init__(type=definitions.eAction_VAlarm_Email)
+            self.mDescription = description
+            self.mSummary = summary
+            self.mAttendees = attendees
+
+        def duplicate(self):
+            return VAlarm.VAlarmEmail(self.mDescription, self.mSummary, self.mAttendees)
+
+        def load(self, valarm):
+            # Get properties
+            self.mDescription = valarm.loadValueString(definitions.cICalProperty_DESCRIPTION)
+            self.mSummary = valarm.loadValueString(definitions.cICalProperty_SUMMARY)
+
+            self.mAttendees = []
+            if valarm.hasProperty(definitions.cICalProperty_ATTENDEE):
+                # Get each attendee
+                range = valarm.getProperties().get(definitions.cICalProperty_ATTENDEE, ())
+                for iter in range:
+                    # Get the attendee value
+                    attendee = iter.getCalAddressValue()
+                    if attendee is not None:
+                        self.mAttendees.append(attendee.getValue())
+
+        def add(self, valarm):
+            # Delete existing then add
+            self.remove(valarm)
+
+            prop = Property(definitions.cICalProperty_DESCRIPTION, self.mDescription)
+            valarm.addProperty(prop)
+
+            prop = Property(definitions.cICalProperty_SUMMARY, self.mSummary)
+            valarm.addProperty(prop)
+
+            for iter in self.mAttendees:
+                prop = Property(definitions.cICalProperty_ATTENDEE, iter, Value.VALUETYPE_CALADDRESS)
+                valarm.addProperty(prop)
+
+        def remove(self, valarm):
+            valarm.removeProperties(definitions.cICalProperty_DESCRIPTION)
+            valarm.removeProperties(definitions.cICalProperty_SUMMARY)
+            valarm.removeProperties(definitions.cICalProperty_ATTENDEE)
+
+        def getDescription(self):
+            return self.mDescription
+
+        def getSummary(self):
+            return self.mSummary
+
+        def getAttendees(self):
+            return self.mAttendees
+
+
+    class VAlarmUnknown(VAlarmAction):
+
+        propertyCardinality_1 = (
+            definitions.cICalProperty_ACTION,
+            definitions.cICalProperty_TRIGGER,
+        )
+
+        propertyCardinality_0_1 = (
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_REPEAT,
+            definitions.cICalProperty_ACKNOWLEDGED,
+        )
+
+        def __init__(self):
+            super(VAlarm.VAlarmUnknown, self).__init__(type=definitions.eAction_VAlarm_Unknown)
+
+        def duplicate(self):
+            return VAlarm.VAlarmUnknown()
+
+
+    class VAlarmURI(VAlarmAction):
+
+        propertyCardinality_1 = (
+            definitions.cICalProperty_ACTION,
+            definitions.cICalProperty_TRIGGER,
+            definitions.cICalProperty_URL,
+        )
+
+        propertyCardinality_0_1 = (
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_REPEAT,
+            definitions.cICalProperty_ACKNOWLEDGED,
+        )
+
+        def __init__(self, uri=None):
+            super(VAlarm.VAlarmURI, self).__init__(type=definitions.eAction_VAlarm_URI)
+            self.mURI = uri
+
+        def duplicate(self):
+            return VAlarm.VAlarmURI(self.mURI)
+
+        def load(self, valarm):
+            # Get properties
+            self.mURI = valarm.loadValueString(definitions.cICalProperty_URL)
+
+        def add(self, valarm):
+            # Delete existing then add
+            self.remove(valarm)
+
+            prop = Property(definitions.cICalProperty_URL, self.mURI)
+            valarm.addProperty(prop)
+
+        def remove(self, valarm):
+            valarm.removeProperties(definitions.cICalProperty_URL)
+
+        def getURI(self):
+            return self.mURI
+
+
+    class VAlarmNone(VAlarmAction):
+
+        propertyCardinality_1 = (
+            definitions.cICalProperty_ACTION,
+        )
+
+        def __init__(self):
+            super(VAlarm.VAlarmNone, self).__init__(type=definitions.eAction_VAlarm_None)
+
+        def duplicate(self):
+            return VAlarm.VAlarmNone()
+
+
+    def getMimeComponentName(self):
+        # Cannot be sent as a separate MIME object
+        return None
+
+    sActionToAlarmMap = {
+        definitions.eAction_VAlarm_Audio: VAlarmAudio,
+        definitions.eAction_VAlarm_Display: VAlarmDisplay,
+        definitions.eAction_VAlarm_Email: VAlarmEmail,
+        definitions.eAction_VAlarm_URI: VAlarmURI,
+        definitions.eAction_VAlarm_None: VAlarmNone,
+    }
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None):
+
+        super(VAlarm, self).__init__(parent=parent)
+
+        self.mAction = definitions.eAction_VAlarm_Display
+        self.mTriggerAbsolute = False
+        self.mTriggerOnStart = True
+        self.mTriggerOn = DateTime()
+
+        # Set duration default to 1 hour
+        self.mTriggerBy = Duration()
+        self.mTriggerBy.setDuration(60 * 60)
+
+        # Does not repeat by default
+        self.mRepeats = 0
+        self.mRepeatInterval = Duration()
+        self.mRepeatInterval.setDuration(5 * 60) # Five minutes
+
+        # Status
+        self.mStatusInit = False
+        self.mAlarmStatus = definitions.eAlarm_Status_Pending
+        self.mLastTrigger = DateTime()
+        self.mNextTrigger = DateTime()
+        self.mDoneCount = 0
+
+        # Create action data
+        self.mActionData = VAlarm.VAlarmDisplay(&quot;&quot;)
+
+
+    def duplicate(self, parent=None):
+        other = super(VAlarm, self).duplicate(parent=parent)
+        other.mAction = self.mAction
+        other.mTriggerAbsolute = self.mTriggerAbsolute
+        other.mTriggerOn = self.mTriggerOn.duplicate()
+        other.mTriggerBy = self.mTriggerBy.duplicate()
+        other.mTriggerOnStart = self.mTriggerOnStart
+
+        other.mRepeats = self.mRepeats
+        other.mRepeatInterval = self.mRepeatInterval.duplicate()
+
+        other.mAlarmStatus = self.mAlarmStatus
+        if self.mLastTrigger is not None:
+            other.mLastTrigger = self.mLastTrigger.duplicate()
+        if self.mNextTrigger is not None:
+            other.mNextTrigger = self.mNextTrigger.duplicate()
+        other.mDoneCount = self.mDoneCount
+
+        other.mActionData = self.mActionData.duplicate()
+        return other
+
+
+    def getType(self):
+        return definitions.cICalComponent_VALARM
+
+
+    def getAction(self):
+        return self.mAction
+
+
+    def getActionData(self):
+        return self.mActionData
+
+
+    def isTriggerAbsolute(self):
+        return self.mTriggerAbsolute
+
+
+    def getTriggerOn(self):
+        return self.mTriggerOn
+
+
+    def getTriggerDuration(self):
+        return self.mTriggerBy
+
+
+    def isTriggerOnStart(self):
+        return self.mTriggerOnStart
+
+
+    def getRepeats(self):
+        return self.mRepeats
+
+
+    def getInterval(self):
+        return self.mRepeatInterval
+
+
+    def added(self):
+        # Added to calendar so add to calendar notifier
+        # calstore::CCalendarNotifier::sCalendarNotifier.AddAlarm(this)
+
+        # Do inherited
+        super(VAlarm, self).added()
+
+
+    def removed(self):
+        # Removed from calendar so add to calendar notifier
+        # calstore::CCalendarNotifier::sCalendarNotifier.RemoveAlarm(this)
+
+        # Do inherited
+        super(VAlarm, self).removed()
+
+
+    def changed(self):
+        # Always force recalc of trigger status
+        self.mStatusInit = False
+
+        # Changed in calendar so change in calendar notifier
+        # calstore::CCalendarNotifier::sCalendarNotifier.ChangedAlarm(this)
+
+        # Do not do inherited as this is always a sub-component and we do not
+        # do top-level component changes
+        # super.changed()
+
+
+    def finalise(self):
+        # Do inherited
+        super(VAlarm, self).finalise()
+
+        # Get the ACTION
+        temp = self.loadValueString(definitions.cICalProperty_ACTION)
+        if temp is not None:
+            self.mAction = VAlarm.sActionMap.get(temp, definitions.eAction_VAlarm_Unknown)
+            self.loadAction()
+
+        # Get the trigger
+        if self.hasProperty(definitions.cICalProperty_TRIGGER):
+            # Determine the type of the value
+            temp1 = self.loadValueDateTime(definitions.cICalProperty_TRIGGER)
+            temp2 = self.loadValueDuration(definitions.cICalProperty_TRIGGER)
+            if temp1 is not None:
+                self.mTriggerAbsolute = True
+                self.mTriggerOn = temp1
+            elif temp2 is not None:
+                self.mTriggerAbsolute = False
+                self.mTriggerBy = temp2
+
+                # Get the property
+                prop = self.findFirstProperty(definitions.cICalProperty_TRIGGER)
+
+                # Look for RELATED parameter
+                if prop.hasParameter(definitions.cICalParameter_RELATED):
+                    temp = prop.getParameterValue(definitions.cICalParameter_RELATED)
+                    if temp == definitions.cICalParameter_RELATED_START:
+                        self.mTriggerOnStart = True
+                    elif temp == definitions.cICalParameter_RELATED_END:
+                        self.mTriggerOnStart = False
+                else:
+                    self.mTriggerOnStart = True
+
+        # Get repeat &amp; interval
+        temp = self.loadValueInteger(definitions.cICalProperty_REPEAT)
+        if temp is not None:
+            self.mRepeats = temp
+        temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
+        if temp is not None:
+            self.mRepeatInterval = temp
+
+        # Set a map key for sorting
+        self.mMapKey = &quot;%s:%s&quot; % (self.mAction, self.mTriggerOn if self.mTriggerAbsolute else self.mTriggerBy,)
+
+        # Alarm status - private to Mulberry
+        status = self.loadValueString(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
+        if status is not None:
+            if status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING:
+                self.mAlarmStatus = definitions.eAlarm_Status_Pending
+            elif status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED:
+                self.mAlarmStatus = definitions.eAlarm_Status_Completed
+            elif status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED:
+                self.mAlarmStatus = definitions.eAlarm_Status_Disabled
+            else:
+                self.mAlarmStatus = definitions.eAlarm_Status_Pending
+
+        # Last trigger time - private to Mulberry
+        temp = self.loadValueDateTime(definitions.cICalProperty_ALARM_X_LASTTRIGGER)
+        if temp is not None:
+            self.mLastTrigger = temp
+
+
+    def validate(self, doFix=False):
+        &quot;&quot;&quot;
+        Validate the data in this component and optionally fix any problems, else raise. If
+        loggedProblems is not None it must be a C{list} and problem descriptions are appended
+        to that.
+        &quot;&quot;&quot;
+
+        # Validate using action specific constraints
+        self.propertyCardinality_1 = self.mActionData.propertyCardinality_1
+        self.propertyCardinality_1_Fix_Empty = self.mActionData.propertyCardinality_1_Fix_Empty
+        self.propertyCardinality_0_1 = self.mActionData.propertyCardinality_0_1
+        self.propertyCardinality_1_More = self.mActionData.propertyCardinality_1_More
+
+        fixed, unfixed = super(VAlarm, self).validate(doFix)
+
+        # Extra constraint: both DURATION and REPEAT must be present togethe
+        if self.hasProperty(definitions.cICalProperty_DURATION) ^ self.hasProperty(definitions.cICalProperty_REPEAT):
+            # Cannot fix this
+            logProblem = &quot;[%s] Properties must be present together: %s, %s&quot; % (
+                self.getType(),
+                definitions.cICalProperty_DURATION,
+                definitions.cICalProperty_REPEAT,
+            )
+            unfixed.append(logProblem)
+
+        return fixed, unfixed
+
+
+    def editStatus(self, status):
+        # Remove existing
+        self.removeProperties(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
+
+        # Updated cached values
+        self.mAlarmStatus = status
+
+        # Add new
+        status_txt = &quot;&quot;
+        if self.mAlarmStatus == definitions.eAlarm_Status_Pending:
+            status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING
+        elif self.mAlarmStatus == definitions.eAlarm_Status_Completed:
+            status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED
+        elif self.mAlarmStatus == definitions.eAlarm_Status_Disabled:
+            status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED
+        self.addProperty(Property(definitions.cICalProperty_ALARM_X_ALARMSTATUS, status_txt))
+
+
+    def editAction(self, action, data):
+        # Remove existing
+        self.removeProperties(definitions.cICalProperty_ACTION)
+        self.mActionData.remove(self)
+        self.mActionData = None
+
+        # Updated cached values
+        self.mAction = action
+        self.mActionData = data
+
+        # Add new properties to alarm
+        action_txt = VAlarm.sActionValueMap.get(self.mAction, definitions.cICalProperty_ACTION_PROCEDURE)
+
+        prop = Property(definitions.cICalProperty_ACTION, action_txt)
+        self.addProperty(prop)
+
+        self.mActionData.add(self)
+
+
+    def editTriggerOn(self, dt):
+        # Remove existing
+        self.removeProperties(definitions.cICalProperty_TRIGGER)
+
+        # Updated cached values
+        self.mTriggerAbsolute = True
+        self.mTriggerOn = dt
+
+        # Add new
+        prop = Property(definitions.cICalProperty_TRIGGER, dt)
+        self.addProperty(prop)
+
+
+    def editTriggerBy(self, duration, trigger_start):
+        # Remove existing
+        self.removeProperties(definitions.cICalProperty_TRIGGER)
+
+        # Updated cached values
+        self.mTriggerAbsolute = False
+        self.mTriggerBy = duration
+        self.mTriggerOnStart = trigger_start
+
+        # Add new (with parameter)
+        prop = Property(definitions.cICalProperty_TRIGGER, duration)
+        attr = Parameter(definitions.cICalParameter_RELATED,
+                 (definitions.cICalParameter_RELATED_START,
+                  definitions.cICalParameter_RELATED_END)[not trigger_start])
+        prop.addParameter(attr)
+        self.addProperty(prop)
+
+
+    def editRepeats(self, repeat, interval):
+        # Remove existing
+        self.removeProperties(definitions.cICalProperty_REPEAT)
+        self.removeProperties(definitions.cICalProperty_DURATION)
+
+        # Updated cached values
+        self.mRepeats = repeat
+        self.mRepeatInterval = interval
+
+        # Add new
+        if self.mRepeats &gt; 0:
+            self.addProperty(Property(definitions.cICalProperty_REPEAT, repeat))
+            self.addProperty(Property(definitions.cICalProperty_DURATION, interval))
+
+
+    def getAlarmStatus(self):
+        return self.mAlarmStatus
+
+
+    def getNextTrigger(self, dt):
+        if not self.mStatusInit:
+            self.initNextTrigger()
+        dt.copy(self.mNextTrigger)
+
+
+    def alarmTriggered(self, dt):
+        # Remove existing
+        self.removeProperties(definitions.cICalProperty_ALARM_X_LASTTRIGGER)
+        self.removeProperties(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
+
+        # Updated cached values
+        self.mLastTrigger.copy(dt)
+
+        if self.mDoneCount &lt; self.mRepeats:
+            self.mNextTrigger = self.mLastTrigger + self.mRepeatInterval
+            dt.copy(self.mNextTrigger)
+            self.mDoneCount += 1
+            self.mAlarmStatus = definitions.eAlarm_Status_Pending
+        else:
+            self.mAlarmStatus = definitions.eAlarm_Status_Completed
+
+        # Add new
+        self.addProperty(Property(definitions.cICalProperty_ALARM_X_LASTTRIGGER, dt))
+        status = &quot;&quot;
+        if self.mAlarmStatus == definitions.eAlarm_Status_Pending:
+            status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING
+        elif self.mAlarmStatus == definitions.eAlarm_Status_Completed:
+            status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED
+        elif self.mAlarmStatus == definitions.eAlarm_Status_Disabled:
+            status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED
+        self.addProperty(Property(definitions.cICalProperty_ALARM_X_ALARMSTATUS, status))
+
+        # Now update dt to the next alarm time
+        return self.mAlarmStatus == definitions.eAlarm_Status_Pending
+
+
+    def loadAction(self):
+        # Delete current one
+        self.mActionData = None
+        self.mActionData = VAlarm.sActionToAlarmMap.get(self.mAction, VAlarm.VAlarmUnknown)()
+        self.mActionData.load(self)
+
+
+    def initNextTrigger(self):
+        # Do not bother if its completed
+        if self.mAlarmStatus == definitions.eAlarm_Status_Completed:
+            return
+        self.mStatusInit = True
+
+        # Look for trigger immediately preceeding or equal to utc now
+        nowutc = DateTime.getNowUTC()
+
+        # Init done counter
+        self.mDoneCount = 0
+
+        # Determine the first trigger
+        trigger = DateTime()
+        self.getFirstTrigger(trigger)
+
+        while self.mDoneCount &lt; self.mRepeats:
+            # See if next trigger is later than now
+            next_trigger = trigger + self.mRepeatInterval
+            if next_trigger &gt; nowutc:
+                break
+            self.mDoneCount += 1
+            trigger = next_trigger
+
+        # Check for completion
+        if trigger == self.mLastTrigger or (nowutc - trigger).getTotalSeconds() &gt; 24 * 60 * 60:
+            if self.mDoneCount == self.mRepeats:
+                self.mAlarmStatus = definitions.eAlarm_Status_Completed
+                return
+            else:
+                trigger = trigger + self.mRepeatInterval
+                self.mDoneCount += 1
+
+        self.mNextTrigger = trigger
+
+
+    def getFirstTrigger(self, dt):
+        # If absolute trigger, use that
+        if self.isTriggerAbsolute():
+            # Get the trigger on
+            dt.copy(self.getTriggerOn())
+        else:
+            # Get the parent embedder class (must be CICalendarComponentRecur type)
+            owner = self.getEmbedder()
+            if owner is not None:
+                # Determine time at which alarm will trigger
+                trigger = (owner.getStart(), owner.getEnd())[not self.isTriggerOnStart()]
+
+                # Offset by duration
+                dt.copy(trigger + self.getTriggerDuration())
+
+Component.registerComponent(definitions.cICalComponent_VALARM, VAlarm)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvalidationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/icalendar/validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/icalendar/validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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">@@ -14,7 +14,7 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar import definitions
</del><ins>+from pycalendar.icalendar import definitions
</ins><span class="cx"> from pycalendar.validation import partial, PropertyValueChecks
</span><span class="cx"> 
</span><span class="cx"> ICALENDAR_VALUE_CHECKS = {
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvavailabilitypyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvavailabilitypy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vavailability.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vavailability.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,109 @@
</span><ins>+##
+#    Copyright (c) 2011-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.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VAvailability(Component):
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_DTSTAMP,
+        definitions.cICalProperty_UID,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_BUSYTYPE,
+        definitions.cICalProperty_CLASS,
+        definitions.cICalProperty_CREATED,
+        definitions.cICalProperty_DESCRIPTION,
+        definitions.cICalProperty_DTSTART,
+        definitions.cICalProperty_LAST_MODIFIED,
+        definitions.cICalProperty_ORGANIZER,
+        definitions.cICalProperty_SEQUENCE,
+        definitions.cICalProperty_SUMMARY,
+        definitions.cICalProperty_URL,
+        definitions.cICalProperty_RECURRENCE_ID,
+        definitions.cICalProperty_DTEND,
+        definitions.cICalProperty_DURATION,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None):
+        super(VAvailability, self).__init__(parent=parent)
+
+
+    def duplicate(self, parent=None):
+        return super(VAvailability, self).duplicate(parent=parent)
+
+
+    def getType(self):
+        return definitions.cICalComponent_VAVAILABILITY
+
+
+    def getMimeComponentName(self):
+        return itipdefinitions.cICalMIMEComponent_VAVAILABILITY
+
+
+    def finalise(self):
+        super(VAvailability, self).finalise()
+
+
+    def validate(self, doFix=False):
+        &quot;&quot;&quot;
+        Validate the data in this component and optionally fix any problems, else raise. If
+        loggedProblems is not None it must be a C{list} and problem descriptions are appended
+        to that.
+        &quot;&quot;&quot;
+
+        fixed, unfixed = super(VAvailability, self).validate(doFix)
+
+        # Extra constraint: only one of DTEND or DURATION
+        if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
+            # Fix by removing the DTEND
+            logProblem = &quot;[%s] Properties must not both be present: %s, %s&quot; % (
+                self.getType(),
+                definitions.cICalProperty_DTEND,
+                definitions.cICalProperty_DURATION,
+            )
+            if doFix:
+                self.removeProperties(definitions.cICalProperty_DTEND)
+                fixed.append(logProblem)
+            else:
+                unfixed.append(logProblem)
+
+        return fixed, unfixed
+
+
+    def addComponent(self, comp):
+        # We can embed the available components only
+        if comp.getType() == definitions.cICalComponent_AVAILABLE:
+            super(VAvailability, self).addComponent(comp)
+        else:
+            raise ValueError
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_UID,
+            definitions.cICalProperty_DTSTART,
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_DTEND,
+        )
+
+Component.registerComponent(definitions.cICalComponent_VAVAILABILITY, VAvailability)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarveventpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarveventpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vevent.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vevent.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vevent.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vevent.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,172 @@
</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.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentrecur import ComponentRecur
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VEvent(ComponentRecur):
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_DTSTAMP,
+        definitions.cICalProperty_UID,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_CLASS,
+        definitions.cICalProperty_CREATED,
+        definitions.cICalProperty_DESCRIPTION,
+        definitions.cICalProperty_GEO,
+        definitions.cICalProperty_LAST_MODIFIED,
+        definitions.cICalProperty_LOCATION,
+        definitions.cICalProperty_ORGANIZER,
+        definitions.cICalProperty_PRIORITY,
+        definitions.cICalProperty_SEQUENCE,
+        # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
+        definitions.cICalProperty_SUMMARY,
+        definitions.cICalProperty_TRANSP,
+        definitions.cICalProperty_URL,
+        definitions.cICalProperty_RECURRENCE_ID,
+        definitions.cICalProperty_RRULE,
+        definitions.cICalProperty_DTEND,
+        definitions.cICalProperty_DURATION,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None):
+        super(VEvent, self).__init__(parent=parent)
+        self.mStatus = definitions.eStatus_VEvent_None
+
+
+    def duplicate(self, parent=None):
+        other = super(VEvent, self).duplicate(parent=parent)
+        other.mStatus = self.mStatus
+        return other
+
+
+    def getType(self):
+        return definitions.cICalComponent_VEVENT
+
+
+    def getMimeComponentName(self):
+        return itipdefinitions.cICalMIMEComponent_VEVENT
+
+
+    def addComponent(self, comp):
+        # We can embed the alarm components only
+        if comp.getType() == definitions.cICalComponent_VALARM:
+            super(VEvent, self).addComponent(comp)
+        else:
+            raise ValueError
+
+
+    def getStatus(self):
+        return self.mStatus
+
+
+    def setStatus(self, status):
+        self.mStatus = status
+
+
+    def finalise(self):
+        # Do inherited
+        super(VEvent, self).finalise()
+
+        temp = self.loadValueString(definitions.cICalProperty_STATUS)
+        if temp is not None:
+            if temp == definitions.cICalProperty_STATUS_TENTATIVE:
+                self.mStatus = definitions.eStatus_VEvent_Tentative
+            elif temp == definitions.cICalProperty_STATUS_CONFIRMED:
+                self.mStatus = definitions.eStatus_VEvent_Confirmed
+            elif temp == definitions.cICalProperty_STATUS_CANCELLED:
+                self.mStatus = definitions.eStatus_VEvent_Cancelled
+
+
+    def validate(self, doFix=False):
+        &quot;&quot;&quot;
+        Validate the data in this component and optionally fix any problems, else raise. If
+        loggedProblems is not None it must be a C{list} and problem descriptions are appended
+        to that.
+        &quot;&quot;&quot;
+
+        fixed, unfixed = super(VEvent, self).validate(doFix)
+
+        # Extra constraint: if METHOD not present, DTSTART must be
+        if self.mParentComponent and not self.mParentComponent.hasProperty(definitions.cICalProperty_METHOD):
+            if not self.hasProperty(definitions.cICalProperty_DTSTART):
+                # Cannot fix a missing required property
+                logProblem = &quot;[%s] Missing required property: %s&quot; % (self.getType(), definitions.cICalProperty_DTSTART,)
+                unfixed.append(logProblem)
+
+        # Extra constraint: only one of DTEND or DURATION
+        if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
+            # Fix by removing the DTEND
+            logProblem = &quot;[%s] Properties must not both be present: %s, %s&quot; % (
+                self.getType(),
+                definitions.cICalProperty_DTEND,
+                definitions.cICalProperty_DURATION,
+            )
+            if doFix:
+                self.removeProperties(definitions.cICalProperty_DTEND)
+                fixed.append(logProblem)
+            else:
+                unfixed.append(logProblem)
+
+        return fixed, unfixed
+
+
+    # Editing
+    def editStatus(self, status):
+        # Only if it is different
+        if self.mStatus != status:
+            # Updated cached values
+            self.mStatus = status
+
+            # Remove existing STATUS items
+            self.removeProperties(definitions.cICalProperty_STATUS)
+
+            # Now create properties
+            value = None
+            if status == definitions.eStatus_VEvent_None:
+                pass
+            elif status == definitions.eStatus_VEvent_Tentative:
+                value = definitions.cICalProperty_STATUS_TENTATIVE
+            elif status == definitions.eStatus_VEvent_Confirmed:
+                value = definitions.cICalProperty_STATUS_CONFIRMED
+            elif status == definitions.eStatus_VEvent_Cancelled:
+                value = definitions.cICalProperty_STATUS_CANCELLED
+            else:
+                pass
+
+            if value is not None:
+                prop = Property(definitions.cICalProperty_STATUS, value)
+                self.addProperty(prop)
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_UID,
+            definitions.cICalProperty_RECURRENCE_ID,
+            definitions.cICalProperty_DTSTART,
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_DTEND,
+        )
+
+Component.registerComponent(definitions.cICalComponent_VEVENT, VEvent)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvfreebusypyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvfreebusypy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vfreebusy.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vfreebusy.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vfreebusy.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vfreebusy.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,347 @@
</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.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.freebusy import FreeBusy
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+from pycalendar.period import Period
+from pycalendar.periodvalue import PeriodValue
+from pycalendar.value import Value
+
+class VFreeBusy(Component):
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_DTSTAMP,
+        definitions.cICalProperty_UID,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_CONTACT,
+        definitions.cICalProperty_DTSTART,
+        definitions.cICalProperty_DTEND,
+        definitions.cICalProperty_ORGANIZER,
+        definitions.cICalProperty_URL,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None):
+        super(VFreeBusy, self).__init__(parent=parent)
+        self.mStart = DateTime()
+        self.mHasStart = False
+        self.mEnd = DateTime()
+        self.mHasEnd = False
+        self.mDuration = False
+        self.mCachedBusyTime = False
+        self.mSpanPeriod = None
+        self.mBusyTime = None
+
+
+    def duplicate(self, parent=None):
+        other = super(VFreeBusy, self).duplicate(parent=parent)
+        other.mStart = self.mStart.duplicate()
+        other.mHasStart = self.mHasStart
+        other.mEnd = self.mEnd.duplicate()
+        other.mHasEnd = self.mHasEnd
+        other.mDuration = self.mDuration
+        other.mCachedBusyTime = False
+        other.mBusyTime = None
+        return other
+
+
+    def getType(self):
+        return definitions.cICalComponent_VFREEBUSY
+
+
+    def getMimeComponentName(self):
+        return itipdefinitions.cICalMIMEComponent_VFREEBUSY
+
+
+    def finalise(self):
+        # Do inherited
+        super(VFreeBusy, self).finalise()
+
+        # Get DTSTART
+        temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
+        self.mHasStart = temp is not None
+        if self.mHasStart:
+            self.mStart = temp
+
+        # Get DTEND
+        temp = self.loadValueDateTime(definitions.cICalProperty_DTEND)
+        if temp is None:
+            # Try DURATION instead
+            temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
+            if temp is not None:
+                self.mEnd = self.mStart + temp
+                self.mDuration = True
+            else:
+                # Force end to start, which will then be fixed to sensible
+                # value later
+                self.mEnd = self.mStart
+        else:
+            self.mHasEnd = True
+            self.mDuration = False
+            self.mEnd = temp
+
+
+    def fixStartEnd(self):
+        # End is always greater than start if start exists
+        if self.mHasStart and self.mEnd &lt;= self.mStart:
+            # Use the start
+            self.mEnd = self.mStart.duplicate()
+            self.mDuration = False
+
+            # Adjust to appropiate non-inclusive end point
+            if self.mStart.isDateOnly():
+                self.mEnd.offsetDay(1)
+
+                # For all day events it makes sense to use duration
+                self.mDuration = True
+            else:
+                # Use end of current day
+                self.mEnd.offsetDay(1)
+                self.mEnd.setHHMMSS(0, 0, 0)
+
+
+    def getStart(self):
+        return self.mStart
+
+
+    def hasStart(self):
+        return self.mHasStart
+
+
+    def getEnd(self):
+        return self.mEnd
+
+
+    def hasEnd(self):
+        return self.mHasEnd
+
+
+    def useDuration(self):
+        return self.mDuration
+
+
+    def getSpanPeriod(self):
+        return self.mSpanPeriod
+
+
+    def getBusyTime(self):
+        return self.mBusyTime
+
+
+    def editTiming(self):
+        # Updated cached values
+        self.mHasStart = False
+        self.mHasEnd = False
+        self.mDuration = False
+        self.mStart.setToday()
+        self.mEnd.setToday()
+
+        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
+        self.removeProperties(definitions.cICalProperty_DTSTART)
+        self.removeProperties(definitions.cICalProperty_DTEND)
+        self.removeProperties(definitions.cICalProperty_DURATION)
+
+
+    def editTimingStartEnd(self, start, end):
+        # Updated cached values
+        self.mHasStart = self.mHasEnd = True
+        self.mStart = start
+        self.mEnd = end
+        self.mDuration = False
+        self.fixStartEnd()
+
+        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
+        self.removeProperties(definitions.cICalProperty_DTSTART)
+        self.removeProperties(definitions.cICalProperty_DTEND)
+        self.removeProperties(definitions.cICalProperty_DURATION)
+
+        # Now create properties
+        prop = Property(definitions.cICalProperty_DTSTART, start)
+        self.addProperty(prop)
+
+        # If its an all day event and the end one day after the start, ignore it
+        temp = start.duplicate()
+        temp.offsetDay(1)
+        if not start.isDateOnly() or end != temp:
+            prop = Property(definitions.cICalProperty_DTEND, end)
+            self.addProperty(prop)
+
+
+    def editTimingStartDuration(self, start, duration):
+        # Updated cached values
+        self.mHasStart = True
+        self.mHasEnd = False
+        self.mStart = start
+        self.mEnd = start + duration
+        self.mDuration = True
+
+        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
+        self.removeProperties(definitions.cICalProperty_DTSTART)
+        self.removeProperties(definitions.cICalProperty_DTEND)
+        self.removeProperties(definitions.cICalProperty_DURATION)
+        self.removeProperties(definitions.cICalProperty_DUE)
+
+        # Now create properties
+        prop = Property(definitions.cICalProperty_DTSTART, start)
+        self.addProperty(prop)
+
+        # If its an all day event and the duration is one day, ignore it
+        if (not start.isDateOnly() or (duration.getWeeks() != 0)
+                or (duration.getDays() &gt; 1)):
+            prop = Property(definitions.cICalProperty_DURATION, duration)
+            self.addProperty(prop)
+
+
+    # Generating info
+    def expandPeriodComp(self, period, list):
+        # Cache the busy-time details if not done already
+        if not self.mCachedBusyTime:
+            self.cacheBusyTime()
+
+        # See if period intersects the busy time span range
+        if (self.mBusyTime is not None) and period.isPeriodOverlap(self.mSpanPeriod):
+            list.append(self)
+
+
+    def expandPeriodFB(self, period, list):
+        # Cache the busy-time details if not done already
+        if not self.mCachedBusyTime:
+            self.cacheBusyTime()
+
+        # See if period intersects the busy time span range
+        if (self.mBusyTime is not None) and period.isPeriodOverlap(self.mSpanPeriod):
+            for fb in self.mBusyTime:
+                list.append(FreeBusy(fb))
+
+
+    def cacheBusyTime(self):
+
+        # Clear out any existing cache
+        self.mBusyTime = []
+
+        # Get all FREEBUSY items and add those that are BUSY
+        min_start = DateTime()
+        max_end = DateTime()
+        props = self.getProperties()
+        result = props.get(definitions.cICalProperty_FREEBUSY, ())
+        for iter in result:
+
+            # Check the properties FBTYPE parameter
+            type = 0
+            is_busy = False
+            if iter.hasParameter(definitions.cICalParameter_FBTYPE):
+
+                fbyype = iter.getParameterValue(definitions.cICalParameter_FBTYPE)
+                if fbyype.upper() == definitions.cICalParameter_FBTYPE_BUSY:
+
+                    is_busy = True
+                    type = FreeBusy.BUSY
+
+                elif fbyype.upper() == definitions.cICalParameter_FBTYPE_BUSYUNAVAILABLE:
+
+                    is_busy = True
+                    type = FreeBusy.BUSYUNAVAILABLE
+
+                elif fbyype.upper() == definitions.cICalParameter_FBTYPE_BUSYTENTATIVE:
+
+                    is_busy = True
+                    type = FreeBusy.BUSYTENTATIVE
+
+                else:
+
+                    is_busy = False
+                    type = FreeBusy.FREE
+
+            else:
+
+                # Default is busy when no parameter
+                is_busy = True
+                type = FreeBusy.BUSY
+
+            # Add this period
+            if is_busy:
+
+                multi = iter.getMultiValue()
+                if (multi is not None) and (multi.getType() == Value.VALUETYPE_PERIOD):
+
+                    for o in multi.getValues():
+
+                        # Double-check type
+                        period = None
+                        if isinstance(o, PeriodValue):
+                            period = o
+
+                        # Double-check type
+                        if period is not None:
+
+                            self.mBusyTime.append(FreeBusy(type, period.getValue()))
+
+                            if len(self.mBusyTime) == 1:
+
+                                min_start = period.getValue().getStart()
+                                max_end = period.getValue().getEnd()
+
+                            else:
+
+                                if min_start &gt; period.getValue().getStart():
+                                    min_start = period.getValue().getStart()
+                                if max_end &lt; period.getValue().getEnd():
+                                    max_end = period.getValue().getEnd()
+
+        # If nothing present, empty the list
+        if len(self.mBusyTime) == 0:
+
+            self.mBusyTime = None
+
+        else:
+
+            # Sort the list by period
+            self.mBusyTime.sort(cmp=lambda x, y: x.getPeriod().getStart().compareDateTime(y.getPeriod().getStart()))
+
+            # Determine range
+            start = DateTime()
+            end = DateTime()
+            if self.mHasStart:
+                start = self.mStart
+            else:
+                start = min_start
+            if self.mHasEnd:
+                end = self.mEnd
+            else:
+                end = max_end
+
+            self.mSpanPeriod = Period(start, end)
+
+        self.mCachedBusyTime = True
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_UID,
+            definitions.cICalProperty_DTSTART,
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_DTEND,
+        )
+
+Component.registerComponent(definitions.cICalComponent_VFREEBUSY, VFreeBusy)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvjournalpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvjournalpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vjournal.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vjournal.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vjournal.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vjournal.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,73 @@
</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.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentrecur import ComponentRecur
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VJournal(ComponentRecur):
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_DTSTAMP,
+        definitions.cICalProperty_UID,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_CLASS,
+        definitions.cICalProperty_CREATED,
+        definitions.cICalProperty_DTSTART,
+        definitions.cICalProperty_LAST_MODIFIED,
+        definitions.cICalProperty_ORGANIZER,
+        definitions.cICalProperty_RECURRENCE_ID,
+        definitions.cICalProperty_SEQUENCE,
+        # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
+        definitions.cICalProperty_SUMMARY,
+        definitions.cICalProperty_URL,
+        definitions.cICalProperty_RRULE,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None):
+        super(VJournal, self).__init__(parent=parent)
+
+
+    def duplicate(self, parent=None):
+        return super(VJournal, self).duplicate(parent=parent)
+
+
+    def getType(self):
+        return definitions.cICalComponent_VJOURNAL
+
+
+    def getMimeComponentName(self):
+        return itipdefinitions.cICalMIMEComponent_VJOURNAL
+
+
+    def finalise(self):
+        super(VJournal, self).finalise()
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_UID,
+            definitions.cICalProperty_RECURRENCE_ID,
+            definitions.cICalProperty_DTSTART,
+        )
+
+Component.registerComponent(definitions.cICalComponent_VJOURNAL, VJournal)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvpollpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvpollpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vpoll.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vpoll.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vpoll.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vpoll.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,79 @@
</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.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VPoll(Component):
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_DTSTAMP,
+        definitions.cICalProperty_UID,
+        definitions.cICalProperty_ORGANIZER,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_ACCEPT_RESPONSE,
+        definitions.cICalProperty_CLASS,
+        definitions.cICalProperty_CREATED,
+        definitions.cICalProperty_COMPLETED,
+        definitions.cICalProperty_DESCRIPTION,
+        definitions.cICalProperty_DTSTART,
+        definitions.cICalProperty_DTEND,
+        definitions.cICalProperty_DURATION,
+        definitions.cICalProperty_LAST_MODIFIED,
+        definitions.cICalProperty_POLL_MODE,
+        definitions.cICalProperty_POLL_PROPERTIES,
+        definitions.cICalProperty_PRIORITY,
+        definitions.cICalProperty_SEQUENCE,
+        definitions.cICalProperty_STATUS,
+        definitions.cICalProperty_SUMMARY,
+        definitions.cICalProperty_URL,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def getType(self):
+        return definitions.cICalComponent_VPOLL
+
+
+    def getMimeComponentName(self):
+        return itipdefinitions.cICalMIMEComponent_VPOLL
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_UID,
+            definitions.cICalProperty_DTSTART,
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_DTEND,
+        )
+
+
+    def sortedComponents(self):
+        &quot;&quot;&quot;
+        Also take POLL-ID into account
+        &quot;&quot;&quot;
+
+        components = self.mComponents[:]
+
+        # Write out the remainder sorted by name, sortKey
+        return sorted(components, key=lambda x: (x.getType().upper(), x.loadValueString(definitions.cICalProperty_POLL_ITEM_ID),))
+
+
+Component.registerComponent(definitions.cICalComponent_VPOLL, VPoll)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvtimezonepyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvtimezonepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vtimezone.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vtimezone.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vtimezone.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vtimezone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,287 @@
</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.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+
+class VTimezone(Component):
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_TZID,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_LAST_MODIFIED,
+        definitions.cICalProperty_TZURL,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    UTCOFFSET_CACHE_MAX_ENTRIES = 100000
+
+    sortSubComponents = False
+
+    def __init__(self, parent=None):
+        super(VTimezone, self).__init__(parent=parent)
+        self.mID = &quot;&quot;
+        self.mUTCOffsetSortKey = None
+        self.mCachedExpandAllMaxYear = None
+        self.mCachedOffsets = None
+
+
+    def duplicate(self, parent=None):
+        other = super(VTimezone, self).duplicate(parent=parent)
+        other.mID = self.mID
+        other.mUTCOffsetSortKey = self.mUTCOffsetSortKey
+        return other
+
+
+    def getType(self):
+        return definitions.cICalComponent_VTIMEZONE
+
+
+    def getMimeComponentName(self):
+        # Cannot be sent as a separate MIME object
+        return None
+
+
+    def addComponent(self, comp):
+        # We can embed the timezone components only
+        if ((comp.getType() == definitions.cICalComponent_STANDARD)
+                or (comp.getType() == definitions.cICalComponent_DAYLIGHT)):
+            super(VTimezone, self).addComponent(comp)
+        else:
+            raise ValueError
+
+
+    def getMapKey(self):
+        return self.mID
+
+
+    def finalise(self):
+        # Get TZID
+        temp = self.loadValueString(definitions.cICalProperty_TZID)
+        if temp is not None:
+            self.mID = temp
+
+        # Sort sub-components by DTSTART
+        self.mComponents.sort(key=lambda x: x.getStart())
+
+        # Do inherited
+        super(VTimezone, self).finalise()
+
+
+    def validate(self, doFix=False):
+        &quot;&quot;&quot;
+        Validate the data in this component and optionally fix any problems, else raise. If
+        loggedProblems is not None it must be a C{list} and problem descriptions are appended
+        to that.
+        &quot;&quot;&quot;
+
+        fixed, unfixed = super(VTimezone, self).validate(doFix)
+
+        # Must have at least one STANDARD or DAYLIGHT sub-component
+        for component in self.mComponents:
+            if component.getType() in (definitions.cICalComponent_STANDARD, definitions.cICalComponent_DAYLIGHT):
+                break
+        else:
+            # Cannot fix a missing required component
+            logProblem = &quot;[%s] At least one component must be present: %s or %s&quot; % (
+                self.getType(),
+                definitions.cICalComponent_STANDARD,
+                definitions.cICalComponent_DAYLIGHT,
+            )
+            unfixed.append(logProblem)
+
+        return fixed, unfixed
+
+
+    def getID(self):
+        return self.mID
+
+
+    def getUTCOffsetSortKey(self):
+        if self.mUTCOffsetSortKey is None:
+            # Take time from first element
+            if len(self.mComponents) &gt; 0:
+                # Initial offset provides the primary key
+                utc_offset1 = self.mComponents[0].getUTCOffset()
+
+                # Presence of secondary is the next key
+                utc_offset2 = utc_offset1
+                if len(self.mComponents) &gt; 1:
+                    utc_offset2 = self.mComponents[1].getUTCOffset()
+
+                # Create key
+                self.mUTCOffsetSortKey = (utc_offset1 + utc_offset2) / 2
+            else:
+                self.mUTCOffsetSortKey = 0
+
+        return self.mUTCOffsetSortKey
+
+
+    def getTimezoneOffsetSeconds(self, dt):
+        &quot;&quot;&quot;
+        Caching implementation of expansion. We cache the entire set of transitions up to one year ahead
+        of the requested time.
+        &quot;&quot;&quot;
+
+        # Need to make the incoming date-time relative to the DTSTART in the
+        # timezone component for proper comparison.
+        # This means making the incoming date-time a floating (no timezone)
+        # item
+        temp = dt.duplicate()
+        temp.setTimezoneID(None)
+
+        # Check whether we need to recache
+        if self.mCachedExpandAllMaxYear is None or temp.mYear &gt;= self.mCachedExpandAllMaxYear:
+            cacheMax = temp.duplicate()
+            cacheMax.setHHMMSS(0, 0, 0)
+            cacheMax.offsetYear(2)
+            cacheMax.setMonth(1)
+            cacheMax.setDay(1)
+            self.mCachedExpandAll = self.expandAll(None, cacheMax)
+            self.mCachedExpandAllMaxYear = cacheMax.mYear
+            self.mCachedOffsets = {}
+
+        # Now search for the transition just below the time we want
+        if len(self.mCachedExpandAll):
+            cacheKey = (temp.mYear, temp.mMonth, temp.mDay, temp.mHours, temp.mMinutes,)
+            i = self.mCachedOffsets.get(cacheKey)
+            if i is None:
+                i = VTimezone.tuple_bisect_right(self.mCachedExpandAll, temp)
+                if len(self.mCachedOffsets) &gt;= self.UTCOFFSET_CACHE_MAX_ENTRIES:
+                    self.mCachedOffsets = {}
+                self.mCachedOffsets[cacheKey] = i
+            if i != 0:
+                return self.mCachedExpandAll[i - 1][2]
+
+        return 0
+
+
+    def getTimezoneDescriptor(self, dt):
+        result = &quot;&quot;
+
+        # Get the closet matching element to the time
+        found = self.findTimezoneElement(dt)
+
+        # Get it
+        if found is not None:
+            if len(found.getTZName()) == 0:
+                tzoffset = found.getUTCOffset()
+                negative = False
+                if tzoffset &lt; 0:
+                    tzoffset = -tzoffset
+                    negative = True
+                result = (&quot;+&quot;, &quot;-&quot;)[negative]
+                hours_offset = tzoffset / (60 * 60)
+                if hours_offset &lt; 10:
+                    result += &quot;0&quot;
+                result += str(hours_offset)
+                mins_offset = (tzoffset / 60) % 60
+                if mins_offset &lt; 10:
+                    result += &quot;0&quot;
+                result += str(mins_offset)
+            else:
+                result = &quot;(&quot;
+                result += found.getTZName()
+                result += &quot;)&quot;
+
+        return result
+
+
+    def mergeTimezone(self, tz):
+        pass
+
+
+    @staticmethod
+    def tuple_bisect_right(a, x):
+        &quot;&quot;&quot;
+        Same as bisect_right except that the values being compared are the first elements
+        of a tuple.
+        &quot;&quot;&quot;
+
+        lo = 0
+        hi = len(a)
+        while lo &lt; hi:
+            mid = (lo + hi) // 2
+            if x &lt; a[mid][0]:
+                hi = mid
+            else:
+                lo = mid + 1
+        return lo
+
+
+    def findTimezoneElement(self, dt):
+        # Need to make the incoming date-time relative to the DTSTART in the
+        # timezone component for proper comparison.
+        # This means making the incoming date-time a floating (no timezone)
+        # item
+        temp = dt.duplicate()
+        temp.setTimezoneID(None)
+
+        # Had to rework this because some VTIMEZONEs have sub-components where the DST instances are interleaved. That
+        # means we have to evaluate each and every sub-component to find the instance immediately less than the time we are checking.
+
+        # Now do the expansion for each one found and pick the lowest
+        found = None
+        dt_found = DateTime()
+
+        for item in self.mComponents:
+            dt_item = item.expandBelow(temp)
+            if temp &gt;= dt_item:
+                if found is not None:
+                    # Compare with the one previously cached and switch to this
+                    # one if newer
+                    if dt_item &gt; dt_found:
+                        found = item
+                        dt_found = dt_item
+                else:
+                    found = item
+                    dt_found = dt_item
+
+        return found
+
+
+    def expandAll(self, start, end, with_name=False):
+        results = []
+        for item in self.mComponents:
+            results.extend(item.expandAll(start, end, with_name))
+        results = [x for x in set(results)]
+        results.sort(key=lambda x: x[0].getPosixTime())
+        return results
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_TZID,
+            definitions.cICalProperty_LAST_MODIFIED,
+            definitions.cICalProperty_TZURL,
+        )
+
+
+    @staticmethod
+    def sortByUTCOffsetComparator(tz1, tz2):
+        sort1 = tz1.getUTCOffsetSortKey()
+        sort2 = tz2.getUTCOffsetSortKey()
+        if sort1 == sort2:
+            return tz1.getID().compareToIgnoreCase(tz2.getID())
+        else:
+            return (1, -1)[sort1 &lt; sort2]
+
+Component.registerComponent(definitions.cICalComponent_VTIMEZONE, VTimezone)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvtimezonedaylightpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvtimezonedaylightpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vtimezonedaylight.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vtimezonedaylight.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vtimezonedaylight.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vtimezonedaylight.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,34 @@
</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.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.vtimezoneelement import VTimezoneElement
+
+class Daylight(VTimezoneElement):
+
+    def __init__(self, parent=None):
+        super(Daylight, self).__init__(parent=parent)
+
+
+    def duplicate(self, parent=None):
+        return super(Daylight, self).duplicate(parent=parent)
+
+
+    def getType(self):
+        return definitions.cICalComponent_DAYLIGHT
+
+Component.registerComponent(definitions.cICalComponent_DAYLIGHT, Daylight)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvtimezoneelementpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvtimezoneelementpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vtimezoneelement.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vtimezoneelement.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vtimezoneelement.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vtimezoneelement.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,219 @@
</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 bisect import bisect_right
+from pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.recurrenceset import RecurrenceSet
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+from pycalendar.period import Period
+from pycalendar.value import Value
+
+class VTimezoneElement(Component):
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_DTSTART,
+        definitions.cICalProperty_TZOFFSETTO,
+        definitions.cICalProperty_TZOFFSETFROM,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_RRULE,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None, dt=None, offset=None):
+        super(VTimezoneElement, self).__init__(parent=parent)
+        self.mStart = dt if dt is not None else DateTime()
+        self.mTZName = &quot;&quot;
+        self.mUTCOffset = offset if offset is not None else 0
+        self.mUTCOffsetFrom = 0
+        self.mRecurrences = RecurrenceSet()
+        self.mCachedExpandBelow = None
+        self.mCachedExpandBelowItems = None
+
+
+    def duplicate(self, parent=None):
+        other = super(VTimezoneElement, self).duplicate(parent=parent)
+        other.mStart = self.mStart.duplicate()
+        other.mTZName = self.mTZName
+        other.mUTCOffset = self.mUTCOffset
+        other.mUTCOffsetFrom = self.mUTCOffsetFrom
+        other.mRecurrences = self.mRecurrences.duplicate()
+        other.mCachedExpandBelow = None
+        other.mCachedExpandBelowItems = None
+        return other
+
+
+    def finalise(self):
+        # Get DTSTART
+        temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
+        if temp is not None:
+            self.mStart = temp
+
+        # Get TZOFFSETTO
+        temp = self.loadValueInteger(definitions.cICalProperty_TZOFFSETTO, Value.VALUETYPE_UTC_OFFSET)
+        if temp is not None:
+            self.mUTCOffset = temp
+
+        # Get TZOFFSETFROM
+        temp = self.loadValueInteger(definitions.cICalProperty_TZOFFSETFROM, Value.VALUETYPE_UTC_OFFSET)
+        if temp is not None:
+            self.mUTCOffsetFrom = temp
+
+        # Get TZNAME
+        temps = self.loadValueString(definitions.cICalProperty_TZNAME)
+        if temps is not None:
+            self.mTZName = temps
+
+        # Get RRULEs
+        self.loadValueRRULE(definitions.cICalProperty_RRULE, self.mRecurrences, True)
+
+        # Get RDATEs
+        self.loadValueRDATE(definitions.cICalProperty_RDATE, self.mRecurrences, True)
+
+        # Do inherited
+        super(VTimezoneElement, self).finalise()
+
+
+    def getSortKey(self):
+        &quot;&quot;&quot;
+        We do not want these components sorted.
+        &quot;&quot;&quot;
+        return &quot;&quot;
+
+
+    def getStart(self):
+        return self.mStart
+
+
+    def getUTCOffset(self):
+        return self.mUTCOffset
+
+
+    def getUTCOffsetFrom(self):
+        return self.mUTCOffsetFrom
+
+
+    def getTZName(self):
+        return self.mTZName
+
+
+    def expandBelow(self, below):
+
+        # Look for recurrences
+        if not self.mRecurrences.hasRecurrence() or self.mStart &gt; below:
+            # Return DTSTART even if it is newer
+            return self.mStart
+        else:
+            # We want to allow recurrence calculation caching to help us here
+            # as this method
+            # gets called a lot - most likely for ever increasing dt values
+            # (which will therefore
+            # invalidate the recurrence cache).
+            #
+            # What we will do is round up the date-time to the next year so
+            # that the recurrence
+            # cache is invalidated less frequently
+
+            temp = DateTime(below.getYear(), 1, 1, 0, 0, 0)
+
+            # Use cache of expansion
+            if self.mCachedExpandBelowItems is None:
+                self.mCachedExpandBelowItems = []
+            if self.mCachedExpandBelow is None:
+                self.mCachedExpandBelow = self.mStart.duplicate()
+            if temp &gt; self.mCachedExpandBelow:
+                self.mCachedExpandBelowItems = []
+                period = Period(self.mStart, temp)
+                self.mRecurrences.expand(self.mStart, period, self.mCachedExpandBelowItems, float_offset=self.mUTCOffsetFrom)
+                self.mCachedExpandBelow = temp
+
+            if len(self.mCachedExpandBelowItems) != 0:
+                # List comes back sorted so we pick the element just less than
+                # the dt value we want
+                i = bisect_right(self.mCachedExpandBelowItems, below)
+                if i != 0:
+                    return self.mCachedExpandBelowItems[i - 1]
+
+                # The first one in the list is the one we want
+                return self.mCachedExpandBelowItems[0]
+
+            return self.mStart
+
+
+    def expandAll(self, start, end, with_name):
+
+        if start is None:
+            start = self.mStart
+
+        # Ignore if there is no change in offset
+        offsetto = self.loadValueInteger(definitions.cICalProperty_TZOFFSETTO, Value.VALUETYPE_UTC_OFFSET)
+        offsetfrom = self.loadValueInteger(definitions.cICalProperty_TZOFFSETFROM, Value.VALUETYPE_UTC_OFFSET)
+#        if offsetto == offsetfrom:
+#            return ()
+
+        # Look for recurrences
+        if self.mStart &gt; end:
+            # Return nothing
+            return ()
+        elif not self.mRecurrences.hasRecurrence():
+            # Return DTSTART even if it is newer
+            if self.mStart &gt;= start:
+                result = (self.mStart, offsetfrom, offsetto,)
+                if with_name:
+                    result += (self.getTZName(),)
+                return (result,)
+            else:
+                return ()
+        else:
+            # We want to allow recurrence calculation caching to help us here
+            # as this method
+            # gets called a lot - most likely for ever increasing dt values
+            # (which will therefore
+            # invalidate the recurrence cache).
+            #
+            # What we will do is round up the date-time to the next year so
+            # that the recurrence
+            # cache is invalidated less frequently
+
+            temp = DateTime(end.getYear(), 1, 1, 0, 0, 0)
+
+            # Use cache of expansion
+            if self.mCachedExpandBelowItems is None:
+                self.mCachedExpandBelowItems = []
+            if self.mCachedExpandBelow is None:
+                self.mCachedExpandBelow = self.mStart.duplicate()
+            if temp &gt; self.mCachedExpandBelow:
+                self.mCachedExpandBelowItems = []
+                period = Period(self.mStart, end)
+                self.mRecurrences.expand(self.mStart, period, self.mCachedExpandBelowItems, float_offset=self.mUTCOffsetFrom)
+                self.mCachedExpandBelow = temp
+
+            if len(self.mCachedExpandBelowItems) != 0:
+                # Return them all within the range
+                results = []
+                for dt in self.mCachedExpandBelowItems:
+                    if dt &gt;= start and dt &lt; end:
+                        result = (dt, offsetfrom, offsetto,)
+                        if with_name:
+                            result += (self.getTZName(),)
+                        results.append(result)
+                return results
+
+            return ()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvtimezonestandardpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvtimezonestandardpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vtimezonestandard.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vtimezonestandard.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vtimezonestandard.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vtimezonestandard.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,34 @@
</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.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.vtimezoneelement import VTimezoneElement
+
+class Standard(VTimezoneElement):
+
+    def __init__(self, parent=None):
+        super(Standard, self).__init__(parent=parent)
+
+
+    def duplicate(self, parent=None):
+        return super(Standard, self).duplicate(parent=parent)
+
+
+    def getType(self):
+        return definitions.cICalComponent_STANDARD
+
+Component.registerComponent(definitions.cICalComponent_STANDARD, Standard)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvtodopyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvtodopy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vtodo.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vtodo.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vtodo.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vtodo.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,369 @@
</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.icalendar import definitions
+from pycalendar.icalendar import itipdefinitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.componentrecur import ComponentRecur
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+import cStringIO as StringIO
+
+class VToDo(ComponentRecur):
+
+    OVERDUE = 0
+    DUE_NOW = 1
+    DUE_LATER = 2
+    DONE = 3
+    CANCELLED = 4
+
+    @staticmethod
+    def sort_for_display(e1, e2):
+        s1 = e1.getMaster()
+        s2 = e2.getMaster()
+
+        # Check status first (convert None -&gt; Needs action for tests)
+        status1 = s1.self.mStatus
+        status2 = s2.self.mStatus
+        if status1 == definitions.eStatus_VToDo_None:
+            status1 = definitions.eStatus_VToDo_NeedsAction
+        if status2 == definitions.eStatus_VToDo_None:
+            status2 = definitions.eStatus_VToDo_NeedsAction
+        if status1 != status2:
+            # More important ones at the top
+            return status1 &lt; status2
+
+        # At this point the status of each is the same
+
+        # If status is cancelled sort by start time
+        if s1.self.mStatus == definitions.eStatus_VToDo_Cancelled:
+            # Older ones at the bottom
+            return s1.mStart &gt; s2.mStart
+
+        # If status is completed sort by completion time
+        if s1.self.mStatus == definitions.eStatus_VToDo_Completed:
+            # Older ones at the bottom
+            return s1.self.mCompleted &gt; s2.self.mCompleted
+
+        # Check due date exists
+        if s1.mHasEnd != s2.mHasEnd:
+            now = DateTime()
+            now.setToday()
+
+            # Ones with due dates after today below ones without due dates
+            if s1.hasEnd():
+                return s1.mEnd &lt;= now
+            elif s2.hasEnd():
+                return now &lt; s2.mEnd
+
+        # Check due dates if present
+        if s1.mHasEnd:
+            if s1.mEnd != s2.mEnd:
+                # Soonest dues dates above later ones
+                return s1.mEnd &lt; s2.mEnd
+
+        # Check priority next
+        if s1.self.mPriority != s2.self.mPriority:
+            # Higher priority above lower ones
+            return s1.self.mPriority &lt; s2.self.mPriority
+
+        # Just use start time - older ones at the top
+        return s1.mStart &lt; s2.mStart
+
+    propertyCardinality_1 = (
+        definitions.cICalProperty_DTSTAMP,
+        definitions.cICalProperty_UID,
+    )
+
+    propertyCardinality_0_1 = (
+        definitions.cICalProperty_CLASS,
+        definitions.cICalProperty_COMPLETED,
+        definitions.cICalProperty_CREATED,
+        definitions.cICalProperty_DESCRIPTION,
+        definitions.cICalProperty_DTSTART,
+        definitions.cICalProperty_GEO,
+        definitions.cICalProperty_LAST_MODIFIED,
+        definitions.cICalProperty_LOCATION,
+        definitions.cICalProperty_ORGANIZER,
+        definitions.cICalProperty_PERCENT_COMPLETE,
+        definitions.cICalProperty_PRIORITY,
+        definitions.cICalProperty_RECURRENCE_ID,
+        definitions.cICalProperty_SEQUENCE,
+        # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
+        definitions.cICalProperty_SUMMARY,
+        definitions.cICalProperty_URL,
+        definitions.cICalProperty_RRULE,
+        definitions.cICalProperty_DUE,
+        definitions.cICalProperty_DURATION,
+    )
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None):
+        super(VToDo, self).__init__(parent=parent)
+        self.mPriority = 0
+        self.mStatus = definitions.eStatus_VToDo_None
+        self.mPercentComplete = 0
+        self.mCompleted = DateTime()
+        self.mHasCompleted = False
+
+
+    def duplicate(self, parent=None):
+        other = super(VToDo, self).duplicate(parent=parent)
+        other.mPriority = self.mPriority
+        other.mStatus = self.mStatus
+        other.mPercentComplete = self.mPercentComplete
+        other.mCompleted = self.mCompleted.duplicate()
+        other.mHasCompleted = self.mHasCompleted
+        return other
+
+
+    def getType(self):
+        return definitions.cICalComponent_VTODO
+
+
+    def getMimeComponentName(self):
+        return itipdefinitions.cICalMIMEComponent_VTODO
+
+
+    def addComponent(self, comp):
+        # We can embed the alarm components only
+        if comp.getType() == definitions.cICalComponent_VALARM:
+            super(VToDo, self).addComponent(comp)
+        else:
+            raise ValueError
+
+
+    def getStatus(self):
+        return self.mStatus
+
+
+    def setStatus(self, status):
+        self.mStatus = status
+
+
+    def getStatusText(self):
+        sout = StringIO()
+
+        if self.mStatus in (definitions.eStatus_VToDo_NeedsAction, definitions.eStatus_VToDo_InProcess):
+            if self.hasEnd():
+                # Check due date
+                today = DateTime()
+                today.setToday()
+                if self.getEnd() &gt; today:
+                    sout.append(&quot;Due: &quot;)
+                    whendue = self.getEnd() - today
+                    if (whendue.getDays() &gt; 0) and (whendue.getDays() &lt;= 7):
+                        sout.write(whendue.getDays())
+                        sout.write(&quot; days&quot;)
+                    else:
+                        sout.write(self.getEnd().getLocaleDate(DateTime.NUMERICDATE))
+                elif self.getEnd() == today:
+                    sout.write(&quot;Due today&quot;)
+                else:
+                    sout.write(&quot;Overdue: &quot;)
+                    overdue = today - self.getEnd()
+                    if overdue.getWeeks() != 0:
+                        sout.write(overdue.getWeeks())
+                        sout.write(&quot; weeks&quot;)
+                    else:
+                        sout.write(overdue.getDays() + 1)
+                        sout.write(&quot; days&quot;)
+            else:
+                sout.write(&quot;Not Completed&quot;)
+        elif self.mStatus == definitions.eStatus_VToDo_Completed:
+            if self.hasCompleted():
+                sout.write(&quot;Completed: &quot;)
+                sout.write(self.getCompleted().getLocaleDate(DateTime.NUMERICDATE))
+            else:
+                sout.write(&quot;Completed&quot;)
+        elif definitions.eStatus_VToDo_Cancelled:
+            sout.write(&quot;Cancelled&quot;)
+
+        return sout.toString()
+
+
+    def getCompletionState(self):
+        if self.mStatus in (definitions.eStatus_VToDo_NeedsAction, definitions.eStatus_VToDo_InProcess):
+            if self.hasEnd():
+                # Check due date
+                today = DateTime()
+                today.setToday()
+                if self.getEnd() &gt; today:
+                    return VToDo.DUE_LATER
+                elif self.getEnd() == today:
+                    return VToDo.DUE_NOW
+                else:
+                    return VToDo.OVERDUE
+            else:
+                return VToDo.DUE_NOW
+        elif self.mStatus == definitions.eStatus_VToDo_Completed:
+            return VToDo.DONE
+        elif self.mStatus == definitions.eStatus_VToDo_Cancelled:
+            return VToDo.CANCELLED
+
+
+    def getPriority(self):
+        return self.mPriority
+
+
+    def setPriority(self, priority):
+        self.mPriority = priority
+
+
+    def getCompleted(self):
+        return self.mCompleted
+
+
+    def hasCompleted(self):
+        return self.mHasCompleted
+
+
+    def finalise(self):
+        # Do inherited
+        super(VToDo, self).finalise()
+
+        # Get DUE
+        temp = self.loadValueDateTime(definitions.cICalProperty_DUE)
+        if temp is None:
+            # Try DURATION instead
+            temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
+            if temp is not None:
+                self.mEnd = self.mStart + temp
+                self.mHasEnd = True
+            else:
+                self.mHasEnd = False
+        else:
+            self.mHasEnd = True
+            self.mEnd = temp
+
+        # Get PRIORITY
+        self.mPriority = self.loadValueInteger(definitions.cICalProperty_PRIORITY)
+
+        # Get STATUS
+        temp = self.loadValueString(definitions.cICalProperty_STATUS)
+        if temp is not None:
+            if temp == definitions.cICalProperty_STATUS_NEEDS_ACTION:
+                self.mStatus = definitions.eStatus_VToDo_NeedsAction
+            elif temp == definitions.cICalProperty_STATUS_COMPLETED:
+                self.mStatus = definitions.eStatus_VToDo_Completed
+            elif temp == definitions.cICalProperty_STATUS_IN_PROCESS:
+                self.mStatus = definitions.eStatus_VToDo_InProcess
+            elif temp == definitions.cICalProperty_STATUS_CANCELLED:
+                self.mStatus = definitions.eStatus_VToDo_Cancelled
+
+        # Get PERCENT-COMPLETE
+        self.mPercentComplete = self.loadValueInteger(definitions.cICalProperty_PERCENT_COMPLETE)
+
+        # Get COMPLETED
+        temp = self.loadValueDateTime(definitions.cICalProperty_COMPLETED)
+        self.mHasCompleted = temp is not None
+        if self.mHasCompleted:
+            self.mCompleted = temp
+
+
+    def validate(self, doFix=False):
+        &quot;&quot;&quot;
+        Validate the data in this component and optionally fix any problems, else raise. If
+        loggedProblems is not None it must be a C{list} and problem descriptions are appended
+        to that.
+        &quot;&quot;&quot;
+
+        fixed, unfixed = super(VToDo, self).validate(doFix)
+
+        # Extra constraint: only one of DUE or DURATION
+        if self.hasProperty(definitions.cICalProperty_DUE) and self.hasProperty(definitions.cICalProperty_DURATION):
+            # Fix by removing the DURATION
+            logProblem = &quot;[%s] Properties must not both be present: %s, %s&quot; % (
+                self.getType(),
+                definitions.cICalProperty_DUE,
+                definitions.cICalProperty_DURATION,
+            )
+            if doFix:
+                self.removeProperties(definitions.cICalProperty_DURATION)
+                fixed.append(logProblem)
+            else:
+                unfixed.append(logProblem)
+
+        # Extra constraint: DTSTART must be present if DURATION is present
+        if self.hasProperty(definitions.cICalProperty_DURATION) and not self.hasProperty(definitions.cICalProperty_DTSTART):
+            # Cannot fix this one
+            logProblem = &quot;[%s] Property must be present: %s with %s&quot; % (
+                self.getType(),
+                definitions.cICalProperty_DTSTART,
+                definitions.cICalProperty_DURATION,
+            )
+            unfixed.append(logProblem)
+
+        return fixed, unfixed
+
+
+    # Editing
+    def editStatus(self, status):
+        # Only if it is different
+        if self.mStatus != status:
+            # Updated cached values
+            self.mStatus = status
+
+            # Remove existing STATUS &amp; COMPLETED items
+            self.removeProperties(definitions.cICalProperty_STATUS)
+            self.removeProperties(definitions.cICalProperty_COMPLETED)
+            self.mHasCompleted = False
+
+            # Now create properties
+            value = None
+            if status == definitions.eStatus_VToDo_NeedsAction:
+                value = definitions.cICalProperty_STATUS_NEEDS_ACTION
+            if status == definitions.eStatus_VToDo_Completed:
+                value = definitions.cICalProperty_STATUS_COMPLETED
+                # Add the completed item
+                self.mCompleted.setNowUTC()
+                self.mHasCompleted = True
+                prop = Property(definitions.cICalProperty_STATUS_COMPLETED, self.mCompleted)
+                self.addProperty(prop)
+            elif status == definitions.eStatus_VToDo_InProcess:
+                value = definitions.cICalProperty_STATUS_IN_PROCESS
+            elif status == definitions.eStatus_VToDo_Cancelled:
+                value = definitions.cICalProperty_STATUS_CANCELLED
+            prop = Property(definitions.cICalProperty_STATUS, value)
+            self.addProperty(prop)
+
+
+    def editCompleted(self, completed):
+        # Remove existing COMPLETED item
+        self.removeProperties(definitions.cICalProperty_COMPLETED)
+        self.mHasCompleted = False
+
+        # Always UTC
+        self.mCompleted = completed.duplicate()
+        self.mCompleted.adjustToUTC()
+        self.mHasCompleted = True
+        prop = Property(definitions.cICalProperty_STATUS_COMPLETED, self.mCompleted)
+        self.addProperty(prop)
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_UID,
+            definitions.cICalProperty_RECURRENCE_ID,
+            definitions.cICalProperty_DTSTART,
+            definitions.cICalProperty_DURATION,
+            definitions.cICalProperty_DUE,
+            definitions.cICalProperty_COMPLETED,
+        )
+
+Component.registerComponent(definitions.cICalComponent_VTODO, VToDo)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarvunknownpyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarvunknownpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/vunknown.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/vunknown.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/vunknown.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/vunknown.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,68 @@
</span><ins>+##
+#    Copyright (c) 2011-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.icalendar import definitions
+from pycalendar.icalendar.component import Component
+from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
+import uuid
+
+class UnknownComponent(Component):
+
+    propertyValueChecks = ICALENDAR_VALUE_CHECKS
+
+    def __init__(self, parent=None, comptype=&quot;&quot;):
+        super(UnknownComponent, self).__init__(parent=parent)
+        self.mType = comptype
+        self.mMapKey = str(uuid.uuid4())
+
+
+    def duplicate(self, parent=None):
+        return super(UnknownComponent, self).duplicate(parent=parent, comptype=self.mType)
+
+
+    def getType(self):
+        return self.mType
+
+
+    def getBeginDelimiter(self):
+        return &quot;BEGIN:&quot; + self.mType
+
+
+    def getEndDelimiter(self):
+        return &quot;END:&quot; + self.mType
+
+
+    def getMimeComponentName(self):
+        return &quot;unknown&quot;
+
+
+    def getMapKey(self):
+        return self.mMapKey
+
+
+    def getSortKey(self):
+        &quot;&quot;&quot;
+        We do not want unknown components sorted.
+        &quot;&quot;&quot;
+        return &quot;&quot;
+
+
+    def sortedPropertyKeyOrder(self):
+        return (
+            definitions.cICalProperty_UID,
+        )
+
+Component.registerComponent(definitions.cICalComponent_UNKNOWN, UnknownComponent)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaricalendarxmldefinitionspyfromrev11912PyCalendarbranchesjson2srcpycalendaricalendarxmldefinitionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/icalendar/xmldefinitions.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/icalendar/xmldefinitions.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/icalendar/xmldefinitions.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/icalendar/xmldefinitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,56 @@
</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.
+##
+
+# iCalendar XML definitions
+
+iCalendar20_namespace = &quot;urn:ietf:params:xml:ns:icalendar-2.0&quot;
+
+icalendar = &quot;icalendar&quot;
+
+value_recur = &quot;recur&quot;
+
+recur_freq = &quot;freq&quot;
+recur_freq_secondly = &quot;SECONDLY&quot;
+recur_freq_minutely = &quot;MINUTELY&quot;
+recur_freq_hourly = &quot;HOURLY&quot;
+recur_freq_daily = &quot;DAILY&quot;
+recur_freq_weekly = &quot;WEEKLY&quot;
+recur_freq_monthly = &quot;MONTHLY&quot;
+recur_freq_yearly = &quot;YEARLY&quot;
+
+recur_count = &quot;count&quot;
+recur_until = &quot;until&quot;
+recur_interval = &quot;interval&quot;
+
+recur_bysecond = &quot;bysecond&quot;
+recur_byminute = &quot;byminute&quot;
+recur_byhour = &quot;byhour&quot;
+recur_byday = &quot;byday&quot;
+recur_bymonthday = &quot;bymonthday&quot;
+recur_byyearday = &quot;byyearday&quot;
+recur_byweekno = &quot;byweekno&quot;
+recur_bymonth = &quot;bymonth&quot;
+recur_bysetpos = &quot;bysetpos&quot;
+recur_wkst = &quot;wkst&quot;
+
+req_status = &quot;request-status&quot;
+req_status_code = &quot;code&quot;
+req_status_description = &quot;description&quot;
+req_status_data = &quot;data&quot;
+
+geo = &quot;geo&quot;
+geo_longitude = &quot;longitude&quot;
+geo_latitude = &quot;latitude&quot;
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarintegervaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/integervalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/integervalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/integervalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -16,24 +16,24 @@
</span><span class="cx"> 
</span><span class="cx"> # iCalendar UTC Offset value
</span><span class="cx"> 
</span><del>-from pycalendar import xmldefs
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.value import Value
</ins><span class="cx"> 
</span><del>-class PyCalendarIntegerValue(PyCalendarValue):
</del><ins>+class IntegerValue(Value):
</ins><span class="cx"> 
</span><span class="cx">     def __init__(self, value=None):
</span><span class="cx">         self.mValue = value if value is not None else 0
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def duplicate(self):
</span><del>-        return PyCalendarIntegerValue(self.mValue)
</del><ins>+        return IntegerValue(self.mValue)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getType(self):
</span><del>-        return PyCalendarValue.VALUETYPE_INTEGER
</del><ins>+        return Value.VALUETYPE_INTEGER
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def parse(self, data):
</del><ins>+    def parse(self, data, variant):
</ins><span class="cx">         self.mValue = int(data)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -50,6 +50,14 @@
</span><span class="cx">         value.text = str(self.mValue)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def parseJSONValue(self, jobject):
+        self.mValue = int(jobject)
+
+
+    def writeJSONValue(self, jobject):
+        jobject.append(self.mValue)
+
+
</ins><span class="cx">     def getValue(self):
</span><span class="cx">         return self.mValue
</span><span class="cx"> 
</span><span class="lines">@@ -57,4 +65,4 @@
</span><span class="cx">     def setValue(self, value):
</span><span class="cx">         self.mValue = value
</span><span class="cx"> 
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_INTEGER, PyCalendarIntegerValue, xmldefs.value_integer)
</del><ins>+Value.registerType(Value.VALUETYPE_INTEGER, IntegerValue, xmldefinitions.value_integer)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendaritipdefinitionspy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/itipdefinitions.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/itipdefinitions.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/itipdefinitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,42 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.
-##
-
-#     2446 Section 3
-
-cICalMethod_PUBLISH = &quot;PUBLISH&quot;
-cICalMethod_REQUEST = &quot;REQUEST&quot;
-cICalMethod_REFRESH = &quot;REFRESH&quot;
-cICalMethod_CANCEL = &quot;CANCEL&quot;
-cICalMethod_ADD = &quot;ADD&quot;
-cICalMethod_REPLY = &quot;REPLY&quot;
-cICalMethod_COUNTER = &quot;COUNTER&quot;
-cICalMethod_DECLINECOUNTER = &quot;DECLINECOUNTER&quot;
-
-#     2447 Section 2.4
-cICalMIMEMethod_PUBLISH = &quot;publish&quot;
-cICalMIMEMethod_REQUEST = &quot;request&quot;
-cICalMIMEMethod_REFRESH = &quot;refresh&quot;
-cICalMIMEMethod_CANCEL = &quot;cancel&quot;
-cICalMIMEMethod_ADD = &quot;add&quot;
-cICalMIMEMethod_REPLY = &quot;reply&quot;
-cICalMIMEMethod_COUNTER = &quot;counter&quot;
-cICalMIMEMethod_DECLINECOUNTER = &quot;declinecounter&quot;
-
-cICalMIMEComponent_VEVENT = &quot;vevent&quot;
-cICalMIMEComponent_VTODO = &quot;vtodo&quot;
-cICalMIMEComponent_VJOURNAL = &quot;vjournal&quot;
-cICalMIMEComponent_VFREEBUSY = &quot;vfreebusy&quot;
-cICalMIMEComponent_VAVAILABILITY = &quot;vavailability&quot;
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarlocalepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/locale.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/locale.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/locale.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrcpycalendarmanagerpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/manager.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/manager.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/manager.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,14 +14,14 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><del>-class PyCalendarManager(object):
</del><ins>+class CalendarManager(object):
</ins><span class="cx"> 
</span><span class="cx">     sICalendarManager = None
</span><span class="cx"> 
</span><span class="cx">     def __init__(self):
</span><del>-        PyCalendarTimezone.sDefaultTimezone = PyCalendarTimezone()
</del><ins>+        Timezone.sDefaultTimezone = Timezone()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def initManager(self):
</span><span class="lines">@@ -29,31 +29,31 @@
</span><span class="cx"> 
</span><span class="cx">         # Eventually we need to read these from prefs - for now they are
</span><span class="cx">         # hard-coded to my personal prefs!
</span><del>-        self.setDefaultTimezone(PyCalendarTimezone(utc=False, tzid=&quot;US/Eastern&quot;))
</del><ins>+        self.setDefaultTimezone(Timezone(utc=False, tzid=&quot;US/Eastern&quot;))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def setDefaultTimezoneID(self, tzid):
</span><span class="cx">         # Check for UTC
</span><span class="cx">         if tzid == &quot;UTC&quot;:
</span><del>-            temp = PyCalendarTimezone(utc=True)
</del><ins>+            temp = Timezone(utc=True)
</ins><span class="cx">             self.setDefaultTimezone(temp)
</span><span class="cx">         else:
</span><del>-            temp = PyCalendarTimezone(utc=False, tzid=tzid)
</del><ins>+            temp = Timezone(utc=False, tzid=tzid)
</ins><span class="cx">             self.setDefaultTimezone(temp)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def setDefaultTimezone(self, tzid):
</span><del>-        PyCalendarTimezone.sDefaultTimezone = tzid
</del><ins>+        Timezone.sDefaultTimezone = tzid
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getDefaultTimezoneID(self):
</span><del>-        if PyCalendarTimezone.sDefaultTimezone.getUTC():
</del><ins>+        if Timezone.sDefaultTimezone.getUTC():
</ins><span class="cx">             return &quot;UTC&quot;
</span><span class="cx">         else:
</span><del>-            return PyCalendarTimezone.sDefaultTimezone.getTimezoneID()
</del><ins>+            return Timezone.sDefaultTimezone.getTimezoneID()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getDefaultTimezone(self):
</span><del>-        return PyCalendarTimezone.sDefaultTimezone
</del><ins>+        return Timezone.sDefaultTimezone
</ins><span class="cx"> 
</span><del>-PyCalendarManager.sICalendarManager = PyCalendarManager()
</del><ins>+CalendarManager.sICalendarManager = CalendarManager()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarmultivaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/multivalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/multivalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/multivalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,9 +14,9 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.value import Value
</ins><span class="cx"> 
</span><del>-class PyCalendarMultiValue(PyCalendarValue):
</del><ins>+class MultiValue(Value):
</ins><span class="cx"> 
</span><span class="cx">     def __init__(self, type):
</span><span class="cx"> 
</span><span class="lines">@@ -29,7 +29,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def duplicate(self):
</span><del>-        other = PyCalendarMultiValue(self.mType)
</del><ins>+        other = MultiValue(self.mType)
</ins><span class="cx">         other.mValues = [i.duplicate() for i in self.mValues]
</span><span class="cx">         return other
</span><span class="cx"> 
</span><span class="lines">@@ -39,7 +39,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getRealType(self):
</span><del>-        return PyCalendarValue.VALUETYPE_MULTIVALUE
</del><ins>+        return Value.VALUETYPE_MULTIVALUE
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getValue(self):
</span><span class="lines">@@ -57,13 +57,13 @@
</span><span class="cx">     def setValue(self, value):
</span><span class="cx">         newValues = []
</span><span class="cx">         for v in value:
</span><del>-            pyCalendarValue = PyCalendarValue.createFromType(self.mType)
-            pyCalendarValue.setValue(v)
-            newValues.append(pyCalendarValue)
</del><ins>+            val = Value.createFromType(self.mType)
+            val.setValue(v)
+            newValues.append(val)
</ins><span class="cx">         self.mValues = newValues
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def parse(self, data):
</del><ins>+    def parse(self, data, variant):
</ins><span class="cx">         # Tokenize on comma
</span><span class="cx">         if &quot;,&quot; in data:
</span><span class="cx">             tokens = data.split(&quot;,&quot;)
</span><span class="lines">@@ -71,8 +71,8 @@
</span><span class="cx">             tokens = (data,)
</span><span class="cx">         for token in tokens:
</span><span class="cx">             # Create single value, and parse data
</span><del>-            value = PyCalendarValue.createFromType(self.mType)
-            value.parse(token)
</del><ins>+            value = Value.createFromType(self.mType)
+            value.parse(token, variant)
</ins><span class="cx">             self.mValues.append(value)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -93,4 +93,16 @@
</span><span class="cx">         for iter in self.mValues:
</span><span class="cx">             iter.writeXML(node, namespace)
</span><span class="cx"> 
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_MULTIVALUE, PyCalendarMultiValue, None)
</del><ins>+
+    def parseJSONValue(self, jobject):
+        for jvalue in jobject:
+            value = Value.createFromType(self.mType)
+            value.parseJSONValue(jvalue)
+            self.mValues.append(value)
+
+
+    def writeJSONValue(self, jobject):
+        for iter in self.mValues:
+            iter.writeJSONValue(jobject)
+
+Value.registerType(Value.VALUETYPE_MULTIVALUE, MultiValue, None)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarnpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/n.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/n.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,124 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.
-##
-
-# vCard ADR value
-
-from pycalendar import utils
-from pycalendar.valueutils import ValueMixin
-
-class N(ValueMixin):
-    &quot;&quot;&quot;
-    mValue is a tuple of seven str or tuples of str
-    &quot;&quot;&quot;
-
-    (
-        LAST,
-        FIRST,
-        MIDDLE,
-        PREFIX,
-        SUFFIX,
-        MAXITEMS
-    ) = range(6)
-
-    def __init__(self, last=&quot;&quot;, first=&quot;&quot;, middle=&quot;&quot;, prefix=&quot;&quot;, suffix=&quot;&quot;):
-        self.mValue = (last, first, middle, prefix, suffix)
-
-
-    def duplicate(self):
-        return N(*self.mValue)
-
-
-    def __hash__(self):
-        return hash(self.mValue)
-
-
-    def __repr__(self):
-        return &quot;N %s&quot; % (self.getText(),)
-
-
-    def __eq__(self, comp):
-        return self.mValue == comp.mValue
-
-
-    def getFirst(self):
-        return self.mValue[N.FIRST]
-
-
-    def setFirst(self, value):
-        self.mValue[N.FIRST] = value
-
-
-    def getLast(self):
-        return self.mValue[N.LAST]
-
-
-    def setLast(self, value):
-        self.mValue[N.LAST] = value
-
-
-    def getMiddle(self):
-        return self.mValue[N.MIDDLE]
-
-
-    def setMiddle(self, value):
-        self.mValue[N.MIDDLE] = value
-
-
-    def getPrefix(self):
-        return self.mValue[N.PREFIX]
-
-
-    def setPrefix(self, value):
-        self.mValue[N.PREFIX] = value
-
-
-    def getSuffix(self):
-        return self.mValue[N.SUFFIX]
-
-
-    def setSuffix(self, value):
-        self.mValue[N.SUFFIX] = value
-
-
-    def getFullName(self):
-
-
-        def _stringOrList(item):
-            return item if isinstance(item, basestring) else &quot; &quot;.join(item)
-
-        results = []
-        for i in (N.PREFIX, N.FIRST, N.MIDDLE, N.LAST, N.SUFFIX):
-            result = _stringOrList(self.mValue[i])
-            if result:
-                results.append(result)
-
-        return &quot; &quot;.join(results)
-
-
-    def parse(self, data):
-        self.mValue = utils.parseDoubleNestedList(data, N.MAXITEMS)
-
-
-    def generate(self, os):
-        utils.generateDoubleNestedList(os, self.mValue)
-
-
-    def getValue(self):
-        return self.mValue
-
-
-    def setValue(self, value):
-        self.mValue = value
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarnvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/nvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/nvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/nvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,51 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.
-##
-
-# vCard ADR value
-
-from pycalendar.n import N
-from pycalendar.value import PyCalendarValue
-
-class NValue(PyCalendarValue):
-
-    def __init__(self, value=None):
-        self.mValue = value if value is not None else N()
-
-
-    def duplicate(self):
-        return NValue(self.mValue.duplicate())
-
-
-    def getType(self):
-        return PyCalendarValue.VALUETYPE_N
-
-
-    def parse(self, data):
-        self.mValue.parse(data)
-
-
-    def generate(self, os):
-        self.mValue.generate(os)
-
-
-    def getValue(self):
-        return self.mValue
-
-
-    def setValue(self, value):
-        self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_N, NValue, None)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarorgvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/orgvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/orgvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/orgvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,54 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.
-##
-
-# vCard ORG value
-
-from pycalendar import utils
-from pycalendar.value import PyCalendarValue
-
-class OrgValue(PyCalendarValue):
-    &quot;&quot;&quot;
-    mValue is a str or tuple of str
-    &quot;&quot;&quot;
-
-    def __init__(self, value=None):
-        self.mValue = value
-
-
-    def duplicate(self):
-        return OrgValue(self.mValue)
-
-
-    def getType(self):
-        return PyCalendarValue.VALUETYPE_ORG
-
-
-    def parse(self, data):
-        self.mValue = utils.parseTextList(data, ';')
-
-
-    def generate(self, os):
-        utils.generateTextList(os, self.mValue, ';')
-
-
-    def getValue(self):
-        return self.mValue
-
-
-    def setValue(self, value):
-        self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_ORG, OrgValue, None)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendaroutputfilterpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/outputfilter.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/outputfilter.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/outputfilter.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -15,7 +15,7 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class PyCalendarOutputFilter(object):
</del><ins>+class OutputFilter(object):
</ins><span class="cx"> 
</span><span class="cx">     def __init__(self, type):
</span><span class="cx">         self.mType = type
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarparameterpyfromrev11912PyCalendarbranchesjson2srcpycalendarparameterpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/parameter.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/parameter.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/parameter.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/parameter.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,132 @@
</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.
+##
+
+&quot;&quot;&quot;
+ICalendar parameter.
+
+The parameter can consist of one or more values, all string.
+&quot;&quot;&quot;
+
+from pycalendar import xmldefinitions, xmlutils
+from pycalendar.utils import encodeParameterValue
+import xml.etree.cElementTree as XML
+
+class Parameter(object):
+
+    def __init__(self, name, value=None):
+        self.mName = name
+        if value is None:
+            self.mValues = []
+        elif isinstance(value, basestring):
+            self.mValues = [value]
+        else:
+            self.mValues = value
+
+
+    def duplicate(self):
+        other = Parameter(self.mName)
+        other.mValues = self.mValues[:]
+        return other
+
+
+    def __hash__(self):
+        return hash((self.mName.upper(), tuple(self.mValues)))
+
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+
+    def __eq__(self, other):
+        if not isinstance(other, Parameter):
+            return False
+        return self.mName.upper() == other.mName.upper() and self.mValues == other.mValues
+
+
+    def getName(self):
+        return self.mName
+
+
+    def setName(self, name):
+        self.mName = name
+
+
+    def getFirstValue(self):
+        return self.mValues[0]
+
+
+    def getValues(self):
+        return self.mValues
+
+
+    def setValues(self, values):
+        self.mValues = values
+
+
+    def addValue(self, value):
+        self.mValues.append(value)
+
+
+    def removeValue(self, value):
+        self.mValues.remove(value)
+        return len(self.mValues)
+
+
+    def generate(self, os):
+        try:
+            os.write(self.mName)
+
+            # To support vCard 2.1 syntax we allow parameters without values
+            if self.mValues:
+                os.write(&quot;=&quot;)
+
+                first = True
+                for s in self.mValues:
+                    if first:
+                        first = False
+                    else:
+                        os.write(&quot;,&quot;)
+
+                    # Write with quotation if required
+                    self.generateValue(os, s)
+
+        except:
+            # We ignore errors
+            pass
+
+
+    def generateValue(self, os, str):
+
+        # ^-escaping
+        str = encodeParameterValue(str)
+
+        # Look for quoting
+        if str.find(&quot;:&quot;) != -1 or str.find(&quot;;&quot;) != -1 or str.find(&quot;,&quot;) != -1:
+            os.write(&quot;\&quot;%s\&quot;&quot; % (str,))
+        else:
+            os.write(str)
+
+
+    def writeXML(self, node, namespace):
+        param = XML.SubElement(node, xmlutils.makeTag(namespace, self.getName()))
+        for value in self.getValues():
+            # TODO: need to figure out proper value types
+            text = XML.SubElement(param, xmlutils.makeTag(namespace, xmldefinitions.value_text))
+            text.text = value
+
+
+    def writeJSON(self, jobject):
+        jobject[self.getName().lower()] = self.mValues if len(self.mValues) != 1 else self.mValues[0]
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarperiodpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/period.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/period.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/period.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,17 +14,17 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar import xmldefs
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
</del><ins>+from pycalendar import xmldefinitions, xmlutils
+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
</ins><span class="cx"> from pycalendar.valueutils import ValueMixin
</span><span class="cx"> import xml.etree.cElementTree as XML
</span><span class="cx"> 
</span><del>-class PyCalendarPeriod(ValueMixin):
</del><ins>+class Period(ValueMixin):
</ins><span class="cx"> 
</span><span class="cx">     def __init__(self, start=None, end=None, duration=None):
</span><span class="cx"> 
</span><del>-        self.mStart = start if start is not None else PyCalendarDateTime()
</del><ins>+        self.mStart = start if start is not None else DateTime()
</ins><span class="cx"> 
</span><span class="cx">         if end is not None:
</span><span class="cx">             self.mEnd = end
</span><span class="lines">@@ -36,12 +36,12 @@
</span><span class="cx">             self.mUseDuration = True
</span><span class="cx">         else:
</span><span class="cx">             self.mEnd = self.mStart.duplicate()
</span><del>-            self.mDuration = PyCalendarDuration()
</del><ins>+            self.mDuration = Duration()
</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 = PyCalendarPeriod(start=self.mStart.duplicate(), end=self.mEnd.duplicate())
</del><ins>+        other = Period(start=self.mStart.duplicate(), end=self.mEnd.duplicate())
</ins><span class="cx">         other.mUseDuration = self.mUseDuration
</span><span class="cx">         return other
</span><span class="cx"> 
</span><span class="lines">@@ -51,7 +51,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __repr__(self):
</span><del>-        return &quot;PyCalendarPeriod %s&quot; % (self.getText(),)
</del><ins>+        return &quot;Period %s&quot; % (self.getText(),)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __str__(self):
</span><span class="lines">@@ -78,19 +78,19 @@
</span><span class="cx">         return period
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def parse(self, data):
</del><ins>+    def parse(self, data, fullISO=False):
</ins><span class="cx">         splits = data.split('/', 1)
</span><span class="cx">         if len(splits) == 2:
</span><span class="cx">             start = splits[0]
</span><span class="cx">             end = splits[1]
</span><span class="cx"> 
</span><del>-            self.mStart.parse(start)
</del><ins>+            self.mStart.parse(start, fullISO)
</ins><span class="cx">             if end[0] == 'P':
</span><span class="cx">                 self.mDuration.parse(end)
</span><span class="cx">                 self.mUseDuration = True
</span><span class="cx">                 self.mEnd = self.mStart + self.mDuration
</span><span class="cx">             else:
</span><del>-                self.mEnd.parse(end)
</del><ins>+                self.mEnd.parse(end, fullISO)
</ins><span class="cx">                 self.mUseDuration = False
</span><span class="cx">                 self.mDuration = self.mEnd - self.mStart
</span><span class="cx">         else:
</span><span class="lines">@@ -110,17 +110,37 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def writeXML(self, node, namespace):
</span><del>-        start = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.period_start))
</del><ins>+        start = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.period_start))
</ins><span class="cx">         start.text = self.mStart.getXMLText()
</span><span class="cx"> 
</span><span class="cx">         if self.mUseDuration:
</span><del>-            duration = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.period_duration))
</del><ins>+            duration = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.period_duration))
</ins><span class="cx">             duration.text = self.mDuration.getText()
</span><span class="cx">         else:
</span><del>-            end = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.period_end))
</del><ins>+            end = XML.SubElement(node, xmlutils.makeTag(namespace, xmldefinitions.period_end))
</ins><span class="cx">             end.text = self.mEnd.getXMLText()
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def parseJSON(self, jobject):
+        &quot;&quot;&quot;
+        jCal encodes this as an array of two values. We convert back into a single &quot;/&quot;
+        separated string and parse as normal.
+        &quot;&quot;&quot;
+        self.parse(&quot;%s/%s&quot; % tuple(jobject), True)
+
+
+    def writeJSON(self, jobject):
+        &quot;&quot;&quot;
+        jCal encodes this value as an array with two components.
+        &quot;&quot;&quot;
+        value = [self.mStart.getXMLText(), ]
+        if self.mUseDuration:
+            value.append(self.mDuration.getText())
+        else:
+            value.append(self.mEnd.getXMLText())
+        jobject.append(value)
+
+
</ins><span class="cx">     def getStart(self):
</span><span class="cx">         return self.mStart
</span><span class="cx"> 
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarperiodvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/periodvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/periodvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/periodvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,42 +14,14 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar import xmldefs
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.period import Period
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
</ins><span class="cx"> 
</span><del>-class PyCalendarPeriodValue(PyCalendarValue):
</del><ins>+class PeriodValue(WrapperValue, Value):
</ins><span class="cx"> 
</span><del>-    def __init__(self, value=None):
-        self.mValue = value if value is not None else PyCalendarPeriod()
</del><ins>+    _wrappedClass = Period
+    _wrappedType = Value.VALUETYPE_PERIOD
</ins><span class="cx"> 
</span><del>-
-    def duplicate(self):
-        return PyCalendarPeriodValue(self.mValue.duplicate())
-
-
-    def getType(self):
-        return PyCalendarValue.VALUETYPE_PERIOD
-
-
-    def parse(self, data):
-        self.mValue.parse(data)
-
-
-    def generate(self, os):
-        self.mValue.generate(os)
-
-
-    def writeXML(self, node, namespace):
-        value = self.getXMLNode(node, namespace)
-        value.text = self.mValue.writeXML()
-
-
-    def getValue(self):
-        return self.mValue
-
-
-    def setValue(self, value):
-        self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_PERIOD, PyCalendarPeriodValue, xmldefs.value_period)
</del><ins>+Value.registerType(Value.VALUETYPE_PERIOD, PeriodValue, xmldefinitions.value_period)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarplaintextvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/plaintextvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/plaintextvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/plaintextvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,11 +14,11 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-# iCalendar UTC Offset value
</del><ins>+# iCalendar generic text-like value
</ins><span class="cx"> 
</span><del>-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.value import Value
</ins><span class="cx"> 
</span><del>-class PyCalendarPlainTextValue(PyCalendarValue):
</del><ins>+class PlainTextValue(Value):
</ins><span class="cx"> 
</span><span class="cx">     def __init__(self, value=''):
</span><span class="cx">         self.mValue = value
</span><span class="lines">@@ -28,7 +28,7 @@
</span><span class="cx">         return self.__class__(self.mValue)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def parse(self, data):
</del><ins>+    def parse(self, data, variant):
</ins><span class="cx">         # No decoding required
</span><span class="cx">         self.mValue = data
</span><span class="cx"> 
</span><span class="lines">@@ -47,6 +47,14 @@
</span><span class="cx">         value.text = self.mValue
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def parseJSONValue(self, jobject):
+        self.mValue = str(jobject)
+
+
+    def writeJSONValue(self, jobject):
+        jobject.append(self.mValue)
+
+
</ins><span class="cx">     def getValue(self):
</span><span class="cx">         return self.mValue
</span><span class="cx"> 
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarpropertypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/property.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/property.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,227 +14,60 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar import definitions, xmldefs
-from pycalendar import stringutils
-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.binaryvalue import PyCalendarBinaryValue
-from pycalendar.caladdressvalue import PyCalendarCalAddressValue
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.datetimevalue import PyCalendarDateTimeValue
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.durationvalue import PyCalendarDurationValue
-from pycalendar.exceptions import PyCalendarInvalidProperty
-from pycalendar.integervalue import PyCalendarIntegerValue
-from pycalendar.multivalue import PyCalendarMultiValue
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.periodvalue import PyCalendarPeriodValue
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.recurrence import PyCalendarRecurrence
-from pycalendar.recurrencevalue import PyCalendarRecurrenceValue
-from pycalendar.requeststatusvalue import PyCalendarRequestStatusValue
-from pycalendar.unknownvalue import PyCalendarUnknownValue
-from pycalendar.urivalue import PyCalendarURIValue
-from pycalendar.utcoffsetvalue import PyCalendarUTCOffsetValue
</del><ins>+from pycalendar import stringutils, xmlutils, xmldefinitions
+from pycalendar.parameter import Parameter
+from pycalendar.binaryvalue import BinaryValue
+from pycalendar.caladdressvalue import CalAddressValue
+from pycalendar.datetimevalue import DateTimeValue
+from pycalendar.durationvalue import DurationValue
+from pycalendar.exceptions import InvalidProperty
+from pycalendar.integervalue import IntegerValue
+from pycalendar.multivalue import MultiValue
+from pycalendar.periodvalue import PeriodValue
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.unknownvalue import UnknownValue
+from pycalendar.urivalue import URIValue
+from pycalendar.utcoffsetvalue import UTCOffsetValue
</ins><span class="cx"> from pycalendar.utils import decodeParameterValue
</span><del>-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.value import Value
</ins><span class="cx"> import cStringIO as StringIO
</span><span class="cx"> import xml.etree.cElementTree as XML
</span><span class="cx"> 
</span><del>-class PyCalendarProperty(object):
</del><ins>+class PropertyBase(object):
</ins><span class="cx"> 
</span><del>-    sDefaultValueTypeMap = {
</del><ins>+    # Mappings between various tokens and internal definitions
+    sDefaultValueTypeMap = {}
+    sValueTypeMap = {}
+    sTypeValueMap = {}
+    sMultiValues = set()
+    sSpecialVariants = {}
</ins><span class="cx"> 
</span><del>-        # 5545 Section 3.7
-        definitions.cICalProperty_CALSCALE         : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_METHOD           : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_PRODID           : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_VERSION          : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+    sUsesGroup = False
</ins><span class="cx"> 
</span><del>-        # 5545 Section 3.8.1
-        definitions.cICalProperty_ATTACH           : PyCalendarValue.VALUETYPE_URI,
-        definitions.cICalProperty_CATEGORIES       : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_CLASS            : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_COMMENT          : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_DESCRIPTION      : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_GEO              : PyCalendarValue.VALUETYPE_GEO,
-        definitions.cICalProperty_LOCATION         : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_PERCENT_COMPLETE : PyCalendarValue.VALUETYPE_INTEGER,
-        definitions.cICalProperty_PRIORITY         : PyCalendarValue.VALUETYPE_INTEGER,
-        definitions.cICalProperty_RESOURCES        : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_STATUS           : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_SUMMARY          : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+    sVariant = &quot;none&quot;   # Used to differentiate different forms of text parsing
</ins><span class="cx"> 
</span><del>-        # 5545 Section 3.8.2
-        definitions.cICalProperty_COMPLETED : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_DTEND     : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_DUE       : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_DTSTART   : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_DURATION  : PyCalendarValue.VALUETYPE_DURATION,
-        definitions.cICalProperty_FREEBUSY  : PyCalendarValue.VALUETYPE_PERIOD,
-        definitions.cICalProperty_TRANSP    : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+    sValue = None
+    sText = None
</ins><span class="cx"> 
</span><del>-        # 5545 Section 3.8.3
-        definitions.cICalProperty_TZID         : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_TZNAME       : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_TZOFFSETFROM : PyCalendarValue.VALUETYPE_UTC_OFFSET,
-        definitions.cICalProperty_TZOFFSETTO   : PyCalendarValue.VALUETYPE_UTC_OFFSET,
-        definitions.cICalProperty_TZURL        : PyCalendarValue.VALUETYPE_URI,
</del><ins>+    @classmethod
+    def registerDefaultValue(cls, propname, valuetype):
+        if propname not in cls.sDefaultValueTypeMap:
+            cls.sDefaultValueTypeMap[propname] = valuetype
</ins><span class="cx"> 
</span><del>-        # 5545 Section 3.8.4
-        definitions.cICalProperty_ATTENDEE      : PyCalendarValue.VALUETYPE_CALADDRESS,
-        definitions.cICalProperty_CONTACT       : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_ORGANIZER     : PyCalendarValue.VALUETYPE_CALADDRESS,
-        definitions.cICalProperty_RECURRENCE_ID : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_RELATED_TO    : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_URL           : PyCalendarValue.VALUETYPE_URI,
-        definitions.cICalProperty_UID           : PyCalendarValue.VALUETYPE_TEXT,
</del><span class="cx"> 
</span><del>-        # 5545 Section 3.8.5
-        definitions.cICalProperty_EXDATE : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_EXRULE : PyCalendarValue.VALUETYPE_RECUR, # 2445 only
-        definitions.cICalProperty_RDATE  : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_RRULE  : PyCalendarValue.VALUETYPE_RECUR,
-
-        # 5545 Section 3.8.6
-        definitions.cICalProperty_ACTION  : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_REPEAT  : PyCalendarValue.VALUETYPE_INTEGER,
-        definitions.cICalProperty_TRIGGER : PyCalendarValue.VALUETYPE_DURATION,
-
-        # 5545 Section 3.8.7
-        definitions.cICalProperty_CREATED       : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_DTSTAMP       : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_LAST_MODIFIED : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_SEQUENCE      : PyCalendarValue.VALUETYPE_INTEGER,
-
-        # 5545 Section 3.8.8
-        definitions.cICalProperty_REQUEST_STATUS : PyCalendarValue.VALUETYPE_REQUEST_STATUS,
-
-        # Extensions: draft-daboo-valarm-extensions-03
-        definitions.cICalProperty_ACKNOWLEDGED   : PyCalendarValue.VALUETYPE_DATETIME,
-
-        # Apple Extensions
-        definitions.cICalProperty_XWRCALNAME  : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_XWRCALDESC  : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_XWRALARMUID : PyCalendarValue.VALUETYPE_TEXT,
-
-        # Mulberry extensions
-        definitions.cICalProperty_ACTION_X_SPEAKTEXT  : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalProperty_ALARM_X_LASTTRIGGER : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalProperty_ALARM_X_ALARMSTATUS : PyCalendarValue.VALUETYPE_TEXT,
-    }
-
-    sValueTypeMap = {
-
-        # 5545 Section 3.3
-        definitions.cICalValue_BINARY      : PyCalendarValue.VALUETYPE_BINARY,
-        definitions.cICalValue_BOOLEAN     : PyCalendarValue.VALUETYPE_BOOLEAN,
-        definitions.cICalValue_CAL_ADDRESS : PyCalendarValue.VALUETYPE_CALADDRESS,
-        definitions.cICalValue_DATE        : PyCalendarValue.VALUETYPE_DATE,
-        definitions.cICalValue_DATE_TIME   : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.cICalValue_DURATION    : PyCalendarValue.VALUETYPE_DURATION,
-        definitions.cICalValue_FLOAT       : PyCalendarValue.VALUETYPE_FLOAT,
-        definitions.cICalValue_INTEGER     : PyCalendarValue.VALUETYPE_INTEGER,
-        definitions.cICalValue_PERIOD      : PyCalendarValue.VALUETYPE_PERIOD,
-        definitions.cICalValue_RECUR       : PyCalendarValue.VALUETYPE_RECUR,
-        definitions.cICalValue_TEXT        : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.cICalValue_TIME        : PyCalendarValue.VALUETYPE_TIME,
-        definitions.cICalValue_URI         : PyCalendarValue.VALUETYPE_URI,
-        definitions.cICalValue_UTC_OFFSET  : PyCalendarValue.VALUETYPE_UTC_OFFSET,
-    }
-
-    sTypeValueMap = {
-
-        # 5545 Section 3.3
-        PyCalendarValue.VALUETYPE_BINARY         : definitions.cICalValue_BINARY,
-        PyCalendarValue.VALUETYPE_BOOLEAN        : definitions.cICalValue_BOOLEAN,
-        PyCalendarValue.VALUETYPE_CALADDRESS     : definitions.cICalValue_CAL_ADDRESS,
-        PyCalendarValue.VALUETYPE_DATE           : definitions.cICalValue_DATE,
-        PyCalendarValue.VALUETYPE_DATETIME       : definitions.cICalValue_DATE_TIME,
-        PyCalendarValue.VALUETYPE_DURATION       : definitions.cICalValue_DURATION,
-        PyCalendarValue.VALUETYPE_FLOAT          : definitions.cICalValue_FLOAT,
-        PyCalendarValue.VALUETYPE_GEO            : definitions.cICalValue_FLOAT,
-        PyCalendarValue.VALUETYPE_INTEGER        : definitions.cICalValue_INTEGER,
-        PyCalendarValue.VALUETYPE_PERIOD         : definitions.cICalValue_PERIOD,
-        PyCalendarValue.VALUETYPE_RECUR          : definitions.cICalValue_RECUR,
-        PyCalendarValue.VALUETYPE_TEXT           : definitions.cICalValue_TEXT,
-        PyCalendarValue.VALUETYPE_REQUEST_STATUS : definitions.cICalValue_TEXT,
-        PyCalendarValue.VALUETYPE_TIME           : definitions.cICalValue_TIME,
-        PyCalendarValue.VALUETYPE_URI            : definitions.cICalValue_URI,
-        PyCalendarValue.VALUETYPE_UTC_OFFSET     : definitions.cICalValue_UTC_OFFSET,
-    }
-
-    sMultiValues = set((
-        definitions.cICalProperty_CATEGORIES,
-        definitions.cICalProperty_RESOURCES,
-        definitions.cICalProperty_FREEBUSY,
-        definitions.cICalProperty_EXDATE,
-        definitions.cICalProperty_RDATE,
-    ))
-
-    @staticmethod
-    def registerDefaultValue(propname, valuetype):
-        if propname not in PyCalendarProperty.sDefaultValueTypeMap:
-            PyCalendarProperty.sDefaultValueTypeMap[propname] = valuetype
-
-
</del><span class="cx">     def __init__(self, name=None, value=None, valuetype=None):
</span><del>-        self._init_PyCalendarProperty()
</del><ins>+
</ins><span class="cx">         self.mName = name if name is not None else &quot;&quot;
</span><ins>+        self.mParameters = {}
+        self.mValue = None
</ins><span class="cx"> 
</span><del>-        # The None check speeds up .duplicate()
-        if value is None:
-            pass
</del><span class="cx"> 
</span><del>-        # Order these based on most likely occurrence to speed up this method
-        elif isinstance(value, str):
-            self._init_attr_value_text(value, valuetype if valuetype else PyCalendarProperty.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarValue.VALUETYPE_UNKNOWN))
-
-        elif isinstance(value, PyCalendarDateTime):
-            self._init_attr_value_datetime(value)
-
-        elif isinstance(value, PyCalendarDuration):
-            self._init_attr_value_duration(value)
-
-        elif isinstance(value, PyCalendarRecurrence):
-            self._init_attr_value_recur(value)
-
-        elif isinstance(value, PyCalendarPeriod):
-            self._init_attr_value_period(value)
-
-        elif isinstance(value, int):
-            self._init_attr_value_int(value)
-
-        elif isinstance(value, list):
-            if name.upper() == definitions.cICalProperty_REQUEST_STATUS:
-                self._init_attr_value_requeststatus(value)
-            else:
-                period_list = False
-                if len(value) != 0:
-                    period_list = isinstance(value[0], PyCalendarPeriod)
-                if period_list:
-                    self._init_attr_value_periodlist(value)
-                else:
-                    self._init_attr_value_datetimelist(value)
-
-        elif isinstance(value, PyCalendarUTCOffsetValue):
-            self._init_attr_value_utcoffset(value)
-
-
</del><span class="cx">     def duplicate(self):
</span><del>-        other = PyCalendarProperty(self.mName)
-        for attrname, attrs in self.mAttributes.items():
-            other.mAttributes[attrname] = [i.duplicate() for i in attrs]
-        other.mValue = self.mValue.duplicate()
</del><ins>+        raise NotImplementedError
</ins><span class="cx"> 
</span><del>-        return other
</del><span class="cx"> 
</span><del>-
</del><span class="cx">     def __hash__(self):
</span><del>-        return hash((
-            self.mName,
-            tuple([tuple(self.mAttributes[attrname]) for attrname in sorted(self.mAttributes.keys())]),
-            self.mValue,
-        ))
</del><ins>+        raise NotImplementedError
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __ne__(self, other):
</span><span class="lines">@@ -242,19 +75,26 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __eq__(self, other):
</span><del>-        if not isinstance(other, PyCalendarProperty):
-            return False
-        return self.mName == other.mName and self.mValue == other.mValue and self.mAttributes == other.mAttributes
</del><ins>+        raise NotImplementedError
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __repr__(self):
</span><del>-        return &quot;PyCalendarProperty: %s&quot; % (self.getText(),)
</del><ins>+        return &quot;Property: %s&quot; % (self.getText(),)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __str__(self):
</span><span class="cx">         return self.getText()
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def getGroup(self):
+        return self.mGroup if self.sUsesGroup else None
+
+
+    def setGroup(self, group):
+        if self.sUsesGroup:
+            self.mGroup = group
+
+
</ins><span class="cx">     def getName(self):
</span><span class="cx">         return self.mName
</span><span class="cx"> 
</span><span class="lines">@@ -263,33 +103,33 @@
</span><span class="cx">         self.mName = name
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def getAttributes(self):
-        return self.mAttributes
</del><ins>+    def getParameters(self):
+        return self.mParameters
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def setAttributes(self, attributes):
-        self.mAttributes = dict([(k.upper(), v) for k, v in attributes.iteritems()])
</del><ins>+    def setParameters(self, parameters):
+        self.mParameters = dict([(k.upper(), v) for k, v in parameters.iteritems()])
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def hasAttribute(self, attr):
-        return attr.upper() in self.mAttributes
</del><ins>+    def hasParameter(self, attr):
+        return attr.upper() in self.mParameters
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def getAttributeValue(self, attr):
-        return self.mAttributes[attr.upper()][0].getFirstValue()
</del><ins>+    def getParameterValue(self, attr):
+        return self.mParameters[attr.upper()][0].getFirstValue()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def addAttribute(self, attr):
-        self.mAttributes.setdefault(attr.getName().upper(), []).append(attr)
</del><ins>+    def addParameter(self, attr):
+        self.mParameters.setdefault(attr.getName().upper(), []).append(attr)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def replaceAttribute(self, attr):
-        self.mAttributes[attr.getName().upper()] = [attr]
</del><ins>+    def replaceParameter(self, attr):
+        self.mParameters[attr.getName().upper()] = [attr]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def removeAttributes(self, attr):
-        if attr.upper() in self.mAttributes:
-            del self.mAttributes[attr.upper()]
</del><ins>+    def removeParameters(self, attr):
+        if attr.upper() in self.mParameters:
+            del self.mParameters[attr.upper()]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getValue(self):
</span><span class="lines">@@ -298,7 +138,7 @@
</span><span class="cx"> 
</span><span class="cx">     def getBinaryValue(self):
</span><span class="cx"> 
</span><del>-        if isinstance(self.mValue, PyCalendarBinaryValue):
</del><ins>+        if isinstance(self.mValue, BinaryValue):
</ins><span class="cx">             return self.mValue
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="lines">@@ -306,7 +146,7 @@
</span><span class="cx"> 
</span><span class="cx">     def getCalAddressValue(self):
</span><span class="cx"> 
</span><del>-        if isinstance(self.mValue, PyCalendarCalAddressValue):
</del><ins>+        if isinstance(self.mValue, CalAddressValue):
</ins><span class="cx">             return self.mValue
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="lines">@@ -314,7 +154,7 @@
</span><span class="cx"> 
</span><span class="cx">     def getDateTimeValue(self):
</span><span class="cx"> 
</span><del>-        if isinstance(self.mValue, PyCalendarDateTimeValue):
</del><ins>+        if isinstance(self.mValue, DateTimeValue):
</ins><span class="cx">             return self.mValue
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="lines">@@ -322,7 +162,7 @@
</span><span class="cx"> 
</span><span class="cx">     def getDurationValue(self):
</span><span class="cx"> 
</span><del>-        if isinstance(self.mValue, PyCalendarDurationValue):
</del><ins>+        if isinstance(self.mValue, DurationValue):
</ins><span class="cx">             return self.mValue
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="lines">@@ -330,7 +170,7 @@
</span><span class="cx"> 
</span><span class="cx">     def getIntegerValue(self):
</span><span class="cx"> 
</span><del>-        if isinstance(self.mValue, PyCalendarIntegerValue):
</del><ins>+        if isinstance(self.mValue, IntegerValue):
</ins><span class="cx">             return self.mValue
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="lines">@@ -338,7 +178,7 @@
</span><span class="cx"> 
</span><span class="cx">     def getMultiValue(self):
</span><span class="cx"> 
</span><del>-        if isinstance(self.mValue, PyCalendarMultiValue):
</del><ins>+        if isinstance(self.mValue, MultiValue):
</ins><span class="cx">             return self.mValue
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="lines">@@ -346,23 +186,15 @@
</span><span class="cx"> 
</span><span class="cx">     def getPeriodValue(self):
</span><span class="cx"> 
</span><del>-        if isinstance(self.mValue, PyCalendarPeriodValue):
</del><ins>+        if isinstance(self.mValue, PeriodValue):
</ins><span class="cx">             return self.mValue
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def getRecurrenceValue(self):
-
-        if isinstance(self.mValue, PyCalendarRecurrenceValue):
-            return self.mValue
-        else:
-            return None
-
-
</del><span class="cx">     def getTextValue(self):
</span><span class="cx"> 
</span><del>-        if isinstance(self.mValue, PyCalendarPlainTextValue):
</del><ins>+        if isinstance(self.mValue, PlainTextValue):
</ins><span class="cx">             return self.mValue
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="lines">@@ -370,7 +202,7 @@
</span><span class="cx"> 
</span><span class="cx">     def getURIValue(self):
</span><span class="cx"> 
</span><del>-        if isinstance(self.mValue, PyCalendarURIValue):
</del><ins>+        if isinstance(self.mValue, URIValue):
</ins><span class="cx">             return self.mValue
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="lines">@@ -378,70 +210,113 @@
</span><span class="cx"> 
</span><span class="cx">     def getUTCOffsetValue(self):
</span><span class="cx"> 
</span><del>-        if isinstance(self.mValue, PyCalendarUTCOffsetValue):
</del><ins>+        if isinstance(self.mValue, UTCOffsetValue):
</ins><span class="cx">             return self.mValue
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def parse(self, data):
-        # Look for attribute or value delimiter
-        prop_name, txt = stringutils.strduptokenstr(data, &quot;;:&quot;)
-        if not prop_name:
-            raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
</del><ins>+    @classmethod
+    def parseText(cls, data):
+        &quot;&quot;&quot;
+        Parse the text format data and return a L{Property}
</ins><span class="cx"> 
</span><del>-        # We have the name
-        self.mName = prop_name
</del><ins>+        @param data: text data
+        @type data: C{str}
+        &quot;&quot;&quot;
</ins><span class="cx"> 
</span><del>-        # TODO: Try to use static string for the name
</del><ins>+        try:
+            prop = cls()
</ins><span class="cx"> 
</span><del>-        # Now loop getting data
</del><ins>+            # Look for parameter or value delimiter
+            prop_name, txt = stringutils.strduptokenstr(data, &quot;;:&quot;)
+            if not prop_name:
+                raise InvalidProperty(&quot;Invalid property&quot;, data)
+
+            # Get the name
+            if prop.sUsesGroup:
+                # Check for group prefix
+                splits = prop_name.split(&quot;.&quot;, 1)
+                if len(splits) == 2:
+                    # We have both group and name
+                    prop.mGroup = splits[0]
+                    prop.mName = splits[1]
+                else:
+                    # We have the name
+                    prop.mName = prop_name
+            else:
+                prop.mName = prop_name
+
+            # Get the parameters
+            txt = prop.parseTextParameters(txt, data)
+
+            # Tidy first
+            prop.mValue = None
+
+            # Get value type from property name
+            value_type = prop.determineValueType()
+
+            # Check for multivalued
+            if prop.mName.upper() in prop.sMultiValues:
+                prop.mValue = MultiValue(value_type)
+            else:
+                # Create the type
+                prop.mValue = Value.createFromType(value_type)
+
+            # Now parse the data
+            prop.mValue.parse(txt, prop.sVariant)
+
+            prop._postCreateValue(value_type)
+
+            return prop
+
+        except Exception:
+            raise InvalidProperty(&quot;Invalid property&quot;, data)
+
+
+    def parseTextParameters(self, txt, data):
+        &quot;&quot;&quot;
+        Parse parameters, return string point at value.
+        &quot;&quot;&quot;
+
</ins><span class="cx">         try:
</span><span class="cx">             while txt:
</span><span class="cx">                 if txt[0] == ';':
</span><del>-                    # Parse attribute
</del><ins>+                    # Parse parameter
</ins><span class="cx"> 
</span><span class="cx">                     # Move past delimiter
</span><span class="cx">                     txt = txt[1:]
</span><span class="cx"> 
</span><span class="cx">                     # Get quoted string or token
</span><del>-                    attribute_name, txt = stringutils.strduptokenstr(txt, &quot;=&quot;)
-                    if attribute_name is None:
-                        raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
</del><ins>+                    parameter_name, txt = stringutils.strduptokenstr(txt, &quot;=&quot;)
+                    if parameter_name is None:
+                        raise InvalidProperty(&quot;Invalid property&quot;, data)
</ins><span class="cx">                     txt = txt[1:]
</span><del>-                    attribute_value, txt = stringutils.strduptokenstr(txt, &quot;:;,&quot;)
-                    if attribute_value is None:
-                        raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
</del><ins>+                    parameter_value, txt = stringutils.strduptokenstr(txt, &quot;:;,&quot;)
+                    if parameter_value is None:
+                        raise InvalidProperty(&quot;Invalid property&quot;, data)
</ins><span class="cx"> 
</span><del>-                    # Now add attribute value (decode ^-escpaing)
-                    attrvalue = PyCalendarAttribute(name=attribute_name, value=decodeParameterValue(attribute_value))
-                    self.mAttributes.setdefault(attribute_name.upper(), []).append(attrvalue)
</del><ins>+                    # Now add parameter value (decode ^-escaping)
+                    attrvalue = Parameter(name=parameter_name, value=decodeParameterValue(parameter_value))
+                    self.mParameters.setdefault(parameter_name.upper(), []).append(attrvalue)
</ins><span class="cx"> 
</span><span class="cx">                     # Look for additional values
</span><span class="cx">                     while txt[0] == ',':
</span><span class="cx">                         txt = txt[1:]
</span><del>-                        attribute_value2, txt = stringutils.strduptokenstr(txt, &quot;:;,&quot;)
-                        if attribute_value2 is None:
-                            raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
-                        attrvalue.addValue(decodeParameterValue(attribute_value2))
</del><ins>+                        parameter_value2, txt = stringutils.strduptokenstr(txt, &quot;:;,&quot;)
+                        if parameter_value2 is None:
+                            raise InvalidProperty(&quot;Invalid property&quot;, data)
+                        attrvalue.addValue(decodeParameterValue(parameter_value2))
</ins><span class="cx">                 elif txt[0] == ':':
</span><del>-                    txt = txt[1:]
-                    self.createValue(txt)
-                    txt = None
</del><ins>+                    return txt[1:]
</ins><span class="cx">                 else:
</span><span class="cx">                     # We should never get here but if we do we need to terminate the loop
</span><del>-                    raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
</del><ins>+                    raise InvalidProperty(&quot;Invalid property&quot;, data)
</ins><span class="cx"> 
</span><span class="cx">         except IndexError:
</span><del>-            raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
</del><ins>+            raise InvalidProperty(&quot;Invalid property&quot;, data)
</ins><span class="cx"> 
</span><del>-        # We must have a value of some kind
-        if self.mValue is None:
-            raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
</del><span class="cx"> 
</span><del>-        return True
-
-
</del><span class="cx">     def getText(self):
</span><span class="cx">         os = StringIO.StringIO()
</span><span class="cx">         self.generate(os)
</span><span class="lines">@@ -465,15 +340,17 @@
</span><span class="cx">     # Write out the actual property, possibly skipping the value
</span><span class="cx">     def generateValue(self, os, novalue):
</span><span class="cx"> 
</span><del>-        self.setupValueAttribute()
</del><ins>+        self.setupValueParameter()
</ins><span class="cx"> 
</span><span class="cx">         # Must write to temp buffer and then wrap
</span><span class="cx">         sout = StringIO.StringIO()
</span><ins>+        if self.sUsesGroup and self.mGroup:
+            sout.write(self.mGroup + &quot;.&quot;)
</ins><span class="cx">         sout.write(self.mName)
</span><span class="cx"> 
</span><del>-        # Write all attributes
-        for key in sorted(self.mAttributes.keys()):
-            for attr in self.mAttributes[key]:
</del><ins>+        # Write all parameters
+        for key in sorted(self.mParameters.keys()):
+            for attr in self.mParameters[key]:
</ins><span class="cx">                 sout.write(&quot;;&quot;)
</span><span class="cx">                 attr.generate(sout)
</span><span class="cx"> 
</span><span class="lines">@@ -493,9 +370,10 @@
</span><span class="cx">             # Look for valid utf8 range and write that out
</span><span class="cx">             start = 0
</span><span class="cx">             written = 0
</span><ins>+            lineWrap = 74
</ins><span class="cx">             while written &lt; len(temp):
</span><span class="cx">                 # Start 74 chars on from where we are
</span><del>-                offset = start + 74
</del><ins>+                offset = start + lineWrap
</ins><span class="cx">                 if offset &gt;= len(temp):
</span><span class="cx">                     line = temp[start:]
</span><span class="cx">                     os.write(line)
</span><span class="lines">@@ -509,6 +387,7 @@
</span><span class="cx">                     line = temp[start:offset]
</span><span class="cx">                     os.write(line)
</span><span class="cx">                     os.write(&quot;\r\n &quot;)
</span><ins>+                    lineWrap = 73   # We are now adding a space at the start
</ins><span class="cx">                     written += offset - start
</span><span class="cx">                     start = offset
</span><span class="cx"> 
</span><span class="lines">@@ -521,7 +400,7 @@
</span><span class="cx">         self.generateValueXML(node, namespace, False)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def generateFilteredXML(self, node, namespace, filter):
</del><ins>+    def writeXMLFiltered(self, node, namespace, filter):
</ins><span class="cx"> 
</span><span class="cx">         # Check for property in filter and whether value is written out
</span><span class="cx">         test, novalue = filter.testPropertyValue(self.mName.upper())
</span><span class="lines">@@ -532,14 +411,14 @@
</span><span class="cx">     # Write out the actual property, possibly skipping the value
</span><span class="cx">     def generateValueXML(self, node, namespace, novalue):
</span><span class="cx"> 
</span><del>-        prop = XML.SubElement(node, xmldefs.makeTag(namespace, self.getName()))
</del><ins>+        prop = XML.SubElement(node, xmlutils.makeTag(namespace, self.getName()))
</ins><span class="cx"> 
</span><del>-        # Write all attributes
-        if len(self.mAttributes):
-            params = XML.SubElement(prop, xmldefs.makeTag(namespace, xmldefs.parameters))
-            for key in sorted(self.mAttributes.keys()):
-                for attr in self.mAttributes[key]:
-                    if attr.getName() != &quot;VALUE&quot;:
</del><ins>+        # Write all parameters
+        if len(self.mParameters):
+            params = XML.SubElement(prop, xmlutils.makeTag(namespace, xmldefinitions.parameters))
+            for key in sorted(self.mParameters.keys()):
+                for attr in self.mParameters[key]:
+                    if attr.getName().lower() != &quot;value&quot;:
</ins><span class="cx">                         attr.writeXML(params, namespace)
</span><span class="cx"> 
</span><span class="cx">         # Write value
</span><span class="lines">@@ -547,90 +426,172 @@
</span><span class="cx">             self.mValue.writeXML(prop, namespace)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def _init_PyCalendarProperty(self):
-        self.mName = &quot;&quot;
-        self.mAttributes = {}
-        self.mValue = None
</del><ins>+    @classmethod
+    def parseJSON(cls, jobject):
+        &quot;&quot;&quot;
+        Parse a JSON property of the form:
</ins><span class="cx"> 
</span><ins>+        [name, attrs, type, value1, value2, ...]
</ins><span class="cx"> 
</span><ins>+        @param jobject: a JSON array
+        @type jobject: C{list}
+        &quot;&quot;&quot;
+
+        try:
+            prop = cls()
+
+            # Get the name
+            prop.mName = jobject[0].upper()
+
+            # Get the parameters
+            if jobject[1]:
+                for name, value in jobject[1].items():
+                    # Now add parameter value
+                    name = name.upper()
+                    attrvalue = Parameter(name=name, value=value)
+                    prop.mParameters.setdefault(name, []).append(attrvalue)
+
+            # Get default value type from property name and insert a VALUE parameter if current value type is not default
+            value_type = cls.sValueTypeMap.get(jobject[2].upper(), Value.VALUETYPE_UNKNOWN)
+            default_type = cls.sDefaultValueTypeMap.get(prop.mName.upper(), Value.VALUETYPE_UNKNOWN)
+            if default_type != value_type:
+                attrvalue = Parameter(name=cls.sValue, value=jobject[2].upper())
+                prop.mParameters.setdefault(cls.sValue, []).append(attrvalue)
+
+            # Get value type from property name
+            value_type = prop.determineValueType()
+
+            # Check for multivalued
+            values = jobject[3:]
+            if prop.mName.upper() in cls.sMultiValues:
+                prop.mValue = MultiValue(value_type)
+                prop.mValue.parseJSONValue(values)
+            else:
+                # Create the type
+                prop.mValue = Value.createFromType(value_type)
+                prop.mValue.parseJSONValue(values[0])
+
+            # Special post-create for some types
+            prop._postCreateValue(value_type)
+
+            return prop
+
+        except Exception:
+            raise InvalidProperty(&quot;Invalid property&quot;, jobject)
+
+
+    def writeJSON(self, jobject):
+
+        # Write it out always with value
+        self.generateValueJSON(jobject, False)
+
+
+    def writeJSONFiltered(self, jobject, filter):
+
+        # Check for property in filter and whether value is written out
+        test, novalue = filter.testPropertyValue(self.mName.upper())
+        if test:
+            self.generateValueJSON(jobject, novalue)
+
+
+    def generateValueJSON(self, jobject, novalue):
+
+        prop = [
+            self.getName().lower(),
+            {},
+        ]
+        jobject.append(prop)
+
+        # Write all parameters
+        for key in sorted(self.mParameters.keys()):
+            for attr in self.mParameters[key]:
+                if attr.getName().lower() != &quot;value&quot;:
+                    attr.writeJSON(prop[1])
+
+        # Write value
+        if self.mValue and not novalue:
+            self.mValue.writeJSON(prop)
+
+
+    def determineValueType(self):
+        # Get value type from property name
+        value_type = self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_UNKNOWN)
+
+        # Check whether custom value is set
+        if self.sValue in self.mParameters:
+            attr = self.getParameterValue(self.sValue)
+            value_type = self.sValueTypeMap.get(attr, value_type)
+
+        # Check for specials
+        if self.mName.upper() in self.sSpecialVariants:
+            # Make sure we have the default value for the special
+            if value_type == self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_UNKNOWN):
+                value_type = self.sSpecialVariants[self.mName.upper()]
+
+        return value_type
+
+
</ins><span class="cx">     def createValue(self, data):
</span><span class="cx">         # Tidy first
</span><span class="cx">         self.mValue = None
</span><span class="cx"> 
</span><span class="cx">         # Get value type from property name
</span><del>-        type = PyCalendarProperty.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarValue.VALUETYPE_UNKNOWN)
</del><ins>+        value_type = self.determineValueType()
</ins><span class="cx"> 
</span><del>-        # Check whether custom value is set
-        if definitions.cICalAttribute_VALUE in self.mAttributes:
-            type = PyCalendarProperty.sValueTypeMap.get(self.getAttributeValue(definitions.cICalAttribute_VALUE), type)
-
</del><span class="cx">         # Check for multivalued
</span><del>-        if self.mName.upper() in PyCalendarProperty.sMultiValues:
-            self.mValue = PyCalendarMultiValue(type)
</del><ins>+        if self.mName.upper() in self.sMultiValues:
+            self.mValue = MultiValue(value_type)
</ins><span class="cx">         else:
</span><span class="cx">             # Create the type
</span><del>-            self.mValue = PyCalendarValue.createFromType(type)
</del><ins>+            self.mValue = Value.createFromType(value_type)
</ins><span class="cx"> 
</span><span class="cx">         # Now parse the data
</span><span class="cx">         try:
</span><del>-            self.mValue.parse(data)
</del><ins>+            self.mValue.parse(data, self.sVariant)
</ins><span class="cx">         except ValueError:
</span><del>-            raise PyCalendarInvalidProperty(&quot;Invalid property value&quot;, data)
</del><ins>+            raise InvalidProperty(&quot;Invalid property value&quot;, data)
</ins><span class="cx"> 
</span><del>-        # Special post-create for some types
-        if type in (PyCalendarValue.VALUETYPE_TIME, PyCalendarValue.VALUETYPE_DATETIME):
-            # Look for TZID attribute
-            tzid = None
-            if (self.hasAttribute(definitions.cICalAttribute_TZID)):
-                tzid = self.getAttributeValue(definitions.cICalAttribute_TZID)
</del><ins>+        self._postCreateValue(value_type)
</ins><span class="cx"> 
</span><del>-                if isinstance(self.mValue, PyCalendarDateTimeValue):
-                    self.mValue.getValue().setTimezoneID(tzid)
-                elif isinstance(self.mValue, PyCalendarMultiValue):
-                    for item in self.mValue.getValues():
-                        if isinstance(item, PyCalendarDateTimeValue):
-                            item.getValue().setTimezoneID(tzid)
</del><span class="cx"> 
</span><ins>+    def _postCreateValue(self, value_type):
+        &quot;&quot;&quot;
+        Do some extra work after creating a value in this property.
</ins><span class="cx"> 
</span><ins>+        @param value_type: the iCalendar VALUE type for this property
+        @type value_type: C{str}
+        &quot;&quot;&quot;
+        pass
+
+
</ins><span class="cx">     def setValue(self, value):
</span><span class="cx">         # Tidy first
</span><span class="cx">         self.mValue = None
</span><span class="cx"> 
</span><span class="cx">         # Get value type from property name
</span><del>-        type = PyCalendarProperty.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarValue.VALUETYPE_TEXT)
</del><ins>+        value_type = self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_TEXT)
</ins><span class="cx"> 
</span><span class="cx">         # Check whether custom value is set
</span><del>-        if definitions.cICalAttribute_VALUE in self.mAttributes:
-            type = PyCalendarProperty.sValueTypeMap.get(self.getAttributeValue(definitions.cICalAttribute_VALUE), type)
</del><ins>+        if self.sValue in self.mParameters:
+            value_type = self.sValueTypeMap.get(self.getParameterValue(self.sValue), value_type)
</ins><span class="cx"> 
</span><span class="cx">         # Check for multivalued
</span><del>-        if self.mName.upper() in PyCalendarProperty.sMultiValues:
-            self.mValue = PyCalendarMultiValue(type)
</del><ins>+        if self.mName.upper() in self.sMultiValues:
+            self.mValue = MultiValue(value_type)
</ins><span class="cx">         else:
</span><span class="cx">             # Create the type
</span><del>-            self.mValue = PyCalendarValue.createFromType(type)
</del><ins>+            self.mValue = Value.createFromType(value_type)
</ins><span class="cx"> 
</span><span class="cx">         self.mValue.setValue(value)
</span><span class="cx"> 
</span><span class="cx">         # Special post-create for some types
</span><del>-        if type in (PyCalendarValue.VALUETYPE_TIME, PyCalendarValue.VALUETYPE_DATETIME):
-            # Look for TZID attribute
-            tzid = None
-            if (self.hasAttribute(definitions.cICalAttribute_TZID)):
-                tzid = self.getAttributeValue(definitions.cICalAttribute_TZID)
</del><ins>+        self._postCreateValue(value_type)
</ins><span class="cx"> 
</span><del>-                if isinstance(self.mValue, PyCalendarDateTimeValue):
-                    self.mValue.getValue().setTimezoneID(tzid)
-                elif isinstance(self.mValue, PyCalendarMultiValue):
-                    for item in self.mValue.getValues():
-                        if isinstance(item, PyCalendarDateTimeValue):
-                            item.getValue().setTimezoneID(tzid)
</del><span class="cx"> 
</span><ins>+    def setupValueParameter(self):
+        if self.sValue in self.mParameters:
+            del self.mParameters[self.sValue]
</ins><span class="cx"> 
</span><del>-    def setupValueAttribute(self):
-        if definitions.cICalAttribute_VALUE in self.mAttributes:
-            del self.mAttributes[definitions.cICalAttribute_VALUE]
-
</del><span class="cx">         # Only if we have a value right now
</span><span class="cx">         if self.mValue is None:
</span><span class="cx">             return
</span><span class="lines">@@ -638,117 +599,47 @@
</span><span class="cx">         # See if current type is default for this property. If there is no mapping available,
</span><span class="cx">         # then always add VALUE if it is not TEXT.
</span><span class="cx">         default_type = self.sDefaultValueTypeMap.get(self.mName.upper())
</span><del>-        actual_type = self.mValue.getType()
</del><ins>+        if self.mName.upper() in self.sSpecialVariants:
+            actual_type = default_type
+        else:
+            actual_type = self.mValue.getType()
</ins><span class="cx">         if default_type is None or default_type != actual_type:
</span><span class="cx">             actual_value = self.sTypeValueMap.get(actual_type)
</span><del>-            if actual_value is not None and (default_type is not None or actual_type != PyCalendarValue.VALUETYPE_TEXT):
-                self.mAttributes.setdefault(definitions.cICalAttribute_VALUE, []).append(PyCalendarAttribute(name=definitions.cICalAttribute_VALUE, value=actual_value))
</del><ins>+            if actual_value is not None and (default_type is not None or actual_type != Value.VALUETYPE_TEXT):
+                self.mParameters.setdefault(self.sValue, []).append(Parameter(name=self.sValue, value=actual_value))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     # Creation
</span><span class="cx">     def _init_attr_value_int(self, ival):
</span><span class="cx">         # Value
</span><del>-        self.mValue = PyCalendarIntegerValue(value=ival)
</del><ins>+        self.mValue = IntegerValue(value=ival)
</ins><span class="cx"> 
</span><del>-        # Attributes
-        self.setupValueAttribute()
</del><ins>+        # Parameters
+        self.setupValueParameter()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def _init_attr_value_text(self, txt, value_type):
</span><span class="cx">         # Value
</span><del>-        self.mValue = PyCalendarValue.createFromType(value_type)
-        if isinstance(self.mValue, PyCalendarPlainTextValue) or isinstance(self.mValue, PyCalendarUnknownValue):
</del><ins>+        self.mValue = Value.createFromType(value_type)
+        if isinstance(self.mValue, PlainTextValue) or isinstance(self.mValue, UnknownValue):
</ins><span class="cx">             self.mValue.setValue(txt)
</span><span class="cx"> 
</span><del>-        # Attributes
-        self.setupValueAttribute()
</del><ins>+        # Parameters
+        self.setupValueParameter()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def _init_attr_value_requeststatus(self, reqstatus):
-        # Value
-        self.mValue = PyCalendarRequestStatusValue(reqstatus)
-
-        # Attributes
-        self.setupValueAttribute()
-
-
</del><span class="cx">     def _init_attr_value_datetime(self, dt):
</span><span class="cx">         # Value
</span><del>-        self.mValue = PyCalendarDateTimeValue(value=dt)
</del><ins>+        self.mValue = DateTimeValue(value=dt)
</ins><span class="cx"> 
</span><del>-        # Attributes
-        self.setupValueAttribute()
</del><ins>+        # Parameters
+        self.setupValueParameter()
</ins><span class="cx"> 
</span><del>-        # Look for timezone
-        if not dt.isDateOnly() and dt.local():
-            if definitions.cICalAttribute_TZID in self.mAttributes:
-                del self.mAttributes[definitions.cICalAttribute_TZID]
-            self.mAttributes.setdefault(definitions.cICalAttribute_TZID, []).append(
-                    PyCalendarAttribute(name=definitions.cICalAttribute_TZID, value=dt.getTimezoneID()))
</del><span class="cx"> 
</span><del>-
-    def _init_attr_value_datetimelist(self, dtl):
-        # Value
-        date_only = (len(dtl) &gt; 0) and dtl[0].isDateOnly()
-        if date_only:
-            self.mValue = PyCalendarMultiValue(PyCalendarValue.VALUETYPE_DATE)
-        else:
-            self.mValue = PyCalendarMultiValue(PyCalendarValue.VALUETYPE_DATETIME)
-
-        for dt in dtl:
-            self.mValue.addValue(PyCalendarDateTimeValue(dt))
-
-        # Attributes
-        self.setupValueAttribute()
-
-        # Look for timezone
-        if ((len(dtl) &gt; 0)
-                and not dtl[0].isDateOnly()
-                and dtl[0].local()):
-            if definitions.cICalAttribute_TZID in self.mAttributes:
-                del self.mAttributes[definitions.cICalAttribute_TZID]
-            self.mAttributes.setdefault(definitions.cICalAttribute_TZID, []).append(
-                    PyCalendarAttribute(name=definitions.cICalAttribute_TZID, value=dtl[0].getTimezoneID()))
-
-
-    def _init_attr_value_periodlist(self, periodlist):
-        # Value
-        self.mValue = PyCalendarMultiValue(PyCalendarValue.VALUETYPE_PERIOD)
-        for period in periodlist:
-            self.mValue.addValue(PyCalendarPeriodValue(period))
-
-        # Attributes
-        self.setupValueAttribute()
-
-
-    def _init_attr_value_duration(self, du):
-        # Value
-        self.mValue = PyCalendarDurationValue(value=du)
-
-        # Attributes
-        self.setupValueAttribute()
-
-
-    def _init_attr_value_period(self, pe):
-        # Value
-        self.mValue = PyCalendarPeriodValue(value=pe)
-
-        # Attributes
-        self.setupValueAttribute()
-
-
-    def _init_attr_value_recur(self, recur):
-        # Value
-        self.mValue = PyCalendarRecurrenceValue(value=recur)
-
-        # Attributes
-        self.setupValueAttribute()
-
-
</del><span class="cx">     def _init_attr_value_utcoffset(self, utcoffset):
</span><span class="cx">         # Value
</span><del>-        self.mValue = PyCalendarUTCOffsetValue()
</del><ins>+        self.mValue = UTCOffsetValue()
</ins><span class="cx">         self.mValue.setValue(utcoffset.getValue())
</span><span class="cx"> 
</span><del>-        # Attributes
-        self.setupValueAttribute()
</del><ins>+        # Parameters
+        self.setupValueParameter()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarrecurrencepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/recurrence.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/recurrence.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/recurrence.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,1637 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from pycalendar import xmldefs
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.valueutils import ValueMixin
-import cStringIO as StringIO
-import xml.etree.cElementTree as XML
-
-def WeekDayNumCompare_compare(w1, w2):
-
-    if w1[0] &lt; w2[0]:
-        return -1
-    elif w1[0] &gt; w2[0]:
-        return 1
-    elif w1[1] &lt; w2[1]:
-        return -1
-    elif w1[1] &gt; w2[1]:
-        return 1
-    else:
-        return 0
-
-
-
-def WeekDayNumSort_less_than(w1, w2):
-
-    return (w1[0] &lt; w2[0]) or (w1[0] == w2[0]) and (w1[1] &lt; w2[1])
-
-
-
-class PyCalendarRecurrence(ValueMixin):
-
-    cFreqMap = {
-        definitions.cICalValue_RECUR_SECONDLY : definitions.eRecurrence_SECONDLY,
-        definitions.cICalValue_RECUR_MINUTELY : definitions.eRecurrence_MINUTELY,
-        definitions.cICalValue_RECUR_HOURLY   : definitions.eRecurrence_HOURLY,
-        definitions.cICalValue_RECUR_DAILY    : definitions.eRecurrence_DAILY,
-        definitions.cICalValue_RECUR_WEEKLY   : definitions.eRecurrence_WEEKLY,
-        definitions.cICalValue_RECUR_MONTHLY  : definitions.eRecurrence_MONTHLY,
-        definitions.cICalValue_RECUR_YEARLY   : definitions.eRecurrence_YEARLY,
-    }
-
-    cFreqToXMLMap = {
-        definitions.eRecurrence_SECONDLY: xmldefs.recur_freq_secondly,
-        definitions.eRecurrence_MINUTELY: xmldefs.recur_freq_minutely,
-        definitions.eRecurrence_HOURLY: xmldefs.recur_freq_hourly,
-        definitions.eRecurrence_DAILY: xmldefs.recur_freq_daily,
-        definitions.eRecurrence_WEEKLY: xmldefs.recur_freq_weekly,
-        definitions.eRecurrence_MONTHLY: xmldefs.recur_freq_monthly,
-        definitions.eRecurrence_YEARLY: xmldefs.recur_freq_yearly,
-    }
-
-    cRecurMap = {
-        definitions.cICalValue_RECUR_FREQ       : definitions.eRecurrence_FREQ,
-        definitions.cICalValue_RECUR_UNTIL      : definitions.eRecurrence_UNTIL,
-        definitions.cICalValue_RECUR_COUNT      : definitions.eRecurrence_COUNT,
-        definitions.cICalValue_RECUR_INTERVAL   : definitions.eRecurrence_INTERVAL,
-        definitions.cICalValue_RECUR_BYSECOND   : definitions.eRecurrence_BYSECOND,
-        definitions.cICalValue_RECUR_BYMINUTE   : definitions.eRecurrence_BYMINUTE,
-        definitions.cICalValue_RECUR_BYHOUR     : definitions.eRecurrence_BYHOUR,
-        definitions.cICalValue_RECUR_BYDAY      : definitions.eRecurrence_BYDAY,
-        definitions.cICalValue_RECUR_BYMONTHDAY : definitions.eRecurrence_BYMONTHDAY,
-        definitions.cICalValue_RECUR_BYYEARDAY  : definitions.eRecurrence_BYYEARDAY,
-        definitions.cICalValue_RECUR_BYWEEKNO   : definitions.eRecurrence_BYWEEKNO,
-        definitions.cICalValue_RECUR_BYMONTH    : definitions.eRecurrence_BYMONTH,
-        definitions.cICalValue_RECUR_BYSETPOS   : definitions.eRecurrence_BYSETPOS,
-        definitions.cICalValue_RECUR_WKST       : definitions.eRecurrence_WKST,
-    }
-
-    cWeekdayMap = {
-        definitions.cICalValue_RECUR_WEEKDAY_SU : definitions.eRecurrence_WEEKDAY_SU,
-        definitions.cICalValue_RECUR_WEEKDAY_MO : definitions.eRecurrence_WEEKDAY_MO,
-        definitions.cICalValue_RECUR_WEEKDAY_TU : definitions.eRecurrence_WEEKDAY_TU,
-        definitions.cICalValue_RECUR_WEEKDAY_WE : definitions.eRecurrence_WEEKDAY_WE,
-        definitions.cICalValue_RECUR_WEEKDAY_TH : definitions.eRecurrence_WEEKDAY_TH,
-        definitions.cICalValue_RECUR_WEEKDAY_FR : definitions.eRecurrence_WEEKDAY_FR,
-        definitions.cICalValue_RECUR_WEEKDAY_SA : definitions.eRecurrence_WEEKDAY_SA,
-    }
-
-    cWeekdayRecurMap = dict([(v, k) for k, v in cWeekdayMap.items()])
-
-    cUnknownIndex = -1
-
-    def __init__(self):
-        self.init_PyCalendarRecurrence()
-
-
-    def duplicate(self):
-        other = PyCalendarRecurrence()
-
-        other.mFreq = self.mFreq
-
-        other.mUseCount = self.mUseCount
-        other.mCount = self.mCount
-        other.mUseUntil = self.mUseUntil
-        if other.mUseUntil:
-            other.mUntil = self.mUntil.duplicate()
-
-        other.mInterval = self.mInterval
-        if self.mBySeconds is not None:
-            other.mBySeconds = self.mBySeconds[:]
-        if self.mByMinutes is not None:
-            other.mByMinutes = self.mByMinutes[:]
-        if self.mByHours is not None:
-            other.mByHours = self.mByHours[:]
-        if self.mByDay is not None:
-            other.mByDay = self.mByDay[:]
-        if self.mByMonthDay is not None:
-            other.mByMonthDay = self.mByMonthDay[:]
-        if self.mByYearDay is not None:
-            other.mByYearDay = self.mByYearDay[:]
-        if self.mByWeekNo is not None:
-            other.mByWeekNo = self.mByWeekNo[:]
-        if self.mByMonth is not None:
-            other.mByMonth = self.mByMonth[:]
-        if self.mBySetPos is not None:
-            other.mBySetPos = self.mBySetPos[:]
-        other.mWeekstart = self.mWeekstart
-
-        other.mCached = self.mCached
-        if self.mCacheStart:
-            other.mCacheStart = self.mCacheStart.duplicate()
-        if self.mCacheUpto:
-            other.mCacheUpto = self.mCacheUpto.duplicate()
-        other.mFullyCached = self.mFullyCached
-        if self.mRecurrences:
-            other.mRecurrences = self.mRecurrences[:]
-
-        return other
-
-
-    def init_PyCalendarRecurrence(self):
-        self.mFreq = definitions.eRecurrence_YEARLY
-
-        self.mUseCount = False
-        self.mCount = 0
-
-        self.mUseUntil = False
-        self.mUntil = None
-
-        self.mInterval = 1
-        self.mBySeconds = None
-        self.mByMinutes = None
-        self.mByHours = None
-        self.mByDay = None
-        self.mByMonthDay = None
-        self.mByYearDay = None
-        self.mByWeekNo = None
-        self.mByMonth = None
-        self.mBySetPos = None
-        self.mWeekstart = definitions.eRecurrence_WEEKDAY_MO
-
-        self.mCached = False
-        self.mCacheStart = None
-        self.mCacheUpto = None
-        self.mFullyCached = False
-        self.mRecurrences = None
-
-
-    def __hash__(self):
-        return hash((
-            self.mFreq,
-            self.mUseCount,
-            self.mCount,
-            self.mUseUntil,
-            self.mUntil,
-            self.mInterval,
-            tuple(self.mBySeconds) if self.mBySeconds else None,
-            tuple(self.mByMinutes) if self.mByMinutes else None,
-            tuple(self.mByHours) if self.mByHours else None,
-            tuple(self.mByDay) if self.mByDay else None,
-            tuple(self.mByMonthDay) if self.mByMonthDay else None,
-            tuple(self.mByYearDay) if self.mByYearDay else None,
-            tuple(self.mByWeekNo) if self.mByWeekNo else None,
-            tuple(self.mByMonth) if self.mByMonth else None,
-            tuple(self.mBySetPos) if self.mBySetPos else None,
-            self.mWeekstart,
-        ))
-
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-
-    def __eq__(self, other):
-        if not isinstance(other, PyCalendarRecurrence):
-            return False
-        return self.equals(other)
-
-
-    def equals(self, comp):
-        return (self.mFreq == comp.mFreq) \
-                and (self.mUseCount == comp.mUseCount) and (self.mCount == comp.mCount) \
-                and (self.mUseUntil == comp.mUseUntil) and (self.mUntil == comp.mUntil) \
-                and (self.mInterval == comp.mInterval) \
-                and self.equalsNum(self.mBySeconds, comp.mBySeconds) \
-                and self.equalsNum(self.mByMinutes, comp.mByMinutes) \
-                and self.equalsNum(self.mByHours, comp.mByHours) \
-                and self.equalsDayNum(self.mByDay, comp.mByDay) \
-                and self.equalsNum(self.mByMonthDay, comp.mByMonthDay) \
-                and self.equalsNum(self.mByYearDay, comp.mByYearDay) \
-                and self.equalsNum(self.mByWeekNo, comp.mByWeekNo) \
-                and self.equalsNum(self.mByMonth, comp.mByMonth) \
-                and self.equalsNum(self.mBySetPos, comp.mBySetPos) \
-                and (self.mWeekstart == comp.mWeekstart)
-
-
-    def equalsNum(self, items1, items2):
-        # Check sizes first
-        if items1 is None:
-            items1 = []
-        if items2 is None:
-            items2 = []
-        if len(items1) != len(items2):
-            return False
-        elif len(items1) == 0:
-            return True
-
-        # Copy and sort each one for comparison
-        temp1 = items1[:]
-        temp2 = items2[:]
-        temp1.sort()
-        temp2.sort()
-
-        for i in range(0, len(temp1)):
-            if temp1[i] != temp2[i]:
-                return False
-        return True
-
-
-    def equalsDayNum(self, items1, items2):
-        # Check sizes first
-        if items1 is None:
-            items1 = []
-        if items2 is None:
-            items2 = []
-        if len(items1) != len(items2):
-            return False
-        elif len(items1) == 0:
-            return True
-
-        # Copy and sort each one for comparison
-        temp1 = items1[:]
-        temp2 = items2[:]
-        temp1.sort()
-        temp2.sort()
-
-        for i in range(0, len(temp1)):
-            if temp1[i] != temp2[i]:
-                return False
-        return True
-
-
-    def _setAndclearIfChanged(self, attr, value):
-        if getattr(self, attr) != value:
-            self.clear()
-            setattr(self, attr, value)
-
-
-    def getFreq(self):
-        return self.mFreq
-
-
-    def setFreq(self, freq):
-        self._setAndclearIfChanged(&quot;mFreq&quot;, freq)
-
-
-    def getUseUntil(self):
-        return self.mUseUntil
-
-
-    def setUseUntil(self, use_until):
-        self._setAndclearIfChanged(&quot;mUseUntil&quot;, use_until)
-
-
-    def getUntil(self):
-        return self.mUntil
-
-
-    def setUntil(self, until):
-        self._setAndclearIfChanged(&quot;mUntil&quot;, until)
-
-
-    def getUseCount(self):
-        return self.mUseCount
-
-
-    def setUseCount(self, use_count):
-        self._setAndclearIfChanged(&quot;mUseCount&quot;, use_count)
-
-
-    def getCount(self):
-        return self.mCount
-
-
-    def setCount(self, count):
-        self._setAndclearIfChanged(&quot;mCount&quot;, count)
-
-
-    def getInterval(self):
-        return self.mInterval
-
-
-    def setInterval(self, interval):
-        self._setAndclearIfChanged(&quot;mInterval&quot;, interval)
-
-
-    def getByMonth(self):
-        return self.mByMonth
-
-
-    def setByMonth(self, by):
-        self._setAndclearIfChanged(&quot;mByMonth&quot;, by[:])
-
-
-    def getByMonthDay(self):
-        return self.mByMonthDay
-
-
-    def setByMonthDay(self, by):
-        self._setAndclearIfChanged(&quot;mByMonthDay&quot;, by[:])
-
-
-    def getByYearDay(self):
-        return self.mByYearDay
-
-
-    def setByYearDay(self, by):
-        self._setAndclearIfChanged(&quot;mByYearDay&quot;, by[:])
-
-
-    def getByDay(self):
-        return self.mByDay
-
-
-    def setByDay(self, by):
-        self._setAndclearIfChanged(&quot;mByDay&quot;, by[:])
-
-
-    def getBySetPos(self):
-        return self.mBySetPos
-
-
-    def setBySetPos(self, by):
-        self._setAndclearIfChanged(&quot;mBySetPos&quot;, by[:])
-
-
-    def parse(self, data):
-        self.init_PyCalendarRecurrence()
-
-        # Tokenise using ''
-        tokens = data.split(&quot;;&quot;)
-        tokens.reverse()
-
-        if len(tokens) == 0:
-            raise ValueError(&quot;PyCalendarRecurrence: Invalid recurrence rule value&quot;)
-
-        while len(tokens) != 0:
-            # Get next token
-            token = tokens.pop()
-            try:
-                tname, tvalue = token.split(&quot;=&quot;)
-            except ValueError:
-                raise ValueError(&quot;PyCalendarRecurrence: Invalid token '%s'&quot; % (token,))
-
-            # Determine token type
-            index = PyCalendarRecurrence.cRecurMap.get(tname, PyCalendarRecurrence.cUnknownIndex)
-            if index == PyCalendarRecurrence.cUnknownIndex:
-                raise ValueError(&quot;PyCalendarRecurrence: Invalid token '%s'&quot; % (tname,))
-
-            # Parse remainder based on index
-            if index == definitions.eRecurrence_FREQ:
-                # Get the FREQ value
-                index = PyCalendarRecurrence.cFreqMap.get(tvalue, PyCalendarRecurrence.cUnknownIndex)
-                if index == PyCalendarRecurrence.cUnknownIndex:
-                    raise ValueError(&quot;PyCalendarRecurrence: Invalid FREQ value&quot;)
-                self.mFreq = index
-
-            elif index == definitions.eRecurrence_UNTIL:
-                if self.mUseCount:
-                    raise ValueError(&quot;PyCalendarRecurrence: Can't have both UNTIL and COUNT&quot;)
-                self.mUseUntil = True
-                if self.mUntil is None:
-                    self.mUntil = PyCalendarDateTime()
-                try:
-                    self.mUntil.parse(tvalue)
-                except ValueError:
-                    raise ValueError(&quot;PyCalendarRecurrence: Invalid UNTIL value&quot;)
-
-            elif index == definitions.eRecurrence_COUNT:
-                if self.mUseUntil:
-                    raise ValueError(&quot;PyCalendarRecurrence: Can't have both UNTIL and COUNT&quot;)
-                self.mUseCount = True
-                try:
-                    self.mCount = int(tvalue)
-                except ValueError:
-                    raise ValueError(&quot;PyCalendarRecurrence: Invalid COUNT value&quot;)
-
-                # Must not be less than one
-                if self.mCount &lt; 1:
-                    raise ValueError(&quot;PyCalendarRecurrence: Invalid COUNT value&quot;)
-
-            elif index == definitions.eRecurrence_INTERVAL:
-                try:
-                    self.mInterval = int(tvalue)
-                except ValueError:
-                    raise ValueError(&quot;PyCalendarRecurrence: Invalid INTERVAL value&quot;)
-
-                # Must NOT be less than one
-                if self.mInterval &lt; 1:
-                    raise ValueError(&quot;PyCalendarRecurrence: Invalid INTERVAL value&quot;)
-
-            elif index == definitions.eRecurrence_BYSECOND:
-                if self.mBySeconds is not None:
-                    raise ValueError(&quot;PyCalendarRecurrence: Only one BYSECOND allowed&quot;)
-                self.mBySeconds = []
-                self.parseList(tvalue, self.mBySeconds, 0, 60, errmsg=&quot;PyCalendarRecurrence: Invalid BYSECOND value&quot;)
-
-            elif index == definitions.eRecurrence_BYMINUTE:
-                if self.mByMinutes is not None:
-                    raise ValueError(&quot;PyCalendarRecurrence: Only one BYMINUTE allowed&quot;)
-                self.mByMinutes = []
-                self.parseList(tvalue, self.mByMinutes, 0, 59, errmsg=&quot;PyCalendarRecurrence: Invalid BYMINUTE value&quot;)
-
-            elif index == definitions.eRecurrence_BYHOUR:
-                if self.mByHours is not None:
-                    raise ValueError(&quot;PyCalendarRecurrence: Only one BYHOUR allowed&quot;)
-                self.mByHours = []
-                self.parseList(tvalue, self.mByHours, 0, 23, errmsg=&quot;PyCalendarRecurrence: Invalid BYHOUR value&quot;)
-
-            elif index == definitions.eRecurrence_BYDAY:
-                if self.mByDay is not None:
-                    raise ValueError(&quot;PyCalendarRecurrence: Only one BYDAY allowed&quot;)
-                self.mByDay = []
-                self.parseListDW(tvalue, self.mByDay, errmsg=&quot;PyCalendarRecurrence: Invalid BYDAY value&quot;)
-
-            elif index == definitions.eRecurrence_BYMONTHDAY:
-                if self.mByMonthDay is not None:
-                    raise ValueError(&quot;PyCalendarRecurrence: Only one BYMONTHDAY allowed&quot;)
-                self.mByMonthDay = []
-                self.parseList(tvalue, self.mByMonthDay, 1, 31, True, errmsg=&quot;PyCalendarRecurrence: Invalid BYMONTHDAY value&quot;)
-
-            elif index == definitions.eRecurrence_BYYEARDAY:
-                if self.mByYearDay is not None:
-                    raise ValueError(&quot;PyCalendarRecurrence: Only one BYYEARDAY allowed&quot;)
-                self.mByYearDay = []
-                self.parseList(tvalue, self.mByYearDay, 1, 366, True, errmsg=&quot;PyCalendarRecurrence: Invalid BYYEARDAY value&quot;)
-
-            elif index == definitions.eRecurrence_BYWEEKNO:
-                if self.mByWeekNo is not None:
-                    raise ValueError(&quot;PyCalendarRecurrence: Only one BYWEEKNO allowed&quot;)
-                self.mByWeekNo = []
-                self.parseList(tvalue, self.mByWeekNo, 1, 53, True, errmsg=&quot;PyCalendarRecurrence: Invalid BYWEEKNO value&quot;)
-
-            elif index == definitions.eRecurrence_BYMONTH:
-                if self.mByMonth is not None:
-                    raise ValueError(&quot;PyCalendarRecurrence: Only one BYMONTH allowed&quot;)
-                self.mByMonth = []
-                self.parseList(tvalue, self.mByMonth, 1, 12, errmsg=&quot;PyCalendarRecurrence: Invalid BYMONTH value&quot;)
-
-            elif index == definitions.eRecurrence_BYSETPOS:
-                if self.mBySetPos is not None:
-                    raise ValueError(&quot;PyCalendarRecurrence: Only one BYSETPOS allowed&quot;)
-                self.mBySetPos = []
-                self.parseList(tvalue, self.mBySetPos, allowNegative=True, errmsg=&quot;PyCalendarRecurrence: Invalid BYSETPOS value&quot;)
-
-            elif index == definitions.eRecurrence_WKST:
-                index = PyCalendarRecurrence.cWeekdayMap.get(tvalue, PyCalendarRecurrence.cUnknownIndex)
-                if (index == PyCalendarRecurrence.cUnknownIndex):
-                    raise ValueError(&quot;PyCalendarRecurrence: Invalid WKST value&quot;)
-                self.mWeekstart = index
-
-
-    def parseList(self, txt, list, min=None, max=None, allowNegative=False, errmsg=&quot;&quot;):
-
-        if &quot;,&quot; in txt:
-            tokens = txt.split(&quot;,&quot;)
-        else:
-            tokens = (txt,)
-
-        for token in tokens:
-            value = int(token)
-            if not allowNegative and value &lt; 0:
-                raise ValueError(errmsg)
-            avalue = abs(value)
-            if min is not None and avalue &lt; min:
-                raise ValueError(errmsg)
-            if max is not None  and avalue &gt; max:
-                raise ValueError(errmsg)
-            list.append(value)
-
-
-    def parseListDW(self, txt, list, errmsg=&quot;&quot;):
-
-        if &quot;,&quot; in txt:
-            tokens = txt.split(&quot;,&quot;)
-        else:
-            tokens = (txt,)
-
-        for token in tokens:
-            # Get number if present
-            num = 0
-            if (len(token) &gt; 0) and token[0] in &quot;+-1234567890&quot;:
-                offset = 0
-                while (offset &lt; len(token)) and token[offset] in &quot;+-1234567890&quot;:
-                    offset += 1
-
-                num = int(token[0:offset])
-                token = token[offset:]
-
-                anum = abs(num)
-                if anum &lt; 1:
-                    raise ValueError(errmsg)
-                if anum &gt; 53:
-                    raise ValueError(errmsg)
-
-            # Get day
-            index = PyCalendarRecurrence.cWeekdayMap.get(token, PyCalendarRecurrence.cUnknownIndex)
-            if (index == PyCalendarRecurrence.cUnknownIndex):
-                raise ValueError(errmsg)
-            wday = index
-
-            list.append((num, wday))
-
-
-    def generate(self, os):
-        try:
-            os.write(definitions.cICalValue_RECUR_FREQ)
-            os.write(&quot;=&quot;)
-
-            if self.mFreq == definitions.eRecurrence_SECONDLY:
-                os.write(definitions.cICalValue_RECUR_SECONDLY)
-
-            elif self.mFreq == definitions.eRecurrence_MINUTELY:
-                os.write(definitions.cICalValue_RECUR_MINUTELY)
-
-            elif self.mFreq == definitions.eRecurrence_HOURLY:
-                os.write(definitions.cICalValue_RECUR_HOURLY)
-
-            elif self.mFreq == definitions.eRecurrence_DAILY:
-                os.write(definitions.cICalValue_RECUR_DAILY)
-
-            elif self.mFreq == definitions.eRecurrence_WEEKLY:
-                os.write(definitions.cICalValue_RECUR_WEEKLY)
-
-            elif self.mFreq == definitions.eRecurrence_MONTHLY:
-                os.write(definitions.cICalValue_RECUR_MONTHLY)
-
-            elif self.mFreq == definitions.eRecurrence_YEARLY:
-                os.write(definitions.cICalValue_RECUR_YEARLY)
-
-            if self.mUseCount:
-                os.write(&quot;;&quot;)
-                os.write(definitions.cICalValue_RECUR_COUNT)
-                os.write(&quot;=&quot;)
-                os.write(str(self.mCount))
-            elif self.mUseUntil:
-                os.write(&quot;;&quot;)
-                os.write(definitions.cICalValue_RECUR_UNTIL)
-                os.write(&quot;=&quot;)
-                self.mUntil.generate(os)
-
-            if self.mInterval &gt; 1:
-                os.write(&quot;;&quot;)
-                os.write(definitions.cICalValue_RECUR_INTERVAL)
-                os.write(&quot;=&quot;)
-                os.write(str(self.mInterval))
-
-            self.generateList(os, definitions.cICalValue_RECUR_BYSECOND, self.mBySeconds)
-            self.generateList(os, definitions.cICalValue_RECUR_BYMINUTE, self.mByMinutes)
-            self.generateList(os, definitions.cICalValue_RECUR_BYHOUR, self.mByHours)
-
-            if (self.mByDay is not None) and (len(self.mByDay) != 0):
-                os.write(&quot;;&quot;)
-                os.write(definitions.cICalValue_RECUR_BYDAY)
-                os.write(&quot;=&quot;)
-                comma = False
-                for iter in self.mByDay:
-                    if comma:
-                        os.write(&quot;,&quot;)
-                    comma = True
-
-                    if iter[0] != 0:
-                        os.write(str(iter[0]))
-
-                    if iter[1] == definitions.eRecurrence_WEEKDAY_SU:
-                        os.write(definitions.cICalValue_RECUR_WEEKDAY_SU)
-
-                    elif iter[1] == definitions.eRecurrence_WEEKDAY_MO:
-                        os.write(definitions.cICalValue_RECUR_WEEKDAY_MO)
-
-                    elif iter[1] == definitions.eRecurrence_WEEKDAY_TU:
-                        os.write(definitions.cICalValue_RECUR_WEEKDAY_TU)
-
-                    elif iter[1] == definitions.eRecurrence_WEEKDAY_WE:
-                        os.write(definitions.cICalValue_RECUR_WEEKDAY_WE)
-
-                    elif iter[1] == definitions.eRecurrence_WEEKDAY_TH:
-                        os.write(definitions.cICalValue_RECUR_WEEKDAY_TH)
-
-                    elif iter[1] == definitions.eRecurrence_WEEKDAY_FR:
-                        os.write(definitions.cICalValue_RECUR_WEEKDAY_FR)
-
-                    elif iter[1] == definitions.eRecurrence_WEEKDAY_SA:
-                        os.write(definitions.cICalValue_RECUR_WEEKDAY_SA)
-
-            self.generateList(os, definitions.cICalValue_RECUR_BYMONTHDAY, self.mByMonthDay)
-            self.generateList(os, definitions.cICalValue_RECUR_BYYEARDAY, self.mByYearDay)
-            self.generateList(os, definitions.cICalValue_RECUR_BYWEEKNO, self.mByWeekNo)
-            self.generateList(os, definitions.cICalValue_RECUR_BYMONTH, self.mByMonth)
-            self.generateList(os, definitions.cICalValue_RECUR_BYSETPOS, self.mBySetPos)
-
-            # MO is the default so we do not need it
-            if self.mWeekstart != definitions.eRecurrence_WEEKDAY_MO:
-                os.write(&quot;;&quot;)
-                os.write(definitions.cICalValue_RECUR_WKST)
-                os.write(&quot;=&quot;)
-
-                if self.mWeekstart == definitions.eRecurrence_WEEKDAY_SU:
-                    os.write(definitions.cICalValue_RECUR_WEEKDAY_SU)
-
-                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_MO:
-                    os.write(definitions.cICalValue_RECUR_WEEKDAY_MO)
-
-                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_TU:
-                    os.write(definitions.cICalValue_RECUR_WEEKDAY_TU)
-
-                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_WE:
-                    os.write(definitions.cICalValue_RECUR_WEEKDAY_WE)
-
-                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_TH:
-                    os.write(definitions.cICalValue_RECUR_WEEKDAY_TH)
-
-                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_FR:
-                    os.write(definitions.cICalValue_RECUR_WEEKDAY_FR)
-
-                elif self.mWeekstart == definitions.eRecurrence_WEEKDAY_SA:
-                    os.write(definitions.cICalValue_RECUR_WEEKDAY_SA)
-
-        except:
-            pass
-
-
-    def generateList(self, os, title, items):
-
-        if (items is not None) and (len(items) != 0):
-            os.write(&quot;;&quot;)
-            os.write(title)
-            os.write(&quot;=&quot;)
-            comma = False
-            for e in items:
-                if comma:
-                    os.write(&quot;,&quot;)
-                comma = True
-                os.write(str(e))
-
-
-    def writeXML(self, node, namespace):
-
-        recur = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.value_recur))
-
-        freq = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_freq))
-        freq.text = self.cFreqToXMLMap[self.mFreq]
-
-        if self.mUseCount:
-            count = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_count))
-            count.text = str(self.mCount)
-        elif self.mUseUntil:
-            until = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_until))
-            self.mUntil.writeXML(until, namespace)
-
-        if self.mInterval &gt; 1:
-            interval = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_interval))
-            interval.text = str(self.mInterval)
-
-        self.writeXMLList(recur, namespace, xmldefs.recur_bysecond, self.mBySeconds)
-        self.writeXMLList(recur, namespace, xmldefs.recur_byminute, self.mByMinutes)
-        self.writeXMLList(recur, namespace, xmldefs.recur_byhour, self.mByHours)
-
-        if self.mByDay is not None and len(self.mByDay) != 0:
-            for iter in self.mByDay:
-                byday = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_byday))
-                data = &quot;&quot;
-                if iter[0] != 0:
-                    data = str(iter[0])
-                data += self.cWeekdayRecurMap.get(iter[1], &quot;&quot;)
-                byday.text = data
-
-        self.writeXMLList(recur, namespace, xmldefs.recur_bymonthday, self.mByMonthDay)
-        self.writeXMLList(recur, namespace, xmldefs.recur_byyearday, self.mByYearDay)
-        self.writeXMLList(recur, namespace, xmldefs.recur_byweekno, self.mByWeekNo)
-        self.writeXMLList(recur, namespace, xmldefs.recur_bymonth, self.mByMonth)
-        self.writeXMLList(recur, namespace, xmldefs.recur_bysetpos, self.mBySetPos)
-
-        # MO is the default so we do not need it
-        if self.mWeekstart != definitions.eRecurrence_WEEKDAY_MO:
-            wkst = XML.SubElement(recur, xmldefs.makeTag(namespace, xmldefs.recur_wkst))
-            wkst.text = self.cWeekdayRecurMap.get(self.mWeekstart, definitions.cICalValue_RECUR_WEEKDAY_MO)
-
-
-    def writeXMLList(self, node, namespace, name, items):
-        if items is not None and len(items) != 0:
-            for item in items:
-                child = XML.SubElement(node, xmldefs.makeTag(namespace, name))
-                child.text = str(item)
-
-
-    def hasBy(self):
-        return (self.mBySeconds is not None) and (len(self.mBySeconds) != 0) \
-                or (self.mByMinutes is not None) and (len(self.mByMinutes) != 0) \
-                or (self.mByHours is not None) and (len(self.mByHours) != 0) \
-                or (self.mByDay is not None) and (len(self.mByDay) != 0) \
-                or (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0) \
-                or (self.mByYearDay is not None) and (len(self.mByYearDay) != 0) \
-                or (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0) \
-                or (self.mByMonth is not None) and (len(self.mByMonth) != 0) \
-                or (self.mBySetPos is not None) and (len(self.mBySetPos) != 0)
-
-
-    def isSimpleRule(self):
-        # One that has no BYxxx rules
-        return not self.hasBy()
-
-
-    def isAdvancedRule(self):
-        # One that has BYMONTH,
-        # BYMONTHDAY (with no negative value),
-        # BYDAY (with multiple unnumbered, or numbered with all the same number
-        # (1..4, -2, -1)
-        # BYSETPOS with +1, or -1 only
-        # no others
-
-        # First checks the ones we do not handle at all
-        if ((self.mBySeconds is not None) and (len(self.mBySeconds) != 0) \
-                or (self.mByMinutes is not None) and (len(self.mByMinutes) != 0) \
-                or (self.mByHours is not None) and (len(self.mByHours) != 0) \
-                or (self.mByYearDay is not None) and (len(self.mByYearDay) != 0) \
-                or (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0)):
-            return False
-
-        # Check BYMONTHDAY numbers (we can handle -7...-1, 1..31)
-        if self.mByMonthDay is not None:
-            for iter in self.mByMonthDay:
-                if (iter &lt; -7) or (iter &gt; 31) or (iter == 0):
-                    return False
-
-        # Check BYDAY numbers
-        if self.mByDay is not None:
-            number = 0
-            first = True
-            for iter in self.mByDay:
-
-                # Get the first number
-                if (first):
-                    number = iter[0]
-                    first = False
-
-                    # Check number range
-                    if (number &gt; 4) or (number &lt; -2):
-                        return False
-
-                # If current differs from last, then we have an error
-                elif number != iter[0]:
-                    return False
-
-        # Check BYSETPOS numbers
-        if self.mBySetPos is not None:
-            if len(self.mBySetPos) &gt; 1:
-                return False
-            if (len(self.mBySetPos) == 1) and (self.mBySetPos[0] != -1) and (self.mBySetPos[0] != 1):
-                return False
-
-        # If we get here it must be OK
-        return True
-
-
-    def getUIDescription(self):
-        try:
-            # For now just use iCal item
-            sout = StringIO()
-            self.generate(sout)
-            result = sout.getvalue()
-        except:
-            result = &quot;&quot;
-
-        return result
-
-
-    def expand(self, start, range, items, float_offset=0):
-
-        # Must have recurrence list at this point
-        if self.mRecurrences is None:
-            self.mRecurrences = []
-
-        # Wipe cache if start is different
-        if self.mCached and (start != self.mCacheStart):
-            self.mCached = False
-            self.mFullyCached = False
-            self.mRecurrences = []
-
-        # Is the current cache complete or does it extend past the requested
-        # range end
-        if not self.mCached or not self.mFullyCached \
-                and (self.mCacheUpto is None or self.mCacheUpto &lt; range.getEnd()):
-            cache_range = range.duplicate()
-
-            # If partially cached just cache from previous cache end up to new
-            # end
-            if self.mCached:
-                cache_range = PyCalendarPeriod(self.mCacheUpto, range.getEnd())
-
-            # Simple expansion is one where there is no BYXXX rule part
-            if not self.hasBy():
-                self.mFullyCached = self.simpleExpand(start, cache_range, self.mRecurrences, float_offset)
-            else:
-                self.mFullyCached = self.complexExpand(start, cache_range, self.mRecurrences, float_offset)
-
-            # Set cache values
-            self.mCached = True
-            self.mCacheStart = start
-            self.mCacheUpto = range.getEnd()
-
-        # Just return the cached items in the requested range
-        limited = not self.mFullyCached
-        for iter in self.mRecurrences:
-            if range.isDateWithinPeriod(iter):
-                items.append(iter)
-            else:
-                limited = True
-        return limited
-
-
-    def simpleExpand(self, start, range, items, float_offset):
-        start_iter = start.duplicate()
-        ctr = 0
-
-        if self.mUseUntil:
-            float_until = self.mUntil.duplicate()
-            if start.floating():
-                float_until.setTimezoneID(0)
-                float_until.offsetSeconds(float_offset)
-
-        while True:
-            # Exit if after period we want
-            if range.isDateAfterPeriod(start_iter):
-                return False
-
-            # Add current one to list
-            items.append(start_iter.duplicate())
-
-            # Get next item
-            start_iter.recur(self.mFreq, self.mInterval)
-
-            # Check limits
-            if self.mUseCount:
-                # Bump counter and exit if over
-                ctr += 1
-                if ctr &gt;= self.mCount:
-                    return True
-            elif self.mUseUntil:
-                # Exit if next item is after until (its OK if its the same as
-                # UNTIL as UNTIL is inclusive)
-                if start_iter &gt; float_until:
-                    return True
-
-
-    def complexExpand(self, start, range, items, float_offset):
-        start_iter = start.duplicate()
-        ctr = 0
-
-        if self.mUseUntil:
-            float_until = self.mUntil.duplicate()
-            if start.floating():
-                float_until.setTimezoneID(None)
-                float_until.offsetSeconds(float_offset)
-
-        # Always add the initial instance DTSTART
-        if self.mUseCount:
-            # Bump counter and exit if over
-            ctr += 1
-            if ctr &gt;= self.mCount:
-                return True
-
-        # Need to re-initialise start based on BYxxx rules
-        while True:
-            # Behaviour is based on frequency
-            set_items = []
-
-            if self.mFreq == definitions.eRecurrence_SECONDLY:
-                self.generateSecondlySet(start_iter, set_items)
-
-            elif self.mFreq == definitions.eRecurrence_MINUTELY:
-                self.generateMinutelySet(start_iter, set_items)
-
-            elif self.mFreq == definitions.eRecurrence_HOURLY:
-                self.generateHourlySet(start_iter, set_items)
-
-            elif self.mFreq == definitions.eRecurrence_DAILY:
-                self.generateDailySet(start_iter, set_items)
-
-            elif self.mFreq == definitions.eRecurrence_WEEKLY:
-                self.generateWeeklySet(start_iter, set_items)
-
-            elif self.mFreq == definitions.eRecurrence_MONTHLY:
-                self.generateMonthlySet(start_iter, set_items)
-
-            elif self.mFreq == definitions.eRecurrence_YEARLY:
-                self.generateYearlySet(start_iter, set_items)
-
-            # Always sort the set as BYxxx rules may not be sorted
-            #set_items.sort(cmp=PyCalendarDateTime.sort)
-            set_items.sort(key=lambda x: x.getPosixTime())
-
-            # Process each one in the generated set
-            for iter in set_items:
-
-                # Ignore if it is before the actual start - we need this
-                # because the expansion
-                # can go back in time from the real start, but we must exclude
-                # those when counting
-                # even if they are not within the requested range
-                if iter &lt; start:
-                    continue
-
-                # Exit if after period we want
-                if range.isDateAfterPeriod(iter):
-                    return False
-
-                # Exit if beyond the UNTIL limit
-                if self.mUseUntil:
-                    # Exit if next item is after until (its OK if its the same
-                    # as UNTIL as UNTIL is inclusive)
-                    if iter &gt; float_until:
-                        return True
-
-                # Special for start instance
-                if (ctr == 1) and (start == iter):
-                    continue
-
-                # Add current one to list
-                items.append(iter)
-
-                # Check limits
-                if self.mUseCount:
-                    # Bump counter and exit if over
-                    ctr += 1
-                    if ctr &gt;= self.mCount:
-                        return True
-
-            # Exit if after period we want
-            if range.isDateAfterPeriod(start_iter):
-                return False
-
-            # Get next item
-            start_iter.recur(self.mFreq, self.mInterval)
-
-
-    def clear(self):
-        self.mCached = False
-        self.mFullyCached = False
-        if self.mRecurrences is not None:
-            self.mRecurrences = []
-
-
-    # IMPORTANT ExcludeFutureRecurrence assumes mCacheStart is setup with the
-    # owning VEVENT's DTSTART
-    # Currently this method is only called when a recurrence is being removed
-    # so
-    # the recurrence data should be cached
-
-    # Exclude dates on or after the chosen one
-    def excludeFutureRecurrence(self, exclude):
-        # Expand the rule up to the exclude date
-        items = []
-        period = PyCalendarPeriod()
-        period.init(self.mCacheStart, exclude)
-        self.expand(self.mCacheStart, period, items)
-
-        # Adjust UNTIL or add one if no COUNT
-        if self.getUseUntil() or not self.getUseCount():
-            # The last one is just less than the exclude date
-            if len(items) != 0:
-                # Now use the data as the UNTIL
-                self.mUseUntil = True
-                self.mUntil = items[-1]
-
-        # Adjust COUNT
-        elif self.getUseCount():
-            # The last one is just less than the exclude date
-            self.mUseCount = True
-            self.mCount = len(items)
-
-        # Now clear out the cached set after making changes
-        self.clear()
-
-
-    def generateYearlySet(self, start, items):
-        # All possible BYxxx are valid, though some combinations are not
-
-        # Start with initial date-time
-        items.append(start.duplicate())
-
-        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
-            items[:] = self.byMonthExpand(items)
-
-        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
-            items[:] = self.byWeekNoExpand(items)
-
-        if (self.mByYearDay is not None) and (len(self.mByYearDay) != 0):
-            items[:] = self.byYearDayExpand(items)
-
-        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
-            items[:] = self.byMonthDayExpand(items)
-
-        if (self.mByDay is not None) and (len(self.mByDay) != 0):
-            # BYDAY is complicated:
-            # if BYDAY is included with BYYEARDAY or BYMONTHDAY then it
-            # contracts the recurrence set
-            # else it expands it, but the expansion depends on the frequency
-            # and other BYxxx periodicities
-
-            if ((self.mByYearDay is not None) and (len(self.mByYearDay) != 0)) \
-                    or ((self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0)):
-                items[:] = self.byDayLimit(items)
-            elif (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
-                items[:] = self.byDayExpandWeekly(items)
-            elif (self.mByMonth is not None) and (len(self.mByMonth) != 0):
-                items[:] = self.byDayExpandMonthly(items)
-            else:
-                items[:] = self.byDayExpandYearly(items)
-
-        if (self.mByHours is not None) and (len(self.mByHours) != 0):
-            items[:] = self.byHourExpand(items)
-
-        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
-            items[:] = self.byMinuteExpand(items)
-
-        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
-            items[:] = self.bySecondExpand(items)
-
-        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
-            items[:] = self.bySetPosLimit(items)
-
-
-    def generateMonthlySet(self, start, items):
-        # Cannot have BYYEARDAY and BYWEEKNO
-
-        # Start with initial date-time
-        items.append(start.duplicate())
-
-        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
-            # BYMONTH limits the range of possible values
-            items[:] = self.byMonthLimit(items)
-            if (len(items) == 0):
-                return
-
-        # No BYWEEKNO
-
-        # No BYYEARDAY
-
-        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
-            items[:] = self.byMonthDayExpand(items)
-
-        if (self.mByDay is not None) and (len(self.mByDay) != 0):
-            # BYDAY is complicated:
-            # if BYDAY is included with BYYEARDAY or BYMONTHDAY then it
-            # contracts the recurrence set
-            # else it expands it, but the expansion depends on the frequency
-            # and other BYxxx periodicities
-
-            if ((self.mByYearDay is not None) and (len(self.mByYearDay) != 0)) \
-                    or ((self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0)):
-                items[:] = self.byDayLimit(items)
-            else:
-                items[:] = self.byDayExpandMonthly(items)
-
-        if ((self.mByHours is not None) and (len(self.mByHours) != 0)):
-            items[:] = self.byHourExpand(items)
-
-        if ((self.mByMinutes is not None) and (len(self.mByMinutes) != 0)):
-            items[:] = self.byMinuteExpand(items)
-
-        if ((self.mBySeconds is not None) and (len(self.mBySeconds) != 0)):
-            items[:] = self.bySecondExpand(items)
-
-        if ((self.mBySetPos is not None) and (len(self.mBySetPos) != 0)):
-            items[:] = self.bySetPosLimit(items)
-
-
-    def generateWeeklySet(self, start, items):
-        # Cannot have BYYEARDAY and BYMONTHDAY
-
-        # Start with initial date-time
-        items.append(start.duplicate())
-
-        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
-            # BYMONTH limits the range of possible values
-            items[:] = self.byMonthLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
-            items[:] = self.byWeekNoLimit(items)
-            if (len(items) == 0):
-                return
-
-        # No BYYEARDAY
-
-        # No BYMONTHDAY
-
-        if (self.mByDay is not None) and (len(self.mByDay) != 0):
-            items[:] = self.byDayExpandWeekly(items)
-
-        if (self.mByHours is not None) and (len(self.mByHours) != 0):
-            items[:] = self.byHourExpand(items)
-
-        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
-            items[:] = self.byMinuteExpand(items)
-
-        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
-            items[:] = self.bySecondExpand(items)
-
-        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
-            items[:] = self.bySetPosLimit(items)
-
-
-    def generateDailySet(self, start, items):
-        # Cannot have BYYEARDAY
-
-        # Start with initial date-time
-        items.append(start.duplicate())
-
-        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
-            # BYMONTH limits the range of possible values
-            items[:] = self.byMonthLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
-            items[:] = self.byWeekNoLimit(items)
-            if (len(items) == 0):
-                return
-
-        # No BYYEARDAY
-
-        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
-            items[:] = self.byMonthDayLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByDay is not None) and (len(self.mByDay) != 0):
-            items[:] = self.byDayLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByHours is not None) and (len(self.mByHours) != 0):
-            items[:] = self.byHourExpand(items)
-
-        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
-            items[:] = self.byMinuteExpand(items)
-
-        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
-            items[:] = self.bySecondExpand(items)
-
-        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
-            items[:] = self.bySetPosLimit(items)
-
-
-    def generateHourlySet(self, start, items):
-        # Cannot have BYYEARDAY
-
-        # Start with initial date-time
-        items.append(start.duplicate())
-
-        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
-            # BYMONTH limits the range of possible values
-            items[:] = self.byMonthLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
-            items[:] = self.byWeekNoLimit(items)
-            if (len(items) == 0):
-                return
-
-        # No BYYEARDAY
-
-        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
-            items[:] = self.byMonthDayLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByDay is not None) and (len(self.mByDay) != 0):
-            items[:] = self.byDayLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByHours is not None) and (len(self.mByHours) != 0):
-            items[:] = self.byHourLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
-            items[:] = self.byMinuteExpand(items)
-
-        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
-            items[:] = self.bySecondExpand(items)
-
-        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
-            items[:] = self.bySetPosLimit(items)
-
-
-    def generateMinutelySet(self, start, items):
-        # Cannot have BYYEARDAY
-
-        # Start with initial date-time
-        items.append(start.duplicate())
-
-        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
-            # BYMONTH limits the range of possible values
-            items[:] = self.byMonthLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
-            items[:] = self.byWeekNoLimit(items)
-            if (len(items) == 0):
-                return
-
-        # No BYYEARDAY
-
-        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
-            items[:] = self.byMonthDayLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByDay is not None) and (len(self.mByDay) != 0):
-            items[:] = self.byDayLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByHours is not None) and (len(self.mByHours) != 0):
-            items[:] = self.byHourLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
-            items[:] = self.byMinuteLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
-            items[:] = self.bySecondExpand(items)
-
-        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
-            items[:] = self.bySetPosLimit(items)
-
-
-    def generateSecondlySet(self, start, items):
-        # Cannot have BYYEARDAY
-
-        # Start with initial date-time
-        items.append(start.duplicate())
-
-        if (self.mByMonth is not None) and (len(self.mByMonth) != 0):
-            # BYMONTH limits the range of possible values
-            items[:] = self.byMonthLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByWeekNo is not None) and (len(self.mByWeekNo) != 0):
-            items[:] = self.byWeekNoLimit(items)
-            if (len(items) == 0):
-                return
-
-        # No BYYEARDAY
-
-        if (self.mByMonthDay is not None) and (len(self.mByMonthDay) != 0):
-            items[:] = self.byMonthDayLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByDay is not None) and (len(self.mByDay) != 0):
-            items[:] = self.byDayLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByHours is not None) and (len(self.mByHours) != 0):
-            items[:] = self.byHourLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mByMinutes is not None) and (len(self.mByMinutes) != 0):
-            items[:] = self.byMinuteLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mBySeconds is not None) and (len(self.mBySeconds) != 0):
-            items[:] = self.bySecondLimit(items)
-            if (len(items) == 0):
-                return
-
-        if (self.mBySetPos is not None) and (len(self.mBySetPos) != 0):
-            items[:] = self.bySetPosLimit(items)
-
-
-    def byMonthExpand(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYMONTH and generating a new date-time for it and
-            # insert into output
-            for iter2 in self.mByMonth:
-                temp = iter1.duplicate()
-                temp.setMonth(iter2)
-                output.append(temp)
-
-        return output
-
-
-    def byWeekNoExpand(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYWEEKNO and generating a new date-time for it and
-            # insert into output
-            for iter2 in self.mByWeekNo:
-                temp = iter1.duplicate()
-                temp.setWeekNo(iter2)
-                output.append(temp)
-
-        return output
-
-
-    def byYearDayExpand(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYYEARDAY and generating a new date-time for it
-            # and insert into output
-            for iter2 in self.mByYearDay:
-                temp = iter1.duplicate()
-                temp.setYearDay(iter2)
-                output.append(temp)
-
-        return output
-
-
-    def byMonthDayExpand(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYMONTHDAY and generating a new date-time for it
-            # and insert into output
-            for iter2 in self.mByMonthDay:
-                temp = iter1.duplicate()
-                temp.setMonthDay(iter2)
-                output.append(temp)
-
-        return output
-
-
-    def byDayExpandYearly(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYDAY and generating a new date-time for it and
-            # insert into output
-            for iter2 in self.mByDay:
-                # Numeric value means specific instance
-                if iter2[0] != 0:
-                    temp = iter1.duplicate()
-                    temp.setDayOfWeekInYear(iter2[0], iter2[1])
-                    output.append(temp)
-                else:
-                    # Every matching day in the year
-                    for  i in range(1, 54):
-                        temp = iter1.duplicate()
-                        temp.setDayOfWeekInYear(i, iter2[1])
-                        if temp.getYear() == (iter1).getYear():
-                            output.append(temp)
-
-        return output
-
-
-    def byDayExpandMonthly(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYDAY and generating a new date-time for it and
-            # insert into output
-            for iter2 in self.mByDay:
-                # Numeric value means specific instance
-                if iter2[0] != 0:
-                    temp = iter1.duplicate()
-                    temp.setDayOfWeekInMonth(iter2[0], iter2[1])
-                    output.append(temp)
-                else:
-                    # Every matching day in the month
-                    for i in range(1, 7):
-                        temp = iter1.duplicate()
-                        temp.setDayOfWeekInMonth(i, iter2[1])
-                        if temp.getMonth() == iter1.getMonth():
-                            output.append(temp)
-
-        return output
-
-
-    def byDayExpandWeekly(self, dates):
-        # Must take into account the WKST value
-
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYDAY and generating a new date-time for it and
-            # insert into output
-            for iter2 in self.mByDay:
-                # Numeric values are meaningless so ignore them
-                if iter2[0] == 0:
-                    temp = iter1.duplicate()
-
-                    # Determine amount of offset to apply to temp to shift it
-                    # to the start of the week (backwards)
-                    week_start_offset = self.mWeekstart - temp.getDayOfWeek()
-                    if week_start_offset &gt; 0:
-                        week_start_offset -= 7
-
-                    # Determine amount of offset from the start of the week to
-                    # the day we want (forwards)
-                    day_in_week_offset = iter2[1] - self.mWeekstart
-                    if day_in_week_offset &lt; 0:
-                        day_in_week_offset += 7
-
-                    # Apply offsets
-                    temp.offsetDay(week_start_offset + day_in_week_offset)
-                    output.append(temp)
-
-        return output
-
-
-    def byHourExpand(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYHOUR and generating a new date-time for it and
-            # insert into output
-            for iter2 in self.mByHours:
-                temp = iter1.duplicate()
-                temp.setHours(iter2)
-                output.append(temp)
-
-        return output
-
-
-    def byMinuteExpand(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYMINUTE and generating a new date-time for it and
-            # insert into output
-            for iter2 in self.mByMinutes:
-                temp = iter1.duplicate()
-                temp.setMinutes(iter2)
-                output.append(temp)
-
-        return output
-
-
-    def bySecondExpand(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYSECOND and generating a new date-time for it and
-            # insert into output
-            for iter2 in self.mBySeconds:
-                temp = iter1.duplicate()
-                temp.setSeconds(iter2)
-                output.append(temp)
-
-        return output
-
-
-    def byMonthLimit(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYMONTH and indicate keep if input month matches
-            keep = False
-            for iter2 in self.mByMonth:
-                keep = (iter1.getMonth() == iter2)
-                if keep:
-                    break
-
-            if keep:
-                output.append(iter1)
-
-        return output
-
-
-    def byWeekNoLimit(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYWEEKNO and indicate keep if input month matches
-            keep = False
-            for iter2 in self.mByWeekNo:
-                keep = iter1.isWeekNo(iter2)
-                if keep:
-                    break
-
-            if keep:
-                output.append(iter1)
-
-        return output
-
-
-    def byMonthDayLimit(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYMONTHDAY and indicate keep if input month
-            # matches
-            keep = False
-            for iter2 in self.mByMonthDay:
-                keep = iter1.isMonthDay(iter2)
-                if keep:
-                    break
-
-            if keep:
-                output.append(iter1)
-
-        return output
-
-
-    def byDayLimit(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYDAY and indicate keep if input month matches
-            keep = False
-            for iter2 in self.mByDay:
-                keep = iter1.isDayOfWeekInMonth(iter2[0], iter2[1])
-                if keep:
-                    break
-
-            if keep:
-                output.append(iter1)
-
-        return output
-
-
-    def byHourLimit(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYHOUR and indicate keep if input hour matches
-            keep = False
-            for iter2 in self.mByHours:
-                keep = (iter1.getHours() == iter2)
-                if keep:
-                    break
-
-            if keep:
-                output.append(iter1)
-
-        return output
-
-
-    def byMinuteLimit(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYMINUTE and indicate keep if input minute matches
-            keep = False
-            for iter2 in self.mByMinutes:
-                keep = (iter1.getMinutes() == iter2)
-                if keep:
-                    break
-
-            if keep:
-                output.append(iter1)
-
-        return output
-
-
-    def bySecondLimit(self, dates):
-        # Loop over all input items
-        output = []
-        for iter1 in dates:
-            # Loop over each BYSECOND and indicate keep if input second matches
-            keep = False
-            for iter2 in self.mBySeconds:
-                keep = (iter1.getSeconds() == iter2)
-                if keep:
-                    break
-
-            if keep:
-                output.append(iter1)
-
-        return output
-
-
-    def bySetPosLimit(self, dates):
-        # The input dates MUST be sorted in order for this to work properly
-        #dates.sort(cmp=PyCalendarDateTime.sort)
-        dates.sort(key=lambda x: x.getPosixTime())
-
-        # Loop over each BYSETPOS and extract the relevant component from the
-        # input array and add to the output
-        output = []
-        input_size = len(dates)
-        for iter in self.mBySetPos:
-            if iter &gt; 0:
-                # Positive values are offset from the start
-                if iter &lt;= input_size:
-                    output.append(dates[iter - 1])
-            elif iter &lt; 0:
-                # Negative values are offset from the end
-                if -iter &lt;= input_size:
-                    output.append(dates[input_size + iter])
-
-        return output
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarrecurrencesetpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/recurrenceset.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/recurrenceset.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/recurrenceset.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,312 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.utils import set_difference
-
-class PyCalendarRecurrenceSet(object):
-
-    def __init__(self):
-        self.mRrules = []
-        self.mExrules = []
-        self.mRdates = []
-        self.mExdates = []
-        self.mRperiods = []
-        self.mExperiods = []
-
-
-    def duplicate(self):
-        other = PyCalendarRecurrenceSet()
-        other.mRrules = [i.duplicate() for i in self.mRrules]
-        other.mExrules = [i.duplicate() for i in self.mExrules]
-        other.mRdates = [i.duplicate() for i in self.mRdates]
-        other.mExdates = [i.duplicate() for i in self.mExdates]
-        other.mRperiods = [i.duplicate() for i in self.mRperiods]
-        other.mExperiods = [i.duplicate() for i in self.mExperiods]
-        return other
-
-
-    def hasRecurrence(self):
-        return ((len(self.mRrules) != 0) or (len(self.mRdates) != 0) or (len(self.mRperiods) != 0)
-                    or (len(self.mExrules) != 0) or (len(self.mExdates) != 0)
-                    or (len(self.mExperiods) != 0))
-
-
-    def equals(self, comp):
-        # Look at RRULEs
-        if not self.equalsRules(self.mRrules, comp.self.mRrules):
-            return False
-
-        # Look at EXRULEs
-        if not self.equalsRules(self.mExrules, comp.self.mExrules):
-            return False
-
-        # Look at RDATEs
-        if not self.equalsDates(self.mRdates, comp.self.mRdates):
-            return False
-        if not self.equalsPeriods(self.mRperiods, comp.self.mRperiods):
-            return False
-
-        # Look at EXDATEs
-        if not self.equalsDates(self.mExdates, comp.self.mExdates):
-            return False
-        if not self.equalsPeriods(self.mExperiods, comp.self.mExperiods):
-            return False
-
-        # If we get here they match
-        return True
-
-
-    def equalsRules(self, rules1, rules2):
-        # Check sizes first
-        if len(rules1) != len(rules2):
-            return False
-        elif len(rules1) == 0:
-            return True
-
-        # Do sledge hammer O(n^2) approach as its not easy to sort these things
-        # for a smarter test.
-        # In most cases there will only be one rule anyway, so this should not
-        # be too painful.
-
-        temp2 = rules2[:]
-
-        for r1 in rules1:
-            found = False
-            for r2 in temp2:
-                if r1.equals(r2):
-                    # Remove the one found so it is not tested again
-                    temp2.remove(r2)
-                    found = True
-                    break
-
-            if not found:
-                return False
-
-        return True
-
-
-    def equalsDates(self, dates1, dates2):
-        # Check sizes first
-        if len(dates1) != len(dates2):
-            return False
-        elif len(dates1) == 0:
-            return True
-
-        # Copy each and sort for comparison
-        dt1 = dates1[:]
-        dt2 = dates2[:]
-
-        dt1.sort(key=lambda x: x.getPosixTime())
-        dt2.sort(key=lambda x: x.getPosixTime())
-
-        return dt1.equal(dt2)
-
-
-    def equalsPeriods(self, periods1, periods2):
-        # Check sizes first
-        if len(periods1) != len(periods2):
-            return False
-        elif len(periods1) == 0:
-            return True
-
-        # Copy each and sort for comparison
-        p1 = periods1[:]
-        p2 = periods2[:]
-
-        p1.sort()
-        p2.sort()
-
-        return p1.equal(p2)
-
-
-    def addRule(self, rule):
-        self.mRrules.append(rule)
-
-
-    def subtractRule(self, rule):
-        self.mExrules.append(rule)
-
-
-    def addDT(self, dt):
-        self.mRdates.append(dt)
-
-
-    def subtractDT(self, dt):
-        self.mExdates.append(dt)
-
-
-    def addPeriod(self, p):
-        self.mRperiods.append(p)
-
-
-    def subtractPeriod(self, p):
-        self.mExperiods.append(p)
-
-
-    def getRules(self):
-        return self.mRrules
-
-
-    def getExrules(self):
-        return self.mExrules
-
-
-    def getDates(self):
-        return self.mRdates
-
-
-    def getExdates(self):
-        return self.mExdates
-
-
-    def getPeriods(self):
-        return self.mRperiods
-
-
-    def getExperiods(self):
-        return self.mExperiods
-
-
-    def expand(self, start, range, items, float_offset=0):
-        # Need to return whether the limit was applied or not
-        limited = False
-
-        # Now create list of items to include
-        include = []
-
-        # Always include the initial DTSTART if within the range
-        if range.isDateWithinPeriod(start):
-            include.append(start)
-        else:
-            limited = True
-
-        # RRULES
-        for iter in self.mRrules:
-            if iter.expand(start, range, include, float_offset=float_offset):
-                limited = True
-
-        # RDATES
-        for iter in self.mRdates:
-            if range.isDateWithinPeriod(iter):
-                include.append(iter)
-            else:
-                limited = True
-        for iter in self.mRperiods:
-            if range.isPeriodOverlap(iter):
-                include.append(iter.getStart())
-            else:
-                limited = True
-
-        # Make sure the list is unique
-        include = [x for x in set(include)]
-        include.sort(key=lambda x: x.getPosixTime())
-
-        # Now create list of items to exclude
-        exclude = []
-
-        # EXRULES
-        for iter in self.mExrules:
-            iter.expand(start, range, exclude, float_offset=float_offset)
-
-        # EXDATES
-        for iter in self.mExdates:
-            if range.isDateWithinPeriod(iter):
-                exclude.append(iter)
-        for iter in self.mExperiods:
-            if range.isPeriodOverlap(iter):
-                exclude.append(iter.getStart())
-
-        # Make sure the list is unique
-        exclude = [x for x in set(exclude)]
-        exclude.sort(key=lambda x: x.getPosixTime())
-
-        # Add difference between to the two sets (include - exclude) to the
-        # results
-        items.extend(set_difference(include, exclude))
-        return limited
-
-
-    def changed(self):
-        # RRULES
-        for iter in self.mRrules:
-            iter.clear()
-
-        # EXRULES
-        for iter in self.mExrules:
-            iter.clear()
-
-
-    def excludeFutureRecurrence(self, exclude):
-        # Adjust RRULES to end before start
-        for iter in self.mRrules:
-            iter.excludeFutureRecurrence(exclude)
-
-        # Remove RDATES on or after start
-        self.mRdates.removeOnOrAfter(exclude)
-        for iter in self.mRperiods:
-            if iter &gt; exclude:
-                self.mRperiods.remove(iter)
-
-
-    # UI operations
-    def isSimpleUI(self):
-        # Right now the Event dialog only handles a single RRULE (but we allow
-        # any number of EXDATES as deleted
-        # instances will appear as EXDATES)
-        if ((len(self.mRrules) &gt; 1) or (len(self.mExrules) &gt; 0)
-                or (len(self.mRdates) &gt; 0) or (len(self.mRperiods) &gt; 0)):
-            return False
-
-        # Also, check the rule iteself
-        elif len(self.mRrules) == 1:
-            return self.mRrules.firstElement().isSimpleRule()
-        else:
-            return True
-
-
-    def isAdvancedUI(self):
-        # Right now the Event dialog only handles a single RRULE
-        if ((len(self.mRrules) &gt; 1) or (len(self.mExrules) &gt; 0)
-                or (len(self.mRdates) &gt; 0) or (len(self.mRperiods) &gt; 0)):
-            return False
-
-        # Also, check the rule iteself
-        elif len(self.mRrules) == 1:
-            return self.mRrules.firstElement().isAdvancedRule()
-        else:
-            return True
-
-
-    def getUIRecurrence(self):
-        if len(self.mRrules) == 1:
-            return self.mRrules[0]
-        else:
-            return None
-
-
-    def getUIDescription(self):
-        # Check for anything
-        if not self.hasRecurrence():
-            return &quot;No Recurrence&quot;
-
-        # Look for a single RRULE and return its descriptor
-        if ((len(self.mRrules) == 1) and (len(self.mExrules) == 0) and (len(self.mRdates) == 0)
-                and (len(self.mExdates) == 0) and (len(self.mRperiods) == 0)
-                and (len(self.mExperiods) == 0)):
-            return self.mRrules.firstElement().getUIDescription()
-
-        # Indicate some form of complex recurrence
-        return &quot;Multiple recurrence rules, dates or exclusions&quot;
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarrecurrencevaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/recurrencevalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/recurrencevalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/recurrencevalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,54 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import xmldefs
-from pycalendar.recurrence import PyCalendarRecurrence
-from pycalendar.value import PyCalendarValue
-
-class PyCalendarRecurrenceValue(PyCalendarValue):
-
-    def __init__(self, value=None):
-        self.mValue = value if value is not None else PyCalendarRecurrence()
-
-
-    def duplicate(self):
-        return PyCalendarRecurrenceValue(self.mValue.duplicate())
-
-
-    def getType(self):
-        return PyCalendarValue.VALUETYPE_RECUR
-
-
-    def parse(self, data):
-        self.mValue.parse(data)
-
-
-    def generate(self, os):
-        self.mValue.generate(os)
-
-
-    def writeXML(self, node, namespace):
-        self.mValue.writeXML(node, namespace)
-
-
-    def getValue(self):
-        return self.mValue
-
-
-    def setValue(self, value):
-        self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_RECUR, PyCalendarRecurrenceValue, xmldefs.value_recur)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarrequeststatusvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/requeststatusvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/requeststatusvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/requeststatusvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,102 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-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.
-##
-
-# iCalendar REQUEST-STATUS value
-
-from pycalendar import utils, xmldefs
-from pycalendar.parser import ParserContext
-from pycalendar.value import PyCalendarValue
-import xml.etree.cElementTree as XML
-
-class PyCalendarRequestStatusValue(PyCalendarValue):
-    &quot;&quot;&quot;
-    The value is a list of strings (either 2 or 3 items)
-    &quot;&quot;&quot;
-
-    def __init__(self, value=None):
-        self.mValue = value if value is not None else [&quot;2.0&quot;, &quot;Success&quot;]
-
-
-    def __hash__(self):
-        return hash(tuple(self.mValue))
-
-
-    def duplicate(self):
-        return PyCalendarRequestStatusValue(self.mValue[:])
-
-
-    def getType(self):
-        return PyCalendarValue.VALUETYPE_REQUEST_STATUS
-
-
-    def parse(self, data):
-
-        result = utils.parseTextList(data, always_list=True)
-        if len(result) == 1:
-            if ParserContext.INVALID_REQUEST_STATUS_VALUE != ParserContext.PARSER_RAISE:
-                if &quot;;&quot; in result[0]:
-                    code, desc = result[0].split(&quot;;&quot;, 1)
-                else:
-                    code = result[0]
-                    desc = &quot;&quot;
-                rest = None
-            else:
-                raise ValueError
-        elif len(result) == 2:
-            code, desc = result
-            rest = None
-        elif len(result) == 3:
-            code, desc, rest = result
-        else:
-            if ParserContext.INVALID_REQUEST_STATUS_VALUE != ParserContext.PARSER_RAISE:
-                code, desc, rest = result[:3]
-            else:
-                raise ValueError
-
-        if &quot;\\&quot; in code and ParserContext.INVALID_REQUEST_STATUS_VALUE in (ParserContext.PARSER_IGNORE, ParserContext.PARSER_FIX):
-            code = code.replace(&quot;\\&quot;, &quot;&quot;)
-        elif ParserContext.INVALID_REQUEST_STATUS_VALUE == ParserContext.PARSER_RAISE:
-            raise ValueError
-
-        # Decoding required
-        self.mValue = [code, desc, rest, ] if rest else [code, desc, ]
-
-
-    # os - StringIO object
-    def generate(self, os):
-        utils.generateTextList(os, self.mValue if len(self.mValue) &lt; 3 or self.mValue[2] else self.mValue[:2])
-
-
-    def writeXML(self, node, namespace):
-        code = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.req_status_code))
-        code.text = self.mValue[0]
-
-        description = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.req_status_description))
-        description.text = self.mValue[1]
-
-        if len(self.mValue) == 3 and self.mValue[2]:
-            data = XML.SubElement(node, xmldefs.makeTag(namespace, xmldefs.req_status_data))
-            data.text = self.mValue[1]
-
-
-    def getValue(self):
-        return self.mValue
-
-
-    def setValue(self, value):
-        self.mValue = value
-
-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_REQUEST_STATUS, PyCalendarRequestStatusValue, None)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarstringutilspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/stringutils.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/stringutils.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/stringutils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrcpycalendartests__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_adrpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_adr.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_adr.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_adr.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,50 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-2012 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.adr import Adr
-import unittest
-
-class TestAdrValue(unittest.TestCase):
-
-    def testInit(self):
-        data = (
-            (
-                (&quot;pobox&quot;, &quot;extended&quot;, &quot;street&quot;, &quot;locality&quot;, &quot;region&quot;, &quot;postalcode&quot;, &quot;country&quot;),
-                &quot;pobox;extended;street;locality;region;postalcode;country&quot;,
-            ),
-            (
-                ((&quot;pobox&quot;,), (&quot;extended&quot;,), (&quot;street1&quot;, &quot;street2&quot;,), &quot;locality&quot;, &quot;region&quot;, (), &quot;country&quot;),
-                &quot;pobox;extended;street1,street2;locality;region;;country&quot;,
-            ),
-        )
-
-        for args, result in data:
-            a = Adr(*args)
-
-            self.assertEqual(
-                a.getValue(),
-                args,
-            )
-
-            self.assertEqual(
-                a.getText(),
-                result,
-            )
-
-            self.assertEqual(
-                a.duplicate().getText(),
-                result,
-            )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_adrvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_adrvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_adrvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_adrvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,62 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-2012 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.adrvalue import AdrValue
-from pycalendar.vcard.property import Property
-import unittest
-
-class TestAdrValue(unittest.TestCase):
-
-    def testParseValue(self):
-
-        items = (
-            (&quot;&quot;, &quot;;;;;;;&quot;),
-            (&quot;;&quot;, &quot;;;;;;;&quot;),
-            (&quot;;;;;;;&quot;, &quot;;;;;;;&quot;),
-            (&quot;;;123 Main Street;Any Town;CA;91921-1234&quot;, &quot;;;123 Main Street;Any Town;CA;91921-1234;&quot;),
-            (&quot;;;;;;;USA&quot;, &quot;;;;;;;USA&quot;),
-            (&quot;POB1&quot;, &quot;POB1;;;;;;&quot;),
-            (&quot;;EXT&quot;, &quot;;EXT;;;;;&quot;),
-            (&quot;;;123 Main Street,The Cards;Any Town;CA;91921-1234&quot;, &quot;;;123 Main Street,The Cards;Any Town;CA;91921-1234;&quot;),
-            (&quot;;;123 Main\, Street,The Cards;Any Town;CA;91921-1234&quot;, &quot;;;123 Main\, Street,The Cards;Any Town;CA;91921-1234;&quot;),
-            (&quot;;;123 Main\, Street,The\, Cards;Any Town;CA;91921-1234&quot;, &quot;;;123 Main\, Street,The\, Cards;Any Town;CA;91921-1234;&quot;),
-        )
-
-        for item, result in items:
-            req = AdrValue()
-            req.parse(item)
-            test = req.getText()
-            self.assertEqual(test, result, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
-
-
-    def testParseProperty(self):
-
-        items = (
-            (&quot;ADR:&quot;, &quot;ADR:;;;;;;&quot;),
-            (&quot;ADR:;&quot;, &quot;ADR:;;;;;;&quot;),
-            (&quot;ADR:;;;;;;&quot;, &quot;ADR:;;;;;;&quot;),
-            (&quot;ADR:;;123 Main Street;Any Town;CA;91921-1234&quot;, &quot;ADR:;;123 Main Street;Any Town;CA;91921-1234;&quot;),
-            (&quot;ADR:;;;;;;USA&quot;, &quot;ADR:;;;;;;USA&quot;),
-            (&quot;ADR:POB1&quot;, &quot;ADR:POB1;;;;;;&quot;),
-            (&quot;ADR:;EXT&quot;, &quot;ADR:;EXT;;;;;&quot;),
-            (&quot;ADR;VALUE=TEXT:;;123 Main Street;Any Town;CA;91921-1234&quot;, &quot;ADR:;;123 Main Street;Any Town;CA;91921-1234;&quot;),
-        )
-
-        for item, result in items:
-            prop = Property()
-            prop.parse(item)
-            test = prop.getText()
-            self.assertEqual(test, result + &quot;\r\n&quot;, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_calendarpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_calendar.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_calendar.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_calendar.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,854 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.exceptions import PyCalendarInvalidData
-from pycalendar.parser import ParserContext
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.property import PyCalendarProperty
-import cStringIO as StringIO
-import difflib
-import unittest
-
-class TestCalendar(unittest.TestCase):
-
-    data = (
-&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-&quot;&quot;&quot;BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-X-WR-CALNAME:PayDay
-BEGIN:VTIMEZONE
-TZID:US/Eastern
-LAST-MODIFIED:20040110T032845Z
-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
-UID:DC3D0301C7790B38631F1FBB@ninevah.local
-DTSTART;VALUE=DATE:20040227
-DTSTAMP:20050211T173501Z
-RRULE:FREQ=MONTHLY;BYDAY=-1MO,-1TU,-1WE,-1TH,-1FR;BYSETPOS=-1
-SUMMARY:PAY DAY
-BEGIN:VALARM
-ACTION:DISPLAY
-DESCRIPTION:Alarm for Organizer!
-TRIGGER;RELATED=START:-PT15M
-END:VALARM
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-&quot;&quot;&quot;BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:12345-67890-3
-DTSTART:20071114T000000Z
-ATTENDEE:mailto:user2@example.com
-EXDATE:20081114T000000Z
-ORGANIZER:mailto:user1@example.com
-RRULE:FREQ=YEARLY
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-ATTACH:http://example.com/test.jpg
-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:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-ATTACH;ENCODING=BASE64;VALUE=BINARY:dGVzdA==
-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:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//Example Inc.//Example Calendar//EN
-BEGIN:VTIMEZONE
-TZID:America/Montreal
-LAST-MODIFIED:20040110T032845Z
-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:VAVAILABILITY
-UID:20061005T133225Z-00001-availability@example.com
-DTSTART;TZID=America/Montreal:20060101T000000
-DTEND;TZID=America/Montreal:20060108T000000
-DTSTAMP:20061005T133225Z
-ORGANIZER:mailto:bernard@example.com
-BEGIN:AVAILABLE
-UID:20061005T133225Z-00001-A-availability@example.com
-DTSTART;TZID=America/Montreal:20060102T090000
-DTEND;TZID=America/Montreal:20060102T120000
-DTSTAMP:20061005T133225Z
-RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR
-SUMMARY:Monday\\, Wednesday and Friday from 9:00 to 12:00
-END:AVAILABLE
-BEGIN:AVAILABLE
-UID:20061005T133225Z-00001-A-availability@example.com
-RECURRENCE-ID;TZID=America/Montreal:20060106T090000
-DTSTART;TZID=America/Montreal:20060106T120000
-DTEND;TZID=America/Montreal:20060106T170000
-DTSTAMP:20061005T133225Z
-SUMMARY:Friday override from 12:00 to 17:00
-END:AVAILABLE
-END:VAVAILABILITY
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-&quot;&quot;&quot;BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//Example Inc.//Example Calendar//EN
-BEGIN:VTODO
-UID:event1@ninevah.local
-CREATED:20060101T150000Z
-DTSTAMP:20051222T205953Z
-SUMMARY:event 1
-END:VTODO
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-BEGIN:X-COMPONENT
-UID:1234
-END:X-COMPONENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-&quot;&quot;&quot;BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//Apple Inc.//iCal 4.0.1//EN
-BEGIN:VTIMEZONE
-TZID:US/Pacific
-BEGIN:DAYLIGHT
-DTSTART:20070311T020000
-RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
-TZNAME:PDT
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0700
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:20071104T020000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
-TZNAME:PST
-TZOFFSETFROM:-0700
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-UID:uid4
-DTSTART;TZID=US/Pacific:20100207T170000
-DTEND;TZID=US/Pacific:20100207T173000
-CREATED:20100203T013849Z
-DTSTAMP:20100203T013909Z
-SEQUENCE:3
-SUMMARY:New Event
-TRANSP:OPAQUE
-BEGIN:VALARM
-ACTION:AUDIO
-ATTACH:Basso
-TRIGGER:-PT20M
-X-WR-ALARMUID:1377CCC7-F85C-4610-8583-9513D4B364E1
-END:VALARM
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-ATTACH:http://example.com/test.jpg
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-X-APPLE-STRUCTURED-LOCATION:geo:123.123,123.123
-X-Test:Some\, text.
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-ATTACH:http://example.com/test.jpg
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-X-APPLE-STRUCTURED-LOCATION;VALUE=URI:geo:123.123,123.123
-X-Test:Some\, text.
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-)
-    data2 = (
-                (
-&quot;&quot;&quot;BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:12345-67890-3
-DTSTART:20071114T000000Z
-ATTENDEE:mailto:user2@example.com
-EXDATE:20081114T000000Z
-ORGANIZER:mailto:user1@example.com
-RRULE:FREQ=YEARLY
-END:VEVENT
-X-TEST:Testing
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-&quot;&quot;&quot;BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-X-TEST:Testing
-BEGIN:VEVENT
-UID:12345-67890-3
-DTSTART:20071114T000000Z
-ATTENDEE:mailto:user2@example.com
-EXDATE:20081114T000000Z
-ORGANIZER:mailto:user1@example.com
-RRULE:FREQ=YEARLY
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-                ),
-)
-
-
-    def testRoundtrip(self):
-
-
-        def _doRoundtrip(caldata, resultdata=None):
-            test1 = resultdata if resultdata is not None else caldata
-
-            cal = PyCalendar()
-            cal.parse(StringIO.StringIO(caldata))
-
-            s = StringIO.StringIO()
-            cal.generate(s)
-            test2 = s.getvalue()
-
-            self.assertEqual(
-                test1,
-                test2,
-                &quot;\n&quot;.join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
-            )
-
-        for item in self.data:
-            _doRoundtrip(item)
-
-        for item1, item2 in self.data2:
-            _doRoundtrip(item1, item2)
-
-
-    def testRoundtripDuplicate(self):
-
-
-        def _doDuplicateRoundtrip(caldata):
-            cal = PyCalendar()
-            cal.parse(StringIO.StringIO(caldata))
-            cal = cal.duplicate()
-
-            s = StringIO.StringIO()
-            cal.generate(s)
-            self.assertEqual(caldata, s.getvalue())
-
-        for item in self.data:
-            _doDuplicateRoundtrip(item)
-
-
-    def testEquality(self):
-
-
-        def _doEquality(caldata):
-            cal1 = PyCalendar()
-            cal1.parse(StringIO.StringIO(caldata))
-
-            cal2 = PyCalendar()
-            cal2.parse(StringIO.StringIO(caldata))
-
-            self.assertEqual(cal1, cal2, &quot;%s\n\n%s&quot; % (cal1, cal2,))
-
-
-        def _doNonEquality(caldata):
-            cal1 = PyCalendar()
-            cal1.parse(StringIO.StringIO(caldata))
-
-            cal2 = PyCalendar()
-            cal2.parse(StringIO.StringIO(caldata))
-            cal2.addProperty(PyCalendarProperty(&quot;X-FOO&quot;, &quot;BAR&quot;))
-
-            self.assertNotEqual(cal1, cal2)
-
-        for item in self.data:
-            _doEquality(item)
-            _doNonEquality(item)
-
-
-    def testParseComponent(self):
-
-        data1 = &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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;)
-
-        data2 = &quot;&quot;&quot;BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//Example Inc.//Example Calendar//EN
-BEGIN:VTIMEZONE
-TZID:America/Montreal
-LAST-MODIFIED:20040110T032845Z
-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
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;)
-
-        result = &quot;&quot;&quot;BEGIN:VCALENDAR
-VERSION:2.0
-CALSCALE:GREGORIAN
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VTIMEZONE
-TZID:America/Montreal
-LAST-MODIFIED:20040110T032845Z
-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
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-DTSTART;VALUE=DATE:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;)
-
-        cal = PyCalendar()
-        cal.parse(StringIO.StringIO(data1))
-        cal.parseComponent(StringIO.StringIO(data2))
-        self.assertEqual(str(cal), result)
-
-
-    def testParseFail(self):
-
-        data = (
-&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-&quot;&quot;&quot;BEGIN:VCARD
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-VERSION:2.0
-END:VCARD
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-&quot;&quot;&quot;BOGUS
-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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-&quot;&quot;&quot;BOGUS
-
-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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-BOGUS
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-
-BOGUS
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-        )
-
-        for item in data:
-            self.assertRaises(PyCalendarInvalidData, PyCalendar.parseText, item)
-
-
-    def testParseBlank(self):
-
-        data = (
-&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-
-
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-        )
-
-        save = ParserContext.BLANK_LINES_IN_DATA
-        for item in data:
-            ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_RAISE
-            self.assertRaises(PyCalendarInvalidData, PyCalendar.parseText, item)
-
-            ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_IGNORE
-            lines = item.split(&quot;\r\n&quot;)
-            result = &quot;\r\n&quot;.join([line for line in lines if line]) + &quot;\r\n&quot;
-            self.assertEqual(str(PyCalendar.parseText(item)), result)
-
-        ParserContext.BLANK_LINES_IN_DATA = save
-
-
-    def testGetVEvents(self):
-
-        data = (
-            (
-                &quot;Non-recurring match&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;),
-                (PyCalendarDateTime(2011, 6, 1),),
-            ),
-            (
-                &quot;Non-recurring no-match&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:20110501
-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;Recurring match&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;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-                (
-                    PyCalendarDateTime(2011, 6, 1),
-                    PyCalendarDateTime(2011, 6, 2),
-                ),
-            ),
-            (
-                &quot;Recurring no match&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:20110501
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-                (),
-            ),
-            (
-                &quot;Recurring with override match&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:20110601T120000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-RECURRENCE-ID;VALUE=DATE:20110602T120000
-DTSTART;VALUE=DATE:20110602T130000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-                (
-                    PyCalendarDateTime(2011, 6, 1, 12, 0, 0),
-                    PyCalendarDateTime(2011, 6, 2, 13, 0, 0),
-                ),
-            ),
-            (
-                &quot;Recurring with override no match&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:20110501T120000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-RECURRENCE-ID;VALUE=DATE:20110502T120000
-DTSTART;VALUE=DATE:20110502T130000
-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;Recurring partial match&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:20110531
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-                (
-                    PyCalendarDateTime(2011, 6, 1),
-                ),
-            ),
-            (
-                &quot;Recurring with override partial match&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:20110531T120000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:New Year's Day
-END:VEVENT
-BEGIN:VEVENT
-UID:C3184A66-1ED0-11D9-A5E0-000A958A3252
-RECURRENCE-ID;VALUE=DATE:20110601T120000
-DTSTART;VALUE=DATE:20110601T130000
-DURATION:P1D
-DTSTAMP:20020101T000000Z
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-                (
-                    PyCalendarDateTime(2011, 6, 1, 13, 0, 0),
-                ),
-            ),
-        )
-
-        for title, caldata, result in data:
-            calendar = PyCalendar.parseText(caldata)
-            instances = []
-            calendar.getVEvents(
-                PyCalendarPeriod(
-                    start=PyCalendarDateTime(2011, 6, 1),
-                    end=PyCalendarDateTime(2011, 7, 1),
-                ),
-                instances
-            )
-            instances = tuple([instance.getInstanceStart() for instance in instances])
-            self.assertEqual(instances, result, &quot;Failed in %s: got %s, expected %s&quot; % (title, instances, result))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_componentrecurpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_componentrecur.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_componentrecur.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_componentrecur.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,66 +0,0 @@
</span><del>-#    Copyright (c) 2007-2012 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.calendar import PyCalendar
-import cStringIO as StringIO
-import unittest
-
-class TestCalendar(unittest.TestCase):
-
-    def testDuplicateWithRecurrenceChange(self):
-
-        data = (
-&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;COUNT=400
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-)
-
-        cal1 = PyCalendar()
-        cal1.parse(StringIO.StringIO(data[0]))
-        cal2 = cal1.duplicate()
-        vevent = cal2.getComponents()[0]
-        rrules = vevent.getRecurrenceSet()
-        for rrule in rrules.getRules():
-            rrule.setUseCount(True)
-            rrule.setCount(400)
-            rrules.changed()
-
-        self.assertEqual(data[0], str(cal1))
-        self.assertEqual(data[1], str(cal2))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_datetimepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_datetime.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_datetime.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_datetime.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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">@@ -14,9 +14,9 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.timezone import Timezone
</ins><span class="cx"> import unittest
</span><span class="cx"> 
</span><span class="cx"> class TestDateTime(unittest.TestCase):
</span><span class="lines">@@ -25,16 +25,16 @@
</span><span class="cx"> 
</span><span class="cx">         items = (
</span><span class="cx">             (
</span><del>-                PyCalendarDateTime(2011, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2011, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">             ),
</span><span class="cx">             (
</span><del>-                PyCalendarDateTime(2011, 1, 1, 0, 0, 0),
-                PyCalendarDateTime(2011, 1, 1, 0, 0, 0),
</del><ins>+                DateTime(2011, 1, 1, 0, 0, 0),
+                DateTime(2011, 1, 1, 0, 0, 0),
</ins><span class="cx">             ),
</span><span class="cx">             (
</span><del>-                PyCalendarDateTime(2011, 1, 1),
-                PyCalendarDateTime(2011, 1, 1),
</del><ins>+                DateTime(2011, 1, 1),
+                DateTime(2011, 1, 1),
</ins><span class="cx">             )
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -47,13 +47,13 @@
</span><span class="cx"> 
</span><span class="cx">         s = set(
</span><span class="cx">             (
</span><del>-                PyCalendarDateTime(2011, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2011, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2011, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">             )
</span><span class="cx">         )
</span><span class="cx"> 
</span><del>-        self.assertTrue(PyCalendarDateTime(2011, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)) in s)
-        self.assertFalse(PyCalendarDateTime(2011, 1, 3, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)) in s)
</del><ins>+        self.assertTrue(DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)) in s)
+        self.assertFalse(DateTime(2011, 1, 3, 0, 0, 0, tzid=Timezone(utc=True)) in s)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def testRoundtrip(self):
</span><span class="lines">@@ -85,11 +85,11 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for item in data1:
</span><del>-            dt = PyCalendarDateTime.parseText(item, False)
</del><ins>+            dt = DateTime.parseText(item, False)
</ins><span class="cx">             self.assertEqual(dt.getText(), item, &quot;Failed on: %s&quot; % (item,))
</span><span class="cx"> 
</span><span class="cx">         for item, result in data2:
</span><del>-            dt = PyCalendarDateTime.parseText(item, True)
</del><ins>+            dt = DateTime.parseText(item, True)
</ins><span class="cx">             self.assertEqual(dt.getText(), result, &quot;Failed on: %s&quot; % (item,))
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -122,16 +122,16 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for item in data1:
</span><del>-            self.assertRaises(ValueError, PyCalendarDateTime.parseText, item, False)
</del><ins>+            self.assertRaises(ValueError, DateTime.parseText, item, False)
</ins><span class="cx"> 
</span><span class="cx">         for item in data2:
</span><del>-            self.assertRaises(ValueError, PyCalendarDateTime.parseText, item, False)
</del><ins>+            self.assertRaises(ValueError, DateTime.parseText, item, False)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def testCachePreserveOnAdjustment(self):
</span><span class="cx"> 
</span><span class="cx">         # UTC first
</span><del>-        dt = PyCalendarDateTime(2012, 6, 7, 12, 0, 0, PyCalendarTimezone(tzid=&quot;utc&quot;))
</del><ins>+        dt = DateTime(2012, 6, 7, 12, 0, 0, Timezone(tzid=&quot;utc&quot;))
</ins><span class="cx">         dt.getPosixTime()
</span><span class="cx"> 
</span><span class="cx">         # check existing cache is complete
</span><span class="lines">@@ -301,9 +301,9 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;)
</span><span class="cx"> 
</span><del>-        PyCalendar.parseText(tzdata)
</del><ins>+        Calendar.parseText(tzdata)
</ins><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime(2012, 6, 7, 12, 0, 0, PyCalendarTimezone(tzid=&quot;America/Pittsburgh&quot;))
</del><ins>+        dt = DateTime(2012, 6, 7, 12, 0, 0, Timezone(tzid=&quot;America/Pittsburgh&quot;))
</ins><span class="cx">         dt.getPosixTime()
</span><span class="cx"> 
</span><span class="cx">         # check existing cache is complete
</span><span class="lines">@@ -326,47 +326,47 @@
</span><span class="cx"> 
</span><span class="cx">     def testSetWeekNo(self):
</span><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        dt = DateTime(2013, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx">         dt.setWeekNo(1)
</span><del>-        self.assertEqual(dt, PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        self.assertEqual(dt, DateTime(2013, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        dt = DateTime(2013, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx">         dt.setWeekNo(2)
</span><del>-        self.assertEqual(dt, PyCalendarDateTime(2013, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        self.assertEqual(dt, DateTime(2013, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 2)
</span><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime(2013, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        dt = DateTime(2013, 1, 8, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 2)
</span><span class="cx">         dt.setWeekNo(1)
</span><del>-        self.assertEqual(dt, PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        self.assertEqual(dt, DateTime(2013, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime(2014, 1, 7, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        dt = DateTime(2014, 1, 7, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 2)
</span><span class="cx">         dt.setWeekNo(1)
</span><del>-        self.assertEqual(dt, PyCalendarDateTime(2013, 12, 31, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        self.assertEqual(dt, DateTime(2013, 12, 31, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime(2012, 12, 31, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        dt = DateTime(2012, 12, 31, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx">         dt.setWeekNo(1)
</span><del>-        self.assertEqual(dt, PyCalendarDateTime(2012, 12, 31, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        self.assertEqual(dt, DateTime(2012, 12, 31, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime(2016, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        dt = DateTime(2016, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 53)
</span><span class="cx">         dt.setWeekNo(1)
</span><del>-        self.assertEqual(dt, PyCalendarDateTime(2016, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        self.assertEqual(dt, DateTime(2016, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx">         dt.setWeekNo(2)
</span><del>-        self.assertEqual(dt, PyCalendarDateTime(2016, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        self.assertEqual(dt, DateTime(2016, 1, 15, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 2)
</span><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime(2016, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        dt = DateTime(2016, 1, 8, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 1)
</span><span class="cx">         dt.setWeekNo(1)
</span><del>-        self.assertEqual(dt, PyCalendarDateTime(2016, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        self.assertEqual(dt, DateTime(2016, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertEqual(dt.getWeekNo(), 1)
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_durationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_duration.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_duration.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_duration.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -15,7 +15,7 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> from cStringIO import StringIO
</span><del>-from pycalendar.duration import PyCalendarDuration
</del><ins>+from pycalendar.duration import Duration
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> import unittest
</span><span class="cx"> 
</span><span class="lines">@@ -56,13 +56,13 @@
</span><span class="cx">             self.assertEqual(os.getvalue(), result)
</span><span class="cx"> 
</span><span class="cx">         for seconds, result in TestDuration.test_data:
</span><del>-            _doTest(PyCalendarDuration(duration=seconds), result)
</del><ins>+            _doTest(Duration(duration=seconds), result)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def testParse(self):
</span><span class="cx"> 
</span><span class="cx">         for seconds, result in TestDuration.test_data:
</span><del>-            duration = PyCalendarDuration().parseText(result)
</del><ins>+            duration = Duration().parseText(result)
</ins><span class="cx">             self.assertEqual(duration.getTotalSeconds(), seconds)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -81,7 +81,7 @@
</span><span class="cx">             &quot;P12DT1SA&quot;,
</span><span class="cx">         )
</span><span class="cx">         for data in test_bad_data:
</span><del>-            self.assertRaises(ValueError, PyCalendarDuration.parseText, data)
</del><ins>+            self.assertRaises(ValueError, Duration.parseText, data)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def testRelaxedBad(self):
</span><span class="lines">@@ -94,8 +94,8 @@
</span><span class="cx">         for text, seconds, result in test_relaxed_data:
</span><span class="cx"> 
</span><span class="cx">             ParserContext.INVALID_DURATION_VALUE = ParserContext.PARSER_FIX
</span><del>-            self.assertEqual(PyCalendarDuration.parseText(text).getTotalSeconds(), seconds)
-            self.assertEqual(PyCalendarDuration.parseText(text).getText(), result)
</del><ins>+            self.assertEqual(Duration.parseText(text).getTotalSeconds(), seconds)
+            self.assertEqual(Duration.parseText(text).getText(), result)
</ins><span class="cx"> 
</span><span class="cx">             ParserContext.INVALID_DURATION_VALUE = ParserContext.PARSER_RAISE
</span><del>-            self.assertRaises(ValueError, PyCalendarDuration.parseText, text)
</del><ins>+            self.assertRaises(ValueError, Duration.parseText, text)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_i18npy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_i18n.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_i18n.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_i18n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,74 +0,0 @@
</span><del>-# coding: utf-8
-##
-#    Copyright (c) 2007-2012 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.attribute import PyCalendarAttribute
-from pycalendar.calendar import PyCalendar
-import cStringIO as StringIO
-import unittest
-
-class TestCalendar(unittest.TestCase):
-
-    def testAddCN(self):
-
-        data = (
-&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-ORGANIZER:user01@example.com
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-    &quot;まだ&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:20020101
-DTEND;VALUE=DATE:20020102
-DTSTAMP:20020101T000000Z
-RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1
-ORGANIZER;CN=まだ:user01@example.com
-SUMMARY:New Year's Day
-END:VEVENT
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-        )
-
-        cal1 = PyCalendar()
-        cal1.parse(StringIO.StringIO(data[0]))
-
-        vevent = cal1.getComponents(&quot;VEVENT&quot;)[0]
-        organizer = vevent.getProperties(&quot;ORGANIZER&quot;)[0]
-        organizer.addAttribute(PyCalendarAttribute(&quot;CN&quot;, data[1]))
-
-        cal2 = PyCalendar()
-        cal2.parse(StringIO.StringIO(data[2]))
-
-        self.assertEqual(str(cal1), str(cal2))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_multivaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_multivalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_multivalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_multivalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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">@@ -15,8 +15,8 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> import unittest
</span><del>-from pycalendar.multivalue import PyCalendarMultiValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.multivalue import MultiValue
+from pycalendar.value import Value
</ins><span class="cx"> 
</span><span class="cx"> class TestMultiValue(unittest.TestCase):
</span><span class="cx"> 
</span><span class="lines">@@ -29,8 +29,8 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for item, result, count in items:
</span><del>-            req = PyCalendarMultiValue(PyCalendarValue.VALUETYPE_TEXT)
-            req.parse(item)
</del><ins>+            req = MultiValue(Value.VALUETYPE_TEXT)
+            req.parse(item, &quot;icalendar&quot;)
</ins><span class="cx">             test = req.getText()
</span><span class="cx">             self.assertEqual(test, result, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</span><span class="cx">             self.assertEqual(len(req.mValues), count, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</span><span class="lines">@@ -38,8 +38,8 @@
</span><span class="cx"> 
</span><span class="cx">     def testSetValue(self):
</span><span class="cx"> 
</span><del>-        req = PyCalendarMultiValue(PyCalendarValue.VALUETYPE_TEXT)
-        req.parse(&quot;Example1, Example2&quot;)
</del><ins>+        req = MultiValue(Value.VALUETYPE_TEXT)
+        req.parse(&quot;Example1, Example2&quot;, &quot;icalendar&quot;)
</ins><span class="cx">         req.setValue((&quot;Example3&quot;, &quot;Example4&quot;,))
</span><span class="cx">         test = req.getText()
</span><span class="cx">         self.assertEqual(test, &quot;Example3,Example4&quot;)
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_npy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_n.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_n.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,92 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-2012 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.n import N
-import unittest
-
-class TestAdrValue(unittest.TestCase):
-
-    def testInit(self):
-
-        data = (
-            (
-                (&quot;last&quot;, &quot;first&quot;, &quot;middle&quot;, &quot;prefix&quot;, &quot;suffix&quot;),
-                &quot;last;first;middle;prefix;suffix&quot;,
-                &quot;prefix first middle last suffix&quot;,
-            ),
-            (
-                (&quot;last&quot;, (&quot;first&quot;,), (&quot;middle1&quot;, &quot;middle2&quot;,), (), (&quot;suffix&quot;,)),
-                &quot;last;first;middle1,middle2;;suffix&quot;,
-                &quot;first middle1 middle2 last suffix&quot;,
-            ),
-        )
-
-        for args, result, fullName in data:
-            n = N(*args)
-
-            self.assertEqual(
-                n.getValue(),
-                args,
-            )
-
-            self.assertEqual(
-                n.getText(),
-                result,
-            )
-
-            self.assertEqual(
-                n.getFullName(),
-                fullName,
-            )
-
-            self.assertEqual(
-                n.duplicate().getText(),
-                result,
-            )
-
-
-    def testInitWithKeywords(self):
-
-        data = (
-            (
-                {&quot;first&quot;: &quot;first&quot;, &quot;last&quot;: &quot;last&quot;, &quot;middle&quot;: &quot;middle&quot;, &quot;prefix&quot;: &quot;prefix&quot;, &quot;suffix&quot;: &quot;suffix&quot;},
-                &quot;last;first;middle;prefix;suffix&quot;,
-                &quot;prefix first middle last suffix&quot;,
-            ),
-            (
-                {&quot;first&quot;: (&quot;first&quot;,), &quot;last&quot;: &quot;last&quot;, &quot;middle&quot;: (&quot;middle1&quot;, &quot;middle2&quot;,), &quot;prefix&quot;: (), &quot;suffix&quot;: (&quot;suffix&quot;,)},
-                &quot;last;first;middle1,middle2;;suffix&quot;,
-                &quot;first middle1 middle2 last suffix&quot;,
-            ),
-        )
-
-        for kwargs, result, fullName in data:
-            n = N(**kwargs)
-
-            self.assertEqual(
-                n.getText(),
-                result,
-            )
-
-            self.assertEqual(
-                n.getFullName(),
-                fullName,
-            )
-
-            self.assertEqual(
-                n.duplicate().getText(),
-                result,
-            )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_nvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_nvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_nvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_nvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,59 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-2012 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.nvalue import NValue
-from pycalendar.vcard.property import Property
-import unittest
-
-class TestNValue(unittest.TestCase):
-
-    def testParseValue(self):
-
-        items = (
-            (&quot;&quot;, &quot;;;;;&quot;),
-            (&quot;;&quot;, &quot;;;;;&quot;),
-            (&quot;;;;;&quot;, &quot;;;;;&quot;),
-            (&quot;Cyrus;Daboo;;Dr.&quot;, &quot;Cyrus;Daboo;;Dr.;&quot;),
-            (&quot;;;;;PhD.&quot;, &quot;;;;;PhD.&quot;),
-            (&quot;Cyrus&quot;, &quot;Cyrus;;;;&quot;),
-            (&quot;;Daboo&quot;, &quot;;Daboo;;;&quot;),
-        )
-
-        for item, result in items:
-            req = NValue()
-            req.parse(item)
-            test = req.getText()
-            self.assertEqual(test, result, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
-
-
-    def testParseProperty(self):
-
-        items = (
-            (&quot;N:&quot;, &quot;N:;;;;&quot;),
-            (&quot;N:;&quot;, &quot;N:;;;;&quot;),
-            (&quot;N:;;;;&quot;, &quot;N:;;;;&quot;),
-            (&quot;N:Cyrus;Daboo;;Dr.&quot;, &quot;N:Cyrus;Daboo;;Dr.;&quot;),
-            (&quot;N:;;;;PhD.&quot;, &quot;N:;;;;PhD.&quot;),
-            (&quot;N:Cyrus&quot;, &quot;N:Cyrus;;;;&quot;),
-            (&quot;N:;Daboo&quot;, &quot;N:;Daboo;;;&quot;),
-            (&quot;N;VALUE=TEXT:Cyrus;Daboo;;Dr.&quot;, &quot;N:Cyrus;Daboo;;Dr.;&quot;),
-        )
-
-        for item, result in items:
-            prop = Property()
-            prop.parse(item)
-            test = prop.getText()
-            self.assertEqual(test, result + &quot;\r\n&quot;, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_orgvaluepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_orgvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_orgvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_orgvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,53 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-2012 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.orgvalue import OrgValue
-from pycalendar.vcard.property import Property
-import unittest
-
-class TestNValue(unittest.TestCase):
-
-    def testParseValue(self):
-
-        items = (
-            (&quot;&quot;, &quot;&quot;),
-            (&quot;Example&quot;, &quot;Example&quot;),
-            (&quot;Example\, Inc.&quot;, &quot;Example\, Inc.&quot;),
-            (&quot;Example\; Inc;Dept. of Silly Walks&quot;, &quot;Example\; Inc;Dept. of Silly Walks&quot;),
-        )
-
-        for item, result in items:
-            req = OrgValue()
-            req.parse(item)
-            test = req.getText()
-            self.assertEqual(test, result, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
-
-
-    def testParseProperty(self):
-
-        items = (
-            (&quot;ORG:&quot;, &quot;ORG:&quot;),
-            (&quot;ORG:Example&quot;, &quot;ORG:Example&quot;),
-            (&quot;ORG:Example\, Inc.&quot;, &quot;ORG:Example\, Inc.&quot;),
-            (&quot;ORG:Example\; Inc;Dept. of Silly Walks&quot;, &quot;ORG:Example\; Inc;Dept. of Silly Walks&quot;),
-            (&quot;ORG;VALUE=TEXT:Example&quot;, &quot;ORG:Example&quot;),
-        )
-
-        for item, result in items:
-            prop = Property()
-            prop.parse(item)
-            test = prop.getText()
-            self.assertEqual(test, result + &quot;\r\n&quot;, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_propertypy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_property.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_property.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,189 +0,0 @@
</span><del>-##
-#    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.attribute import PyCalendarAttribute
-from pycalendar.exceptions import PyCalendarInvalidProperty
-from pycalendar.parser import ParserContext
-from pycalendar.property import PyCalendarProperty
-from pycalendar.value import PyCalendarValue
-import unittest
-
-class TestProperty(unittest.TestCase):
-
-    test_data = (
-        # Different value types
-        &quot;ATTACH;VALUE=BINARY:VGVzdA==&quot;,
-        &quot;attach;VALUE=BINARY:VGVzdA==&quot;,
-        &quot;ORGANIZER:mailto:jdoe@example.com&quot;,
-        &quot;DTSTART;TZID=US/Eastern:20060226T120000&quot;,
-        &quot;DTSTART;VALUE=DATE:20060226&quot;,
-        &quot;DTSTART:20060226T130000Z&quot;,
-        &quot;X-FOO:BAR&quot;,
-        &quot;DURATION:PT10M&quot;,
-        &quot;duraTION:PT10M&quot;,
-        &quot;SEQUENCE:1&quot;,
-        &quot;RDATE:20060226T120000Z,20060227T120000Z&quot;,
-        &quot;FREEBUSY:20060226T120000Z/20060227T120000Z&quot;,
-        &quot;SUMMARY:Some \\ntext&quot;,
-        &quot;RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=-1&quot;,
-        &quot;REQUEST-STATUS:2.0;Success&quot;,
-        &quot;URI:http://www.example.com&quot;,
-        &quot;TZOFFSETFROM:-0500&quot;,
-        &quot;X-Test:Some\, text.&quot;,
-        &quot;X-Test:Some:, text.&quot;,
-        &quot;X-APPLE-STRUCTURED-LOCATION;VALUE=URI:geo:123.123,123.123&quot;,
-        &quot;X-CALENDARSERVER-PRIVATE-COMMENT:This\\ntest\\nis\\, here.\\n&quot;,
-
-        # Various parameters
-        &quot;DTSTART;TZID=\&quot;Somewhere, else\&quot;:20060226T120000&quot;,
-        &quot;ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:jdoe@example.com&quot;,
-        &quot;X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-APPLE-ABUID=ab\\://Work;X-TITLE=\&quot;10\\n XX S. XXX Dr.\\nSuite XXX\\nXX XX XXXXX\\nUnited States\&quot;:\&quot;geo:11.111111,-11.111111\&quot;&quot;,
-
-        # Parameter escaping
-        &quot;ATTENDEE;CN=My ^'Test^' Name;ROLE=CHAIR:mailto:jdoe@example.com&quot;,
-    )
-
-
-    def testParseGenerate(self):
-
-        for data in TestProperty.test_data:
-            prop = PyCalendarProperty()
-            prop.parse(data)
-            propstr = str(prop).replace(&quot;\r\n &quot;, &quot;&quot;)
-            self.assertEqual(propstr[:-2], data, &quot;Failed parse/generate: %s to %s&quot; % (data, propstr,))
-
-
-    def testEquality(self):
-
-        for data in TestProperty.test_data:
-            prop1 = PyCalendarProperty()
-            prop1.parse(data)
-            prop2 = PyCalendarProperty()
-            prop2.parse(data)
-            self.assertEqual(prop1, prop2, &quot;Failed equality: %s&quot; % (data,))
-
-
-    def testParseBad(self):
-
-        test_bad_data = (
-            &quot;DTSTART;TZID=US/Eastern:abc&quot;,
-            &quot;DTSTART;VALUE=DATE:20060226T&quot;,
-            &quot;DTSTART:20060226T120000A&quot;,
-            &quot;X-FOO;:BAR&quot;,
-            &quot;DURATION:A&quot;,
-            &quot;SEQUENCE:b&quot;,
-            &quot;RDATE:20060226T120000Z;20060227T120000Z&quot;,
-            &quot;FREEBUSY:20060226T120000Z/ABC&quot;,
-            &quot;SUMMARY:Some \\qtext&quot;,
-            &quot;RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,VE;BYSETPOS=-1&quot;,
-            &quot;TZOFFSETFROM:-050&quot;,
-            &quot;&quot;&quot;ATTENDEE;CN=&quot;\\&quot;;CUTYPE=INDIVIDUAL;PARTSTAT=X-UNDELIVERABLE:invalid:nomai
- l&quot;&quot;&quot;,
-        )
-        save = ParserContext.INVALID_ESCAPE_SEQUENCES
-        for data in test_bad_data:
-            ParserContext.INVALID_ESCAPE_SEQUENCES = ParserContext.PARSER_RAISE
-            prop = PyCalendarProperty()
-            self.assertRaises(PyCalendarInvalidProperty, prop.parse, data)
-        ParserContext.INVALID_ESCAPE_SEQUENCES = save
-
-
-    def testHash(self):
-
-        hashes = []
-        for item in TestProperty.test_data:
-            prop = PyCalendarProperty()
-            prop.parse(item)
-            hashes.append(hash(prop))
-        hashes.sort()
-        for i in range(1, len(hashes)):
-            self.assertNotEqual(hashes[i - 1], hashes[i])
-
-
-    def testDefaultValueCreate(self):
-
-        test_data = (
-            (&quot;ATTENDEE&quot;, &quot;mailto:attendee@example.com&quot;, &quot;ATTENDEE:mailto:attendee@example.com\r\n&quot;),
-            (&quot;attendee&quot;, &quot;mailto:attendee@example.com&quot;, &quot;attendee:mailto:attendee@example.com\r\n&quot;),
-            (&quot;ORGANIZER&quot;, &quot;mailto:organizer@example.com&quot;, &quot;ORGANIZER:mailto:organizer@example.com\r\n&quot;),
-            (&quot;ORGANizer&quot;, &quot;mailto:organizer@example.com&quot;, &quot;ORGANizer:mailto:organizer@example.com\r\n&quot;),
-            (&quot;URL&quot;, &quot;http://example.com/tz1&quot;, &quot;URL:http://example.com/tz1\r\n&quot;),
-            (&quot;TZURL&quot;, &quot;http://example.com/tz2&quot;, &quot;TZURL:http://example.com/tz2\r\n&quot;),
-        )
-        for propname, propvalue, result in test_data:
-            prop = PyCalendarProperty(name=propname, value=propvalue)
-            self.assertEqual(str(prop), result)
-
-
-    def testGEOValueRoundtrip(self):
-
-        data = &quot;GEO:123.456,789.101&quot;
-        prop = PyCalendarProperty()
-        prop.parse(data)
-        self.assertEqual(str(prop), data + &quot;\r\n&quot;)
-
-
-    def testUnknownValueRoundtrip(self):
-
-        data = &quot;X-FOO:Text, not escaped&quot;
-        prop = PyCalendarProperty()
-        prop.parse(data)
-        self.assertEqual(str(prop), data + &quot;\r\n&quot;)
-
-        prop = PyCalendarProperty(&quot;X-FOO&quot;, &quot;Text, not escaped&quot;)
-        self.assertEqual(str(prop), data + &quot;\r\n&quot;)
-
-        data = &quot;X-FOO:Text\\, escaped\\n&quot;
-        prop = PyCalendarProperty()
-        prop.parse(data)
-        self.assertEqual(str(prop), data + &quot;\r\n&quot;)
-
-        prop = PyCalendarProperty(&quot;X-FOO&quot;, &quot;Text\\, escaped\\n&quot;)
-        self.assertEqual(str(prop), data + &quot;\r\n&quot;)
-
-
-    def testNewRegistrationValueRoundtrip(self):
-
-        PyCalendarProperty.registerDefaultValue(&quot;X-SPECIAL-REGISTRATION&quot;, PyCalendarValue.VALUETYPE_TEXT)
-
-        data = &quot;X-SPECIAL-REGISTRATION:Text\\, escaped\\n&quot;
-        prop = PyCalendarProperty()
-        prop.parse(data)
-        self.assertEqual(str(prop), &quot;X-SPECIAL-REGISTRATION:Text\\, escaped\\n\r\n&quot;)
-
-        prop = PyCalendarProperty(&quot;X-SPECIAL-REGISTRATION&quot;, &quot;Text, escaped\n&quot;)
-        self.assertEqual(str(prop), &quot;X-SPECIAL-REGISTRATION:Text\\, escaped\\n\r\n&quot;)
-
-
-    def testParameterEncodingDecoding(self):
-
-        prop = PyCalendarProperty(&quot;X-FOO&quot;, &quot;Test&quot;)
-        prop.addAttribute(PyCalendarAttribute(&quot;X-BAR&quot;, &quot;\&quot;Check\&quot;&quot;))
-        self.assertEqual(str(prop), &quot;X-FOO;X-BAR=^'Check^':Test\r\n&quot;)
-
-        prop.addAttribute(PyCalendarAttribute(&quot;X-BAR2&quot;, &quot;Check\nThis\tOut\n&quot;))
-        self.assertEqual(str(prop), &quot;X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test\r\n&quot;)
-
-        data = &quot;X-FOO;X-BAR=^'Check^':Test&quot;
-        prop = PyCalendarProperty()
-        prop.parse(data)
-        self.assertEqual(prop.getAttributeValue(&quot;X-BAR&quot;), &quot;\&quot;Check\&quot;&quot;)
-
-        data = &quot;X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test&quot;
-        prop = PyCalendarProperty()
-        prop.parse(data)
-        self.assertEqual(prop.getAttributeValue(&quot;X-BAR&quot;), &quot;\&quot;Check\&quot;&quot;)
-        self.assertEqual(prop.getAttributeValue(&quot;X-BAR2&quot;), &quot;Check\nThis\tOut\n&quot;)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_recurrencepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,161 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-2012 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 PyCalendarDateTime
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.recurrence import PyCalendarRecurrence
-import unittest
-
-class TestRecurrence(unittest.TestCase):
-
-    items = (
-        &quot;FREQ=DAILY&quot;,
-        &quot;FREQ=YEARLY;COUNT=400&quot;,
-        &quot;FREQ=MONTHLY;UNTIL=20110102&quot;,
-        &quot;FREQ=MONTHLY;UNTIL=20110102T090000&quot;,
-        &quot;FREQ=MONTHLY;UNTIL=20110102T100000Z&quot;,
-        &quot;FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=-1&quot;,
-
-        # These are from RFC5545 examples
-        &quot;FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1&quot;,
-        &quot;FREQ=YEARLY;UNTIL=19730429T070000Z;BYDAY=-1SU;BYMONTH=4&quot;,
-        &quot;FREQ=YEARLY;UNTIL=20060402T070000Z;BYDAY=1SU;BYMONTH=4&quot;,
-        &quot;FREQ=YEARLY;BYDAY=2SU;BYMONTH=3&quot;,
-        &quot;FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10&quot;,
-        &quot;FREQ=DAILY;INTERVAL=2&quot;,
-        &quot;FREQ=DAILY;COUNT=5;INTERVAL=10&quot;,
-        &quot;FREQ=DAILY;UNTIL=20000131T140000Z;BYMONTH=1&quot;,
-        &quot;FREQ=WEEKLY;INTERVAL=2;WKST=SU&quot;,
-        &quot;FREQ=WEEKLY;UNTIL=19971007T000000Z;BYDAY=TU,TH;WKST=SU&quot;,
-        &quot;FREQ=WEEKLY;COUNT=10;BYDAY=TU,TH;WKST=SU&quot;,
-        &quot;FREQ=WEEKLY;UNTIL=19971224T000000Z;INTERVAL=2;BYDAY=MO,WE,FR;WKST=SU&quot;,
-        &quot;FREQ=WEEKLY;COUNT=8;INTERVAL=2;BYDAY=TU,TH;WKST=SU&quot;,
-        &quot;FREQ=MONTHLY;BYMONTHDAY=-3&quot;,
-        &quot;FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1&quot;,
-        &quot;FREQ=MONTHLY;COUNT=10;INTERVAL=18;BYMONTHDAY=10,11,12,13,14,15&quot;,
-        &quot;FREQ=YEARLY;COUNT=10;INTERVAL=3;BYYEARDAY=1,100,200&quot;,
-        &quot;FREQ=YEARLY;BYDAY=MO;BYWEEKNO=20&quot;,
-        &quot;FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3&quot;,
-        &quot;FREQ=DAILY;BYMINUTE=0,20,40;BYHOUR=9,10,11,12,13,14,15,16&quot;,
-    )
-
-
-    def testParse(self):
-
-        for item in TestRecurrence.items:
-            recur = PyCalendarRecurrence()
-            recur.parse(item)
-            self.assertEqual(recur.getText(), item, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
-
-
-    def testParseInvalid(self):
-
-        items = (
-            &quot;&quot;,
-            &quot;FREQ=&quot;,
-            &quot;FREQ=MICROSECONDLY&quot;,
-            &quot;FREQ=YEARLY;COUNT=ABC&quot;,
-            &quot;FREQ=YEARLY;COUNT=123;UNTIL=20110102&quot;,
-            &quot;FREQ=MONTHLY;UNTIL=20110102T&quot;,
-            &quot;FREQ=MONTHLY;UNTIL=20110102t090000&quot;,
-            &quot;FREQ=MONTHLY;UNTIL=20110102T100000z&quot;,
-            &quot;FREQ=MONTHLY;UNTIL=20110102TAABBCCz&quot;,
-            &quot;FREQ=MONTHLY;BYDAY=A&quot;,
-            &quot;FREQ=MONTHLY;BYDAY=+1,3MO&quot;,
-            &quot;FREQ=MONTHLY;BYHOUR=A&quot;,
-            &quot;FREQ=MONTHLY;BYHOUR=54&quot;,
-        )
-
-        for item in items:
-            self.assertRaises(ValueError, PyCalendarRecurrence().parse, item)
-
-
-    def testEquality(self):
-
-        recur1 = PyCalendarRecurrence()
-        recur1.parse(&quot;FREQ=YEARLY;COUNT=400&quot;)
-        recur2 = PyCalendarRecurrence()
-        recur2.parse(&quot;COUNT=400;FREQ=YEARLY&quot;)
-
-        self.assertEqual(recur1, recur2)
-
-
-    def testInequality(self):
-
-        recur1 = PyCalendarRecurrence()
-        recur1.parse(&quot;FREQ=YEARLY;COUNT=400&quot;)
-        recur2 = PyCalendarRecurrence()
-        recur2.parse(&quot;COUNT=400;FREQ=YEARLY;BYMONTH=1&quot;)
-
-        self.assertNotEqual(recur1, recur2)
-
-
-    def testHash(self):
-
-        hashes = []
-        for item in TestRecurrence.items:
-            recur = PyCalendarRecurrence()
-            recur.parse(item)
-            hashes.append(hash(recur))
-        hashes.sort()
-        for i in range(1, len(hashes)):
-            self.assertNotEqual(hashes[i - 1], hashes[i])
-
-
-    def testByWeekNoExpand(self):
-
-        recur = PyCalendarRecurrence()
-        recur.parse(&quot;FREQ=YEARLY;BYWEEKNO=1,2&quot;)
-        start = PyCalendarDateTime(2013, 1, 1, 0, 0, 0)
-        end = PyCalendarDateTime(2017, 1, 1, 0, 0, 0)
-        items = []
-        range = PyCalendarPeriod(start, end)
-        recur.expand(start, range, items)
-        self.assertEqual(
-            items,
-            [
-                PyCalendarDateTime(2013, 1, 1, 0, 0, 0),
-                PyCalendarDateTime(2013, 1, 8, 0, 0, 0),
-                PyCalendarDateTime(2014, 1, 1, 0, 0, 0),
-                PyCalendarDateTime(2014, 1, 8, 0, 0, 0),
-                PyCalendarDateTime(2015, 1, 1, 0, 0, 0),
-                PyCalendarDateTime(2015, 1, 8, 0, 0, 0),
-                PyCalendarDateTime(2016, 1, 8, 0, 0, 0),
-                PyCalendarDateTime(2016, 1, 15, 0, 0, 0),
-            ],
-        )
-        print items
-
-
-    def testClearOnChange(self):
-
-        recur = PyCalendarRecurrence()
-        recur.parse(&quot;FREQ=DAILY&quot;)
-
-        start = PyCalendarDateTime(2013, 1, 1, 0, 0, 0)
-        end = PyCalendarDateTime(2017, 1, 1, 0, 0, 0)
-        range = PyCalendarPeriod(start, end)
-        items = []
-        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)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_requeststatuspy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_requeststatus.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_requeststatus.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_requeststatus.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,95 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-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.parser import ParserContext
-from pycalendar.property import PyCalendarProperty
-from pycalendar.requeststatusvalue import PyCalendarRequestStatusValue
-import unittest
-
-class TestRequestStatus(unittest.TestCase):
-
-    def testParseValue(self):
-
-        items = (
-            &quot;2.0;Success&quot;,
-            &quot;2.0;Success\;here&quot;,
-            &quot;2.0;Success;Extra&quot;,
-            &quot;2.0;Success\;here;Extra&quot;,
-            &quot;2.0;Success;Extra\;here&quot;,
-            &quot;2.0;Success\;here;Extra\;here too&quot;,
-        )
-
-        for item in items:
-            req = PyCalendarRequestStatusValue()
-            req.parse(item)
-            self.assertEqual(req.getText(), item, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
-
-
-    def testBadValue(self):
-
-        bad_value = &quot;2.0\;Success&quot;
-        ok_value = &quot;2.0;Success&quot;
-
-        # Fix the value
-        oldContext = ParserContext.INVALID_REQUEST_STATUS_VALUE
-        ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_FIX
-        req = PyCalendarRequestStatusValue()
-        req.parse(bad_value)
-        self.assertEqual(req.getText(), ok_value, &quot;Failed to parse and re-generate '%s'&quot; % (bad_value,))
-
-        # Raise the value
-        ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_RAISE
-        req = PyCalendarRequestStatusValue()
-        self.assertRaises(ValueError, req.parse, bad_value)
-
-        ParserContext.INVALID_REQUEST_STATUS_VALUE = oldContext
-
-
-    def testTruncatedValue(self):
-
-        bad_value = &quot;2.0&quot;
-        ok_value = &quot;2.0;&quot;
-
-        # Fix the value
-        oldContext = ParserContext.INVALID_REQUEST_STATUS_VALUE
-        ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_FIX
-        req = PyCalendarRequestStatusValue()
-        req.parse(bad_value)
-        self.assertEqual(req.getText(), ok_value, &quot;Failed to parse and re-generate '%s'&quot; % (bad_value,))
-
-        # Raise the value
-        ParserContext.INVALID_REQUEST_STATUS_VALUE = ParserContext.PARSER_RAISE
-        req = PyCalendarRequestStatusValue()
-        self.assertRaises(ValueError, req.parse, bad_value)
-
-        ParserContext.INVALID_REQUEST_STATUS_VALUE = oldContext
-
-
-    def testParseProperty(self):
-
-        items = (
-            &quot;REQUEST-STATUS:2.0;Success&quot;,
-            &quot;REQUEST-STATUS:2.0;Success\;here&quot;,
-            &quot;REQUEST-STATUS:2.0;Success;Extra&quot;,
-            &quot;REQUEST-STATUS:2.0;Success\;here;Extra&quot;,
-            &quot;REQUEST-STATUS:2.0;Success;Extra\;here&quot;,
-            &quot;REQUEST-STATUS:2.0;Success\;here;Extra\;here too&quot;,
-        )
-
-        for item in items:
-            req = PyCalendarProperty()
-            req.parse(item)
-            self.assertEqual(req.getText(), item + &quot;\r\n&quot;, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_timezonepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_timezone.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_timezone.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_timezone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,235 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
-import unittest
-
-class TestCalendar(unittest.TestCase):
-
-    def testOffsets(self):
-
-        data = (
-                    (&quot;&quot;&quot;BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-PRODID:-//calendarserver.org//Zonal//EN
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:America/New_York
-X-LIC-LOCATION:America/New_York
-BEGIN:STANDARD
-DTSTART:18831118T120358
-RDATE:18831118T120358
-TZNAME:EST
-TZOFFSETFROM:-045602
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19180331T020000
-RRULE:FREQ=YEARLY;UNTIL=19190330T070000Z;BYDAY=-1SU;BYMONTH=3
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:19181027T020000
-RRULE:FREQ=YEARLY;UNTIL=19191026T060000Z;BYDAY=-1SU;BYMONTH=10
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:STANDARD
-DTSTART:19200101T000000
-RDATE:19200101T000000
-RDATE:19420101T000000
-RDATE:19460101T000000
-RDATE:19670101T000000
-TZNAME:EST
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19200328T020000
-RDATE:19200328T020000
-RDATE:19740106T020000
-RDATE:19750223T020000
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:19201031T020000
-RDATE:19201031T020000
-RDATE:19450930T020000
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19210424T020000
-RRULE:FREQ=YEARLY;UNTIL=19410427T070000Z;BYDAY=-1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:19210925T020000
-RRULE:FREQ=YEARLY;UNTIL=19410928T060000Z;BYDAY=-1SU;BYMONTH=9
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19420209T020000
-RDATE:19420209T020000
-TZNAME:EWT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:DAYLIGHT
-DTSTART:19450814T190000
-RDATE:19450814T190000
-TZNAME:EPT
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:DAYLIGHT
-DTSTART:19460428T020000
-RRULE:FREQ=YEARLY;UNTIL=19660424T070000Z;BYDAY=-1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:19460929T020000
-RRULE:FREQ=YEARLY;UNTIL=19540926T060000Z;BYDAY=-1SU;BYMONTH=9
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:STANDARD
-DTSTART:19551030T020000
-RRULE:FREQ=YEARLY;UNTIL=19661030T060000Z;BYDAY=-1SU;BYMONTH=10
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19670430T020000
-RRULE:FREQ=YEARLY;UNTIL=19730429T070000Z;BYDAY=-1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:19671029T020000
-RRULE:FREQ=YEARLY;UNTIL=20061029T060000Z;BYDAY=-1SU;BYMONTH=10
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:19760425T020000
-RRULE:FREQ=YEARLY;UNTIL=19860427T070000Z;BYDAY=-1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:DAYLIGHT
-DTSTART:19870405T020000
-RRULE:FREQ=YEARLY;UNTIL=20060402T070000Z;BYDAY=1SU;BYMONTH=4
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:DAYLIGHT
-DTSTART:20070311T020000
-RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
-TZNAME:EDT
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:20071104T020000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
-TZNAME:EST
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-END:VTIMEZONE
-END:VCALENDAR
-&quot;&quot;&quot;,
-                (
-                    (PyCalendarDateTime(1942, 2, 8), -5),
-                    (PyCalendarDateTime(1942, 2, 10), -4),
-                    (PyCalendarDateTime(2011, 1, 1), -5),
-                    (PyCalendarDateTime(2011, 4, 1), -4),
-                    (PyCalendarDateTime(2011, 10, 24), -4),
-                    (PyCalendarDateTime(2011, 11, 8), -5),
-                    (PyCalendarDateTime(2006, 1, 1), -5),
-                    (PyCalendarDateTime(2006, 4, 1), -5),
-                    (PyCalendarDateTime(2006, 5, 1), -4),
-                    (PyCalendarDateTime(2006, 10, 1), -4),
-                    (PyCalendarDateTime(2006, 10, 24), -4),
-                    (PyCalendarDateTime(2006, 11, 8), -5),
-                )
-            ),
-                    (&quot;&quot;&quot;BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-PRODID:-//calendarserver.org//Zonal//EN
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:Etc/GMT+8
-X-LIC-LOCATION:Etc/GMT+8
-BEGIN:STANDARD
-DTSTART:18000101T000000
-RDATE:18000101T000000
-TZNAME:GMT+8
-TZOFFSETFROM:-0800
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-END:VCALENDAR
-&quot;&quot;&quot;,
-                (
-                    (PyCalendarDateTime(1942, 2, 8), -8),
-                    (PyCalendarDateTime(1942, 2, 10), -8),
-                    (PyCalendarDateTime(2011, 1, 1), -8),
-                    (PyCalendarDateTime(2011, 4, 1), -8),
-                )
-            ),
-        )
-
-        for tzdata, offsets in data:
-
-            cal = PyCalendar.parseText(tzdata.replace(&quot;\n&quot;, &quot;\r\n&quot;))
-            tz = cal.getComponents()[0]
-
-            for dt, offset in offsets:
-                tzoffset = tz.getTimezoneOffsetSeconds(dt)
-                self.assertEqual(tzoffset, offset * 60 * 60, &quot;Failed to match offset for %s at %s with caching&quot; % (tz.getID(), dt,))
-            for dt, offset in reversed(offsets):
-                tzoffset = tz.getTimezoneOffsetSeconds(dt)
-                self.assertEqual(tzoffset, offset * 60 * 60, &quot;Failed to match offset for %s at %s with caching, reversed&quot; % (tz.getID(), dt,))
-
-            for dt, offset in offsets:
-                tz.mCachedExpandAllMax = None
-                tzoffset = tz.getTimezoneOffsetSeconds(dt)
-                self.assertEqual(tzoffset, offset * 60 * 60, &quot;Failed to match offset for %s at %s without caching&quot; % (tz.getID(), dt,))
-            for dt, offset in reversed(offsets):
-                tz.mCachedExpandAllMax = None
-                tzoffset = tz.getTimezoneOffsetSeconds(dt)
-                self.assertEqual(tzoffset, offset * 60 * 60, &quot;Failed to match offset for %s at %s without caching, reversed&quot; % (tz.getID(), dt,))
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_urivaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_urivalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_urivalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_urivalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2012-2013 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">@@ -15,11 +15,11 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> from pycalendar.parser import ParserContext
</span><del>-from pycalendar.urivalue import PyCalendarURIValue
-from pycalendar.vcard.property import Property
</del><ins>+from pycalendar.urivalue import URIValue
+from pycalendar.icalendar.property import Property
</ins><span class="cx"> import unittest
</span><span class="cx"> 
</span><del>-class TestNValue(unittest.TestCase):
</del><ins>+class TestURIValue(unittest.TestCase):
</ins><span class="cx"> 
</span><span class="cx">     def testParseValue(self):
</span><span class="cx"> 
</span><span class="lines">@@ -35,8 +35,8 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for item, result in items:
</span><del>-            req = PyCalendarURIValue()
-            req.parse(item)
</del><ins>+            req = URIValue()
+            req.parse(item, &quot;icalendar&quot;)
</ins><span class="cx">             test = req.getText()
</span><span class="cx">             self.assertEqual(test, result, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</span><span class="cx"> 
</span><span class="lines">@@ -48,8 +48,8 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for item, result in items:
</span><del>-            req = PyCalendarURIValue()
-            req.parse(item)
</del><ins>+            req = URIValue()
+            req.parse(item, &quot;icalendar&quot;)
</ins><span class="cx">             test = req.getText()
</span><span class="cx">             self.assertEqual(test, result, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</span><span class="cx"> 
</span><span class="lines">@@ -68,8 +68,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for item, result in items:
</span><del>-            prop = Property()
-            prop.parse(item)
</del><ins>+            prop = Property.parseText(item)
</ins><span class="cx">             test = prop.getText()
</span><span class="cx">             self.assertEqual(test, result + &quot;\r\n&quot;, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</span><span class="cx"> 
</span><span class="lines">@@ -81,7 +80,6 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for item, result in items:
</span><del>-            prop = Property()
-            prop.parse(item)
</del><ins>+            prop = Property.parseText(item)
</ins><span class="cx">             test = prop.getText()
</span><span class="cx">             self.assertEqual(test, result + &quot;\r\n&quot;, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_utilspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_utils.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_utils.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_utils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2012-2013 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></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_validationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/tests/test_validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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">@@ -14,7 +14,7 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.property import PyCalendarProperty
</del><ins>+from pycalendar.icalendar.property import Property
</ins><span class="cx"> from pycalendar.validation import partial, PropertyValueChecks
</span><span class="cx"> import unittest
</span><span class="cx"> 
</span><span class="lines">@@ -40,8 +40,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for prop, test, result in props:
</span><del>-            property = PyCalendarProperty()
-            property.parse(prop)
</del><ins>+            property = Property.parseText(prop)
</ins><span class="cx">             self.assertEqual(PropertyValueChecks.stringValue(test, property), result)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -55,8 +54,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for prop, result in props:
</span><del>-            property = PyCalendarProperty()
-            property.parse(prop)
</del><ins>+            property = Property.parseText(prop)
</ins><span class="cx">             self.assertEqual(PropertyValueChecks.alwaysUTC(property), result)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -72,8 +70,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for prop, low, high, result in props:
</span><del>-            property = PyCalendarProperty()
-            property.parse(prop)
</del><ins>+            property = Property.parseText(prop)
</ins><span class="cx">             self.assertEqual(PropertyValueChecks.numericRange(low, high, property), result)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -87,6 +84,5 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for prop, result in props:
</span><del>-            property = PyCalendarProperty()
-            property.parse(prop)
</del><ins>+            property = Property.parseText(prop)
</ins><span class="cx">             self.assertEqual(PropertyValueChecks.positiveIntegerOrZero(property), result)
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarteststest_xmlpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/tests/test_xml.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/tests/test_xml.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/tests/test_xml.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,104 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.calendar import PyCalendar
-import cStringIO as StringIO
-import difflib
-import unittest
-
-class TestCalendar(unittest.TestCase):
-
-    data = (
-                (
-&quot;&quot;&quot;BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//mulberrymail.com//Mulberry v4.0//EN
-BEGIN:VEVENT
-UID:12345-67890-3
-DTSTART:20071114T000000Z
-ATTENDEE:mailto:user2@example.com
-EXDATE:20081114T000000Z
-ORGANIZER:mailto:user1@example.com
-RRULE:FREQ=YEARLY
-END:VEVENT
-X-TEST:Testing
-END:VCALENDAR
-&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;),
-
-&quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
-&lt;ns0:icalendar xmlns:ns0=&quot;urn:ietf:params:xml:ns:icalendar-2.0&quot;&gt;
-  &lt;ns0:vcalendar&gt;
-    &lt;ns0:properties&gt;
-      &lt;ns0:version&gt;
-        &lt;ns0:text&gt;2.0&lt;/ns0:text&gt;
-      &lt;/ns0:version&gt;
-      &lt;ns0:prodid&gt;
-        &lt;ns0:text&gt;-//mulberrymail.com//Mulberry v4.0//EN&lt;/ns0:text&gt;
-      &lt;/ns0:prodid&gt;
-      &lt;ns0:x-test&gt;
-        &lt;ns0:unknown&gt;Testing&lt;/ns0:unknown&gt;
-      &lt;/ns0:x-test&gt;
-    &lt;/ns0:properties&gt;
-    &lt;ns0:components&gt;
-      &lt;ns0:vevent&gt;
-        &lt;ns0:properties&gt;
-          &lt;ns0:uid&gt;
-            &lt;ns0:text&gt;12345-67890-3&lt;/ns0:text&gt;
-          &lt;/ns0:uid&gt;
-          &lt;ns0:dtstart&gt;
-            &lt;ns0:date-time&gt;2007-11-14T00:00:00Z&lt;/ns0:date-time&gt;
-          &lt;/ns0:dtstart&gt;
-          &lt;ns0:attendee&gt;
-            &lt;ns0:cal-address&gt;mailto:user2@example.com&lt;/ns0:cal-address&gt;
-          &lt;/ns0:attendee&gt;
-          &lt;ns0:exdate&gt;
-            &lt;ns0:date-time&gt;2008-11-14T00:00:00Z&lt;/ns0:date-time&gt;
-          &lt;/ns0:exdate&gt;
-          &lt;ns0:organizer&gt;
-            &lt;ns0:cal-address&gt;mailto:user1@example.com&lt;/ns0:cal-address&gt;
-          &lt;/ns0:organizer&gt;
-          &lt;ns0:rrule&gt;
-            &lt;ns0:recur&gt;
-              &lt;ns0:freq&gt;YEARLY&lt;/ns0:freq&gt;
-            &lt;/ns0:recur&gt;
-          &lt;/ns0:rrule&gt;
-        &lt;/ns0:properties&gt;
-      &lt;/ns0:vevent&gt;
-    &lt;/ns0:components&gt;
-  &lt;/ns0:vcalendar&gt;
-&lt;/ns0:icalendar&gt;
-&quot;&quot;&quot;,
-                ),
-)
-
-    def testGenerateXML(self):
-
-        def _doRoundtrip(caldata, resultdata=None):
-            test1 = resultdata if resultdata is not None else caldata
-
-            cal = PyCalendar()
-            cal.parse(StringIO.StringIO(caldata))
-
-            test2 = cal.getTextXML()
-
-            self.assertEqual(
-                test1,
-                test2,
-                &quot;\n&quot;.join(difflib.unified_diff(str(test1).splitlines(), test2.splitlines()))
-            )
-
-        for item1, item2 in self.data:
-            _doRoundtrip(item1, item2)
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendartextvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/textvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/textvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/textvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -16,17 +16,17 @@
</span><span class="cx"> 
</span><span class="cx"> # iCalendar UTC Offset value
</span><span class="cx"> 
</span><del>-from pycalendar import utils, xmldefs
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import utils, xmldefinitions
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.value import Value
</ins><span class="cx"> 
</span><del>-class PyCalendarTextValue(PyCalendarPlainTextValue):
</del><ins>+class TextValue(PlainTextValue):
</ins><span class="cx"> 
</span><span class="cx">     def getType(self):
</span><del>-        return PyCalendarValue.VALUETYPE_TEXT
</del><ins>+        return Value.VALUETYPE_TEXT
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def parse(self, data):
</del><ins>+    def parse(self, data, variant):
</ins><span class="cx">         # Decoding required
</span><span class="cx">         self.mValue = utils.decodeTextValue(data)
</span><span class="cx"> 
</span><span class="lines">@@ -39,4 +39,4 @@
</span><span class="cx">         except:
</span><span class="cx">             pass
</span><span class="cx"> 
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_TEXT, PyCalendarTextValue, xmldefs.value_text)
</del><ins>+Value.registerType(Value.VALUETYPE_TEXT, TextValue, xmldefinitions.value_text)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendartimezonepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/timezone.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/timezone.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/timezone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -15,9 +15,9 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> from pycalendar import stringutils
</span><del>-from pycalendar.timezonedb import PyCalendarTimezoneDatabase
</del><ins>+from pycalendar.timezonedb import TimezoneDatabase
</ins><span class="cx"> 
</span><del>-class PyCalendarTimezone(object):
</del><ins>+class Timezone(object):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Wrapper around a timezone specification. There are three options:
</span><span class="cx"> 
</span><span class="lines">@@ -41,13 +41,13 @@
</span><span class="cx">             self.mTimezone = None
</span><span class="cx"> 
</span><span class="cx">             # Copy default timezone if it exists
</span><del>-            if PyCalendarTimezone.sDefaultTimezone is not None:
-                self.mUTC = PyCalendarTimezone.sDefaultTimezone.mUTC
-                self.mTimezone = PyCalendarTimezone.sDefaultTimezone.mTimezone
</del><ins>+            if Timezone.sDefaultTimezone is not None:
+                self.mUTC = Timezone.sDefaultTimezone.mUTC
+                self.mTimezone = Timezone.sDefaultTimezone.mTimezone
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def duplicate(self):
</span><del>-        return PyCalendarTimezone(self.mUTC, self.mTimezone)
</del><ins>+        return Timezone(self.mUTC, self.mTimezone)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def equals(self, comp):
</span><span class="lines">@@ -63,7 +63,7 @@
</span><span class="cx">     @staticmethod
</span><span class="cx">     def same(utc1, tzid1, utc2, tzid2):
</span><span class="cx">         # Always match if any one of them is 'floating'
</span><del>-        if PyCalendarTimezone.is_float(utc1, tzid1) or PyCalendarTimezone.is_float(utc2, tzid2):
</del><ins>+        if Timezone.is_float(utc1, tzid1) or Timezone.is_float(utc2, tzid2):
</ins><span class="cx">             return True
</span><span class="cx">         elif utc1 != utc2:
</span><span class="cx">             return False
</span><span class="lines">@@ -104,19 +104,19 @@
</span><span class="cx">         if self.mUTC:
</span><span class="cx">             return 0
</span><span class="cx">         elif self.mTimezone is None:
</span><del>-            return PyCalendarTimezoneDatabase.getTimezoneOffsetSeconds(PyCalendarTimezone.sDefaultTimezone.getTimezoneID(), dt)
</del><ins>+            return TimezoneDatabase.getTimezoneOffsetSeconds(Timezone.sDefaultTimezone.getTimezoneID(), dt)
</ins><span class="cx">         elif isinstance(self.mTimezone, int):
</span><span class="cx">             return self.mTimezone
</span><span class="cx">         else:
</span><span class="cx">             # Look up timezone and resolve date using default timezones
</span><del>-            return PyCalendarTimezoneDatabase.getTimezoneOffsetSeconds(self.mTimezone, dt)
</del><ins>+            return TimezoneDatabase.getTimezoneOffsetSeconds(self.mTimezone, dt)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def timeZoneDescriptor(self, dt):
</span><span class="cx">         if self.mUTC:
</span><span class="cx">             return &quot;(UTC)&quot;
</span><span class="cx">         elif self.mTimezone is None:
</span><del>-            return PyCalendarTimezoneDatabase.getTimezoneDescriptor(PyCalendarTimezone.sDefaultTimezone.getTimezoneID(), dt)
</del><ins>+            return TimezoneDatabase.getTimezoneDescriptor(Timezone.sDefaultTimezone.getTimezoneID(), dt)
</ins><span class="cx">         elif isinstance(self.mTimezone, int):
</span><span class="cx">             sign = &quot;-&quot; if self.mTimezone &lt; 0 else &quot;+&quot;
</span><span class="cx">             hours = abs(self.mTimezone) / 3600
</span><span class="lines">@@ -124,6 +124,6 @@
</span><span class="cx">             return &quot;%s%02d%02d&quot; % (sign, hours, minutes,)
</span><span class="cx">         else:
</span><span class="cx">             # Look up timezone and resolve date using default timezones
</span><del>-            return PyCalendarTimezoneDatabase.getTimezoneDescriptor(self.mTimezone, dt)
</del><ins>+            return TimezoneDatabase.getTimezoneDescriptor(self.mTimezone, dt)
</ins><span class="cx"> 
</span><del>-PyCalendarTimezone.sDefaultTimezone = PyCalendarTimezone()
</del><ins>+Timezone.sDefaultTimezone = Timezone()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendartimezonedbpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/timezonedb.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/timezonedb.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/timezonedb.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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">@@ -14,11 +14,11 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.exceptions import PyCalendarNoTimezoneInDatabase, \
-    PyCalendarInvalidData
</del><ins>+from pycalendar.exceptions import NoTimezoneInDatabase, \
+    InvalidData
</ins><span class="cx"> import os
</span><span class="cx"> 
</span><del>-class PyCalendarTimezoneDatabase(object):
</del><ins>+class TimezoneDatabase(object):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     On demand timezone database cache. This scans a TZdb directory for .ics files matching a
</span><span class="cx">     TZID and caches the component data in a calendar from whence the actual component is returned.
</span><span class="lines">@@ -29,20 +29,20 @@
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="cx">     def createTimezoneDatabase(dbpath):
</span><del>-        PyCalendarTimezoneDatabase.sTimezoneDatabase = PyCalendarTimezoneDatabase()
-        PyCalendarTimezoneDatabase.sTimezoneDatabase.setPath(dbpath)
</del><ins>+        TimezoneDatabase.sTimezoneDatabase = TimezoneDatabase()
+        TimezoneDatabase.sTimezoneDatabase.setPath(dbpath)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="cx">     def clearTimezoneDatabase():
</span><del>-        if PyCalendarTimezoneDatabase.sTimezoneDatabase is not None:
-            PyCalendarTimezoneDatabase.sTimezoneDatabase.clear()
</del><ins>+        if TimezoneDatabase.sTimezoneDatabase is not None:
+            TimezoneDatabase.sTimezoneDatabase.clear()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __init__(self):
</span><del>-        from pycalendar.calendar import PyCalendar
</del><ins>+        from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx">         self.dbpath = None
</span><del>-        self.calendar = PyCalendar()
</del><ins>+        self.calendar = Calendar()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def setPath(self, dbpath):
</span><span class="lines">@@ -50,27 +50,27 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def clear(self):
</span><del>-        from pycalendar.calendar import PyCalendar
-        self.calendar = PyCalendar()
</del><ins>+        from pycalendar.icalendar.calendar import Calendar
+        self.calendar = Calendar()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="cx">     def getTimezoneDatabase():
</span><del>-        if PyCalendarTimezoneDatabase.sTimezoneDatabase is None:
-            PyCalendarTimezoneDatabase.sTimezoneDatabase = PyCalendarTimezoneDatabase()
-        return PyCalendarTimezoneDatabase.sTimezoneDatabase
</del><ins>+        if TimezoneDatabase.sTimezoneDatabase is None:
+            TimezoneDatabase.sTimezoneDatabase = TimezoneDatabase()
+        return TimezoneDatabase.sTimezoneDatabase
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="cx">     def getTimezone(tzid):
</span><span class="cx"> 
</span><span class="cx">         # Check whether current cached
</span><del>-        tzdb = PyCalendarTimezoneDatabase.getTimezoneDatabase()
</del><ins>+        tzdb = TimezoneDatabase.getTimezoneDatabase()
</ins><span class="cx">         tz = tzdb.calendar.getTimezone(tzid)
</span><span class="cx">         if tz is None:
</span><span class="cx">             try:
</span><span class="cx">                 tzdb.cacheTimezone(tzid)
</span><del>-            except PyCalendarNoTimezoneInDatabase:
</del><ins>+            except NoTimezoneInDatabase:
</ins><span class="cx">                 pass
</span><span class="cx">             tz = tzdb.calendar.getTimezone(tzid)
</span><span class="cx"> 
</span><span class="lines">@@ -83,10 +83,10 @@
</span><span class="cx">         Return a VTIMEZONE inside a valid VCALENDAR
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        tz = PyCalendarTimezoneDatabase.getTimezone(tzid)
</del><ins>+        tz = TimezoneDatabase.getTimezone(tzid)
</ins><span class="cx">         if tz is not None:
</span><del>-            from pycalendar.calendar import PyCalendar
-            cal = PyCalendar()
</del><ins>+            from pycalendar.icalendar.calendar import Calendar
+            cal = Calendar()
</ins><span class="cx">             cal.addComponent(tz.duplicate(cal))
</span><span class="cx">             return cal
</span><span class="cx">         else:
</span><span class="lines">@@ -96,7 +96,7 @@
</span><span class="cx">     @staticmethod
</span><span class="cx">     def getTimezoneOffsetSeconds(tzid, dt):
</span><span class="cx">         # Cache it first
</span><del>-        tz = PyCalendarTimezoneDatabase.getTimezone(tzid)
</del><ins>+        tz = TimezoneDatabase.getTimezone(tzid)
</ins><span class="cx">         if tz is not None:
</span><span class="cx">             return tz.getTimezoneOffsetSeconds(dt)
</span><span class="cx">         else:
</span><span class="lines">@@ -106,7 +106,7 @@
</span><span class="cx">     @staticmethod
</span><span class="cx">     def getTimezoneDescriptor(tzid, dt):
</span><span class="cx">         # Cache it first
</span><del>-        tz = PyCalendarTimezoneDatabase.getTimezone(tzid)
</del><ins>+        tz = TimezoneDatabase.getTimezone(tzid)
</ins><span class="cx">         if tz is not None:
</span><span class="cx">             return tz.getTimezoneDescriptor(dt)
</span><span class="cx">         else:
</span><span class="lines">@@ -123,10 +123,10 @@
</span><span class="cx">         if tzpath.startswith(self.dbpath) and os.path.isfile(tzpath):
</span><span class="cx">             try:
</span><span class="cx">                 self.calendar.parseComponent(open(tzpath))
</span><del>-            except (IOError, PyCalendarInvalidData):
-                raise PyCalendarNoTimezoneInDatabase(self.dbpath, tzid)
</del><ins>+            except (IOError, InvalidData):
+                raise NoTimezoneInDatabase(self.dbpath, tzid)
</ins><span class="cx">         else:
</span><del>-            raise PyCalendarNoTimezoneInDatabase(self.dbpath, tzid)
</del><ins>+            raise NoTimezoneInDatabase(self.dbpath, tzid)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def addTimezone(self, tz):
</span><span class="lines">@@ -140,7 +140,7 @@
</span><span class="cx">         Merge each timezone from other calendar.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        tzdb = PyCalendarTimezoneDatabase.getTimezoneDatabase()
</del><ins>+        tzdb = TimezoneDatabase.getTimezoneDatabase()
</ins><span class="cx"> 
</span><span class="cx">         # Not if our own calendar
</span><span class="cx">         if cal is tzdb.calendar:
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarunknownvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/unknownvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/unknownvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/unknownvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -16,13 +16,13 @@
</span><span class="cx"> 
</span><span class="cx"> # iCalendar Unknown value - one whose default type we don't know about
</span><span class="cx"> 
</span><del>-from pycalendar import xmldefs
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.value import Value
</ins><span class="cx"> 
</span><del>-class PyCalendarUnknownValue(PyCalendarPlainTextValue):
</del><ins>+class UnknownValue(PlainTextValue):
</ins><span class="cx"> 
</span><span class="cx">     def getType(self):
</span><del>-        return PyCalendarUnknownValue.VALUETYPE_UNKNOWN
</del><ins>+        return UnknownValue.VALUETYPE_UNKNOWN
</ins><span class="cx"> 
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_UNKNOWN, PyCalendarUnknownValue, xmldefs.value_unknown)
</del><ins>+Value.registerType(Value.VALUETYPE_UNKNOWN, UnknownValue, xmldefinitions.value_unknown)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarurivaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/urivalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/urivalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/urivalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -16,18 +16,18 @@
</span><span class="cx"> 
</span><span class="cx"> # iCalendar URI value
</span><span class="cx"> 
</span><del>-from pycalendar import xmldefs, utils
-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions, utils
+from pycalendar.plaintextvalue import PlainTextValue
+from pycalendar.value import Value
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> 
</span><del>-class PyCalendarURIValue(PyCalendarPlainTextValue):
</del><ins>+class URIValue(PlainTextValue):
</ins><span class="cx"> 
</span><span class="cx">     def getType(self):
</span><del>-        return PyCalendarURIValue.VALUETYPE_URI
</del><ins>+        return URIValue.VALUETYPE_URI
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def parse(self, data):
</del><ins>+    def parse(self, data, variant):
</ins><span class="cx"> 
</span><span class="cx">         if ParserContext.BACKSLASH_IN_URI_VALUE == ParserContext.PARSER_FIX:
</span><span class="cx">             # Decoding required
</span><span class="lines">@@ -50,6 +50,6 @@
</span><span class="cx">             except:
</span><span class="cx">                 pass
</span><span class="cx">         else:
</span><del>-            super(PyCalendarURIValue, self).generate(os)
</del><ins>+            super(URIValue, self).generate(os)
</ins><span class="cx"> 
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_URI, PyCalendarURIValue, xmldefs.value_uri)
</del><ins>+Value.registerType(Value.VALUETYPE_URI, URIValue, xmldefinitions.value_uri)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarutcoffsetvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/utcoffsetvalue.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/utcoffsetvalue.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/utcoffsetvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -17,27 +17,30 @@
</span><span class="cx"> # iCalendar UTC Offset value
</span><span class="cx"> 
</span><span class="cx"> from cStringIO import StringIO
</span><del>-from pycalendar import xmldefs
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar import xmldefinitions
+from pycalendar.value import Value
</ins><span class="cx"> 
</span><del>-class PyCalendarUTCOffsetValue(PyCalendarValue):
</del><ins>+class UTCOffsetValue(Value):
</ins><span class="cx"> 
</span><span class="cx">     def __init__(self, value=0):
</span><span class="cx">         self.mValue = value
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def duplicate(self):
</span><del>-        return PyCalendarUTCOffsetValue(self.mValue)
</del><ins>+        return UTCOffsetValue(self.mValue)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getType(self):
</span><del>-        return PyCalendarValue.VALUETYPE_UTC_OFFSET
</del><ins>+        return Value.VALUETYPE_UTC_OFFSET
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def parse(self, data):
</del><ins>+    def parse(self, data, variant):
+
+        fullISO = (variant == &quot;vcard&quot;)
+
</ins><span class="cx">         # Must be of specific lengths
</span><span class="cx">         datalen = len(data)
</span><del>-        if datalen not in (5, 7):
</del><ins>+        if datalen not in ((6, 9,) if fullISO else (5, 7,)):
</ins><span class="cx">             self.mValue = 0
</span><span class="cx">             raise ValueError
</span><span class="cx"> 
</span><span class="lines">@@ -50,12 +53,14 @@
</span><span class="cx">         hours = int(data[1:3])
</span><span class="cx"> 
</span><span class="cx">         # Get minutes
</span><del>-        mins = int(data[3:5])
</del><ins>+        index = 4 if fullISO else 3
+        mins = int(data[index:index + 2])
</ins><span class="cx"> 
</span><span class="cx">         # Get seconds if present
</span><span class="cx">         secs = 0
</span><del>-        if datalen == 7 :
-            secs = int(data[5:])
</del><ins>+        if datalen &gt; 6:
+            index = 7 if fullISO else 5
+            secs = int(data[index:])
</ins><span class="cx"> 
</span><span class="cx">         self.mValue = ((hours * 60) + mins) * 60 + secs
</span><span class="cx">         if not plus:
</span><span class="lines">@@ -63,36 +68,31 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     # os - StringIO object
</span><del>-    def generate(self, os):
</del><ins>+    def generate(self, os, fullISO=False):
</ins><span class="cx">         try:
</span><span class="cx">             abs_value = self.mValue
</span><del>-            if self.mValue &lt; 0 :
-                os.write(&quot;-&quot;)
</del><ins>+            if abs_value &lt; 0 :
+                sign = &quot;-&quot;
</ins><span class="cx">                 abs_value = -self.mValue
</span><span class="cx">             else:
</span><del>-                os.write(&quot;+&quot;)
</del><ins>+                sign = &quot;+&quot;
</ins><span class="cx"> 
</span><span class="cx">             secs = abs_value % 60
</span><span class="cx">             mins = (abs_value / 60) % 60
</span><span class="cx">             hours = abs_value / (60 * 60)
</span><span class="cx"> 
</span><del>-            if (hours &lt; 10):
-                os.write(&quot;0&quot;)
-            os.write(str(hours))
-            if (mins &lt; 10):
-                os.write(&quot;0&quot;)
-            os.write(str(mins))
</del><ins>+            s = (&quot;%s%02d:%02d&quot; if fullISO else &quot;%s%02d%02d&quot;) % (sign, hours, mins,)
</ins><span class="cx">             if (secs != 0):
</span><del>-                if (secs &lt; 10):
-                    os.write(&quot;0&quot;)
-                os.write(str(secs))
</del><ins>+                s = (&quot;%s:%02d&quot; if fullISO else &quot;%s%02d&quot;) % (s, secs,)
+
+            os.write(s)
</ins><span class="cx">         except:
</span><span class="cx">             pass
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def writeXML(self, node, namespace):
</span><span class="cx"> 
</span><del>-        os = StringIO.StringIO()
</del><ins>+        os = StringIO()
</ins><span class="cx">         self.generate(os)
</span><span class="cx">         text = os.getvalue()
</span><span class="cx">         text = text[:-2] + &quot;:&quot; + text[-2:]
</span><span class="lines">@@ -101,6 +101,18 @@
</span><span class="cx">         value.text = text
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def parseJSONValue(self, jobject):
+        self.parse(str(jobject), variant=&quot;vcard&quot;)
+
+
+    def writeJSONValue(self, jobject):
+
+        os = StringIO()
+        self.generate(os, fullISO=True)
+        text = os.getvalue()
+        jobject.append(text)
+
+
</ins><span class="cx">     def getValue(self):
</span><span class="cx">         return self.mValue
</span><span class="cx"> 
</span><span class="lines">@@ -108,4 +120,4 @@
</span><span class="cx">     def setValue(self, value):
</span><span class="cx">         self.mValue = value
</span><span class="cx"> 
</span><del>-PyCalendarValue.registerType(PyCalendarValue.VALUETYPE_UTC_OFFSET, PyCalendarUTCOffsetValue, xmldefs.value_utc_offset)
</del><ins>+Value.registerType(Value.VALUETYPE_UTC_OFFSET, UTCOffsetValue, xmldefinitions.value_utc_offset)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarutilspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/utils.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/utils.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/utils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -438,17 +438,17 @@
</span><span class="cx"> 
</span><span class="cx"> # Display elements
</span><span class="cx"> def getMonthTable(month, year, weekstart, table, today_index):
</span><del>-    from pycalendar.datetime import PyCalendarDateTime
</del><ins>+    from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx">     # Get today
</span><del>-    today = PyCalendarDateTime.getToday(None)
</del><ins>+    today = DateTime.getToday(None)
</ins><span class="cx">     today_index = [-1, -1]
</span><span class="cx"> 
</span><span class="cx">     # Start with empty table
</span><span class="cx">     table = []
</span><span class="cx"> 
</span><span class="cx">     # Determine first weekday in month
</span><del>-    temp = PyCalendarDateTime(year, month, 1, 0)
</del><ins>+    temp = DateTime(year, month, 1, 0)
</ins><span class="cx">     row = -1
</span><span class="cx">     initial_col = temp.getDayOfWeek() - weekstart
</span><span class="cx">     if initial_col &lt; 0:
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvalarmpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/valarm.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/valarm.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/valarm.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,705 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.component import PyCalendarComponent
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.property import PyCalendarProperty
-from pycalendar.value import PyCalendarValue
-
-class PyCalendarVAlarm(PyCalendarComponent):
-
-    sActionMap = {
-        definitions.cICalProperty_ACTION_AUDIO: definitions.eAction_VAlarm_Audio,
-        definitions.cICalProperty_ACTION_DISPLAY: definitions.eAction_VAlarm_Display,
-        definitions.cICalProperty_ACTION_EMAIL: definitions.eAction_VAlarm_Email,
-        definitions.cICalProperty_ACTION_PROCEDURE: definitions.eAction_VAlarm_Procedure,
-        definitions.cICalProperty_ACTION_URI: definitions.eAction_VAlarm_URI,
-        definitions.cICalProperty_ACTION_NONE: definitions.eAction_VAlarm_None,
-    }
-
-    sActionValueMap = {
-        definitions.eAction_VAlarm_Audio: definitions.cICalProperty_ACTION_AUDIO,
-        definitions.eAction_VAlarm_Display: definitions.cICalProperty_ACTION_DISPLAY,
-        definitions.eAction_VAlarm_Email: definitions.cICalProperty_ACTION_EMAIL,
-        definitions.eAction_VAlarm_Procedure: definitions.cICalProperty_ACTION_PROCEDURE,
-        definitions.eAction_VAlarm_URI: definitions.cICalProperty_ACTION_URI,
-        definitions.eAction_VAlarm_None: definitions.cICalProperty_ACTION_NONE,
-    }
-
-    # Classes for each action encapsulating action-specific data
-    class PyCalendarVAlarmAction(object):
-
-        propertyCardinality_1 = ()
-        propertyCardinality_1_Fix_Empty = ()
-        propertyCardinality_0_1 = ()
-        propertyCardinality_1_More = ()
-
-        def __init__(self, type):
-            self.mType = type
-
-        def duplicate(self):
-            return PyCalendarVAlarm.PyCalendarVAlarmAction(self.mType)
-
-        def load(self, valarm):
-            pass
-
-        def add(self, valarm):
-            pass
-
-        def remove(self, valarm):
-            pass
-
-        def getType(self):
-            return self.mType
-
-
-    class PyCalendarVAlarmAudio(PyCalendarVAlarmAction):
-
-        propertyCardinality_1 = (
-            definitions.cICalProperty_ACTION,
-            definitions.cICalProperty_TRIGGER,
-        )
-
-        propertyCardinality_0_1 = (
-            definitions.cICalProperty_DURATION,
-            definitions.cICalProperty_REPEAT,
-            definitions.cICalProperty_ATTACH,
-            definitions.cICalProperty_ACKNOWLEDGED,
-        )
-
-        def __init__(self, speak=None):
-            super(PyCalendarVAlarm.PyCalendarVAlarmAudio, self).__init__(type=definitions.eAction_VAlarm_Audio)
-            self.mSpeakText = speak
-
-        def duplicate(self):
-            return PyCalendarVAlarm.PyCalendarVAlarmAudio(self.mSpeakText)
-
-        def load(self, valarm):
-            # Get properties
-            self.mSpeakText = valarm.loadValueString(definitions.cICalProperty_ACTION_X_SPEAKTEXT)
-
-        def add(self, valarm):
-            # Delete existing then add
-            self.remove(valarm)
-
-            prop = PyCalendarProperty(definitions.cICalProperty_ACTION_X_SPEAKTEXT, self.mSpeakText)
-            valarm.addProperty(prop)
-
-        def remove(self, valarm):
-            valarm.removeProperties(definitions.cICalProperty_ACTION_X_SPEAKTEXT)
-
-        def isSpeakText(self):
-            return len(self.mSpeakText) != 0
-
-        def getSpeakText(self):
-            return self.mSpeakText
-
-
-    class PyCalendarVAlarmDisplay(PyCalendarVAlarmAction):
-
-        propertyCardinality_1 = (
-            definitions.cICalProperty_ACTION,
-            definitions.cICalProperty_TRIGGER,
-        )
-
-        propertyCardinality_1_Fix_Empty = (
-            definitions.cICalProperty_DESCRIPTION,
-        )
-
-        propertyCardinality_0_1 = (
-            definitions.cICalProperty_DURATION,
-            definitions.cICalProperty_REPEAT,
-            definitions.cICalProperty_ACKNOWLEDGED,
-        )
-
-        def __init__(self, description=None):
-            super(PyCalendarVAlarm.PyCalendarVAlarmDisplay, self).__init__(type=definitions.eAction_VAlarm_Display)
-            self.mDescription = description
-
-        def duplicate(self):
-            return PyCalendarVAlarm.PyCalendarVAlarmDisplay(self.mDescription)
-
-        def load(self, valarm):
-            # Get properties
-            self.mDescription = valarm.loadValueString(definitions.cICalProperty_DESCRIPTION)
-
-        def add(self, valarm):
-            # Delete existing then add
-            self.remove(valarm)
-
-            prop = PyCalendarProperty(definitions.cICalProperty_DESCRIPTION, self.mDescription)
-            valarm.addProperty(prop)
-
-        def remove(self, valarm):
-            valarm.removeProperties(definitions.cICalProperty_DESCRIPTION)
-
-        def getDescription(self):
-            return self.mDescription
-
-
-    class PyCalendarVAlarmEmail(PyCalendarVAlarmAction):
-
-        propertyCardinality_1 = (
-            definitions.cICalProperty_ACTION,
-            definitions.cICalProperty_TRIGGER,
-        )
-
-        propertyCardinality_1_Fix_Empty = (
-            definitions.cICalProperty_DESCRIPTION,
-            definitions.cICalProperty_SUMMARY,
-        )
-
-        propertyCardinality_0_1 = (
-            definitions.cICalProperty_DURATION,
-            definitions.cICalProperty_REPEAT,
-            definitions.cICalProperty_ACKNOWLEDGED,
-        )
-
-        propertyCardinality_1_More = (
-            definitions.cICalProperty_ATTENDEE,
-        )
-
-        def __init__(self, description=None, summary=None, attendees=None):
-            super(PyCalendarVAlarm.PyCalendarVAlarmEmail, self).__init__(type=definitions.eAction_VAlarm_Email)
-            self.mDescription = description
-            self.mSummary = summary
-            self.mAttendees = attendees
-
-        def duplicate(self):
-            return PyCalendarVAlarm.PyCalendarVAlarmEmail(self.mDescription, self.mSummary, self.mAttendees)
-
-        def load(self, valarm):
-            # Get properties
-            self.mDescription = valarm.loadValueString(definitions.cICalProperty_DESCRIPTION)
-            self.mSummary = valarm.loadValueString(definitions.cICalProperty_SUMMARY)
-
-            self.mAttendees = []
-            if valarm.hasProperty(definitions.cICalProperty_ATTENDEE):
-                # Get each attendee
-                range = valarm.getProperties().get(definitions.cICalProperty_ATTENDEE, ())
-                for iter in range:
-                    # Get the attendee value
-                    attendee = iter.getCalAddressValue()
-                    if attendee is not None:
-                        self.mAttendees.append(attendee.getValue())
-
-        def add(self, valarm):
-            # Delete existing then add
-            self.remove(valarm)
-
-            prop = PyCalendarProperty(definitions.cICalProperty_DESCRIPTION, self.mDescription)
-            valarm.addProperty(prop)
-
-            prop = PyCalendarProperty(definitions.cICalProperty_SUMMARY, self.mSummary)
-            valarm.addProperty(prop)
-
-            for iter in self.mAttendees:
-                prop = PyCalendarProperty(definitions.cICalProperty_ATTENDEE, iter, PyCalendarValue.VALUETYPE_CALADDRESS)
-                valarm.addProperty(prop)
-
-        def remove(self, valarm):
-            valarm.removeProperties(definitions.cICalProperty_DESCRIPTION)
-            valarm.removeProperties(definitions.cICalProperty_SUMMARY)
-            valarm.removeProperties(definitions.cICalProperty_ATTENDEE)
-
-        def getDescription(self):
-            return self.mDescription
-
-        def getSummary(self):
-            return self.mSummary
-
-        def getAttendees(self):
-            return self.mAttendees
-
-
-    class PyCalendarVAlarmUnknown(PyCalendarVAlarmAction):
-
-        propertyCardinality_1 = (
-            definitions.cICalProperty_ACTION,
-            definitions.cICalProperty_TRIGGER,
-        )
-
-        propertyCardinality_0_1 = (
-            definitions.cICalProperty_DURATION,
-            definitions.cICalProperty_REPEAT,
-            definitions.cICalProperty_ACKNOWLEDGED,
-        )
-
-        def __init__(self):
-            super(PyCalendarVAlarm.PyCalendarVAlarmUnknown, self).__init__(type=definitions.eAction_VAlarm_Unknown)
-
-        def duplicate(self):
-            return PyCalendarVAlarm.PyCalendarVAlarmUnknown()
-
-
-    class PyCalendarVAlarmURI(PyCalendarVAlarmAction):
-
-        propertyCardinality_1 = (
-            definitions.cICalProperty_ACTION,
-            definitions.cICalProperty_TRIGGER,
-            definitions.cICalProperty_URL,
-        )
-
-        propertyCardinality_0_1 = (
-            definitions.cICalProperty_DURATION,
-            definitions.cICalProperty_REPEAT,
-            definitions.cICalProperty_ACKNOWLEDGED,
-        )
-
-        def __init__(self, uri=None):
-            super(PyCalendarVAlarm.PyCalendarVAlarmURI, self).__init__(type=definitions.eAction_VAlarm_URI)
-            self.mURI = uri
-
-        def duplicate(self):
-            return PyCalendarVAlarm.PyCalendarVAlarmURI(self.mURI)
-
-        def load(self, valarm):
-            # Get properties
-            self.mURI = valarm.loadValueString(definitions.cICalProperty_URL)
-
-        def add(self, valarm):
-            # Delete existing then add
-            self.remove(valarm)
-
-            prop = PyCalendarProperty(definitions.cICalProperty_URL, self.mURI)
-            valarm.addProperty(prop)
-
-        def remove(self, valarm):
-            valarm.removeProperties(definitions.cICalProperty_URL)
-
-        def getURI(self):
-            return self.mURI
-
-
-    class PyCalendarVAlarmNone(PyCalendarVAlarmAction):
-
-        propertyCardinality_1 = (
-            definitions.cICalProperty_ACTION,
-        )
-
-        def __init__(self):
-            super(PyCalendarVAlarm.PyCalendarVAlarmNone, self).__init__(type=definitions.eAction_VAlarm_None)
-
-        def duplicate(self):
-            return PyCalendarVAlarm.PyCalendarVAlarmNone()
-
-
-    def getMimeComponentName(self):
-        # Cannot be sent as a separate MIME object
-        return None
-
-    sActionToAlarmMap = {
-        definitions.eAction_VAlarm_Audio: PyCalendarVAlarmAudio,
-        definitions.eAction_VAlarm_Display: PyCalendarVAlarmDisplay,
-        definitions.eAction_VAlarm_Email: PyCalendarVAlarmEmail,
-        definitions.eAction_VAlarm_URI: PyCalendarVAlarmURI,
-        definitions.eAction_VAlarm_None: PyCalendarVAlarmNone,
-    }
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    def __init__(self, parent=None):
-
-        super(PyCalendarVAlarm, self).__init__(parent=parent)
-
-        self.mAction = definitions.eAction_VAlarm_Display
-        self.mTriggerAbsolute = False
-        self.mTriggerOnStart = True
-        self.mTriggerOn = PyCalendarDateTime()
-
-        # Set duration default to 1 hour
-        self.mTriggerBy = PyCalendarDuration()
-        self.mTriggerBy.setDuration(60 * 60)
-
-        # Does not repeat by default
-        self.mRepeats = 0
-        self.mRepeatInterval = PyCalendarDuration()
-        self.mRepeatInterval.setDuration(5 * 60) # Five minutes
-
-        # Status
-        self.mStatusInit = False
-        self.mAlarmStatus = definitions.eAlarm_Status_Pending
-        self.mLastTrigger = PyCalendarDateTime()
-        self.mNextTrigger = PyCalendarDateTime()
-        self.mDoneCount = 0
-
-        # Create action data
-        self.mActionData = PyCalendarVAlarm.PyCalendarVAlarmDisplay(&quot;&quot;)
-
-
-    def duplicate(self, parent=None):
-        other = super(PyCalendarVAlarm, self).duplicate(parent=parent)
-        other.mAction = self.mAction
-        other.mTriggerAbsolute = self.mTriggerAbsolute
-        other.mTriggerOn = self.mTriggerOn.duplicate()
-        other.mTriggerBy = self.mTriggerBy.duplicate()
-        other.mTriggerOnStart = self.mTriggerOnStart
-
-        other.mRepeats = self.mRepeats
-        other.mRepeatInterval = self.mRepeatInterval.duplicate()
-
-        other.mAlarmStatus = self.mAlarmStatus
-        if self.mLastTrigger is not None:
-            other.mLastTrigger = self.mLastTrigger.duplicate()
-        if self.mNextTrigger is not None:
-            other.mNextTrigger = self.mNextTrigger.duplicate()
-        other.mDoneCount = self.mDoneCount
-
-        other.mActionData = self.mActionData.duplicate()
-        return other
-
-
-    def getType(self):
-        return definitions.cICalComponent_VALARM
-
-
-    def getAction(self):
-        return self.mAction
-
-
-    def getActionData(self):
-        return self.mActionData
-
-
-    def isTriggerAbsolute(self):
-        return self.mTriggerAbsolute
-
-
-    def getTriggerOn(self):
-        return self.mTriggerOn
-
-
-    def getTriggerDuration(self):
-        return self.mTriggerBy
-
-
-    def isTriggerOnStart(self):
-        return self.mTriggerOnStart
-
-
-    def getRepeats(self):
-        return self.mRepeats
-
-
-    def getInterval(self):
-        return self.mRepeatInterval
-
-
-    def added(self):
-        # Added to calendar so add to calendar notifier
-        # calstore::CCalendarNotifier::sCalendarNotifier.AddAlarm(this)
-
-        # Do inherited
-        super(PyCalendarVAlarm, self).added()
-
-
-    def removed(self):
-        # Removed from calendar so add to calendar notifier
-        # calstore::CCalendarNotifier::sCalendarNotifier.RemoveAlarm(this)
-
-        # Do inherited
-        super(PyCalendarVAlarm, self).removed()
-
-
-    def changed(self):
-        # Always force recalc of trigger status
-        self.mStatusInit = False
-
-        # Changed in calendar so change in calendar notifier
-        # calstore::CCalendarNotifier::sCalendarNotifier.ChangedAlarm(this)
-
-        # Do not do inherited as this is always a sub-component and we do not
-        # do top-level component changes
-        # super.changed()
-
-
-    def finalise(self):
-        # Do inherited
-        super(PyCalendarVAlarm, self).finalise()
-
-        # Get the ACTION
-        temp = self.loadValueString(definitions.cICalProperty_ACTION)
-        if temp is not None:
-            self.mAction = PyCalendarVAlarm.sActionMap.get(temp, definitions.eAction_VAlarm_Unknown)
-            self.loadAction()
-
-        # Get the trigger
-        if self.hasProperty(definitions.cICalProperty_TRIGGER):
-            # Determine the type of the value
-            temp1 = self.loadValueDateTime(definitions.cICalProperty_TRIGGER)
-            temp2 = self.loadValueDuration(definitions.cICalProperty_TRIGGER)
-            if temp1 is not None:
-                self.mTriggerAbsolute = True
-                self.mTriggerOn = temp1
-            elif temp2 is not None:
-                self.mTriggerAbsolute = False
-                self.mTriggerBy = temp2
-
-                # Get the property
-                prop = self.findFirstProperty(definitions.cICalProperty_TRIGGER)
-
-                # Look for RELATED attribute
-                if prop.hasAttribute(definitions.cICalAttribute_RELATED):
-                    temp = prop.getAttributeValue(definitions.cICalAttribute_RELATED)
-                    if temp == definitions.cICalAttribute_RELATED_START:
-                        self.mTriggerOnStart = True
-                    elif temp == definitions.cICalAttribute_RELATED_END:
-                        self.mTriggerOnStart = False
-                else:
-                    self.mTriggerOnStart = True
-
-        # Get repeat &amp; interval
-        temp = self.loadValueInteger(definitions.cICalProperty_REPEAT)
-        if temp is not None:
-            self.mRepeats = temp
-        temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
-        if temp is not None:
-            self.mRepeatInterval = temp
-
-        # Set a map key for sorting
-        self.mMapKey = &quot;%s:%s&quot; % (self.mAction, self.mTriggerOn if self.mTriggerAbsolute else self.mTriggerBy,)
-
-        # Alarm status - private to Mulberry
-        status = self.loadValueString(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
-        if status is not None:
-            if status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING:
-                self.mAlarmStatus = definitions.eAlarm_Status_Pending
-            elif status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED:
-                self.mAlarmStatus = definitions.eAlarm_Status_Completed
-            elif status == definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED:
-                self.mAlarmStatus = definitions.eAlarm_Status_Disabled
-            else:
-                self.mAlarmStatus = definitions.eAlarm_Status_Pending
-
-        # Last trigger time - private to Mulberry
-        temp = self.loadValueDateTime(definitions.cICalProperty_ALARM_X_LASTTRIGGER)
-        if temp is not None:
-            self.mLastTrigger = temp
-
-
-    def validate(self, doFix=False):
-        &quot;&quot;&quot;
-        Validate the data in this component and optionally fix any problems, else raise. If
-        loggedProblems is not None it must be a C{list} and problem descriptions are appended
-        to that.
-        &quot;&quot;&quot;
-
-        # Validate using action specific constraints
-        self.propertyCardinality_1 = self.mActionData.propertyCardinality_1
-        self.propertyCardinality_1_Fix_Empty = self.mActionData.propertyCardinality_1_Fix_Empty
-        self.propertyCardinality_0_1 = self.mActionData.propertyCardinality_0_1
-        self.propertyCardinality_1_More = self.mActionData.propertyCardinality_1_More
-
-        fixed, unfixed = super(PyCalendarVAlarm, self).validate(doFix)
-
-        # Extra constraint: both DURATION and REPEAT must be present togethe
-        if self.hasProperty(definitions.cICalProperty_DURATION) ^ self.hasProperty(definitions.cICalProperty_REPEAT):
-            # Cannot fix this
-            logProblem = &quot;[%s] Properties must be present together: %s, %s&quot; % (
-                self.getType(),
-                definitions.cICalProperty_DURATION,
-                definitions.cICalProperty_REPEAT,
-            )
-            unfixed.append(logProblem)
-
-        return fixed, unfixed
-
-
-    def editStatus(self, status):
-        # Remove existing
-        self.removeProperties(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
-
-        # Updated cached values
-        self.mAlarmStatus = status
-
-        # Add new
-        status_txt = &quot;&quot;
-        if self.mAlarmStatus == definitions.eAlarm_Status_Pending:
-            status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING
-        elif self.mAlarmStatus == definitions.eAlarm_Status_Completed:
-            status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED
-        elif self.mAlarmStatus == definitions.eAlarm_Status_Disabled:
-            status_txt = definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED
-        self.addProperty(PyCalendarProperty(definitions.cICalProperty_ALARM_X_ALARMSTATUS, status_txt))
-
-
-    def editAction(self, action, data):
-        # Remove existing
-        self.removeProperties(definitions.cICalProperty_ACTION)
-        self.mActionData.remove(self)
-        self.mActionData = None
-
-        # Updated cached values
-        self.mAction = action
-        self.mActionData = data
-
-        # Add new properties to alarm
-        action_txt = PyCalendarVAlarm.sActionValueMap.get(self.mAction, definitions.cICalProperty_ACTION_PROCEDURE)
-
-        prop = PyCalendarProperty(definitions.cICalProperty_ACTION, action_txt)
-        self.addProperty(prop)
-
-        self.mActionData.add(self)
-
-
-    def editTriggerOn(self, dt):
-        # Remove existing
-        self.removeProperties(definitions.cICalProperty_TRIGGER)
-
-        # Updated cached values
-        self.mTriggerAbsolute = True
-        self.mTriggerOn = dt
-
-        # Add new
-        prop = PyCalendarProperty(definitions.cICalProperty_TRIGGER, dt)
-        self.addProperty(prop)
-
-
-    def editTriggerBy(self, duration, trigger_start):
-        # Remove existing
-        self.removeProperties(definitions.cICalProperty_TRIGGER)
-
-        # Updated cached values
-        self.mTriggerAbsolute = False
-        self.mTriggerBy = duration
-        self.mTriggerOnStart = trigger_start
-
-        # Add new (with attribute)
-        prop = PyCalendarProperty(definitions.cICalProperty_TRIGGER, duration)
-        attr = PyCalendarAttribute(definitions.cICalAttribute_RELATED,
-                 (definitions.cICalAttribute_RELATED_START,
-                  definitions.cICalAttribute_RELATED_END)[not trigger_start])
-        prop.addAttribute(attr)
-        self.addProperty(prop)
-
-
-    def editRepeats(self, repeat, interval):
-        # Remove existing
-        self.removeProperties(definitions.cICalProperty_REPEAT)
-        self.removeProperties(definitions.cICalProperty_DURATION)
-
-        # Updated cached values
-        self.mRepeats = repeat
-        self.mRepeatInterval = interval
-
-        # Add new
-        if self.mRepeats &gt; 0:
-            self.addProperty(PyCalendarProperty(definitions.cICalProperty_REPEAT, repeat))
-            self.addProperty(PyCalendarProperty(definitions.cICalProperty_DURATION, interval))
-
-
-    def getAlarmStatus(self):
-        return self.mAlarmStatus
-
-
-    def getNextTrigger(self, dt):
-        if not self.mStatusInit:
-            self.initNextTrigger()
-        dt.copy(self.mNextTrigger)
-
-
-    def alarmTriggered(self, dt):
-        # Remove existing
-        self.removeProperties(definitions.cICalProperty_ALARM_X_LASTTRIGGER)
-        self.removeProperties(definitions.cICalProperty_ALARM_X_ALARMSTATUS)
-
-        # Updated cached values
-        self.mLastTrigger.copy(dt)
-
-        if self.mDoneCount &lt; self.mRepeats:
-            self.mNextTrigger = self.mLastTrigger + self.mRepeatInterval
-            dt.copy(self.mNextTrigger)
-            self.mDoneCount += 1
-            self.mAlarmStatus = definitions.eAlarm_Status_Pending
-        else:
-            self.mAlarmStatus = definitions.eAlarm_Status_Completed
-
-        # Add new
-        self.addProperty(PyCalendarProperty(definitions.cICalProperty_ALARM_X_LASTTRIGGER, dt))
-        status = &quot;&quot;
-        if self.mAlarmStatus == definitions.eAlarm_Status_Pending:
-            status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_PENDING
-        elif self.mAlarmStatus == definitions.eAlarm_Status_Completed:
-            status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_COMPLETED
-        elif self.mAlarmStatus == definitions.eAlarm_Status_Disabled:
-            status = definitions.cICalProperty_ALARM_X_ALARMSTATUS_DISABLED
-        self.addProperty(PyCalendarProperty(definitions.cICalProperty_ALARM_X_ALARMSTATUS, status))
-
-        # Now update dt to the next alarm time
-        return self.mAlarmStatus == definitions.eAlarm_Status_Pending
-
-
-    def loadAction(self):
-        # Delete current one
-        self.mActionData = None
-        self.mActionData = PyCalendarVAlarm.sActionToAlarmMap.get(self.mAction, PyCalendarVAlarm.PyCalendarVAlarmUnknown)()
-        self.mActionData.load(self)
-
-
-    def initNextTrigger(self):
-        # Do not bother if its completed
-        if self.mAlarmStatus == definitions.eAlarm_Status_Completed:
-            return
-        self.mStatusInit = True
-
-        # Look for trigger immediately preceeding or equal to utc now
-        nowutc = PyCalendarDateTime.getNowUTC()
-
-        # Init done counter
-        self.mDoneCount = 0
-
-        # Determine the first trigger
-        trigger = PyCalendarDateTime()
-        self.getFirstTrigger(trigger)
-
-        while self.mDoneCount &lt; self.mRepeats:
-            # See if next trigger is later than now
-            next_trigger = trigger + self.mRepeatInterval
-            if next_trigger &gt; nowutc:
-                break
-            self.mDoneCount += 1
-            trigger = next_trigger
-
-        # Check for completion
-        if trigger == self.mLastTrigger or (nowutc - trigger).getTotalSeconds() &gt; 24 * 60 * 60:
-            if self.mDoneCount == self.mRepeats:
-                self.mAlarmStatus = definitions.eAlarm_Status_Completed
-                return
-            else:
-                trigger = trigger + self.mRepeatInterval
-                self.mDoneCount += 1
-
-        self.mNextTrigger = trigger
-
-
-    def getFirstTrigger(self, dt):
-        # If absolute trigger, use that
-        if self.isTriggerAbsolute():
-            # Get the trigger on
-            dt.copy(self.getTriggerOn())
-        else:
-            # Get the parent embedder class (must be CICalendarComponentRecur type)
-            owner = self.getEmbedder()
-            if owner is not None:
-                # Determine time at which alarm will trigger
-                trigger = (owner.getStart(), owner.getEnd())[not self.isTriggerOnStart()]
-
-                # Offset by duration
-                dt.copy(trigger + self.getTriggerDuration())
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvalidationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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">@@ -14,7 +14,7 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
</del><ins>+from pycalendar.plaintextvalue import PlainTextValue
</ins><span class="cx"> 
</span><span class="cx"> # Grabbed from http://docs.python.org/library/functools.html since we need to support Python 2.5
</span><span class="cx"> def partial(func, *args, **keywords):
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx">     def stringValue(text, property):
</span><span class="cx"> 
</span><span class="cx">         value = property.getValue()
</span><del>-        if value and isinstance(value, PyCalendarPlainTextValue):
</del><ins>+        if value and isinstance(value, PlainTextValue):
</ins><span class="cx">             value = value.getValue()
</span><span class="cx">             return value.lower() == text.lower()
</span><span class="cx"> 
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvalidatorpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/validator.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/validator.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/validator.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> #!/usr/bin/env python
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2012-2013 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">@@ -15,8 +15,8 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.exceptions import PyCalendarError
</del><ins>+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.exceptions import ErrorBase
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> from pycalendar.vcard.card import Card
</span><span class="cx"> import os
</span><span class="lines">@@ -33,14 +33,14 @@
</span><span class="cx"> 
</span><span class="cx">     if data.find(&quot;BEGIN:VCALENDAR&quot;) != -1:
</span><span class="cx">         try:
</span><del>-            cal = PyCalendar.parseText(data)
-        except PyCalendarError, e:
</del><ins>+            cal = Calendar.parseText(data)
+        except ErrorBase, e:
</ins><span class="cx">             print &quot;Failed to parse iCalendar: %r&quot; % (e,)
</span><span class="cx">             sys.exit(1)
</span><span class="cx">     elif data.find(&quot;BEGIN:VCARD&quot;) != -1:
</span><span class="cx">         try:
</span><span class="cx">             cal = Card.parseText(data)
</span><del>-        except PyCalendarError, e:
</del><ins>+        except ErrorBase, e:
</ins><span class="cx">             print &quot;Failed to parse vCard: %r&quot; % (e,)
</span><span class="cx">             sys.exit(1)
</span><span class="cx">     else:
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvaluepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/value.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/value.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/value.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -16,11 +16,11 @@
</span><span class="cx"> 
</span><span class="cx"> # ICalendar Value class
</span><span class="cx"> 
</span><ins>+from pycalendar import xmlutils
</ins><span class="cx"> from pycalendar.valueutils import ValueMixin
</span><del>-from pycalendar import xmldefs
</del><span class="cx"> import xml.etree.cElementTree as XML
</span><span class="cx"> 
</span><del>-class PyCalendarValue(ValueMixin):
</del><ins>+class Value(ValueMixin):
</ins><span class="cx"> 
</span><span class="cx">     (
</span><span class="cx">         VALUETYPE_ADR,
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx"> 
</span><span class="cx">     _typeMap = {}
</span><span class="cx">     _xmlMap = {}
</span><ins>+    _jsonMap = {}
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __hash__(self):
</span><span class="lines">@@ -61,25 +62,26 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __eq__(self, other):
</span><del>-        if not isinstance(other, PyCalendarValue):
</del><ins>+        if not isinstance(other, Value):
</ins><span class="cx">             return False
</span><span class="cx">         return self.getType() == other.getType() and self.getValue() == other.getValue()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><del>-    def registerType(clz, type, cls, xmlNode):
</del><ins>+    def registerType(clz, type, cls, xmlNode, jsonNode=None):
</ins><span class="cx">         clz._typeMap[type] = cls
</span><span class="cx">         clz._xmlMap[type] = xmlNode
</span><ins>+        clz._jsonMap[type] = xmlNode if jsonNode is None else jsonNode
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><del>-    def createFromType(clz, type):
-        # Create the type
-        created = clz._typeMap.get(type, None)
</del><ins>+    def createFromType(clz, value_type):
+        # Create the value type
+        created = clz._typeMap.get(value_type, None)
</ins><span class="cx">         if created:
</span><span class="cx">             return created()
</span><span class="cx">         else:
</span><del>-            return clz._typeMap.get(PyCalendarValue.VALUETYPE_UNKNOWN)(type)
</del><ins>+            return clz._typeMap.get(Value.VALUETYPE_UNKNOWN)(value_type)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getType(self):
</span><span class="lines">@@ -98,9 +100,26 @@
</span><span class="cx">         raise NotImplementedError
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def parse(self, data, variant):
+        raise NotImplementedError
+
+
</ins><span class="cx">     def writeXML(self, node, namespace):
</span><span class="cx">         raise NotImplementedError
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def parseJSONValue(self, jobject):
+        raise NotImplementedError
+
+
+    def writeJSON(self, jobject):
+        jobject.append(self._jsonMap[self.getType()])
+        self.writeJSONValue(jobject)
+
+
+    def writeJSONValue(self, jobject):
+        raise NotImplementedError
+
+
</ins><span class="cx">     def getXMLNode(self, node, namespace):
</span><del>-        return XML.SubElement(node, xmldefs.makeTag(namespace, self._xmlMap[self.getType()]))
</del><ins>+        return XML.SubElement(node, xmlutils.makeTag(namespace, self._xmlMap[self.getType()]))
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvalueutilspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/valueutils.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/valueutils.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/valueutils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -19,6 +19,9 @@
</span><span class="cx"> from cStringIO import StringIO
</span><span class="cx"> 
</span><span class="cx"> class ValueMixin(object):
</span><ins>+    &quot;&quot;&quot;
+    Mix-in for operations common to Value's and value-specific classes.
+    &quot;&quot;&quot;
</ins><span class="cx"> 
</span><span class="cx">     def __str__(self):
</span><span class="cx">         return self.getText()
</span><span class="lines">@@ -47,3 +50,61 @@
</span><span class="cx"> 
</span><span class="cx">     def writeXML(self, node, namespace):
</span><span class="cx">         raise NotImplementedError
</span><ins>+
+
+    def parseJSON(self, jobject):
+        raise NotImplementedError
+
+
+    def writeJSON(self, jobject):
+        raise NotImplementedError
+
+
+
+class WrapperValue(object):
+    &quot;&quot;&quot;
+    Mix-in for Value derived classes that wrap a value-specific class.
+    &quot;&quot;&quot;
+
+    _wrappedClass = None
+    _wrappedType = None
+
+    def __init__(self, value=None):
+        self.mValue = value if value is not None else self._wrappedClass()
+
+
+    def getType(self):
+        return self._wrappedType
+
+
+    def duplicate(self):
+        return self.__class__(self.mValue.duplicate())
+
+
+    def parse(self, data, variant):
+        self.mValue.parse(data)
+
+
+    def generate(self, os):
+        self.mValue.generate(os)
+
+
+    def writeXML(self, node, namespace):
+        value = self.getXMLNode(node, namespace)
+        value.text = self.mValue.writeXML()
+
+
+    def parseJSONValue(self, jobject):
+        self.mValue.parseJSON(jobject)
+
+
+    def writeJSONValue(self, jobject):
+        self.mValue.writeJSON(jobject)
+
+
+    def getValue(self):
+        return self.mValue
+
+
+    def setValue(self, value):
+        self.mValue = value
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvavailabilitypy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vavailability.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vavailability.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vavailability.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,107 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-2012 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 import definitions
-from pycalendar import itipdefinitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-
-class PyCalendarVAvailability(PyCalendarComponent):
-
-    propertyCardinality_1 = (
-        definitions.cICalProperty_DTSTAMP,
-        definitions.cICalProperty_UID,
-    )
-
-    propertyCardinality_0_1 = (
-        definitions.cICalProperty_BUSYTYPE,
-        definitions.cICalProperty_CLASS,
-        definitions.cICalProperty_CREATED,
-        definitions.cICalProperty_DESCRIPTION,
-        definitions.cICalProperty_DTSTART,
-        definitions.cICalProperty_LAST_MODIFIED,
-        definitions.cICalProperty_ORGANIZER,
-        definitions.cICalProperty_SEQUENCE,
-        definitions.cICalProperty_SUMMARY,
-        definitions.cICalProperty_URL,
-        definitions.cICalProperty_RECURRENCE_ID,
-        definitions.cICalProperty_DTEND,
-        definitions.cICalProperty_DURATION,
-    )
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    def __init__(self, parent=None):
-        super(PyCalendarVAvailability, self).__init__(parent=parent)
-
-
-    def duplicate(self, parent=None):
-        return super(PyCalendarVAvailability, self).duplicate(parent=parent)
-
-
-    def getType(self):
-        return definitions.cICalComponent_VAVAILABILITY
-
-
-    def getMimeComponentName(self):
-        return itipdefinitions.cICalMIMEComponent_VAVAILABILITY
-
-
-    def finalise(self):
-        super(PyCalendarVAvailability, self).finalise()
-
-
-    def validate(self, doFix=False):
-        &quot;&quot;&quot;
-        Validate the data in this component and optionally fix any problems, else raise. If
-        loggedProblems is not None it must be a C{list} and problem descriptions are appended
-        to that.
-        &quot;&quot;&quot;
-
-        fixed, unfixed = super(PyCalendarVAvailability, self).validate(doFix)
-
-        # Extra constraint: only one of DTEND or DURATION
-        if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
-            # Fix by removing the DTEND
-            logProblem = &quot;[%s] Properties must not both be present: %s, %s&quot; % (
-                self.getType(),
-                definitions.cICalProperty_DTEND,
-                definitions.cICalProperty_DURATION,
-            )
-            if doFix:
-                self.removeProperties(definitions.cICalProperty_DTEND)
-                fixed.append(logProblem)
-            else:
-                unfixed.append(logProblem)
-
-        return fixed, unfixed
-
-
-    def addComponent(self, comp):
-        # We can embed the available components only
-        if comp.getType() == definitions.cICalComponent_AVAILABLE:
-            super(PyCalendarVAvailability, self).addComponent(comp)
-        else:
-            raise ValueError
-
-
-    def sortedPropertyKeyOrder(self):
-        return (
-            definitions.cICalProperty_UID,
-            definitions.cICalProperty_DTSTART,
-            definitions.cICalProperty_DURATION,
-            definitions.cICalProperty_DTEND,
-        )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcard__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> #
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardadrpyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardadrpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/adr.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/adr.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/adr.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/adr.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,135 @@
</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.
+##
+
+# vCard ADR value
+
+from pycalendar import utils
+from pycalendar.valueutils import ValueMixin
+
+class Adr(ValueMixin):
+    &quot;&quot;&quot;
+    mValue is a tuple of seven str or tuples of str
+    &quot;&quot;&quot;
+
+    (
+        POBOX,
+        EXTENDED,
+        STREET,
+        LOCALITY,
+        REGION,
+        POSTALCODE,
+        COUNTRY,
+        MAXITEMS
+    ) = range(8)
+
+    def __init__(self, pobox=&quot;&quot;, extended=&quot;&quot;, street=&quot;&quot;, locality=&quot;&quot;, region=&quot;&quot;, postalcode=&quot;&quot;, country=&quot;&quot;):
+        self.mValue = (pobox, extended, street, locality, region, postalcode, country)
+
+
+    def duplicate(self):
+        return Adr(*self.mValue)
+
+
+    def __hash__(self):
+        return hash(self.mValue)
+
+
+    def __repr__(self):
+        return &quot;ADR %s&quot; % (self.getText(),)
+
+
+    def __eq__(self, comp):
+        return self.mValue == comp.mValue
+
+
+    def getPobox(self):
+        return self.mValue[Adr.POBOX]
+
+
+    def setPobox(self, value):
+        self.mValue[Adr.POBOX] = value
+
+
+    def getExtended(self):
+        return self.mValue[Adr.EXTENDED]
+
+
+    def setExtended(self, value):
+        self.mValue[Adr.EXTENDED] = value
+
+
+    def getStreet(self):
+        return self.mValue[Adr.STREET]
+
+
+    def setStreet(self, value):
+        self.mValue[Adr.STREET] = value
+
+
+    def getLocality(self):
+        return self.mValue[Adr.LOCALITY]
+
+
+    def setLocality(self, value):
+        self.mValue[Adr.LOCALITY] = value
+
+
+    def getRegion(self):
+        return self.mValue[Adr.REGION]
+
+
+    def setRegion(self, value):
+        self.mValue[Adr.REGION] = value
+
+
+    def getPostalCode(self):
+        return self.mValue[Adr.POSTALCODE]
+
+
+    def setPostalCode(self, value):
+        self.mValue[Adr.POSTALCODE] = value
+
+
+    def getCountry(self):
+        return self.mValue[Adr.COUNTRY]
+
+
+    def setCountry(self, value):
+        self.mValue[Adr.COUNTRY] = value
+
+
+    def parse(self, data):
+        self.mValue = utils.parseDoubleNestedList(data, Adr.MAXITEMS)
+
+
+    def generate(self, os):
+        utils.generateDoubleNestedList(os, self.mValue)
+
+
+    def parseJSON(self, jobject):
+        self.mValue = tuple(jobject)
+
+
+    def writeJSON(self, jobject):
+        jobject.append(list(self.mValue))
+
+
+    def getValue(self):
+        return self.mValue
+
+
+    def setValue(self, value):
+        self.mValue = value
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardadrvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardadrvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/adrvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/adrvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/adrvalue.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/adrvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,28 @@
</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.
+##
+
+# vCard ADR value
+
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
+from pycalendar.vcard.adr import Adr
+
+class AdrValue(WrapperValue, Value):
+
+    _wrappedClass = Adr
+    _wrappedType = Value.VALUETYPE_ADR
+
+Value.registerType(Value.VALUETYPE_ADR, AdrValue, None)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardcardpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/card.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/card.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/card.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -15,9 +15,8 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> from cStringIO import StringIO
</span><del>-from pycalendar.componentbase import PyCalendarComponentBase
-from pycalendar.exceptions import PyCalendarInvalidData, \
-    PyCalendarValidationError
</del><ins>+from pycalendar.containerbase import ContainerBase
+from pycalendar.exceptions import InvalidData
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> from pycalendar.utils import readFoldedLine
</span><span class="cx"> from pycalendar.vcard import definitions
</span><span class="lines">@@ -25,21 +24,17 @@
</span><span class="cx">     Property_PRODID, Property_UID
</span><span class="cx"> from pycalendar.vcard.property import Property
</span><span class="cx"> from pycalendar.vcard.validation import VCARD_VALUE_CHECKS
</span><ins>+import json
</ins><span class="cx"> 
</span><del>-class Card(PyCalendarComponentBase):
</del><ins>+class Card(ContainerBase):
</ins><span class="cx"> 
</span><del>-    sProdID = &quot;-//mulberrymail.com//Mulberry v4.0//EN&quot;
-    sDomain = &quot;mulberrymail.com&quot;
</del><ins>+    sContainerDescriptor = &quot;vCard&quot;
+    sComponentType = None
+    sPropertyType = Property
</ins><span class="cx"> 
</span><del>-    @staticmethod
-    def setPRODID(prodid):
-        Card.sProdID = prodid
</del><ins>+    sFormatText = &quot;text/vcard&quot;
+    sFormatJSON = &quot;application/vcard+json&quot;
</ins><span class="cx"> 
</span><del>-
-    @staticmethod
-    def setDomain(domain):
-        Card.sDomain = domain
-
</del><span class="cx">     propertyCardinality_1 = (
</span><span class="cx">         definitions.Property_VERSION,
</span><span class="cx">         definitions.Property_N,
</span><span class="lines">@@ -58,13 +53,6 @@
</span><span class="cx"> 
</span><span class="cx">     propertyValueChecks = VCARD_VALUE_CHECKS
</span><span class="cx"> 
</span><del>-    def __init__(self, add_defaults=True):
-        super(Card, self).__init__()
-
-        if add_defaults:
-            self.addDefaultProperties()
-
-
</del><span class="cx">     def duplicate(self):
</span><span class="cx">         return super(Card, self).duplicate()
</span><span class="cx"> 
</span><span class="lines">@@ -73,25 +61,6 @@
</span><span class="cx">         return VCARD
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def finalise(self):
-        pass
-
-
-    def validate(self, doFix=False, doRaise=False):
-        &quot;&quot;&quot;
-        Validate the data in this component and optionally fix any problems. Return
-        a tuple containing two lists: the first describes problems that were fixed, the
-        second problems that were not fixed. Caller can then decide what to do with unfixed
-        issues.
-        &quot;&quot;&quot;
-
-        # Optional raise behavior
-        fixed, unfixed = super(Card, self).validate(doFix)
-        if doRaise and unfixed:
-            raise PyCalendarValidationError(&quot;;&quot;.join(unfixed))
-        return fixed, unfixed
-
-
</del><span class="cx">     def sortedPropertyKeyOrder(self):
</span><span class="cx">         return (
</span><span class="cx">             Property_VERSION,
</span><span class="lines">@@ -100,12 +69,24 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    @staticmethod
-    def parseMultiple(ins):
</del><ins>+    @classmethod
+    def parseMultipleData(cls, data, format):
</ins><span class="cx"> 
</span><ins>+        if format == cls.sFormatText:
+            return cls.parseMultipleTextData(data)
+        elif format == cls.sFormatJSON:
+            return cls.parseMultipleJSONData(data)
+
+
+    @classmethod
+    def parseMultipleTextData(cls, ins):
+
+        if isinstance(ins, str):
+            ins = StringIO(ins)
+
</ins><span class="cx">         results = []
</span><span class="cx"> 
</span><del>-        card = Card(add_defaults=False)
</del><ins>+        card = cls(add_defaults=False)
</ins><span class="cx"> 
</span><span class="cx">         LOOK_FOR_VCARD = 0
</span><span class="cx">         GET_PROPERTY = 1
</span><span class="lines">@@ -129,11 +110,11 @@
</span><span class="cx">                 elif len(line) == 0:
</span><span class="cx">                     # Raise if requested, otherwise just ignore
</span><span class="cx">                     if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
</span><del>-                        raise PyCalendarInvalidData(&quot;vCard data has blank lines&quot;)
</del><ins>+                        raise InvalidData(&quot;vCard data has blank lines&quot;)
</ins><span class="cx"> 
</span><span class="cx">                 # Unrecognized data
</span><span class="cx">                 else:
</span><del>-                    raise PyCalendarInvalidData(&quot;vCard data not recognized&quot;, line)
</del><ins>+                    raise InvalidData(&quot;vCard data not recognized&quot;, line)
</ins><span class="cx"> 
</span><span class="cx">             elif state == GET_PROPERTY:
</span><span class="cx"> 
</span><span class="lines">@@ -145,7 +126,7 @@
</span><span class="cx"> 
</span><span class="cx">                     # Validate some things
</span><span class="cx">                     if not card.hasProperty(&quot;VERSION&quot;):
</span><del>-                        raise PyCalendarInvalidData(&quot;vCard missing VERSION&quot;, &quot;&quot;)
</del><ins>+                        raise InvalidData(&quot;vCard missing VERSION&quot;, &quot;&quot;)
</ins><span class="cx"> 
</span><span class="cx">                     results.append(card)
</span><span class="cx"> 
</span><span class="lines">@@ -157,119 +138,42 @@
</span><span class="cx">                 elif len(line) == 0:
</span><span class="cx">                     # Raise if requested, otherwise just ignore
</span><span class="cx">                     if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
</span><del>-                        raise PyCalendarInvalidData(&quot;vCard data has blank lines&quot;)
</del><ins>+                        raise InvalidData(&quot;vCard data has blank lines&quot;)
</ins><span class="cx"> 
</span><span class="cx">                 # Must be a property
</span><span class="cx">                 else:
</span><span class="cx"> 
</span><del>-                    # Parse attribute/value for top-level calendar item
-                    prop = Property()
-                    if prop.parse(line):
</del><ins>+                    # Parse parameter/value for top-level calendar item
+                    prop = Property.parseText(line)
</ins><span class="cx"> 
</span><del>-                        # Check for valid property
-                        if not card.validProperty(prop):
-                            raise PyCalendarInvalidData(&quot;Invalid property&quot;, str(prop))
-                        else:
-                            card.addProperty(prop)
</del><ins>+                    # Check for valid property
+                    if not card.validProperty(prop):
+                        raise InvalidData(&quot;Invalid property&quot;, str(prop))
+                    else:
+                        card.addProperty(prop)
</ins><span class="cx"> 
</span><span class="cx">         # Check for truncated data
</span><span class="cx">         if state != LOOK_FOR_VCARD:
</span><del>-            raise PyCalendarInvalidData(&quot;vCard data not complete&quot;)
</del><ins>+            raise InvalidData(&quot;vCard data not complete&quot;)
</ins><span class="cx"> 
</span><span class="cx">         return results
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    @staticmethod
-    def parseText(data):
</del><ins>+    @classmethod
+    def parseMultipleJSONData(cls, data):
</ins><span class="cx"> 
</span><del>-        cal = Card(add_defaults=False)
-        if cal.parse(StringIO(data)):
-            return cal
-        else:
-            return None
</del><ins>+        if not isinstance(data, str):
+            data = data.read()
+        try:
+            jobjects = json.loads(data)
+        except ValueError, e:
+            raise InvalidData(e, data)
+        results = []
+        for jobject in jobjects:
+            results.append(cls.parseJSON(jobject, None, cls(add_defaults=False)))
+        return results
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def parse(self, ins):
-
-        result = False
-
-        self.setProperties({})
-
-        LOOK_FOR_VCARD = 0
-        GET_PROPERTY = 1
-
-        state = LOOK_FOR_VCARD
-
-        # Get lines looking for start of calendar
-        lines = [None, None]
-
-        while readFoldedLine(ins, lines):
-
-            line = lines[0]
-            if state == LOOK_FOR_VCARD:
-
-                # Look for start
-                if line == self.getBeginDelimiter():
-                    # Next state
-                    state = GET_PROPERTY
-
-                    # Indicate success at this point
-                    result = True
-
-                # Handle blank line
-                elif len(line) == 0:
-                    # Raise if requested, otherwise just ignore
-                    if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
-                        raise PyCalendarInvalidData(&quot;vCard data has blank lines&quot;)
-
-                # Unrecognized data
-                else:
-                    raise PyCalendarInvalidData(&quot;vCard data not recognized&quot;, line)
-
-            elif state == GET_PROPERTY:
-
-                # Look for end of object
-                if line == self.getEndDelimiter():
-
-                    # Finalise the current calendar
-                    self.finalise()
-
-                    # Change state
-                    state = LOOK_FOR_VCARD
-
-                # Blank line
-                elif len(line) == 0:
-                    # Raise if requested, otherwise just ignore
-                    if ParserContext.BLANK_LINES_IN_DATA == ParserContext.PARSER_RAISE:
-                        raise PyCalendarInvalidData(&quot;vCard data has blank lines&quot;)
-
-                # Must be a property
-                else:
-
-                    # Parse attribute/value for top-level calendar item
-                    prop = Property()
-                    try:
-                        if prop.parse(line):
-
-                            # Check for valid property
-                            if not self.validProperty(prop):
-                                raise PyCalendarInvalidData(&quot;Invalid property&quot;, str(prop))
-                            else:
-                                self.addProperty(prop)
-                    except IndexError:
-                        print line
-
-        # Check for truncated data
-        if state != LOOK_FOR_VCARD:
-            raise PyCalendarInvalidData(&quot;vCard data not complete&quot;, &quot;&quot;)
-
-        # Validate some things
-        if result and not self.hasProperty(&quot;VERSION&quot;):
-            raise PyCalendarInvalidData(&quot;vCard missing VERSION&quot;, &quot;&quot;)
-
-        return result
-
-
</del><span class="cx">     def addDefaultProperties(self):
</span><span class="cx">         self.addProperty(Property(definitions.Property_PRODID, Card.sProdID))
</span><span class="cx">         self.addProperty(Property(definitions.Property_VERSION, &quot;3.0&quot;))
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcarddefinitionspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/definitions.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/definitions.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/definitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardnpyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardnpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/n.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/n.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/n.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,132 @@
</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.
+##
+
+# vCard ADR value
+
+from pycalendar import utils
+from pycalendar.valueutils import ValueMixin
+
+class N(ValueMixin):
+    &quot;&quot;&quot;
+    mValue is a tuple of seven str or tuples of str
+    &quot;&quot;&quot;
+
+    (
+        LAST,
+        FIRST,
+        MIDDLE,
+        PREFIX,
+        SUFFIX,
+        MAXITEMS
+    ) = range(6)
+
+    def __init__(self, last=&quot;&quot;, first=&quot;&quot;, middle=&quot;&quot;, prefix=&quot;&quot;, suffix=&quot;&quot;):
+        self.mValue = (last, first, middle, prefix, suffix)
+
+
+    def duplicate(self):
+        return N(*self.mValue)
+
+
+    def __hash__(self):
+        return hash(self.mValue)
+
+
+    def __repr__(self):
+        return &quot;N %s&quot; % (self.getText(),)
+
+
+    def __eq__(self, comp):
+        return self.mValue == comp.mValue
+
+
+    def getFirst(self):
+        return self.mValue[N.FIRST]
+
+
+    def setFirst(self, value):
+        self.mValue[N.FIRST] = value
+
+
+    def getLast(self):
+        return self.mValue[N.LAST]
+
+
+    def setLast(self, value):
+        self.mValue[N.LAST] = value
+
+
+    def getMiddle(self):
+        return self.mValue[N.MIDDLE]
+
+
+    def setMiddle(self, value):
+        self.mValue[N.MIDDLE] = value
+
+
+    def getPrefix(self):
+        return self.mValue[N.PREFIX]
+
+
+    def setPrefix(self, value):
+        self.mValue[N.PREFIX] = value
+
+
+    def getSuffix(self):
+        return self.mValue[N.SUFFIX]
+
+
+    def setSuffix(self, value):
+        self.mValue[N.SUFFIX] = value
+
+
+    def getFullName(self):
+
+
+        def _stringOrList(item):
+            return item if isinstance(item, basestring) else &quot; &quot;.join(item)
+
+        results = []
+        for i in (N.PREFIX, N.FIRST, N.MIDDLE, N.LAST, N.SUFFIX):
+            result = _stringOrList(self.mValue[i])
+            if result:
+                results.append(result)
+
+        return &quot; &quot;.join(results)
+
+
+    def parse(self, data):
+        self.mValue = utils.parseDoubleNestedList(data, N.MAXITEMS)
+
+
+    def generate(self, os):
+        utils.generateDoubleNestedList(os, self.mValue)
+
+
+    def parseJSON(self, jobject):
+        self.mValue = tuple(jobject)
+
+
+    def writeJSON(self, jobject):
+        jobject.append(list(self.mValue))
+
+
+    def getValue(self):
+        return self.mValue
+
+
+    def setValue(self, value):
+        self.mValue = value
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardnvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardnvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/nvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/nvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/nvalue.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/nvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,28 @@
</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.
+##
+
+# vCard N value
+
+from pycalendar.value import Value
+from pycalendar.valueutils import WrapperValue
+from pycalendar.vcard.n import N
+
+class NValue(WrapperValue, Value):
+
+    _wrappedClass = N
+    _wrappedType = Value.VALUETYPE_N
+
+Value.registerType(Value.VALUETYPE_N, NValue, None)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardorgvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardorgvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/orgvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/orgvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/orgvalue.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/orgvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,62 @@
</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.
+##
+
+# vCard ORG value
+
+from pycalendar import utils
+from pycalendar.value import Value
+
+class OrgValue(Value):
+    &quot;&quot;&quot;
+    mValue is a str or tuple of str
+    &quot;&quot;&quot;
+
+    def __init__(self, value=None):
+        self.mValue = value
+
+
+    def duplicate(self):
+        return OrgValue(self.mValue)
+
+
+    def getType(self):
+        return Value.VALUETYPE_ORG
+
+
+    def parse(self, data, variant=&quot;vcard&quot;):
+        self.mValue = utils.parseTextList(data, ';')
+
+
+    def generate(self, os):
+        utils.generateTextList(os, self.mValue, ';')
+
+
+    def parseJSONValue(self, jobject):
+        self.mValue = tuple(jobject)
+
+
+    def writeJSONValue(self, jobject):
+        jobject.append(list(self.mValue))
+
+
+    def getValue(self):
+        return self.mValue
+
+
+    def setValue(self, value):
+        self.mValue = value
+
+Value.registerType(Value.VALUETYPE_ORG, OrgValue, None)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardpropertypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/property.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/property.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -15,113 +15,109 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> from pycalendar import stringutils
</span><del>-from pycalendar.adr import Adr
-from pycalendar.adrvalue import AdrValue
-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.datetimevalue import PyCalendarDateTimeValue
-from pycalendar.exceptions import PyCalendarInvalidProperty
-from pycalendar.integervalue import PyCalendarIntegerValue
-from pycalendar.multivalue import PyCalendarMultiValue
-from pycalendar.n import N
-from pycalendar.nvalue import NValue
-from pycalendar.orgvalue import OrgValue
</del><ins>+from pycalendar.parameter import Parameter
+from pycalendar.datetime import DateTime
+from pycalendar.exceptions import InvalidProperty
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><del>-from pycalendar.plaintextvalue import PyCalendarPlainTextValue
-from pycalendar.unknownvalue import PyCalendarUnknownValue
-from pycalendar.utcoffsetvalue import PyCalendarUTCOffsetValue
</del><ins>+from pycalendar.property import PropertyBase
+from pycalendar.utcoffsetvalue import UTCOffsetValue
</ins><span class="cx"> from pycalendar.utils import decodeParameterValue
</span><del>-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.value import Value
</ins><span class="cx"> from pycalendar.vcard import definitions
</span><ins>+from pycalendar.vcard.adr import Adr
+from pycalendar.vcard.adrvalue import AdrValue
+from pycalendar.vcard.n import N
+from pycalendar.vcard.nvalue import NValue
+from pycalendar.vcard.orgvalue import OrgValue
</ins><span class="cx"> import cStringIO as StringIO
</span><span class="cx"> 
</span><span class="cx"> handleOptions = (&quot;allow&quot;, &quot;ignore&quot;, &quot;fix&quot;, &quot;raise&quot;)
</span><span class="cx"> missingParameterValues = &quot;fix&quot;
</span><span class="cx"> 
</span><del>-class Property(object):
</del><ins>+class Property(PropertyBase):
</ins><span class="cx"> 
</span><span class="cx">     sDefaultValueTypeMap = {
</span><span class="cx"> 
</span><span class="cx">         #     2425 Properties
</span><del>-        definitions.Property_SOURCE  : PyCalendarValue.VALUETYPE_URI,
-        definitions.Property_NAME    : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_PROFILE : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+        definitions.Property_SOURCE  : Value.VALUETYPE_URI,
+        definitions.Property_NAME    : Value.VALUETYPE_TEXT,
+        definitions.Property_PROFILE : Value.VALUETYPE_TEXT,
</ins><span class="cx"> 
</span><span class="cx">         #     2426 vCard Properties
</span><span class="cx"> 
</span><span class="cx">         #     2426 Section 3.1
</span><del>-        definitions.Property_FN       : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_N        : PyCalendarValue.VALUETYPE_N,
-        definitions.Property_NICKNAME : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_PHOTO    : PyCalendarValue.VALUETYPE_BINARY,
-        definitions.Property_BDAY     : PyCalendarValue.VALUETYPE_DATE,
</del><ins>+        definitions.Property_FN       : Value.VALUETYPE_TEXT,
+        definitions.Property_N        : Value.VALUETYPE_TEXT,
+        definitions.Property_NICKNAME : Value.VALUETYPE_TEXT,
+        definitions.Property_PHOTO    : Value.VALUETYPE_BINARY,
+        definitions.Property_BDAY     : Value.VALUETYPE_DATE,
</ins><span class="cx"> 
</span><span class="cx">         #     2426 Section 3.2
</span><del>-        definitions.Property_ADR   : PyCalendarValue.VALUETYPE_ADR,
-        definitions.Property_LABEL : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+        definitions.Property_ADR   : Value.VALUETYPE_TEXT,
+        definitions.Property_LABEL : Value.VALUETYPE_TEXT,
</ins><span class="cx"> 
</span><span class="cx">         #     2426 Section 3.3
</span><del>-        definitions.Property_TEL    : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_EMAIL  : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_MAILER : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+        definitions.Property_TEL    : Value.VALUETYPE_TEXT,
+        definitions.Property_EMAIL  : Value.VALUETYPE_TEXT,
+        definitions.Property_MAILER : Value.VALUETYPE_TEXT,
</ins><span class="cx"> 
</span><span class="cx">         #     2426 Section 3.4
</span><del>-        definitions.Property_TZ  : PyCalendarValue.VALUETYPE_UTC_OFFSET,
-        definitions.Property_GEO : PyCalendarValue.VALUETYPE_GEO,
</del><ins>+        definitions.Property_TZ  : Value.VALUETYPE_UTC_OFFSET,
+        definitions.Property_GEO : Value.VALUETYPE_FLOAT,
</ins><span class="cx"> 
</span><span class="cx">         #     2426 Section 3.5
</span><del>-        definitions.Property_TITLE : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_ROLE  : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_LOGO  : PyCalendarValue.VALUETYPE_BINARY,
-        definitions.Property_AGENT : PyCalendarValue.VALUETYPE_VCARD,
-        definitions.Property_ORG   : PyCalendarValue.VALUETYPE_ORG,
</del><ins>+        definitions.Property_TITLE : Value.VALUETYPE_TEXT,
+        definitions.Property_ROLE  : Value.VALUETYPE_TEXT,
+        definitions.Property_LOGO  : Value.VALUETYPE_BINARY,
+        definitions.Property_AGENT : Value.VALUETYPE_VCARD,
+        definitions.Property_ORG   : Value.VALUETYPE_TEXT,
</ins><span class="cx"> 
</span><span class="cx">         #     2426 Section 3.6
</span><del>-        definitions.Property_CATEGORIES  : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_NOTE        : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_PRODID      : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_REV         : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.Property_SORT_STRING : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_SOUND       : PyCalendarValue.VALUETYPE_BINARY,
-        definitions.Property_UID         : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_URL         : PyCalendarValue.VALUETYPE_URI,
-        definitions.Property_VERSION     : PyCalendarValue.VALUETYPE_TEXT,
</del><ins>+        definitions.Property_CATEGORIES  : Value.VALUETYPE_TEXT,
+        definitions.Property_NOTE        : Value.VALUETYPE_TEXT,
+        definitions.Property_PRODID      : Value.VALUETYPE_TEXT,
+        definitions.Property_REV         : Value.VALUETYPE_DATETIME,
+        definitions.Property_SORT_STRING : Value.VALUETYPE_TEXT,
+        definitions.Property_SOUND       : Value.VALUETYPE_BINARY,
+        definitions.Property_UID         : Value.VALUETYPE_TEXT,
+        definitions.Property_URL         : Value.VALUETYPE_URI,
+        definitions.Property_VERSION     : Value.VALUETYPE_TEXT,
</ins><span class="cx"> 
</span><span class="cx">         #     2426 Section 3.7
</span><del>-        definitions.Property_CLASS       : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Property_KEY         : PyCalendarValue.VALUETYPE_BINARY,
</del><ins>+        definitions.Property_CLASS       : Value.VALUETYPE_TEXT,
+        definitions.Property_KEY         : Value.VALUETYPE_BINARY,
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     sValueTypeMap = {
</span><del>-        definitions.Value_BINARY      : PyCalendarValue.VALUETYPE_BINARY,
-        definitions.Value_BOOLEAN     : PyCalendarValue.VALUETYPE_BOOLEAN,
-        definitions.Value_DATE        : PyCalendarValue.VALUETYPE_DATE,
-        definitions.Value_DATE_TIME   : PyCalendarValue.VALUETYPE_DATETIME,
-        definitions.Value_FLOAT       : PyCalendarValue.VALUETYPE_FLOAT,
-        definitions.Value_INTEGER     : PyCalendarValue.VALUETYPE_INTEGER,
-        definitions.Value_TEXT        : PyCalendarValue.VALUETYPE_TEXT,
-        definitions.Value_TIME        : PyCalendarValue.VALUETYPE_TIME,
-        definitions.Value_URI         : PyCalendarValue.VALUETYPE_URI,
-        definitions.Value_UTCOFFSET   : PyCalendarValue.VALUETYPE_UTC_OFFSET,
-        definitions.Value_VCARD       : PyCalendarValue.VALUETYPE_VCARD,
</del><ins>+        definitions.Value_BINARY      : Value.VALUETYPE_BINARY,
+        definitions.Value_BOOLEAN     : Value.VALUETYPE_BOOLEAN,
+        definitions.Value_DATE        : Value.VALUETYPE_DATE,
+        definitions.Value_DATE_TIME   : Value.VALUETYPE_DATETIME,
+        definitions.Value_FLOAT       : Value.VALUETYPE_FLOAT,
+        definitions.Value_INTEGER     : Value.VALUETYPE_INTEGER,
+        definitions.Value_TEXT        : Value.VALUETYPE_TEXT,
+        definitions.Value_TIME        : Value.VALUETYPE_TIME,
+        definitions.Value_URI         : Value.VALUETYPE_URI,
+        definitions.Value_UTCOFFSET   : Value.VALUETYPE_UTC_OFFSET,
+        definitions.Value_VCARD       : Value.VALUETYPE_VCARD,
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     sTypeValueMap = {
</span><del>-        PyCalendarValue.VALUETYPE_ADR        : definitions.Value_TEXT,
-        PyCalendarValue.VALUETYPE_BINARY     : definitions.Value_BINARY,
-        PyCalendarValue.VALUETYPE_BOOLEAN    : definitions.Value_BOOLEAN,
-        PyCalendarValue.VALUETYPE_DATE       : definitions.Value_DATE,
-        PyCalendarValue.VALUETYPE_DATETIME   : definitions.Value_DATE_TIME,
-        PyCalendarValue.VALUETYPE_FLOAT      : definitions.Value_FLOAT,
-        PyCalendarValue.VALUETYPE_GEO        : definitions.Value_FLOAT,
-        PyCalendarValue.VALUETYPE_INTEGER    : definitions.Value_INTEGER,
-        PyCalendarValue.VALUETYPE_N          : definitions.Value_TEXT,
-        PyCalendarValue.VALUETYPE_ORG        : definitions.Value_TEXT,
-        PyCalendarValue.VALUETYPE_TEXT       : definitions.Value_TEXT,
-        PyCalendarValue.VALUETYPE_TIME       : definitions.Value_TIME,
-        PyCalendarValue.VALUETYPE_URI        : definitions.Value_URI,
-        PyCalendarValue.VALUETYPE_UTC_OFFSET : definitions.Value_UTCOFFSET,
-        PyCalendarValue.VALUETYPE_VCARD      : definitions.Value_VCARD,
</del><ins>+        Value.VALUETYPE_ADR        : definitions.Value_TEXT,
+        Value.VALUETYPE_BINARY     : definitions.Value_BINARY,
+        Value.VALUETYPE_BOOLEAN    : definitions.Value_BOOLEAN,
+        Value.VALUETYPE_DATE       : definitions.Value_DATE,
+        Value.VALUETYPE_DATETIME   : definitions.Value_DATE_TIME,
+        Value.VALUETYPE_FLOAT      : definitions.Value_FLOAT,
+        Value.VALUETYPE_GEO        : definitions.Value_FLOAT,
+        Value.VALUETYPE_INTEGER    : definitions.Value_INTEGER,
+        Value.VALUETYPE_N          : definitions.Value_TEXT,
+        Value.VALUETYPE_ORG        : definitions.Value_TEXT,
+        Value.VALUETYPE_TEXT       : definitions.Value_TEXT,
+        Value.VALUETYPE_TIME       : definitions.Value_TIME,
+        Value.VALUETYPE_URI        : definitions.Value_URI,
+        Value.VALUETYPE_UTC_OFFSET : definitions.Value_UTCOFFSET,
+        Value.VALUETYPE_VCARD      : definitions.Value_VCARD,
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     sMultiValues = set((
</span><span class="lines">@@ -129,26 +125,37 @@
</span><span class="cx">         definitions.Property_CATEGORIES,
</span><span class="cx">     ))
</span><span class="cx"> 
</span><del>-    sTextVariants = set((
-        definitions.Property_ADR,
-        definitions.Property_N,
-        definitions.Property_ORG,
-    ))
</del><ins>+    sSpecialVariants = {
+        definitions.Property_ADR : Value.VALUETYPE_ADR,
+        definitions.Property_GEO : Value.VALUETYPE_GEO,
+        definitions.Property_N: Value.VALUETYPE_N,
+        definitions.Property_ORG: Value.VALUETYPE_ORG,
+    }
</ins><span class="cx"> 
</span><ins>+    sUsesGroup = True
+
+    sVariant = &quot;vcard&quot;
+
+    sValue = definitions.Parameter_VALUE
+    sText = definitions.Value_TEXT
+
</ins><span class="cx">     def __init__(self, group=None, name=None, value=None, valuetype=None):
</span><del>-        self._init_PyCalendarProperty()
</del><span class="cx"> 
</span><ins>+        super(Property, self).__init__(name, value, valuetype)
+
</ins><span class="cx">         self.mGroup = group
</span><span class="cx"> 
</span><del>-        self.mName = name if name is not None else &quot;&quot;
</del><ins>+        # The None check speeds up .duplicate()
+        if value is None:
+            pass
</ins><span class="cx"> 
</span><span class="cx">         if isinstance(value, int):
</span><span class="cx">             self._init_attr_value_int(value)
</span><span class="cx"> 
</span><span class="cx">         elif isinstance(value, str):
</span><del>-            self._init_attr_value_text(value, valuetype if valuetype else Property.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarValue.VALUETYPE_TEXT))
</del><ins>+            self._init_attr_value_text(value, valuetype if valuetype else self.sDefaultValueTypeMap.get(self.mName.upper(), Value.VALUETYPE_TEXT))
</ins><span class="cx"> 
</span><del>-        elif isinstance(value, PyCalendarDateTime):
</del><ins>+        elif isinstance(value, DateTime):
</ins><span class="cx">             self._init_attr_value_datetime(value)
</span><span class="cx"> 
</span><span class="cx">         elif isinstance(value, Adr):
</span><span class="lines">@@ -166,14 +173,14 @@
</span><span class="cx">                 # Assume everything else is a text list
</span><span class="cx">                 self._init_attr_value_text_list(value)
</span><span class="cx"> 
</span><del>-        elif isinstance(value, PyCalendarUTCOffsetValue):
</del><ins>+        elif isinstance(value, UTCOffsetValue):
</ins><span class="cx">             self._init_attr_value_utcoffset(value)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def duplicate(self):
</span><span class="cx">         other = Property(self.mGroup, self.mName)
</span><del>-        for attrname, attrs in self.mAttributes.items():
-            other.mAttributes[attrname] = [i.duplicate() for i in attrs]
</del><ins>+        for attrname, attrs in self.mParameters.items():
+            other.mParameters[attrname] = [i.duplicate() for i in attrs]
</ins><span class="cx">         other.mValue = self.mValue.duplicate()
</span><span class="cx"> 
</span><span class="cx">         return other
</span><span class="lines">@@ -181,16 +188,13 @@
</span><span class="cx"> 
</span><span class="cx">     def __hash__(self):
</span><span class="cx">         return hash((
</span><ins>+            self.mGroup,
</ins><span class="cx">             self.mName,
</span><del>-            tuple([tuple(self.mAttributes[attrname]) for attrname in sorted(self.mAttributes.keys())]),
</del><ins>+            tuple([tuple(self.mParameters[attrname]) for attrname in sorted(self.mParameters.keys())]),
</ins><span class="cx">             self.mValue,
</span><span class="cx">         ))
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-
</del><span class="cx">     def __eq__(self, other):
</span><span class="cx">         if not isinstance(other, Property):
</span><span class="cx">             return False
</span><span class="lines">@@ -198,89 +202,20 @@
</span><span class="cx">             self.mGroup == self.mGroup and
</span><span class="cx">             self.mName == other.mName and
</span><span class="cx">             self.mValue == other.mValue and
</span><del>-            self.mAttributes == other.mAttributes
</del><ins>+            self.mParameters == other.mParameters
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def __repr__(self):
-        return &quot;vCard Property: %s&quot; % (self.getText(),)
</del><ins>+    def parseTextParameters(self, txt, data):
+        &quot;&quot;&quot;
+        Parse parameters, return string point at value.
+        &quot;&quot;&quot;
</ins><span class="cx"> 
</span><del>-
-    def __str__(self):
-        return self.getText()
-
-
-    def getGroup(self):
-        return self.mGroup
-
-
-    def setGroup(self, group):
-        self.mGroup = group
-
-
-    def getName(self):
-        return self.mName
-
-
-    def setName(self, name):
-        self.mName = name
-
-
-    def getAttributes(self):
-        return self.mAttributes
-
-
-    def setAttributes(self, attributes):
-        self.mAttributes = dict([(k.upper(), v) for k, v in attributes.iteritems()])
-
-
-    def hasAttribute(self, attr):
-        return attr.upper() in self.mAttributes
-
-
-    def getAttributeValue(self, attr):
-        return self.mAttributes[attr.upper()][0].getFirstValue()
-
-
-    def addAttribute(self, attr):
-        self.mAttributes.setdefault(attr.getName().upper(), []).append(attr)
-
-
-    def replaceAttribute(self, attr):
-        self.mAttributes[attr.getName().upper()] = [attr]
-
-
-    def removeAttributes(self, attr):
-        if attr.upper() in self.mAttributes:
-            del self.mAttributes[attr.upper()]
-
-
-    def getValue(self):
-        return self.mValue
-
-
-    def parse(self, data):
-        # Look for attribute or value delimiter
-        prop_name, txt = stringutils.strduptokenstr(data, &quot;;:&quot;)
-        if not prop_name:
-            raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
-
-        # Check for group prefix
-        splits = prop_name.split(&quot;.&quot;, 1)
-        if len(splits) == 2:
-            # We have both group and name
-            self.mGroup = splits[0]
-            self.mName = splits[1]
-        else:
-            # We have the name
-            self.mName = prop_name
-
-        # Now loop getting data
</del><span class="cx">         try:
</span><span class="cx">             stripValueSpaces = False    # Fix for AB.app base PHOTO properties that use two spaces at start of line
</span><span class="cx">             while txt:
</span><span class="cx">                 if txt[0] == ';':
</span><del>-                    # Parse attribute
</del><ins>+                    # Parse parameter
</ins><span class="cx"> 
</span><span class="cx">                     # Move past delimiter
</span><span class="cx">                     txt = txt[1:]
</span><span class="lines">@@ -288,99 +223,72 @@
</span><span class="cx">                     # Get quoted string or token - in iCalendar we only look for &quot;=&quot; here
</span><span class="cx">                     # but for &quot;broken&quot; vCard BASE64 property we need to also terminate on
</span><span class="cx">                     # &quot;:;&quot;
</span><del>-                    attribute_name, txt = stringutils.strduptokenstr(txt, &quot;=:;&quot;)
-                    if attribute_name is None:
-                        raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
</del><ins>+                    parameter_name, txt = stringutils.strduptokenstr(txt, &quot;=:;&quot;)
+                    if parameter_name is None:
+                        raise InvalidProperty(&quot;Invalid property&quot;, data)
</ins><span class="cx"> 
</span><span class="cx">                     if txt[0] != &quot;=&quot;:
</span><span class="cx">                         # Deal with parameters without values
</span><span class="cx">                         if ParserContext.VCARD_2_NO_PARAMETER_VALUES == ParserContext.PARSER_RAISE:
</span><del>-                            raise PyCalendarInvalidProperty(&quot;Invalid property parameter&quot;, data)
</del><ins>+                            raise InvalidProperty(&quot;Invalid property parameter&quot;, data)
</ins><span class="cx">                         elif ParserContext.VCARD_2_NO_PARAMETER_VALUES == ParserContext.PARSER_ALLOW:
</span><del>-                            attribute_value = None
</del><ins>+                            parameter_value = None
</ins><span class="cx">                         else: # PARSER_IGNORE and PARSER_FIX
</span><del>-                            attribute_name = None
</del><ins>+                            parameter_name = None
</ins><span class="cx"> 
</span><del>-                        if attribute_name.upper() == &quot;BASE64&quot; and ParserContext.VCARD_2_BASE64 == ParserContext.PARSER_FIX:
-                            attribute_name = definitions.Parameter_ENCODING
-                            attribute_value = definitions.Parameter_Value_ENCODING_B
</del><ins>+                        if parameter_name.upper() == &quot;BASE64&quot; and ParserContext.VCARD_2_BASE64 == ParserContext.PARSER_FIX:
+                            parameter_name = definitions.Parameter_ENCODING
+                            parameter_value = definitions.Parameter_Value_ENCODING_B
</ins><span class="cx">                             stripValueSpaces = True
</span><span class="cx">                     else:
</span><span class="cx">                         txt = txt[1:]
</span><del>-                        attribute_value, txt = stringutils.strduptokenstr(txt, &quot;:;,&quot;)
-                        if attribute_value is None:
-                            raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
</del><ins>+                        parameter_value, txt = stringutils.strduptokenstr(txt, &quot;:;,&quot;)
+                        if parameter_value is None:
+                            raise InvalidProperty(&quot;Invalid property&quot;, data)
</ins><span class="cx"> 
</span><del>-                    # Now add attribute value (decode ^-escaping)
-                    if attribute_name is not None:
-                        attrvalue = PyCalendarAttribute(name=attribute_name, value=decodeParameterValue(attribute_value))
-                        self.mAttributes.setdefault(attribute_name.upper(), []).append(attrvalue)
</del><ins>+                    # Now add parameter value (decode ^-escaping)
+                    if parameter_name is not None:
+                        attrvalue = Parameter(name=parameter_name, value=decodeParameterValue(parameter_value))
+                        self.mParameters.setdefault(parameter_name.upper(), []).append(attrvalue)
</ins><span class="cx"> 
</span><span class="cx">                     # Look for additional values
</span><span class="cx">                     while txt[0] == ',':
</span><span class="cx">                         txt = txt[1:]
</span><del>-                        attribute_value2, txt = stringutils.strduptokenstr(txt, &quot;:;,&quot;)
-                        if attribute_value2 is None:
-                            raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
-                        attrvalue.addValue(decodeParameterValue(attribute_value2))
</del><ins>+                        parameter_value2, txt = stringutils.strduptokenstr(txt, &quot;:;,&quot;)
+                        if parameter_value2 is None:
+                            raise InvalidProperty(&quot;Invalid property&quot;, data)
+                        attrvalue.addValue(decodeParameterValue(parameter_value2))
</ins><span class="cx">                 elif txt[0] == ':':
</span><span class="cx">                     txt = txt[1:]
</span><span class="cx">                     if stripValueSpaces:
</span><span class="cx">                         txt = txt.replace(&quot; &quot;, &quot;&quot;)
</span><del>-                    self.createValue(txt)
-                    txt = None
</del><ins>+                    return txt
</ins><span class="cx"> 
</span><span class="cx">         except IndexError:
</span><del>-            raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
</del><ins>+            raise InvalidProperty(&quot;Invalid property&quot;, data)
</ins><span class="cx"> 
</span><del>-        # We must have a value of some kind
-        if self.mValue is None:
-            raise PyCalendarInvalidProperty(&quot;Invalid property&quot;, data)
</del><span class="cx"> 
</span><del>-        return True
-
-
-    def getText(self):
-        os = StringIO.StringIO()
-        self.generate(os)
-        return os.getvalue()
-
-
-    def generate(self, os):
-
-        # Write it out always with value
-        self.generateValue(os, False)
-
-
-    def generateFiltered(self, os, filter):
-
-        # Check for property in filter and whether value is written out
-        test, novalue = filter.testPropertyValue(self.mName.upper())
-        if test:
-            self.generateValue(os, novalue)
-
-
</del><span class="cx">     # Write out the actual property, possibly skipping the value
</span><span class="cx">     def generateValue(self, os, novalue):
</span><span class="cx"> 
</span><del>-        self.setupValueAttribute()
</del><ins>+        # Special case AB.app PHOTO values
+        if self.mName.upper() == &quot;PHOTO&quot; and self.mValue.getType() == Value.VALUETYPE_BINARY:
+            self.setupValueParameter()
</ins><span class="cx"> 
</span><del>-        # Must write to temp buffer and then wrap
-        sout = StringIO.StringIO()
-        if self.mGroup:
-            sout.write(self.mGroup + &quot;.&quot;)
-        sout.write(self.mName)
</del><ins>+            # Must write to temp buffer and then wrap
+            sout = StringIO.StringIO()
+            if self.mGroup:
+                sout.write(self.mGroup + &quot;.&quot;)
+            sout.write(self.mName)
</ins><span class="cx"> 
</span><del>-        # Write all attributes
-        for key in sorted(self.mAttributes.keys()):
-            for attr in self.mAttributes[key]:
-                sout.write(&quot;;&quot;)
-                attr.generate(sout)
</del><ins>+            # Write all parameters
+            for key in sorted(self.mParameters.keys()):
+                for attr in self.mParameters[key]:
+                    sout.write(&quot;;&quot;)
+                    attr.generate(sout)
</ins><span class="cx"> 
</span><del>-        # Write value
-        sout.write(&quot;:&quot;)
-        if self.mName.upper() == &quot;PHOTO&quot; and self.mValue.getType() == PyCalendarValue.VALUETYPE_BINARY:
-            # Handle AB.app PHOTO values
</del><ins>+            # Write value
+            sout.write(&quot;:&quot;)
</ins><span class="cx">             sout.write(&quot;\r\n&quot;)
</span><span class="cx"> 
</span><span class="cx">             value = self.mValue.getText()
</span><span class="lines">@@ -395,179 +303,31 @@
</span><span class="cx">             sout.write(&quot; &quot;)
</span><span class="cx">             sout.write(value[offset:])
</span><span class="cx">             os.write(sout.getvalue())
</span><ins>+            os.write(&quot;\r\n&quot;)
</ins><span class="cx">         else:
</span><del>-            if self.mValue and not novalue:
-                self.mValue.generate(sout)
</del><ins>+            super(Property, self).generateValue(os, novalue)
</ins><span class="cx"> 
</span><del>-            # Get string text
-            temp = sout.getvalue()
-            sout.close()
</del><span class="cx"> 
</span><del>-            # Look for line length exceed
-            if len(temp) &lt; 75:
-                os.write(temp)
-            else:
-                # Look for valid utf8 range and write that out
-                start = 0
-                written = 0
-                lineWrap = 74
-                while written &lt; len(temp):
-                    # Start 74 chars on from where we are
-                    offset = start + lineWrap
-                    if offset &gt;= len(temp):
-                        line = temp[start:]
-                        os.write(line)
-                        written = len(temp)
-                    else:
-                        # Check whether next char is valid utf8 lead byte
-                        while (temp[offset] &gt; 0x7F) and ((ord(temp[offset]) &amp; 0xC0) == 0x80):
-                            # Step back until we have a valid char
-                            offset -= 1
-
-                        line = temp[start:offset]
-                        os.write(line)
-                        os.write(&quot;\r\n &quot;)
-                        lineWrap = 73   # We are now adding a space at the start
-                        written += offset - start
-                        start = offset
-
-        os.write(&quot;\r\n&quot;)
-
-
-    def _init_PyCalendarProperty(self):
-        self.mGroup = None
-        self.mName = &quot;&quot;
-        self.mAttributes = {}
-        self.mValue = None
-
-
-    def createValue(self, data):
-        # Tidy first
-        self.mValue = None
-
-        # Get value type from property name
-        valueType = Property.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarValue.VALUETYPE_TEXT)
-
-        # Check whether custom value is set
-        if definitions.Parameter_VALUE in self.mAttributes:
-            attr = self.getAttributeValue(definitions.Parameter_VALUE)
-            if attr != definitions.Value_TEXT or self.mName.upper() not in Property.sTextVariants:
-                valueType = Property.sValueTypeMap.get(attr, valueType)
-
-        # Check for multivalued
-        if self.mName.upper() in Property.sMultiValues:
-            self.mValue = PyCalendarMultiValue(valueType)
-        else:
-            # Create the type
-            self.mValue = PyCalendarValue.createFromType(valueType)
-
-        # Now parse the data
-        try:
-            if valueType in (PyCalendarValue.VALUETYPE_DATE, PyCalendarValue.VALUETYPE_DATETIME):
-                # vCard supports a slightly different, expanded form, of date
-                self.mValue.parse(data, fullISO=True)
-            else:
-                self.mValue.parse(data)
-        except ValueError:
-            raise PyCalendarInvalidProperty(&quot;Invalid property value&quot;, data)
-
-
-    def setValue(self, value):
-        # Tidy first
-        self.mValue = None
-
-        # Get value type from property name
-        valueType = Property.sDefaultValueTypeMap.get(self.mName.upper(), PyCalendarUnknownValue)
-
-        # Check whether custom value is set
-        if definitions.Parameter_VALUE in self.mAttributes:
-            attr = self.getAttributeValue(definitions.Parameter_VALUE)
-            if attr != definitions.Value_TEXT or self.mName.upper() not in Property.sTextVariants:
-                valueType = Property.sValueTypeMap.get(attr, valueType)
-
-        # Check for multivalued
-        if self.mName.upper() in Property.sMultiValues:
-            self.mValue = PyCalendarMultiValue(valueType)
-        else:
-            # Create the type
-            self.mValue = PyCalendarValue.createFromType(valueType)
-
-        self.mValue.setValue(value)
-
-
-    def setupValueAttribute(self):
-        if definitions.Parameter_VALUE in self.mAttributes:
-            del self.mAttributes[definitions.Parameter_VALUE]
-
-        # Only if we have a value right now
-        if self.mValue is None:
-            return
-
-        # See if current type is default for this property. If there is no mapping available,
-        # then always add VALUE if it is not TEXT.
-        default_type = Property.sDefaultValueTypeMap.get(self.mName.upper())
-        actual_type = self.mValue.getType()
-        if default_type is None or default_type != actual_type:
-            actual_value = self.sTypeValueMap.get(actual_type)
-            if actual_value is not None and (default_type is not None or actual_type != PyCalendarValue.VALUETYPE_TEXT):
-                self.mAttributes.setdefault(definitions.Parameter_VALUE, []).append(PyCalendarAttribute(name=definitions.Parameter_VALUE, value=actual_value))
-
-
</del><span class="cx">     # Creation
</span><del>-    def _init_attr_value_int(self, ival):
-        # Value
-        self.mValue = PyCalendarIntegerValue(value=ival)
-
-        # Attributes
-        self.setupValueAttribute()
-
-
-    def _init_attr_value_text(self, txt, value_type):
-        # Value
-        self.mValue = PyCalendarValue.createFromType(value_type)
-        if isinstance(self.mValue, PyCalendarPlainTextValue) or isinstance(self.mValue, PyCalendarUnknownValue):
-            self.mValue.setValue(txt)
-
-        # Attributes
-        self.setupValueAttribute()
-
-
</del><span class="cx">     def _init_attr_value_adr(self, reqstatus):
</span><span class="cx">         # Value
</span><span class="cx">         self.mValue = AdrValue(reqstatus)
</span><span class="cx"> 
</span><del>-        # Attributes
-        self.setupValueAttribute()
</del><ins>+        # Parameters
+        self.setupValueParameter()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def _init_attr_value_n(self, reqstatus):
</span><span class="cx">         # Value
</span><span class="cx">         self.mValue = NValue(reqstatus)
</span><span class="cx"> 
</span><del>-        # Attributes
-        self.setupValueAttribute()
</del><ins>+        # Parameters
+        self.setupValueParameter()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def _init_attr_value_org(self, reqstatus):
</span><span class="cx">         # Value
</span><span class="cx">         self.mValue = OrgValue(reqstatus)
</span><span class="cx"> 
</span><del>-        # Attributes
-        self.setupValueAttribute()
-
-
-    def _init_attr_value_datetime(self, dt):
-        # Value
-        self.mValue = PyCalendarDateTimeValue(value=dt)
-
-        # Attributes
-        self.setupValueAttribute()
-
-
-    def _init_attr_value_utcoffset(self, utcoffset):
-        # Value
-        self.mValue = PyCalendarUTCOffsetValue()
-        self.mValue.setValue(utcoffset.getValue())
-
-        # Attributes
-        self.setupValueAttribute()
</del><ins>+        # Parameters
+        self.setupValueParameter()
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardtests__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/tests/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> #
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_adrpyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardteststest_adrpy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/tests/test_adr.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/tests/test_adr.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_adr.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_adr.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,50 @@
</span><ins>+##
+#    Copyright (c) 2011-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.vcard.adr import Adr
+import unittest
+
+class TestAdrValue(unittest.TestCase):
+
+    def testInit(self):
+        data = (
+            (
+                (&quot;pobox&quot;, &quot;extended&quot;, &quot;street&quot;, &quot;locality&quot;, &quot;region&quot;, &quot;postalcode&quot;, &quot;country&quot;),
+                &quot;pobox;extended;street;locality;region;postalcode;country&quot;,
+            ),
+            (
+                ((&quot;pobox&quot;,), (&quot;extended&quot;,), (&quot;street1&quot;, &quot;street2&quot;,), &quot;locality&quot;, &quot;region&quot;, (), &quot;country&quot;),
+                &quot;pobox;extended;street1,street2;locality;region;;country&quot;,
+            ),
+        )
+
+        for args, result in data:
+            a = Adr(*args)
+
+            self.assertEqual(
+                a.getValue(),
+                args,
+            )
+
+            self.assertEqual(
+                a.getText(),
+                result,
+            )
+
+            self.assertEqual(
+                a.duplicate().getText(),
+                result,
+            )
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_adrvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardteststest_adrvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/tests/test_adrvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/tests/test_adrvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_adrvalue.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_adrvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,61 @@
</span><ins>+##
+#    Copyright (c) 2011-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.vcard.adrvalue import AdrValue
+from pycalendar.vcard.property import Property
+import unittest
+
+class TestAdrValue(unittest.TestCase):
+
+    def testParseValue(self):
+
+        items = (
+            (&quot;&quot;, &quot;;;;;;;&quot;),
+            (&quot;;&quot;, &quot;;;;;;;&quot;),
+            (&quot;;;;;;;&quot;, &quot;;;;;;;&quot;),
+            (&quot;;;123 Main Street;Any Town;CA;91921-1234&quot;, &quot;;;123 Main Street;Any Town;CA;91921-1234;&quot;),
+            (&quot;;;;;;;USA&quot;, &quot;;;;;;;USA&quot;),
+            (&quot;POB1&quot;, &quot;POB1;;;;;;&quot;),
+            (&quot;;EXT&quot;, &quot;;EXT;;;;;&quot;),
+            (&quot;;;123 Main Street,The Cards;Any Town;CA;91921-1234&quot;, &quot;;;123 Main Street,The Cards;Any Town;CA;91921-1234;&quot;),
+            (&quot;;;123 Main\, Street,The Cards;Any Town;CA;91921-1234&quot;, &quot;;;123 Main\, Street,The Cards;Any Town;CA;91921-1234;&quot;),
+            (&quot;;;123 Main\, Street,The\, Cards;Any Town;CA;91921-1234&quot;, &quot;;;123 Main\, Street,The\, Cards;Any Town;CA;91921-1234;&quot;),
+        )
+
+        for item, result in items:
+            req = AdrValue()
+            req.parse(item, &quot;vcard&quot;)
+            test = req.getText()
+            self.assertEqual(test, result, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
+
+
+    def testParseProperty(self):
+
+        items = (
+            (&quot;ADR:&quot;, &quot;ADR:;;;;;;&quot;),
+            (&quot;ADR:;&quot;, &quot;ADR:;;;;;;&quot;),
+            (&quot;ADR:;;;;;;&quot;, &quot;ADR:;;;;;;&quot;),
+            (&quot;ADR:;;123 Main Street;Any Town;CA;91921-1234&quot;, &quot;ADR:;;123 Main Street;Any Town;CA;91921-1234;&quot;),
+            (&quot;ADR:;;;;;;USA&quot;, &quot;ADR:;;;;;;USA&quot;),
+            (&quot;ADR:POB1&quot;, &quot;ADR:POB1;;;;;;&quot;),
+            (&quot;ADR:;EXT&quot;, &quot;ADR:;EXT;;;;;&quot;),
+            (&quot;ADR;VALUE=TEXT:;;123 Main Street;Any Town;CA;91921-1234&quot;, &quot;ADR:;;123 Main Street;Any Town;CA;91921-1234;&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="PyCalendartrunksrcpycalendarvcardteststest_cardpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/tests/test_card.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_card.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_card.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,7 +14,7 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.exceptions import PyCalendarInvalidData
</del><ins>+from pycalendar.exceptions import InvalidData
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> from pycalendar.vcard.card import Card
</span><span class="cx"> from pycalendar.vcard.property import Property
</span><span class="lines">@@ -343,7 +343,7 @@
</span><span class="cx"> 
</span><span class="cx">         for item, results in data:
</span><span class="cx"> 
</span><del>-            cards = Card.parseMultiple(StringIO.StringIO(item))
</del><ins>+            cards = Card.parseMultipleTextData(StringIO.StringIO(item))
</ins><span class="cx">             self.assertEqual(len(cards), len(results))
</span><span class="cx">             for card, result in zip(cards, results):
</span><span class="cx">                 self.assertEqual(str(card), result, &quot;\n&quot;.join(difflib.unified_diff(str(card).splitlines(), result.splitlines())))
</span><span class="lines">@@ -383,7 +383,7 @@
</span><span class="cx"> REV:20110323T202004Z
</span><span class="cx"> TEL;type=WORK;type=pref:555-1212
</span><span class="cx"> TEL;type=HOME:532-1234
</span><del>-X-ABUID:5B77BC10-E9DB-48C4-8BE1-BAB5E38E1E43:ABPerson
</del><ins>+X-ABUID:5B77BC10-E9DB-48C4-8BE1-BAB5E38E1E43\:ABPerson
</ins><span class="cx"> END:VCARD
</span><span class="cx"> &quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;)
</span><span class="cx"> 
</span><span class="lines">@@ -473,7 +473,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for item in data:
</span><del>-            self.assertRaises(PyCalendarInvalidData, Card.parseText, item)
</del><ins>+            self.assertRaises(InvalidData, Card.parseText, item)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def testParseBlank(self):
</span><span class="lines">@@ -561,7 +561,7 @@
</span><span class="cx">         save = ParserContext.BLANK_LINES_IN_DATA
</span><span class="cx">         for item in data:
</span><span class="cx">             ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_RAISE
</span><del>-            self.assertRaises(PyCalendarInvalidData, Card.parseText, item)
</del><ins>+            self.assertRaises(InvalidData, Card.parseText, item)
</ins><span class="cx"> 
</span><span class="cx">             ParserContext.BLANK_LINES_IN_DATA = ParserContext.PARSER_IGNORE
</span><span class="cx">             lines = item.split(&quot;\r\n&quot;)
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_npyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardteststest_npy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/tests/test_n.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/tests/test_n.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_n.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_n.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,92 @@
</span><ins>+##
+#    Copyright (c) 2011-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.vcard.n import N
+import unittest
+
+class TestAdrValue(unittest.TestCase):
+
+    def testInit(self):
+
+        data = (
+            (
+                (&quot;last&quot;, &quot;first&quot;, &quot;middle&quot;, &quot;prefix&quot;, &quot;suffix&quot;),
+                &quot;last;first;middle;prefix;suffix&quot;,
+                &quot;prefix first middle last suffix&quot;,
+            ),
+            (
+                (&quot;last&quot;, (&quot;first&quot;,), (&quot;middle1&quot;, &quot;middle2&quot;,), (), (&quot;suffix&quot;,)),
+                &quot;last;first;middle1,middle2;;suffix&quot;,
+                &quot;first middle1 middle2 last suffix&quot;,
+            ),
+        )
+
+        for args, result, fullName in data:
+            n = N(*args)
+
+            self.assertEqual(
+                n.getValue(),
+                args,
+            )
+
+            self.assertEqual(
+                n.getText(),
+                result,
+            )
+
+            self.assertEqual(
+                n.getFullName(),
+                fullName,
+            )
+
+            self.assertEqual(
+                n.duplicate().getText(),
+                result,
+            )
+
+
+    def testInitWithKeywords(self):
+
+        data = (
+            (
+                {&quot;first&quot;: &quot;first&quot;, &quot;last&quot;: &quot;last&quot;, &quot;middle&quot;: &quot;middle&quot;, &quot;prefix&quot;: &quot;prefix&quot;, &quot;suffix&quot;: &quot;suffix&quot;},
+                &quot;last;first;middle;prefix;suffix&quot;,
+                &quot;prefix first middle last suffix&quot;,
+            ),
+            (
+                {&quot;first&quot;: (&quot;first&quot;,), &quot;last&quot;: &quot;last&quot;, &quot;middle&quot;: (&quot;middle1&quot;, &quot;middle2&quot;,), &quot;prefix&quot;: (), &quot;suffix&quot;: (&quot;suffix&quot;,)},
+                &quot;last;first;middle1,middle2;;suffix&quot;,
+                &quot;first middle1 middle2 last suffix&quot;,
+            ),
+        )
+
+        for kwargs, result, fullName in data:
+            n = N(**kwargs)
+
+            self.assertEqual(
+                n.getText(),
+                result,
+            )
+
+            self.assertEqual(
+                n.getFullName(),
+                fullName,
+            )
+
+            self.assertEqual(
+                n.duplicate().getText(),
+                result,
+            )
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_nvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardteststest_nvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/tests/test_nvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/tests/test_nvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_nvalue.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_nvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,58 @@
</span><ins>+##
+#    Copyright (c) 2011-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.vcard.nvalue import NValue
+from pycalendar.vcard.property import Property
+import unittest
+
+class TestNValue(unittest.TestCase):
+
+    def testParseValue(self):
+
+        items = (
+            (&quot;&quot;, &quot;;;;;&quot;),
+            (&quot;;&quot;, &quot;;;;;&quot;),
+            (&quot;;;;;&quot;, &quot;;;;;&quot;),
+            (&quot;Cyrus;Daboo;;Dr.&quot;, &quot;Cyrus;Daboo;;Dr.;&quot;),
+            (&quot;;;;;PhD.&quot;, &quot;;;;;PhD.&quot;),
+            (&quot;Cyrus&quot;, &quot;Cyrus;;;;&quot;),
+            (&quot;;Daboo&quot;, &quot;;Daboo;;;&quot;),
+        )
+
+        for item, result in items:
+            req = NValue()
+            req.parse(item, &quot;vcard&quot;)
+            test = req.getText()
+            self.assertEqual(test, result, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
+
+
+    def testParseProperty(self):
+
+        items = (
+            (&quot;N:&quot;, &quot;N:;;;;&quot;),
+            (&quot;N:;&quot;, &quot;N:;;;;&quot;),
+            (&quot;N:;;;;&quot;, &quot;N:;;;;&quot;),
+            (&quot;N:Cyrus;Daboo;;Dr.&quot;, &quot;N:Cyrus;Daboo;;Dr.;&quot;),
+            (&quot;N:;;;;PhD.&quot;, &quot;N:;;;;PhD.&quot;),
+            (&quot;N:Cyrus&quot;, &quot;N:Cyrus;;;;&quot;),
+            (&quot;N:;Daboo&quot;, &quot;N:;Daboo;;;&quot;),
+            (&quot;N;VALUE=TEXT:Cyrus;Daboo;;Dr.&quot;, &quot;N:Cyrus;Daboo;;Dr.;&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="PyCalendartrunksrcpycalendarvcardteststest_orgvaluepyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardteststest_orgvaluepy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/tests/test_orgvalue.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/tests/test_orgvalue.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_orgvalue.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_orgvalue.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,52 @@
</span><ins>+##
+#    Copyright (c) 2011-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.vcard.orgvalue import OrgValue
+from pycalendar.vcard.property import Property
+import unittest
+
+class TestNValue(unittest.TestCase):
+
+    def testParseValue(self):
+
+        items = (
+            (&quot;&quot;, &quot;&quot;),
+            (&quot;Example&quot;, &quot;Example&quot;),
+            (&quot;Example\, Inc.&quot;, &quot;Example\, Inc.&quot;),
+            (&quot;Example\; Inc;Dept. of Silly Walks&quot;, &quot;Example\; Inc;Dept. of Silly Walks&quot;),
+        )
+
+        for item, result in items:
+            req = OrgValue()
+            req.parse(item, &quot;vcard&quot;)
+            test = req.getText()
+            self.assertEqual(test, result, &quot;Failed to parse and re-generate '%s'&quot; % (item,))
+
+
+    def testParseProperty(self):
+
+        items = (
+            (&quot;ORG:&quot;, &quot;ORG:&quot;),
+            (&quot;ORG:Example&quot;, &quot;ORG:Example&quot;),
+            (&quot;ORG:Example\, Inc.&quot;, &quot;ORG:Example\, Inc.&quot;),
+            (&quot;ORG:Example\; Inc;Dept. of Silly Walks&quot;, &quot;ORG:Example\; Inc;Dept. of Silly Walks&quot;),
+            (&quot;ORG;VALUE=TEXT:Example&quot;, &quot;ORG:Example&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="PyCalendartrunksrcpycalendarvcardteststest_propertypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/tests/test_property.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_property.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_property.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,8 +14,8 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.exceptions import PyCalendarInvalidProperty
</del><ins>+from pycalendar.parameter import Parameter
+from pycalendar.exceptions import InvalidProperty
</ins><span class="cx"> from pycalendar.parser import ParserContext
</span><span class="cx"> from pycalendar.vcard.property import Property
</span><span class="cx"> import unittest
</span><span class="lines">@@ -34,13 +34,14 @@
</span><span class="cx">         &quot;item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;CA;11111;USA&quot;,
</span><span class="cx">         &quot;X-Test:Some\, text.&quot;,
</span><span class="cx">         &quot;X-Test;VALUE=URI:geio:123.123,123.123&quot;,
</span><ins>+        &quot;X-ABUID:5B77BC10-E9DB-48C4-8BE1-BAB5E38E1E43\\:ABPerson&quot;,
+        &quot;X-ABUID:5B77BC10-E9DB-48C4-8BE1-BAB5E38E1E43:ABPerson&quot;,
</ins><span class="cx">     )
</span><span class="cx"> 
</span><span class="cx">     def testParseGenerate(self):
</span><span class="cx"> 
</span><span class="cx">         for data in TestProperty.test_data:
</span><del>-            prop = Property()
-            prop.parse(data)
</del><ins>+            prop = Property.parseText(data)
</ins><span class="cx">             propstr = str(prop)
</span><span class="cx">             self.assertEqual(propstr[:-2], data, &quot;Failed parse/generate: %s to %s&quot; % (data, propstr,))
</span><span class="cx"> 
</span><span class="lines">@@ -48,10 +49,8 @@
</span><span class="cx">     def testEquality(self):
</span><span class="cx"> 
</span><span class="cx">         for data in TestProperty.test_data:
</span><del>-            prop1 = Property()
-            prop1.parse(data)
-            prop2 = Property()
-            prop2.parse(data)
</del><ins>+            prop1 = Property.parseText(data)
+            prop2 = Property.parseText(data)
</ins><span class="cx">             self.assertEqual(prop1, prop2, &quot;Failed equality: %s&quot; % (data,))
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -64,8 +63,7 @@
</span><span class="cx">         save = ParserContext.INVALID_ESCAPE_SEQUENCES
</span><span class="cx">         for data in test_bad_data:
</span><span class="cx">             ParserContext.INVALID_ESCAPE_SEQUENCES = ParserContext.PARSER_RAISE
</span><del>-            prop = Property()
-            self.assertRaises(PyCalendarInvalidProperty, prop.parse, data)
</del><ins>+            self.assertRaises(InvalidProperty, Property.parseText, data)
</ins><span class="cx">         ParserContext.INVALID_ESCAPE_SEQUENCES = save
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -73,8 +71,7 @@
</span><span class="cx"> 
</span><span class="cx">         hashes = []
</span><span class="cx">         for item in TestProperty.test_data:
</span><del>-            prop = Property()
-            prop.parse(item)
</del><ins>+            prop = Property.parseText(item)
</ins><span class="cx">             hashes.append(hash(prop))
</span><span class="cx">         hashes.sort()
</span><span class="cx">         for i in range(1, len(hashes)):
</span><span class="lines">@@ -98,19 +95,17 @@
</span><span class="cx">     def testParameterEncodingDecoding(self):
</span><span class="cx"> 
</span><span class="cx">         prop = Property(name=&quot;X-FOO&quot;, value=&quot;Test&quot;)
</span><del>-        prop.addAttribute(PyCalendarAttribute(&quot;X-BAR&quot;, &quot;\&quot;Check\&quot;&quot;))
</del><ins>+        prop.addParameter(Parameter(&quot;X-BAR&quot;, &quot;\&quot;Check\&quot;&quot;))
</ins><span class="cx">         self.assertEqual(str(prop), &quot;X-FOO;X-BAR=^'Check^':Test\r\n&quot;)
</span><span class="cx"> 
</span><del>-        prop.addAttribute(PyCalendarAttribute(&quot;X-BAR2&quot;, &quot;Check\nThis\tOut\n&quot;))
</del><ins>+        prop.addParameter(Parameter(&quot;X-BAR2&quot;, &quot;Check\nThis\tOut\n&quot;))
</ins><span class="cx">         self.assertEqual(str(prop), &quot;X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test\r\n&quot;)
</span><span class="cx"> 
</span><span class="cx">         data = &quot;X-FOO;X-BAR=^'Check^':Test&quot;
</span><del>-        prop = Property()
-        prop.parse(data)
-        self.assertEqual(prop.getAttributeValue(&quot;X-BAR&quot;), &quot;\&quot;Check\&quot;&quot;)
</del><ins>+        prop = Property.parseText(data)
+        self.assertEqual(prop.getParameterValue(&quot;X-BAR&quot;), &quot;\&quot;Check\&quot;&quot;)
</ins><span class="cx"> 
</span><span class="cx">         data = &quot;X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test&quot;
</span><del>-        prop = Property()
-        prop.parse(data)
-        self.assertEqual(prop.getAttributeValue(&quot;X-BAR&quot;), &quot;\&quot;Check\&quot;&quot;)
-        self.assertEqual(prop.getAttributeValue(&quot;X-BAR2&quot;), &quot;Check\nThis\tOut\n&quot;)
</del><ins>+        prop = Property.parseText(data)
+        self.assertEqual(prop.getParameterValue(&quot;X-BAR&quot;), &quot;\&quot;Check\&quot;&quot;)
+        self.assertEqual(prop.getParameterValue(&quot;X-BAR2&quot;), &quot;Check\nThis\tOut\n&quot;)
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardteststest_validationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/tests/test_validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/tests/test_validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/tests/test_validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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">@@ -14,7 +14,7 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.exceptions import PyCalendarValidationError
</del><ins>+from pycalendar.exceptions import ValidationError
</ins><span class="cx"> from pycalendar.vcard.card import Card
</span><span class="cx"> import unittest
</span><span class="cx"> 
</span><span class="lines">@@ -210,7 +210,7 @@
</span><span class="cx">         for title, test_old, test_new, test_fixed, test_unfixed, test_raises in data:
</span><span class="cx">             card = Card.parseText(test_old)
</span><span class="cx">             if test_raises:
</span><del>-                self.assertRaises(PyCalendarValidationError, card.validate, doFix=False, doRaise=True)
</del><ins>+                self.assertRaises(ValidationError, card.validate, doFix=False, doRaise=True)
</ins><span class="cx">             else:
</span><span class="cx">                 try:
</span><span class="cx">                     fixed, unfixed = card.validate(doFix=False, doRaise=False)
</span></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardvalidationpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/pycalendar/vcard/validation.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/validation.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vcard/validation.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2011-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2011-2013 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></pre></div>
<a id="PyCalendartrunksrcpycalendarvcardxmldefinitionspyfromrev11912PyCalendarbranchesjson2srcpycalendarvcardxmldefinitionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/vcard/xmldefinitions.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/vcard/xmldefinitions.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vcard/xmldefinitions.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/vcard/xmldefinitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,19 @@
</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.
+##
+
+# vCard XML definitions
+
+vCard40_namespace = &quot;urn:ietf:params:xml:ns:vcard-4.0&quot;
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarveventpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vevent.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vevent.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vevent.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,169 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from pycalendar import itipdefinitions
-from pycalendar.componentrecur import PyCalendarComponentRecur
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.property import PyCalendarProperty
-
-class PyCalendarVEvent(PyCalendarComponentRecur):
-
-    propertyCardinality_1 = (
-        definitions.cICalProperty_DTSTAMP,
-        definitions.cICalProperty_UID,
-    )
-
-    propertyCardinality_0_1 = (
-        definitions.cICalProperty_CLASS,
-        definitions.cICalProperty_CREATED,
-        definitions.cICalProperty_DESCRIPTION,
-        definitions.cICalProperty_GEO,
-        definitions.cICalProperty_LAST_MODIFIED,
-        definitions.cICalProperty_LOCATION,
-        definitions.cICalProperty_ORGANIZER,
-        definitions.cICalProperty_PRIORITY,
-        definitions.cICalProperty_SEQUENCE,
-        # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
-        definitions.cICalProperty_SUMMARY,
-        definitions.cICalProperty_TRANSP,
-        definitions.cICalProperty_URL,
-        definitions.cICalProperty_RECURRENCE_ID,
-        definitions.cICalProperty_RRULE,
-        definitions.cICalProperty_DTEND,
-        definitions.cICalProperty_DURATION,
-    )
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    def __init__(self, parent=None):
-        super(PyCalendarVEvent, self).__init__(parent=parent)
-        self.mStatus = definitions.eStatus_VEvent_None
-
-
-    def duplicate(self, parent=None):
-        other = super(PyCalendarVEvent, self).duplicate(parent=parent)
-        other.mStatus = self.mStatus
-        return other
-
-
-    def getType(self):
-        return definitions.cICalComponent_VEVENT
-
-
-    def getMimeComponentName(self):
-        return itipdefinitions.cICalMIMEComponent_VEVENT
-
-
-    def addComponent(self, comp):
-        # We can embed the alarm components only
-        if comp.getType() == definitions.cICalComponent_VALARM:
-            super(PyCalendarVEvent, self).addComponent(comp)
-        else:
-            raise ValueError
-
-
-    def getStatus(self):
-        return self.mStatus
-
-
-    def setStatus(self, status):
-        self.mStatus = status
-
-
-    def finalise(self):
-        # Do inherited
-        super(PyCalendarVEvent, self).finalise()
-
-        temp = self.loadValueString(definitions.cICalProperty_STATUS)
-        if temp is not None:
-            if temp == definitions.cICalProperty_STATUS_TENTATIVE:
-                self.mStatus = definitions.eStatus_VEvent_Tentative
-            elif temp == definitions.cICalProperty_STATUS_CONFIRMED:
-                self.mStatus = definitions.eStatus_VEvent_Confirmed
-            elif temp == definitions.cICalProperty_STATUS_CANCELLED:
-                self.mStatus = definitions.eStatus_VEvent_Cancelled
-
-
-    def validate(self, doFix=False):
-        &quot;&quot;&quot;
-        Validate the data in this component and optionally fix any problems, else raise. If
-        loggedProblems is not None it must be a C{list} and problem descriptions are appended
-        to that.
-        &quot;&quot;&quot;
-
-        fixed, unfixed = super(PyCalendarVEvent, self).validate(doFix)
-
-        # Extra constraint: if METHOD not present, DTSTART must be
-        if self.mParentComponent and not self.mParentComponent.hasProperty(definitions.cICalProperty_METHOD):
-            if not self.hasProperty(definitions.cICalProperty_DTSTART):
-                # Cannot fix a missing required property
-                logProblem = &quot;[%s] Missing required property: %s&quot; % (self.getType(), definitions.cICalProperty_DTSTART,)
-                unfixed.append(logProblem)
-
-        # Extra constraint: only one of DTEND or DURATION
-        if self.hasProperty(definitions.cICalProperty_DTEND) and self.hasProperty(definitions.cICalProperty_DURATION):
-            # Fix by removing the DTEND
-            logProblem = &quot;[%s] Properties must not both be present: %s, %s&quot; % (
-                self.getType(),
-                definitions.cICalProperty_DTEND,
-                definitions.cICalProperty_DURATION,
-            )
-            if doFix:
-                self.removeProperties(definitions.cICalProperty_DTEND)
-                fixed.append(logProblem)
-            else:
-                unfixed.append(logProblem)
-
-        return fixed, unfixed
-
-
-    # Editing
-    def editStatus(self, status):
-        # Only if it is different
-        if self.mStatus != status:
-            # Updated cached values
-            self.mStatus = status
-
-            # Remove existing STATUS items
-            self.removeProperties(definitions.cICalProperty_STATUS)
-
-            # Now create properties
-            value = None
-            if status == definitions.eStatus_VEvent_None:
-                pass
-            elif status == definitions.eStatus_VEvent_Tentative:
-                value = definitions.cICalProperty_STATUS_TENTATIVE
-            elif status == definitions.eStatus_VEvent_Confirmed:
-                value = definitions.cICalProperty_STATUS_CONFIRMED
-            elif status == definitions.eStatus_VEvent_Cancelled:
-                value = definitions.cICalProperty_STATUS_CANCELLED
-            else:
-                pass
-
-            if value is not None:
-                prop = PyCalendarProperty(definitions.cICalProperty_STATUS, value)
-                self.addProperty(prop)
-
-
-    def sortedPropertyKeyOrder(self):
-        return (
-            definitions.cICalProperty_UID,
-            definitions.cICalProperty_RECURRENCE_ID,
-            definitions.cICalProperty_DTSTART,
-            definitions.cICalProperty_DURATION,
-            definitions.cICalProperty_DTEND,
-        )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvfreebusypy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vfreebusy.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vfreebusy.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vfreebusy.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,345 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from pycalendar import itipdefinitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.freebusy import PyCalendarFreeBusy
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.periodvalue import PyCalendarPeriodValue
-from pycalendar.property import PyCalendarProperty
-from pycalendar.value import PyCalendarValue
-
-class PyCalendarVFreeBusy(PyCalendarComponent):
-
-    propertyCardinality_1 = (
-        definitions.cICalProperty_DTSTAMP,
-        definitions.cICalProperty_UID,
-    )
-
-    propertyCardinality_0_1 = (
-        definitions.cICalProperty_CONTACT,
-        definitions.cICalProperty_DTSTART,
-        definitions.cICalProperty_DTEND,
-        definitions.cICalProperty_ORGANIZER,
-        definitions.cICalProperty_URL,
-    )
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    def __init__(self, parent=None):
-        super(PyCalendarVFreeBusy, self).__init__(parent=parent)
-        self.mStart = PyCalendarDateTime()
-        self.mHasStart = False
-        self.mEnd = PyCalendarDateTime()
-        self.mHasEnd = False
-        self.mDuration = False
-        self.mCachedBusyTime = False
-        self.mSpanPeriod = None
-        self.mBusyTime = None
-
-
-    def duplicate(self, parent=None):
-        other = super(PyCalendarVFreeBusy, self).duplicate(parent=parent)
-        other.mStart = self.mStart.duplicate()
-        other.mHasStart = self.mHasStart
-        other.mEnd = self.mEnd.duplicate()
-        other.mHasEnd = self.mHasEnd
-        other.mDuration = self.mDuration
-        other.mCachedBusyTime = False
-        other.mBusyTime = None
-        return other
-
-
-    def getType(self):
-        return definitions.cICalComponent_VFREEBUSY
-
-
-    def getMimeComponentName(self):
-        return itipdefinitions.cICalMIMEComponent_VFREEBUSY
-
-
-    def finalise(self):
-        # Do inherited
-        super(PyCalendarVFreeBusy, self).finalise()
-
-        # Get DTSTART
-        temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
-        self.mHasStart = temp is not None
-        if self.mHasStart:
-            self.mStart = temp
-
-        # Get DTEND
-        temp = self.loadValueDateTime(definitions.cICalProperty_DTEND)
-        if temp is None:
-            # Try DURATION instead
-            temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
-            if temp is not None:
-                self.mEnd = self.mStart + temp
-                self.mDuration = True
-            else:
-                # Force end to start, which will then be fixed to sensible
-                # value later
-                self.mEnd = self.mStart
-        else:
-            self.mHasEnd = True
-            self.mDuration = False
-            self.mEnd = temp
-
-
-    def fixStartEnd(self):
-        # End is always greater than start if start exists
-        if self.mHasStart and self.mEnd &lt;= self.mStart:
-            # Use the start
-            self.mEnd = self.mStart.duplicate()
-            self.mDuration = False
-
-            # Adjust to appropiate non-inclusive end point
-            if self.mStart.isDateOnly():
-                self.mEnd.offsetDay(1)
-
-                # For all day events it makes sense to use duration
-                self.mDuration = True
-            else:
-                # Use end of current day
-                self.mEnd.offsetDay(1)
-                self.mEnd.setHHMMSS(0, 0, 0)
-
-
-    def getStart(self):
-        return self.mStart
-
-
-    def hasStart(self):
-        return self.mHasStart
-
-
-    def getEnd(self):
-        return self.mEnd
-
-
-    def hasEnd(self):
-        return self.mHasEnd
-
-
-    def useDuration(self):
-        return self.mDuration
-
-
-    def getSpanPeriod(self):
-        return self.mSpanPeriod
-
-
-    def getBusyTime(self):
-        return self.mBusyTime
-
-
-    def editTiming(self):
-        # Updated cached values
-        self.mHasStart = False
-        self.mHasEnd = False
-        self.mDuration = False
-        self.mStart.setToday()
-        self.mEnd.setToday()
-
-        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
-        self.removeProperties(definitions.cICalProperty_DTSTART)
-        self.removeProperties(definitions.cICalProperty_DTEND)
-        self.removeProperties(definitions.cICalProperty_DURATION)
-
-
-    def editTimingStartEnd(self, start, end):
-        # Updated cached values
-        self.mHasStart = self.mHasEnd = True
-        self.mStart = start
-        self.mEnd = end
-        self.mDuration = False
-        self.fixStartEnd()
-
-        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
-        self.removeProperties(definitions.cICalProperty_DTSTART)
-        self.removeProperties(definitions.cICalProperty_DTEND)
-        self.removeProperties(definitions.cICalProperty_DURATION)
-
-        # Now create properties
-        prop = PyCalendarProperty(definitions.cICalProperty_DTSTART, start)
-        self.addProperty(prop)
-
-        # If its an all day event and the end one day after the start, ignore it
-        temp = start.duplicate()
-        temp.offsetDay(1)
-        if not start.isDateOnly() or end != temp:
-            prop = PyCalendarProperty(definitions.cICalProperty_DTEND, end)
-            self.addProperty(prop)
-
-
-    def editTimingStartDuration(self, start, duration):
-        # Updated cached values
-        self.mHasStart = True
-        self.mHasEnd = False
-        self.mStart = start
-        self.mEnd = start + duration
-        self.mDuration = True
-
-        # Remove existing DTSTART &amp; DTEND &amp; DURATION &amp; DUE items
-        self.removeProperties(definitions.cICalProperty_DTSTART)
-        self.removeProperties(definitions.cICalProperty_DTEND)
-        self.removeProperties(definitions.cICalProperty_DURATION)
-        self.removeProperties(definitions.cICalProperty_DUE)
-
-        # Now create properties
-        prop = PyCalendarProperty(definitions.cICalProperty_DTSTART, start)
-        self.addProperty(prop)
-
-        # If its an all day event and the duration is one day, ignore it
-        if (not start.isDateOnly() or (duration.getWeeks() != 0)
-                or (duration.getDays() &gt; 1)):
-            prop = PyCalendarProperty(definitions.cICalProperty_DURATION, duration)
-            self.addProperty(prop)
-
-
-    # Generating info
-    def expandPeriodComp(self, period, list):
-        # Cache the busy-time details if not done already
-        if not self.mCachedBusyTime:
-            self.cacheBusyTime()
-
-        # See if period intersects the busy time span range
-        if (self.mBusyTime is not None) and period.isPeriodOverlap(self.mSpanPeriod):
-            list.append(self)
-
-
-    def expandPeriodFB(self, period, list):
-        # Cache the busy-time details if not done already
-        if not self.mCachedBusyTime:
-            self.cacheBusyTime()
-
-        # See if period intersects the busy time span range
-        if (self.mBusyTime is not None) and period.isPeriodOverlap(self.mSpanPeriod):
-            for fb in self.mBusyTime:
-                list.append(PyCalendarFreeBusy(fb))
-
-
-    def cacheBusyTime(self):
-
-        # Clear out any existing cache
-        self.mBusyTime = []
-
-        # Get all FREEBUSY items and add those that are BUSY
-        min_start = PyCalendarDateTime()
-        max_end = PyCalendarDateTime()
-        props = self.getProperties()
-        result = props.get(definitions.cICalProperty_FREEBUSY, ())
-        for iter in result:
-
-            # Check the properties FBTYPE attribute
-            type = 0
-            is_busy = False
-            if iter.hasAttribute(definitions.cICalAttribute_FBTYPE):
-
-                fbyype = iter.getAttributeValue(definitions.cICalAttribute_FBTYPE)
-                if fbyype.upper() == definitions.cICalAttribute_FBTYPE_BUSY:
-
-                    is_busy = True
-                    type = PyCalendarFreeBusy.BUSY
-
-                elif fbyype.upper() == definitions.cICalAttribute_FBTYPE_BUSYUNAVAILABLE:
-
-                    is_busy = True
-                    type = PyCalendarFreeBusy.BUSYUNAVAILABLE
-
-                elif fbyype.upper() == definitions.cICalAttribute_FBTYPE_BUSYTENTATIVE:
-
-                    is_busy = True
-                    type = PyCalendarFreeBusy.BUSYTENTATIVE
-
-                else:
-
-                    is_busy = False
-                    type = PyCalendarFreeBusy.FREE
-
-            else:
-
-                # Default is busy when no attribute
-                is_busy = True
-                type = PyCalendarFreeBusy.BUSY
-
-            # Add this period
-            if is_busy:
-
-                multi = iter.getMultiValue()
-                if (multi is not None) and (multi.getType() == PyCalendarValue.VALUETYPE_PERIOD):
-
-                    for o in multi.getValues():
-
-                        # Double-check type
-                        period = None
-                        if isinstance(o, PyCalendarPeriodValue):
-                            period = o
-
-                        # Double-check type
-                        if period is not None:
-
-                            self.mBusyTime.append(PyCalendarFreeBusy(type, period.getValue()))
-
-                            if len(self.mBusyTime) == 1:
-
-                                min_start = period.getValue().getStart()
-                                max_end = period.getValue().getEnd()
-
-                            else:
-
-                                if min_start &gt; period.getValue().getStart():
-                                    min_start = period.getValue().getStart()
-                                if max_end &lt; period.getValue().getEnd():
-                                    max_end = period.getValue().getEnd()
-
-        # If nothing present, empty the list
-        if len(self.mBusyTime) == 0:
-
-            self.mBusyTime = None
-
-        else:
-
-            # Sort the list by period
-            self.mBusyTime.sort(cmp=lambda x, y: x.getPeriod().getStart().compareDateTime(y.getPeriod().getStart()))
-
-            # Determine range
-            start = PyCalendarDateTime()
-            end = PyCalendarDateTime()
-            if self.mHasStart:
-                start = self.mStart
-            else:
-                start = min_start
-            if self.mHasEnd:
-                end = self.mEnd
-            else:
-                end = max_end
-
-            self.mSpanPeriod = PyCalendarPeriod(start, end)
-
-        self.mCachedBusyTime = True
-
-
-    def sortedPropertyKeyOrder(self):
-        return (
-            definitions.cICalProperty_UID,
-            definitions.cICalProperty_DTSTART,
-            definitions.cICalProperty_DURATION,
-            definitions.cICalProperty_DTEND,
-        )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvjournalpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vjournal.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vjournal.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vjournal.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,70 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from pycalendar import itipdefinitions
-from pycalendar.componentrecur import PyCalendarComponentRecur
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-
-class PyCalendarVJournal(PyCalendarComponentRecur):
-
-    propertyCardinality_1 = (
-        definitions.cICalProperty_DTSTAMP,
-        definitions.cICalProperty_UID,
-    )
-
-    propertyCardinality_0_1 = (
-        definitions.cICalProperty_CLASS,
-        definitions.cICalProperty_CREATED,
-        definitions.cICalProperty_DTSTART,
-        definitions.cICalProperty_LAST_MODIFIED,
-        definitions.cICalProperty_ORGANIZER,
-        definitions.cICalProperty_RECURRENCE_ID,
-        definitions.cICalProperty_SEQUENCE,
-        # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
-        definitions.cICalProperty_SUMMARY,
-        definitions.cICalProperty_URL,
-        definitions.cICalProperty_RRULE,
-    )
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    def __init__(self, parent=None):
-        super(PyCalendarVJournal, self).__init__(parent=parent)
-
-
-    def duplicate(self, parent=None):
-        return super(PyCalendarVJournal, self).duplicate(parent=parent)
-
-
-    def getType(self):
-        return definitions.cICalComponent_VJOURNAL
-
-
-    def getMimeComponentName(self):
-        return itipdefinitions.cICalMIMEComponent_VJOURNAL
-
-
-    def finalise(self):
-        super(PyCalendarVJournal, self).finalise()
-
-
-    def sortedPropertyKeyOrder(self):
-        return (
-            definitions.cICalProperty_UID,
-            definitions.cICalProperty_RECURRENCE_ID,
-            definitions.cICalProperty_DTSTART,
-        )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvtimezonepy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vtimezone.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vtimezone.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vtimezone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,285 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-
-class PyCalendarVTimezone(PyCalendarComponent):
-
-    propertyCardinality_1 = (
-        definitions.cICalProperty_TZID,
-    )
-
-    propertyCardinality_0_1 = (
-        definitions.cICalProperty_LAST_MODIFIED,
-        definitions.cICalProperty_TZURL,
-    )
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    UTCOFFSET_CACHE_MAX_ENTRIES = 100000
-
-    sortSubComponents = False
-
-    def __init__(self, parent=None):
-        super(PyCalendarVTimezone, self).__init__(parent=parent)
-        self.mID = &quot;&quot;
-        self.mUTCOffsetSortKey = None
-        self.mCachedExpandAllMaxYear = None
-        self.mCachedOffsets = None
-
-
-    def duplicate(self, parent=None):
-        other = super(PyCalendarVTimezone, self).duplicate(parent=parent)
-        other.mID = self.mID
-        other.mUTCOffsetSortKey = self.mUTCOffsetSortKey
-        return other
-
-
-    def getType(self):
-        return definitions.cICalComponent_VTIMEZONE
-
-
-    def getMimeComponentName(self):
-        # Cannot be sent as a separate MIME object
-        return None
-
-
-    def addComponent(self, comp):
-        # We can embed the timezone components only
-        if ((comp.getType() == definitions.cICalComponent_STANDARD)
-                or (comp.getType() == definitions.cICalComponent_DAYLIGHT)):
-            super(PyCalendarVTimezone, self).addComponent(comp)
-        else:
-            raise ValueError
-
-
-    def getMapKey(self):
-        return self.mID
-
-
-    def finalise(self):
-        # Get TZID
-        temp = self.loadValueString(definitions.cICalProperty_TZID)
-        if temp is not None:
-            self.mID = temp
-
-        # Sort sub-components by DTSTART
-        self.mComponents.sort(key=lambda x: x.getStart())
-
-        # Do inherited
-        super(PyCalendarVTimezone, self).finalise()
-
-
-    def validate(self, doFix=False):
-        &quot;&quot;&quot;
-        Validate the data in this component and optionally fix any problems, else raise. If
-        loggedProblems is not None it must be a C{list} and problem descriptions are appended
-        to that.
-        &quot;&quot;&quot;
-
-        fixed, unfixed = super(PyCalendarVTimezone, self).validate(doFix)
-
-        # Must have at least one STANDARD or DAYLIGHT sub-component
-        for component in self.mComponents:
-            if component.getType() in (definitions.cICalComponent_STANDARD, definitions.cICalComponent_DAYLIGHT):
-                break
-        else:
-            # Cannot fix a missing required component
-            logProblem = &quot;[%s] At least one component must be present: %s or %s&quot; % (
-                self.getType(),
-                definitions.cICalComponent_STANDARD,
-                definitions.cICalComponent_DAYLIGHT,
-            )
-            unfixed.append(logProblem)
-
-        return fixed, unfixed
-
-
-    def getID(self):
-        return self.mID
-
-
-    def getUTCOffsetSortKey(self):
-        if self.mUTCOffsetSortKey is None:
-            # Take time from first element
-            if len(self.mComponents) &gt; 0:
-                # Initial offset provides the primary key
-                utc_offset1 = self.mComponents[0].getUTCOffset()
-
-                # Presence of secondary is the next key
-                utc_offset2 = utc_offset1
-                if len(self.mComponents) &gt; 1:
-                    utc_offset2 = self.mComponents[1].getUTCOffset()
-
-                # Create key
-                self.mUTCOffsetSortKey = (utc_offset1 + utc_offset2) / 2
-            else:
-                self.mUTCOffsetSortKey = 0
-
-        return self.mUTCOffsetSortKey
-
-
-    def getTimezoneOffsetSeconds(self, dt):
-        &quot;&quot;&quot;
-        Caching implementation of expansion. We cache the entire set of transitions up to one year ahead
-        of the requested time.
-        &quot;&quot;&quot;
-
-        # Need to make the incoming date-time relative to the DTSTART in the
-        # timezone component for proper comparison.
-        # This means making the incoming date-time a floating (no timezone)
-        # item
-        temp = dt.duplicate()
-        temp.setTimezoneID(None)
-
-        # Check whether we need to recache
-        if self.mCachedExpandAllMaxYear is None or temp.mYear &gt;= self.mCachedExpandAllMaxYear:
-            cacheMax = temp.duplicate()
-            cacheMax.setHHMMSS(0, 0, 0)
-            cacheMax.offsetYear(2)
-            cacheMax.setMonth(1)
-            cacheMax.setDay(1)
-            self.mCachedExpandAll = self.expandAll(None, cacheMax)
-            self.mCachedExpandAllMaxYear = cacheMax.mYear
-            self.mCachedOffsets = {}
-
-        # Now search for the transition just below the time we want
-        if len(self.mCachedExpandAll):
-            cacheKey = (temp.mYear, temp.mMonth, temp.mDay, temp.mHours, temp.mMinutes,)
-            i = self.mCachedOffsets.get(cacheKey)
-            if i is None:
-                i = PyCalendarVTimezone.tuple_bisect_right(self.mCachedExpandAll, temp)
-                if len(self.mCachedOffsets) &gt;= self.UTCOFFSET_CACHE_MAX_ENTRIES:
-                    self.mCachedOffsets = {}
-                self.mCachedOffsets[cacheKey] = i
-            if i != 0:
-                return self.mCachedExpandAll[i - 1][2]
-
-        return 0
-
-
-    def getTimezoneDescriptor(self, dt):
-        result = &quot;&quot;
-
-        # Get the closet matching element to the time
-        found = self.findTimezoneElement(dt)
-
-        # Get it
-        if found is not None:
-            if len(found.getTZName()) == 0:
-                tzoffset = found.getUTCOffset()
-                negative = False
-                if tzoffset &lt; 0:
-                    tzoffset = -tzoffset
-                    negative = True
-                result = (&quot;+&quot;, &quot;-&quot;)[negative]
-                hours_offset = tzoffset / (60 * 60)
-                if hours_offset &lt; 10:
-                    result += &quot;0&quot;
-                result += str(hours_offset)
-                mins_offset = (tzoffset / 60) % 60
-                if mins_offset &lt; 10:
-                    result += &quot;0&quot;
-                result += str(mins_offset)
-            else:
-                result = &quot;(&quot;
-                result += found.getTZName()
-                result += &quot;)&quot;
-
-        return result
-
-
-    def mergeTimezone(self, tz):
-        pass
-
-
-    @staticmethod
-    def tuple_bisect_right(a, x):
-        &quot;&quot;&quot;
-        Same as bisect_right except that the values being compared are the first elements
-        of a tuple.
-        &quot;&quot;&quot;
-
-        lo = 0
-        hi = len(a)
-        while lo &lt; hi:
-            mid = (lo + hi) // 2
-            if x &lt; a[mid][0]:
-                hi = mid
-            else:
-                lo = mid + 1
-        return lo
-
-
-    def findTimezoneElement(self, dt):
-        # Need to make the incoming date-time relative to the DTSTART in the
-        # timezone component for proper comparison.
-        # This means making the incoming date-time a floating (no timezone)
-        # item
-        temp = dt.duplicate()
-        temp.setTimezoneID(None)
-
-        # Had to rework this because some VTIMEZONEs have sub-components where the DST instances are interleaved. That
-        # means we have to evaluate each and every sub-component to find the instance immediately less than the time we are checking.
-
-        # Now do the expansion for each one found and pick the lowest
-        found = None
-        dt_found = PyCalendarDateTime()
-
-        for item in self.mComponents:
-            dt_item = item.expandBelow(temp)
-            if temp &gt;= dt_item:
-                if found is not None:
-                    # Compare with the one previously cached and switch to this
-                    # one if newer
-                    if dt_item &gt; dt_found:
-                        found = item
-                        dt_found = dt_item
-                else:
-                    found = item
-                    dt_found = dt_item
-
-        return found
-
-
-    def expandAll(self, start, end, with_name=False):
-        results = []
-        for item in self.mComponents:
-            results.extend(item.expandAll(start, end, with_name))
-        results = [x for x in set(results)]
-        results.sort(key=lambda x: x[0].getPosixTime())
-        return results
-
-
-    def sortedPropertyKeyOrder(self):
-        return (
-            definitions.cICalProperty_TZID,
-            definitions.cICalProperty_LAST_MODIFIED,
-            definitions.cICalProperty_TZURL,
-        )
-
-
-    @staticmethod
-    def sortByUTCOffsetComparator(tz1, tz2):
-        sort1 = tz1.getUTCOffsetSortKey()
-        sort2 = tz2.getUTCOffsetSortKey()
-        if sort1 == sort2:
-            return tz1.getID().compareToIgnoreCase(tz2.getID())
-        else:
-            return (1, -1)[sort1 &lt; sort2]
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvtimezonedaylightpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vtimezonedaylight.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vtimezonedaylight.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vtimezonedaylight.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,31 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from vtimezoneelement import PyCalendarVTimezoneElement
-
-class PyCalendarVTimezoneDaylight(PyCalendarVTimezoneElement):
-
-    def __init__(self, parent=None):
-        super(PyCalendarVTimezoneDaylight, self).__init__(parent=parent)
-
-
-    def duplicate(self, parent=None):
-        return super(PyCalendarVTimezoneDaylight, self).duplicate(parent=parent)
-
-
-    def getType(self):
-        return definitions.cICalComponent_DAYLIGHT
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvtimezoneelementpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vtimezoneelement.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vtimezoneelement.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vtimezoneelement.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,219 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 bisect import bisect_right
-from pycalendar import definitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.recurrenceset import PyCalendarRecurrenceSet
-from pycalendar.value import PyCalendarValue
-
-class PyCalendarVTimezoneElement(PyCalendarComponent):
-
-    propertyCardinality_1 = (
-        definitions.cICalProperty_DTSTART,
-        definitions.cICalProperty_TZOFFSETTO,
-        definitions.cICalProperty_TZOFFSETFROM,
-    )
-
-    propertyCardinality_0_1 = (
-        definitions.cICalProperty_RRULE,
-    )
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    def __init__(self, parent=None, dt=None, offset=None):
-        super(PyCalendarVTimezoneElement, self).__init__(parent=parent)
-        self.mStart = dt if dt is not None else PyCalendarDateTime()
-        self.mTZName = &quot;&quot;
-        self.mUTCOffset = offset if offset is not None else 0
-        self.mUTCOffsetFrom = 0
-        self.mRecurrences = PyCalendarRecurrenceSet()
-        self.mCachedExpandBelow = None
-        self.mCachedExpandBelowItems = None
-
-
-    def duplicate(self, parent=None):
-        other = super(PyCalendarVTimezoneElement, self).duplicate(parent=parent)
-        other.mStart = self.mStart.duplicate()
-        other.mTZName = self.mTZName
-        other.mUTCOffset = self.mUTCOffset
-        other.mUTCOffsetFrom = self.mUTCOffsetFrom
-        other.mRecurrences = self.mRecurrences.duplicate()
-        other.mCachedExpandBelow = None
-        other.mCachedExpandBelowItems = None
-        return other
-
-
-    def finalise(self):
-        # Get DTSTART
-        temp = self.loadValueDateTime(definitions.cICalProperty_DTSTART)
-        if temp is not None:
-            self.mStart = temp
-
-        # Get TZOFFSETTO
-        temp = self.loadValueInteger(definitions.cICalProperty_TZOFFSETTO, PyCalendarValue.VALUETYPE_UTC_OFFSET)
-        if temp is not None:
-            self.mUTCOffset = temp
-
-        # Get TZOFFSETFROM
-        temp = self.loadValueInteger(definitions.cICalProperty_TZOFFSETFROM, PyCalendarValue.VALUETYPE_UTC_OFFSET)
-        if temp is not None:
-            self.mUTCOffsetFrom = temp
-
-        # Get TZNAME
-        temps = self.loadValueString(definitions.cICalProperty_TZNAME)
-        if temps is not None:
-            self.mTZName = temps
-
-        # Get RRULEs
-        self.loadValueRRULE(definitions.cICalProperty_RRULE, self.mRecurrences, True)
-
-        # Get RDATEs
-        self.loadValueRDATE(definitions.cICalProperty_RDATE, self.mRecurrences, True)
-
-        # Do inherited
-        super(PyCalendarVTimezoneElement, self).finalise()
-
-
-    def getSortKey(self):
-        &quot;&quot;&quot;
-        We do not want these components sorted.
-        &quot;&quot;&quot;
-        return &quot;&quot;
-
-
-    def getStart(self):
-        return self.mStart
-
-
-    def getUTCOffset(self):
-        return self.mUTCOffset
-
-
-    def getUTCOffsetFrom(self):
-        return self.mUTCOffsetFrom
-
-
-    def getTZName(self):
-        return self.mTZName
-
-
-    def expandBelow(self, below):
-
-        # Look for recurrences
-        if not self.mRecurrences.hasRecurrence() or self.mStart &gt; below:
-            # Return DTSTART even if it is newer
-            return self.mStart
-        else:
-            # We want to allow recurrence calculation caching to help us here
-            # as this method
-            # gets called a lot - most likely for ever increasing dt values
-            # (which will therefore
-            # invalidate the recurrence cache).
-            #
-            # What we will do is round up the date-time to the next year so
-            # that the recurrence
-            # cache is invalidated less frequently
-
-            temp = PyCalendarDateTime(below.getYear(), 1, 1, 0, 0, 0)
-
-            # Use cache of expansion
-            if self.mCachedExpandBelowItems is None:
-                self.mCachedExpandBelowItems = []
-            if self.mCachedExpandBelow is None:
-                self.mCachedExpandBelow = self.mStart.duplicate()
-            if temp &gt; self.mCachedExpandBelow:
-                self.mCachedExpandBelowItems = []
-                period = PyCalendarPeriod(self.mStart, temp)
-                self.mRecurrences.expand(self.mStart, period, self.mCachedExpandBelowItems, float_offset=self.mUTCOffsetFrom)
-                self.mCachedExpandBelow = temp
-
-            if len(self.mCachedExpandBelowItems) != 0:
-                # List comes back sorted so we pick the element just less than
-                # the dt value we want
-                i = bisect_right(self.mCachedExpandBelowItems, below)
-                if i != 0:
-                    return self.mCachedExpandBelowItems[i - 1]
-
-                # The first one in the list is the one we want
-                return self.mCachedExpandBelowItems[0]
-
-            return self.mStart
-
-
-    def expandAll(self, start, end, with_name):
-
-        if start is None:
-            start = self.mStart
-
-        # Ignore if there is no change in offset
-        offsetto = self.loadValueInteger(definitions.cICalProperty_TZOFFSETTO, PyCalendarValue.VALUETYPE_UTC_OFFSET)
-        offsetfrom = self.loadValueInteger(definitions.cICalProperty_TZOFFSETFROM, PyCalendarValue.VALUETYPE_UTC_OFFSET)
-#        if offsetto == offsetfrom:
-#            return ()
-
-        # Look for recurrences
-        if self.mStart &gt; end:
-            # Return nothing
-            return ()
-        elif not self.mRecurrences.hasRecurrence():
-            # Return DTSTART even if it is newer
-            if self.mStart &gt;= start:
-                result = (self.mStart, offsetfrom, offsetto,)
-                if with_name:
-                    result += (self.getTZName(),)
-                return (result,)
-            else:
-                return ()
-        else:
-            # We want to allow recurrence calculation caching to help us here
-            # as this method
-            # gets called a lot - most likely for ever increasing dt values
-            # (which will therefore
-            # invalidate the recurrence cache).
-            #
-            # What we will do is round up the date-time to the next year so
-            # that the recurrence
-            # cache is invalidated less frequently
-
-            temp = PyCalendarDateTime(end.getYear(), 1, 1, 0, 0, 0)
-
-            # Use cache of expansion
-            if self.mCachedExpandBelowItems is None:
-                self.mCachedExpandBelowItems = []
-            if self.mCachedExpandBelow is None:
-                self.mCachedExpandBelow = self.mStart.duplicate()
-            if temp &gt; self.mCachedExpandBelow:
-                self.mCachedExpandBelowItems = []
-                period = PyCalendarPeriod(self.mStart, end)
-                self.mRecurrences.expand(self.mStart, period, self.mCachedExpandBelowItems, float_offset=self.mUTCOffsetFrom)
-                self.mCachedExpandBelow = temp
-
-            if len(self.mCachedExpandBelowItems) != 0:
-                # Return them all within the range
-                results = []
-                for dt in self.mCachedExpandBelowItems:
-                    if dt &gt;= start and dt &lt; end:
-                        result = (dt, offsetfrom, offsetto,)
-                        if with_name:
-                            result += (self.getTZName(),)
-                        results.append(result)
-                return results
-
-            return ()
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvtimezonestandardpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vtimezonestandard.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vtimezonestandard.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vtimezonestandard.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,31 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from pycalendar.vtimezoneelement import PyCalendarVTimezoneElement
-
-class PyCalendarVTimezoneStandard(PyCalendarVTimezoneElement):
-
-    def __init__(self, parent=None):
-        super(PyCalendarVTimezoneStandard, self).__init__(parent=parent)
-
-
-    def duplicate(self, parent=None):
-        return super(PyCalendarVTimezoneStandard, self).duplicate(parent=parent)
-
-
-    def getType(self):
-        return definitions.cICalComponent_STANDARD
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvtodopy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vtodo.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vtodo.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vtodo.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,366 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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 import definitions
-from pycalendar import itipdefinitions
-from pycalendar.componentrecur import PyCalendarComponentRecur
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-from pycalendar.property import PyCalendarProperty
-import cStringIO as StringIO
-
-class PyCalendarVToDo(PyCalendarComponentRecur):
-
-    OVERDUE = 0
-    DUE_NOW = 1
-    DUE_LATER = 2
-    DONE = 3
-    CANCELLED = 4
-
-    @staticmethod
-    def sort_for_display(e1, e2):
-        s1 = e1.getMaster()
-        s2 = e2.getMaster()
-
-        # Check status first (convert None -&gt; Needs action for tests)
-        status1 = s1.self.mStatus
-        status2 = s2.self.mStatus
-        if status1 == definitions.eStatus_VToDo_None:
-            status1 = definitions.eStatus_VToDo_NeedsAction
-        if status2 == definitions.eStatus_VToDo_None:
-            status2 = definitions.eStatus_VToDo_NeedsAction
-        if status1 != status2:
-            # More important ones at the top
-            return status1 &lt; status2
-
-        # At this point the status of each is the same
-
-        # If status is cancelled sort by start time
-        if s1.self.mStatus == definitions.eStatus_VToDo_Cancelled:
-            # Older ones at the bottom
-            return s1.mStart &gt; s2.mStart
-
-        # If status is completed sort by completion time
-        if s1.self.mStatus == definitions.eStatus_VToDo_Completed:
-            # Older ones at the bottom
-            return s1.self.mCompleted &gt; s2.self.mCompleted
-
-        # Check due date exists
-        if s1.mHasEnd != s2.mHasEnd:
-            now = PyCalendarDateTime()
-            now.setToday()
-
-            # Ones with due dates after today below ones without due dates
-            if s1.hasEnd():
-                return s1.mEnd &lt;= now
-            elif s2.hasEnd():
-                return now &lt; s2.mEnd
-
-        # Check due dates if present
-        if s1.mHasEnd:
-            if s1.mEnd != s2.mEnd:
-                # Soonest dues dates above later ones
-                return s1.mEnd &lt; s2.mEnd
-
-        # Check priority next
-        if s1.self.mPriority != s2.self.mPriority:
-            # Higher priority above lower ones
-            return s1.self.mPriority &lt; s2.self.mPriority
-
-        # Just use start time - older ones at the top
-        return s1.mStart &lt; s2.mStart
-
-    propertyCardinality_1 = (
-        definitions.cICalProperty_DTSTAMP,
-        definitions.cICalProperty_UID,
-    )
-
-    propertyCardinality_0_1 = (
-        definitions.cICalProperty_CLASS,
-        definitions.cICalProperty_COMPLETED,
-        definitions.cICalProperty_CREATED,
-        definitions.cICalProperty_DESCRIPTION,
-        definitions.cICalProperty_DTSTART,
-        definitions.cICalProperty_GEO,
-        definitions.cICalProperty_LAST_MODIFIED,
-        definitions.cICalProperty_LOCATION,
-        definitions.cICalProperty_ORGANIZER,
-        definitions.cICalProperty_PERCENT_COMPLETE,
-        definitions.cICalProperty_PRIORITY,
-        definitions.cICalProperty_RECURRENCE_ID,
-        definitions.cICalProperty_SEQUENCE,
-        # definitions.cICalProperty_STATUS, # Special fix done for multiple STATUS
-        definitions.cICalProperty_SUMMARY,
-        definitions.cICalProperty_URL,
-        definitions.cICalProperty_RRULE,
-        definitions.cICalProperty_DUE,
-        definitions.cICalProperty_DURATION,
-    )
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    def __init__(self, parent=None):
-        super(PyCalendarVToDo, self).__init__(parent=parent)
-        self.mPriority = 0
-        self.mStatus = definitions.eStatus_VToDo_None
-        self.mPercentComplete = 0
-        self.mCompleted = PyCalendarDateTime()
-        self.mHasCompleted = False
-
-
-    def duplicate(self, parent=None):
-        other = super(PyCalendarVToDo, self).duplicate(parent=parent)
-        other.mPriority = self.mPriority
-        other.mStatus = self.mStatus
-        other.mPercentComplete = self.mPercentComplete
-        other.mCompleted = self.mCompleted.duplicate()
-        other.mHasCompleted = self.mHasCompleted
-        return other
-
-
-    def getType(self):
-        return definitions.cICalComponent_VTODO
-
-
-    def getMimeComponentName(self):
-        return itipdefinitions.cICalMIMEComponent_VTODO
-
-
-    def addComponent(self, comp):
-        # We can embed the alarm components only
-        if comp.getType() == definitions.cICalComponent_VALARM:
-            super(PyCalendarVToDo, self).addComponent(comp)
-        else:
-            raise ValueError
-
-
-    def getStatus(self):
-        return self.mStatus
-
-
-    def setStatus(self, status):
-        self.mStatus = status
-
-
-    def getStatusText(self):
-        sout = StringIO()
-
-        if self.mStatus in (definitions.eStatus_VToDo_NeedsAction, definitions.eStatus_VToDo_InProcess):
-            if self.hasEnd():
-                # Check due date
-                today = PyCalendarDateTime()
-                today.setToday()
-                if self.getEnd() &gt; today:
-                    sout.append(&quot;Due: &quot;)
-                    whendue = self.getEnd() - today
-                    if (whendue.getDays() &gt; 0) and (whendue.getDays() &lt;= 7):
-                        sout.write(whendue.getDays())
-                        sout.write(&quot; days&quot;)
-                    else:
-                        sout.write(self.getEnd().getLocaleDate(PyCalendarDateTime.NUMERICDATE))
-                elif self.getEnd() == today:
-                    sout.write(&quot;Due today&quot;)
-                else:
-                    sout.write(&quot;Overdue: &quot;)
-                    overdue = today - self.getEnd()
-                    if overdue.getWeeks() != 0:
-                        sout.write(overdue.getWeeks())
-                        sout.write(&quot; weeks&quot;)
-                    else:
-                        sout.write(overdue.getDays() + 1)
-                        sout.write(&quot; days&quot;)
-            else:
-                sout.write(&quot;Not Completed&quot;)
-        elif self.mStatus == definitions.eStatus_VToDo_Completed:
-            if self.hasCompleted():
-                sout.write(&quot;Completed: &quot;)
-                sout.write(self.getCompleted().getLocaleDate(PyCalendarDateTime.NUMERICDATE))
-            else:
-                sout.write(&quot;Completed&quot;)
-        elif definitions.eStatus_VToDo_Cancelled:
-            sout.write(&quot;Cancelled&quot;)
-
-        return sout.toString()
-
-
-    def getCompletionState(self):
-        if self.mStatus in (definitions.eStatus_VToDo_NeedsAction, definitions.eStatus_VToDo_InProcess):
-            if self.hasEnd():
-                # Check due date
-                today = PyCalendarDateTime()
-                today.setToday()
-                if self.getEnd() &gt; today:
-                    return PyCalendarVToDo.DUE_LATER
-                elif self.getEnd() == today:
-                    return PyCalendarVToDo.DUE_NOW
-                else:
-                    return PyCalendarVToDo.OVERDUE
-            else:
-                return PyCalendarVToDo.DUE_NOW
-        elif self.mStatus == definitions.eStatus_VToDo_Completed:
-            return PyCalendarVToDo.DONE
-        elif self.mStatus == definitions.eStatus_VToDo_Cancelled:
-            return PyCalendarVToDo.CANCELLED
-
-
-    def getPriority(self):
-        return self.mPriority
-
-
-    def setPriority(self, priority):
-        self.mPriority = priority
-
-
-    def getCompleted(self):
-        return self.mCompleted
-
-
-    def hasCompleted(self):
-        return self.mHasCompleted
-
-
-    def finalise(self):
-        # Do inherited
-        super(PyCalendarVToDo, self).finalise()
-
-        # Get DUE
-        temp = self.loadValueDateTime(definitions.cICalProperty_DUE)
-        if temp is None:
-            # Try DURATION instead
-            temp = self.loadValueDuration(definitions.cICalProperty_DURATION)
-            if temp is not None:
-                self.mEnd = self.mStart + temp
-                self.mHasEnd = True
-            else:
-                self.mHasEnd = False
-        else:
-            self.mHasEnd = True
-            self.mEnd = temp
-
-        # Get PRIORITY
-        self.mPriority = self.loadValueInteger(definitions.cICalProperty_PRIORITY)
-
-        # Get STATUS
-        temp = self.loadValueString(definitions.cICalProperty_STATUS)
-        if temp is not None:
-            if temp == definitions.cICalProperty_STATUS_NEEDS_ACTION:
-                self.mStatus = definitions.eStatus_VToDo_NeedsAction
-            elif temp == definitions.cICalProperty_STATUS_COMPLETED:
-                self.mStatus = definitions.eStatus_VToDo_Completed
-            elif temp == definitions.cICalProperty_STATUS_IN_PROCESS:
-                self.mStatus = definitions.eStatus_VToDo_InProcess
-            elif temp == definitions.cICalProperty_STATUS_CANCELLED:
-                self.mStatus = definitions.eStatus_VToDo_Cancelled
-
-        # Get PERCENT-COMPLETE
-        self.mPercentComplete = self.loadValueInteger(definitions.cICalProperty_PERCENT_COMPLETE)
-
-        # Get COMPLETED
-        temp = self.loadValueDateTime(definitions.cICalProperty_COMPLETED)
-        self.mHasCompleted = temp is not None
-        if self.mHasCompleted:
-            self.mCompleted = temp
-
-
-    def validate(self, doFix=False):
-        &quot;&quot;&quot;
-        Validate the data in this component and optionally fix any problems, else raise. If
-        loggedProblems is not None it must be a C{list} and problem descriptions are appended
-        to that.
-        &quot;&quot;&quot;
-
-        fixed, unfixed = super(PyCalendarVToDo, self).validate(doFix)
-
-        # Extra constraint: only one of DUE or DURATION
-        if self.hasProperty(definitions.cICalProperty_DUE) and self.hasProperty(definitions.cICalProperty_DURATION):
-            # Fix by removing the DURATION
-            logProblem = &quot;[%s] Properties must not both be present: %s, %s&quot; % (
-                self.getType(),
-                definitions.cICalProperty_DUE,
-                definitions.cICalProperty_DURATION,
-            )
-            if doFix:
-                self.removeProperties(definitions.cICalProperty_DURATION)
-                fixed.append(logProblem)
-            else:
-                unfixed.append(logProblem)
-
-        # Extra constraint: DTSTART must be present if DURATION is present
-        if self.hasProperty(definitions.cICalProperty_DURATION) and not self.hasProperty(definitions.cICalProperty_DTSTART):
-            # Cannot fix this one
-            logProblem = &quot;[%s] Property must be present: %s with %s&quot; % (
-                self.getType(),
-                definitions.cICalProperty_DTSTART,
-                definitions.cICalProperty_DURATION,
-            )
-            unfixed.append(logProblem)
-
-        return fixed, unfixed
-
-
-    # Editing
-    def editStatus(self, status):
-        # Only if it is different
-        if self.mStatus != status:
-            # Updated cached values
-            self.mStatus = status
-
-            # Remove existing STATUS &amp; COMPLETED items
-            self.removeProperties(definitions.cICalProperty_STATUS)
-            self.removeProperties(definitions.cICalProperty_COMPLETED)
-            self.mHasCompleted = False
-
-            # Now create properties
-            value = None
-            if status == definitions.eStatus_VToDo_NeedsAction:
-                value = definitions.cICalProperty_STATUS_NEEDS_ACTION
-            if status == definitions.eStatus_VToDo_Completed:
-                value = definitions.cICalProperty_STATUS_COMPLETED
-                # Add the completed item
-                self.mCompleted.setNowUTC()
-                self.mHasCompleted = True
-                prop = PyCalendarProperty(definitions.cICalProperty_STATUS_COMPLETED, self.mCompleted)
-                self.addProperty(prop)
-            elif status == definitions.eStatus_VToDo_InProcess:
-                value = definitions.cICalProperty_STATUS_IN_PROCESS
-            elif status == definitions.eStatus_VToDo_Cancelled:
-                value = definitions.cICalProperty_STATUS_CANCELLED
-            prop = PyCalendarProperty(definitions.cICalProperty_STATUS, value)
-            self.addProperty(prop)
-
-
-    def editCompleted(self, completed):
-        # Remove existing COMPLETED item
-        self.removeProperties(definitions.cICalProperty_COMPLETED)
-        self.mHasCompleted = False
-
-        # Always UTC
-        self.mCompleted = completed.duplicate()
-        self.mCompleted.adjustToUTC()
-        self.mHasCompleted = True
-        prop = PyCalendarProperty(definitions.cICalProperty_STATUS_COMPLETED, self.mCompleted)
-        self.addProperty(prop)
-
-
-    def sortedPropertyKeyOrder(self):
-        return (
-            definitions.cICalProperty_UID,
-            definitions.cICalProperty_RECURRENCE_ID,
-            definitions.cICalProperty_DTSTART,
-            definitions.cICalProperty_DURATION,
-            definitions.cICalProperty_DUE,
-            definitions.cICalProperty_COMPLETED,
-        )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarvunknownpy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/vunknown.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/vunknown.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/vunknown.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,66 +0,0 @@
</span><del>-##
-#    Copyright (c) 2011-2012 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 import definitions
-from pycalendar.component import PyCalendarComponent
-from pycalendar.icalendar.validation import ICALENDAR_VALUE_CHECKS
-import uuid
-
-class PyCalendarUnknownComponent(PyCalendarComponent):
-
-    propertyValueChecks = ICALENDAR_VALUE_CHECKS
-
-    def __init__(self, parent=None, comptype=&quot;&quot;):
-        super(PyCalendarUnknownComponent, self).__init__(parent=parent)
-        self.mType = comptype
-        self.mMapKey = str(uuid.uuid4())
-
-
-    def duplicate(self, parent=None):
-        return super(PyCalendarUnknownComponent, self).duplicate(parent=parent, comptype=self.mType)
-
-
-    def getType(self):
-        return self.mType
-
-
-    def getBeginDelimiter(self):
-        return &quot;BEGIN:&quot; + self.mType
-
-
-    def getEndDelimiter(self):
-        return &quot;END:&quot; + self.mType
-
-
-    def getMimeComponentName(self):
-        return &quot;unknown&quot;
-
-
-    def getMapKey(self):
-        return self.mMapKey
-
-
-    def getSortKey(self):
-        &quot;&quot;&quot;
-        We do not want unknown components sorted.
-        &quot;&quot;&quot;
-        return &quot;&quot;
-
-
-    def sortedPropertyKeyOrder(self):
-        return (
-            definitions.cICalProperty_UID,
-        )
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarxmldefinitionspyfromrev11912PyCalendarbranchesjson2srcpycalendarxmldefinitionspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/xmldefinitions.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/xmldefinitions.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/xmldefinitions.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/xmldefinitions.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,41 @@
</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.
+##
+
+# Generic XML definitions
+
+iCalendar20_namespace = &quot;urn:ietf:params:xml:ns:icalendar-2.0&quot;
+
+components = &quot;components&quot;
+properties = &quot;properties&quot;
+parameters = &quot;parameters&quot;
+
+value_binary = &quot;binary&quot;
+value_boolean = &quot;boolean&quot;
+value_cal_address = &quot;cal-address&quot;
+value_date = &quot;date&quot;
+value_date_time = &quot;date-time&quot;
+value_duration = &quot;duration&quot;
+value_float = &quot;float&quot;
+value_integer = &quot;integer&quot;
+value_period = &quot;period&quot;
+value_text = &quot;text&quot;
+value_unknown = &quot;unknown&quot;
+value_uri = &quot;uri&quot;
+value_utc_offset = &quot;utc-offset&quot;
+
+period_start = &quot;start&quot;
+period_end = &quot;end&quot;
+period_duration = &quot;duration&quot;
</ins></span></pre></div>
<a id="PyCalendartrunksrcpycalendarxmldefspy"></a>
<div class="delfile"><h4>Deleted: PyCalendar/trunk/src/pycalendar/xmldefs.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/xmldefs.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/pycalendar/xmldefs.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,104 +0,0 @@
</span><del>-##
-#    Copyright (c) 2007-2012 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.
-##
-
-import xml.etree.cElementTree as XML
-
-# iCalendar/vCard XML definitions
-
-iCalendar20_namespace = &quot;urn:ietf:params:xml:ns:icalendar-2.0&quot;
-
-icalendar = &quot;icalendar&quot;
-components = &quot;components&quot;
-properties = &quot;properties&quot;
-parameters = &quot;parameters&quot;
-
-value_binary = &quot;binary&quot;
-value_boolean = &quot;boolean&quot;
-value_cal_address = &quot;cal-address&quot;
-value_date = &quot;date&quot;
-value_date_time = &quot;date-time&quot;
-value_duration = &quot;duration&quot;
-value_integer = &quot;integer&quot;
-value_period = &quot;period&quot;
-value_recur = &quot;recur&quot;
-value_text = &quot;text&quot;
-value_unknown = &quot;unknown&quot;
-value_uri = &quot;uri&quot;
-value_utc_offset = &quot;utc-offset&quot;
-
-period_start = &quot;start&quot;
-period_end = &quot;end&quot;
-period_duration = &quot;duration&quot;
-
-recur_freq = &quot;freq&quot;
-recur_freq_secondly = &quot;SECONDLY&quot;
-recur_freq_minutely = &quot;MINUTELY&quot;
-recur_freq_hourly = &quot;HOURLY&quot;
-recur_freq_daily = &quot;DAILY&quot;
-recur_freq_weekly = &quot;WEEKLY&quot;
-recur_freq_monthly = &quot;MONTHLY&quot;
-recur_freq_yearly = &quot;YEARLY&quot;
-
-recur_count = &quot;count&quot;
-recur_until = &quot;until&quot;
-recur_interval = &quot;interval&quot;
-
-recur_bysecond = &quot;bysecond&quot;
-recur_byminute = &quot;byminute&quot;
-recur_byhour = &quot;byhour&quot;
-recur_byday = &quot;byday&quot;
-recur_bymonthday = &quot;bymonthday&quot;
-recur_byyearday = &quot;byyearday&quot;
-recur_byweekno = &quot;byweekno&quot;
-recur_bymonth = &quot;bymonth&quot;
-recur_bysetpos = &quot;bysetpos&quot;
-recur_wkst = &quot;wkst&quot;
-
-req_status_code = &quot;code&quot;
-req_status_description = &quot;description&quot;
-req_status_data = &quot;data&quot;
-
-vCard40_namespace = &quot;urn:ietf:params:xml:ns:vcard-4.0&quot;
-
-def makeTag(namespace, name):
-    return &quot;{%s}%s&quot; % (namespace, name.lower(),)
-
-
-
-def toString(root):
-
-    data = &quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\n&quot;&quot;&quot;
-
-    INDENT = 2
-
-    # Generate indentation
-    def _indentNode(node, level=0):
-
-        if node.text is not None and node.text.strip():
-            return
-        elif len(node.getchildren()):
-            indent = &quot;\n&quot; + &quot; &quot; * (level + 1) * INDENT
-            node.text = indent
-            for child in node.getchildren():
-                child.tail = indent
-                _indentNode(child, level + 1)
-            if len(node.getchildren()):
-                node.getchildren()[-1].tail = &quot;\n&quot; + &quot; &quot; * level * INDENT
-
-    _indentNode(root, 0)
-    data += XML.tostring(root) + &quot;\n&quot;
-
-    return data
</del></span></pre></div>
<a id="PyCalendartrunksrcpycalendarxmlutilspyfromrev11912PyCalendarbranchesjson2srcpycalendarxmlutilspy"></a>
<div class="copfile"><h4>Copied: PyCalendar/trunk/src/pycalendar/xmlutils.py (from rev 11912, PyCalendar/branches/json-2/src/pycalendar/xmlutils.py) (0 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/pycalendar/xmlutils.py                                (rev 0)
+++ PyCalendar/trunk/src/pycalendar/xmlutils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -0,0 +1,47 @@
</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.
+##
+
+import xml.etree.cElementTree as XML
+
+def makeTag(namespace, name):
+    return &quot;{%s}%s&quot; % (namespace, name.lower(),)
+
+
+
+def toString(root):
+
+    data = &quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\n&quot;&quot;&quot;
+
+    INDENT = 2
+
+    # Generate indentation
+    def _indentNode(node, level=0):
+
+        if node.text is not None and node.text.strip():
+            return
+        elif len(node.getchildren()):
+            indent = &quot;\n&quot; + &quot; &quot; * (level + 1) * INDENT
+            node.text = indent
+            for child in node.getchildren():
+                child.tail = indent
+                _indentNode(child, level + 1)
+            if len(node.getchildren()):
+                node.getchildren()[-1].tail = &quot;\n&quot; + &quot; &quot; * level * INDENT
+
+    _indentNode(root, 0)
+    data += XML.tostring(root) + &quot;\n&quot;
+
+    return data
</ins></span></pre></div>
<a id="PyCalendartrunksrczonal__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrczonalrulepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/rule.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/rule.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/rule.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,14 +14,14 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar import definitions
-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.recurrence import Recurrence
+from pycalendar.icalendar.vtimezonedaylight import Daylight
+from pycalendar.icalendar.vtimezonestandard import Standard
+from pycalendar.utcoffsetvalue import UTCOffsetValue
</ins><span class="cx"> from pycalendar.utils import daysInMonth
</span><del>-from pycalendar.vtimezonestandard import PyCalendarVTimezoneStandard
-from pycalendar.utcoffsetvalue import PyCalendarUTCOffsetValue
-from pycalendar.vtimezonedaylight import PyCalendarVTimezoneDaylight
-from pycalendar.property import PyCalendarProperty
-from pycalendar.recurrence import PyCalendarRecurrence
</del><span class="cx"> import utils
</span><span class="cx"> 
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="lines">@@ -114,23 +114,23 @@
</span><span class="cx">     # Some useful mapping tables
</span><span class="cx"> 
</span><span class="cx">     LASTDAY_NAME_TO_DAY = {
</span><del>-        &quot;lastSun&quot;: PyCalendarDateTime.SUNDAY,
-        &quot;lastMon&quot;: PyCalendarDateTime.MONDAY,
-        &quot;lastTue&quot;: PyCalendarDateTime.TUESDAY,
-        &quot;lastWed&quot;: PyCalendarDateTime.WEDNESDAY,
-        &quot;lastThu&quot;: PyCalendarDateTime.THURSDAY,
-        &quot;lastFri&quot;: PyCalendarDateTime.FRIDAY,
-        &quot;lastSat&quot;: PyCalendarDateTime.SATURDAY,
</del><ins>+        &quot;lastSun&quot;: DateTime.SUNDAY,
+        &quot;lastMon&quot;: DateTime.MONDAY,
+        &quot;lastTue&quot;: DateTime.TUESDAY,
+        &quot;lastWed&quot;: DateTime.WEDNESDAY,
+        &quot;lastThu&quot;: DateTime.THURSDAY,
+        &quot;lastFri&quot;: DateTime.FRIDAY,
+        &quot;lastSat&quot;: DateTime.SATURDAY,
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     DAY_NAME_TO_DAY = {
</span><del>-        &quot;Sun&quot;: PyCalendarDateTime.SUNDAY,
-        &quot;Mon&quot;: PyCalendarDateTime.MONDAY,
-        &quot;Tue&quot;: PyCalendarDateTime.TUESDAY,
-        &quot;Wed&quot;: PyCalendarDateTime.WEDNESDAY,
-        &quot;Thu&quot;: PyCalendarDateTime.THURSDAY,
-        &quot;Fri&quot;: PyCalendarDateTime.FRIDAY,
-        &quot;Sat&quot;: PyCalendarDateTime.SATURDAY,
</del><ins>+        &quot;Sun&quot;: DateTime.SUNDAY,
+        &quot;Mon&quot;: DateTime.MONDAY,
+        &quot;Tue&quot;: DateTime.TUESDAY,
+        &quot;Wed&quot;: DateTime.WEDNESDAY,
+        &quot;Thu&quot;: DateTime.THURSDAY,
+        &quot;Fri&quot;: DateTime.FRIDAY,
+        &quot;Sat&quot;: DateTime.SATURDAY,
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     LASTDAY_NAME_TO_RDAY = {
</span><span class="lines">@@ -144,13 +144,13 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     DAY_NAME_TO_RDAY = {
</span><del>-        PyCalendarDateTime.SUNDAY: definitions.eRecurrence_WEEKDAY_SU,
-        PyCalendarDateTime.MONDAY: definitions.eRecurrence_WEEKDAY_MO,
-        PyCalendarDateTime.TUESDAY: definitions.eRecurrence_WEEKDAY_TU,
-        PyCalendarDateTime.WEDNESDAY: definitions.eRecurrence_WEEKDAY_WE,
-        PyCalendarDateTime.THURSDAY: definitions.eRecurrence_WEEKDAY_TH,
-        PyCalendarDateTime.FRIDAY: definitions.eRecurrence_WEEKDAY_FR,
-        PyCalendarDateTime.SATURDAY: definitions.eRecurrence_WEEKDAY_SA,
</del><ins>+        DateTime.SUNDAY: definitions.eRecurrence_WEEKDAY_SU,
+        DateTime.MONDAY: definitions.eRecurrence_WEEKDAY_MO,
+        DateTime.TUESDAY: definitions.eRecurrence_WEEKDAY_TU,
+        DateTime.WEDNESDAY: definitions.eRecurrence_WEEKDAY_WE,
+        DateTime.THURSDAY: definitions.eRecurrence_WEEKDAY_TH,
+        DateTime.FRIDAY: definitions.eRecurrence_WEEKDAY_FR,
+        DateTime.SATURDAY: definitions.eRecurrence_WEEKDAY_SA,
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     MONTH_NAME_TO_POS = {
</span><span class="lines">@@ -288,11 +288,11 @@
</span><span class="cx">         @param year:  the year to determine the transition for
</span><span class="cx">         @type year: C{int}
</span><span class="cx"> 
</span><del>-        @return: C{tuple} of L{PyCalendarDateTime} and C{str} (which is the special
</del><ins>+        @return: C{tuple} of L{DateTime} and C{str} (which is the special
</ins><span class="cx">             tzdata mode character
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         # Create a floating date-time
</span><del>-        dt = PyCalendarDateTime()
</del><ins>+        dt = DateTime()
</ins><span class="cx"> 
</span><span class="cx">         # Setup base year/month/day
</span><span class="cx">         dt.setYear(year)
</span><span class="lines">@@ -342,7 +342,7 @@
</span><span class="cx">         Get RRULE BYxxx part items from the Rule data.
</span><span class="cx"> 
</span><span class="cx">         @param start: start date-time for the recurrence set
</span><del>-        @type start: L{PyCalendarDateTime}
</del><ins>+        @type start: L{DateTime}
</ins><span class="cx">         @param indicatedDay: the day that the Rule indicates for recurrence
</span><span class="cx">         @type indicatedDay: C{int}
</span><span class="cx">         @param indicatedOffset: the offset that the Rule indicates for recurrence
</span><span class="lines">@@ -449,13 +449,13 @@
</span><span class="cx">         Generate a VTIMEZONE sub-component for this Rule.
</span><span class="cx"> 
</span><span class="cx">         @param vtz: VTIMEZONE to add to
</span><del>-        @type vtz: L{PyCalendarVTimezone}
</del><ins>+        @type vtz: L{VTimezone}
</ins><span class="cx">         @param zonerule: the Zone rule line being used
</span><span class="cx">         @type zonerule: L{ZoneRule}
</span><span class="cx">         @param start: the start time for the first instance
</span><del>-        @type start: L{PyCalendarDateTime}
</del><ins>+        @type start: L{DateTime}
</ins><span class="cx">         @param end: the start time for the last instance
</span><del>-        @type end: L{PyCalendarDateTime}
</del><ins>+        @type end: L{DateTime}
</ins><span class="cx">         @param offsetfrom: the UTC offset-from
</span><span class="cx">         @type offsetfrom: C{int}
</span><span class="cx">         @param offsetto: the UTC offset-to
</span><span class="lines">@@ -467,31 +467,31 @@
</span><span class="cx">         # Determine type of component based on offset
</span><span class="cx">         dstoffset = self.getOffset()
</span><span class="cx">         if dstoffset == 0:
</span><del>-            comp = PyCalendarVTimezoneStandard(parent=vtz)
</del><ins>+            comp = Standard(parent=vtz)
</ins><span class="cx">         else:
</span><del>-            comp = PyCalendarVTimezoneDaylight(parent=vtz)
</del><ins>+            comp = Daylight(parent=vtz)
</ins><span class="cx"> 
</span><span class="cx">         # Do offsets
</span><del>-        tzoffsetfrom = PyCalendarUTCOffsetValue(offsetfrom)
-        tzoffsetto = PyCalendarUTCOffsetValue(offsetto)
</del><ins>+        tzoffsetfrom = UTCOffsetValue(offsetfrom)
+        tzoffsetto = UTCOffsetValue(offsetto)
</ins><span class="cx"> 
</span><del>-        comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZOFFSETFROM, tzoffsetfrom))
-        comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZOFFSETTO, tzoffsetto))
</del><ins>+        comp.addProperty(Property(definitions.cICalProperty_TZOFFSETFROM, tzoffsetfrom))
+        comp.addProperty(Property(definitions.cICalProperty_TZOFFSETTO, tzoffsetto))
</ins><span class="cx"> 
</span><span class="cx">         # Do TZNAME
</span><span class="cx">         if zonerule.format.find(&quot;%&quot;) != -1:
</span><span class="cx">             tzname = zonerule.format % (self.letter if self.letter != &quot;-&quot; else &quot;&quot;,)
</span><span class="cx">         else:
</span><span class="cx">             tzname = zonerule.format
</span><del>-        comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZNAME, tzname))
</del><ins>+        comp.addProperty(Property(definitions.cICalProperty_TZNAME, tzname))
</ins><span class="cx"> 
</span><span class="cx">         # Do DTSTART
</span><del>-        comp.addProperty(PyCalendarProperty(definitions.cICalProperty_DTSTART, start))
</del><ins>+        comp.addProperty(Property(definitions.cICalProperty_DTSTART, start))
</ins><span class="cx"> 
</span><span class="cx">         # Now determine the recurrences (use RDATE if only one year or
</span><span class="cx">         # number of instances is one)
</span><span class="cx">         if self.toYear != &quot;only&quot; and instanceCount != 1:
</span><del>-            rrule = PyCalendarRecurrence()
</del><ins>+            rrule = Recurrence()
</ins><span class="cx">             rrule.setFreq(definitions.eRecurrence_YEARLY)
</span><span class="cx">             rrule.setByMonth((Rule.MONTH_NAME_TO_POS[self.inMonth],))
</span><span class="cx">             if self.onDay in Rule.LASTDAY_NAME_TO_RDAY:
</span><span class="lines">@@ -566,9 +566,9 @@
</span><span class="cx">                 rrule.setUseUntil(True)
</span><span class="cx">                 rrule.setUntil(until)
</span><span class="cx"> 
</span><del>-            comp.addProperty(PyCalendarProperty(definitions.cICalProperty_RRULE, rrule))
</del><ins>+            comp.addProperty(Property(definitions.cICalProperty_RRULE, rrule))
</ins><span class="cx">         else:
</span><del>-            comp.addProperty(PyCalendarProperty(definitions.cICalProperty_RDATE, start))
</del><ins>+            comp.addProperty(Property(definitions.cICalProperty_RDATE, start))
</ins><span class="cx"> 
</span><span class="cx">         comp.finalise()
</span><span class="cx">         vtz.addComponent(comp)
</span></span></pre></div>
<a id="PyCalendartrunksrczonaltests__init__py"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tests/__init__.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tests/__init__.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tests/__init__.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrczonalteststest_rulepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tests/test_rule.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tests/test_rule.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tests/test_rule.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -16,7 +16,7 @@
</span><span class="cx"> 
</span><span class="cx"> import unittest
</span><span class="cx"> from zonal.rule import Rule, RuleSet
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> class TestRule(unittest.TestCase):
</span><span class="cx"> 
</span><span class="lines">@@ -37,9 +37,9 @@
</span><span class="cx"> 
</span><span class="cx">     def test_datetimeforyear(self):
</span><span class="cx">         data = (
</span><del>-            (&quot;Rule\tGuat\t2006\tonly\t-\tOct\t1\t0:00\t0\tS&quot;, 2006, PyCalendarDateTime(2006, 10, 1, 0, 0, 0), &quot;&quot;),
-            (&quot;Rule\tAlgeria\t1916\t1919\t-\tOct\tSun&gt;=1\t23:00s\t0\t-&quot;, 1916, PyCalendarDateTime(1916, 10, 1, 23, 0, 0), &quot;s&quot;),
-            (&quot;Rule\tGhana\t1936\t1942\t-\tSep\t1\t0:00\t0:20\tGHST&quot;, 1937, PyCalendarDateTime(1937, 9, 1, 0, 0, 0), &quot;&quot;),
</del><ins>+            (&quot;Rule\tGuat\t2006\tonly\t-\tOct\t1\t0:00\t0\tS&quot;, 2006, DateTime(2006, 10, 1, 0, 0, 0), &quot;&quot;),
+            (&quot;Rule\tAlgeria\t1916\t1919\t-\tOct\tSun&gt;=1\t23:00s\t0\t-&quot;, 1916, DateTime(1916, 10, 1, 23, 0, 0), &quot;s&quot;),
+            (&quot;Rule\tGhana\t1936\t1942\t-\tSep\t1\t0:00\t0:20\tGHST&quot;, 1937, DateTime(1937, 9, 1, 0, 0, 0), &quot;&quot;),
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for ruletext, year, dt, special in data:
</span></span></pre></div>
<a id="PyCalendartrunksrczonalteststest_zonepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tests/test_zone.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tests/test_zone.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tests/test_zone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -17,7 +17,7 @@
</span><span class="cx"> import unittest
</span><span class="cx"> from zonal.zone import Zone
</span><span class="cx"> from zonal.rule import RuleSet
</span><del>-from pycalendar.calendar import PyCalendar
</del><ins>+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> 
</span><span class="cx"> class TestZone(unittest.TestCase):
</span><span class="cx"> 
</span><span class="lines">@@ -92,7 +92,7 @@
</span><span class="cx">         ruleset.parse(rules)
</span><span class="cx">         rules = {ruleset.name: ruleset}
</span><span class="cx"> 
</span><del>-        cal = PyCalendar()
</del><ins>+        cal = Calendar()
</ins><span class="cx">         vtz = zone.vtimezone(cal, rules, 2006, 2011)
</span><span class="cx"> 
</span><span class="cx">         self.assertEqual(str(vtz), result)
</span></span></pre></div>
<a id="PyCalendartrunksrczonaltzconvertpy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tzconvert.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tzconvert.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tzconvert.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> #!/usr/bin/env python
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -18,7 +18,7 @@
</span><span class="cx"> from __future__ import with_statement
</span><span class="cx"> 
</span><span class="cx"> from difflib import unified_diff
</span><del>-from pycalendar.calendar import PyCalendar
</del><ins>+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> import cStringIO as StringIO
</span><span class="cx"> import getopt
</span><span class="cx"> import os
</span><span class="lines">@@ -126,7 +126,7 @@
</span><span class="cx">         Generate iCalendar data for all VTIMEZONEs or just those specified
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        cal = PyCalendar()
</del><ins>+        cal = Calendar()
</ins><span class="cx">         for zone in self.zones.itervalues():
</span><span class="cx">             if filterzones and zone.name not in filterzones:
</span><span class="cx">                 continue
</span><span class="lines">@@ -151,7 +151,7 @@
</span><span class="cx">         for zone in self.zones.itervalues():
</span><span class="cx">             if filterzones and zone.name not in filterzones:
</span><span class="cx">                 continue
</span><del>-            cal = PyCalendar()
</del><ins>+            cal = Calendar()
</ins><span class="cx">             vtz = zone.vtimezone(cal, self.rules, minYear, maxYear)
</span><span class="cx">             cal.addComponent(vtz)
</span><span class="cx"> 
</span><span class="lines">@@ -251,7 +251,7 @@
</span><span class="cx">     if len(args) == 1:
</span><span class="cx">         rootdir = os.path.expanduser(args[0])
</span><span class="cx"> 
</span><del>-    PyCalendar.sProdID = prodid
</del><ins>+    Calendar.sProdID = prodid
</ins><span class="cx"> 
</span><span class="cx">     zonedir = os.path.join(rootdir, &quot;tzdata&quot;)
</span><span class="cx">     zonefiles = (
</span><span class="lines">@@ -284,14 +284,14 @@
</span><span class="cx">         ))
</span><span class="cx"> 
</span><span class="cx">         icsdir = &quot;../2008i/zoneinfo&quot;
</span><del>-        cal = PyCalendar()
</del><ins>+        cal = Calendar()
</ins><span class="cx">         for file in (checkName,):
</span><span class="cx">             fin = open(os.path.join(icsdir, file + &quot;.ics&quot;), &quot;r&quot;)
</span><span class="cx">             cal.parse(fin)
</span><span class="cx"> 
</span><span class="cx">         for vtz in cal.getVTimezoneDB():
</span><del>-            #from pycalendar.vtimezoneelement import PyCalendarVTimezoneElement
-            #vtz.mEmbedded.sort(PyCalendarVTimezoneElement.sort_dtstart)
</del><ins>+            #from pycalendar.vtimezoneelement import VTimezoneElement
+            #vtz.mEmbedded.sort(VTimezoneElement.sort_dtstart)
</ins><span class="cx">             for embedded in vtz.mEmbedded:
</span><span class="cx">                 embedded.finalise()
</span><span class="cx">             vtz.finalise()
</span></span></pre></div>
<a id="PyCalendartrunksrczonaltzdumppy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tzdump.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tzdump.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tzdump.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> #!/usr/bin/env python
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -15,22 +15,22 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.exceptions import InvalidData
+from pycalendar.icalendar.calendar import Calendar
+import getopt
</ins><span class="cx"> import os
</span><span class="cx"> import sys
</span><del>-import getopt
-from pycalendar.exceptions import PyCalendarInvalidData
</del><span class="cx"> 
</span><span class="cx"> def loadCalendar(file, verbose):
</span><span class="cx"> 
</span><del>-    cal = PyCalendar()
</del><ins>+    cal = Calendar()
</ins><span class="cx">     if verbose:
</span><span class="cx">         print &quot;Parsing calendar data: %s&quot; % (file,)
</span><span class="cx">     fin = open(file, &quot;r&quot;)
</span><span class="cx">     try:
</span><span class="cx">         cal.parse(fin)
</span><del>-    except PyCalendarInvalidData, e:
</del><ins>+    except InvalidData, e:
</ins><span class="cx">         print &quot;Failed to parse bad data: %s&quot; % (e.mData,)
</span><span class="cx">         raise
</span><span class="cx">     return cal
</span><span class="lines">@@ -41,7 +41,7 @@
</span><span class="cx"> 
</span><span class="cx">     vtz = cal.getComponents()[0]
</span><span class="cx">     expanded = vtz.expandAll(start, end)
</span><del>-    expanded.sort(cmp=lambda x, y: PyCalendarDateTime.sort(x[0], y[0]))
</del><ins>+    expanded.sort(cmp=lambda x, y: DateTime.sort(x[0], y[0]))
</ins><span class="cx">     return expanded
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -125,8 +125,8 @@
</span><span class="cx">         usage(&quot;Must have one argument&quot;)
</span><span class="cx">     fpath = os.path.expanduser(args[0])
</span><span class="cx"> 
</span><del>-    start = PyCalendarDateTime(year=startYear, month=1, day=1)
-    end = PyCalendarDateTime(year=endYear, month=1, day=1)
</del><ins>+    start = DateTime(year=startYear, month=1, day=1)
+    end = DateTime(year=endYear, month=1, day=1)
</ins><span class="cx"> 
</span><span class="cx">     cal = loadCalendar(fpath, verbose)
</span><span class="cx">     dates = getExpandedDates(cal, start, end)
</span></span></pre></div>
<a id="PyCalendartrunksrczonaltzverifypy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/tzverify.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/tzverify.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/tzverify.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> #!/usr/bin/env python
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -15,13 +15,13 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.exceptions import InvalidData
+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> from tzconvert import tzconvert
</span><ins>+import getopt
</ins><span class="cx"> import os
</span><span class="cx"> import sys
</span><del>-import getopt
-from pycalendar.exceptions import PyCalendarInvalidData
</del><span class="cx"> 
</span><span class="cx"> def loadCalendarFromZoneinfo(zoneinfopath, skips=(), verbose=False, quiet=False):
</span><span class="cx"> 
</span><span class="lines">@@ -51,14 +51,14 @@
</span><span class="cx"> 
</span><span class="cx"> def loadCalendar(files, verbose):
</span><span class="cx"> 
</span><del>-    cal = PyCalendar()
</del><ins>+    cal = Calendar()
</ins><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><span class="cx">         fin = open(file, &quot;r&quot;)
</span><span class="cx">         try:
</span><span class="cx">             cal.parse(fin)
</span><del>-        except PyCalendarInvalidData, e:
</del><ins>+        except InvalidData, e:
</ins><span class="cx">             print &quot;Failed to parse bad data: %s&quot; % (e.mData,)
</span><span class="cx">             raise
</span><span class="cx">     return CalendarZonesWrapper(calendar=cal)
</span><span class="lines">@@ -164,7 +164,7 @@
</span><span class="cx"> 
</span><span class="cx"> def sortedList(setdata):
</span><span class="cx">     l = list(setdata)
</span><del>-    l.sort(cmp=lambda x, y: PyCalendarDateTime.sort(x[0], y[0]))
</del><ins>+    l.sort(cmp=lambda x, y: DateTime.sort(x[0], y[0]))
</ins><span class="cx">     return l
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -249,8 +249,8 @@
</span><span class="cx">     zonedir1 = os.path.expanduser(args[0])
</span><span class="cx">     zonedir2 = os.path.expanduser(args[1])
</span><span class="cx"> 
</span><del>-    start = PyCalendarDateTime(year=startYear, month=1, day=1)
-    end = PyCalendarDateTime(year=endYear, month=1, day=1)
</del><ins>+    start = DateTime(year=startYear, month=1, day=1)
+    end = DateTime(year=endYear, month=1, day=1)
</ins><span class="cx"> 
</span><span class="cx">     zonefiles = (
</span><span class="cx">         &quot;northamerica&quot;,
</span></span></pre></div>
<a id="PyCalendartrunksrczonalutilspy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/utils.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/utils.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/utils.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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></pre></div>
<a id="PyCalendartrunksrczonalzonepy"></a>
<div class="modfile"><h4>Modified: PyCalendar/trunk/src/zonal/zone.py (11913 => 11914)</h4>
<pre class="diff"><span>
<span class="info">--- PyCalendar/trunk/src/zonal/zone.py        2013-11-08 20:27:23 UTC (rev 11913)
+++ PyCalendar/trunk/src/zonal/zone.py        2013-11-08 20:35:58 UTC (rev 11914)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> ##
</span><del>-#    Copyright (c) 2007-2012 Cyrus Daboo. All rights reserved.
</del><ins>+#    Copyright (c) 2007-2013 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">@@ -14,14 +14,14 @@
</span><span class="cx"> #    limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.vtimezone import PyCalendarVTimezone
-from pycalendar.property import PyCalendarProperty
-from pycalendar import definitions
-from pycalendar.vtimezonestandard import PyCalendarVTimezoneStandard
-from pycalendar.utcoffsetvalue import PyCalendarUTCOffsetValue
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.property import Property
+from pycalendar.icalendar.vtimezone import VTimezone
+from pycalendar.icalendar.vtimezonestandard import Standard
+from pycalendar.utcoffsetvalue import UTCOffsetValue
+import rule
</ins><span class="cx"> import utils
</span><del>-import rule
</del><span class="cx"> 
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> Class that maintains a TZ data Zone.
</span><span class="lines">@@ -129,7 +129,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Start at 1/1/1800 with the offset from the initial zone rule
</span><del>-        start = PyCalendarDateTime(year=1800, month=1, day=1, hours=0, minutes=0, seconds=0)
</del><ins>+        start = DateTime(year=1800, month=1, day=1, hours=0, minutes=0, seconds=0)
</ins><span class="cx">         start_offset = self.rules[0].getUTCOffset()
</span><span class="cx">         start_stdoffset = self.rules[0].getUTCOffset()
</span><span class="cx">         startdt = start.duplicate()
</span><span class="lines">@@ -178,7 +178,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Generate a VTIMEZONE for this Zone.
</span><span class="cx"> 
</span><del>-        @param calendar: the L{PyCalendar} object for the VCALENDAR in which the VTIMEZONE
</del><ins>+        @param calendar: the L{Calendar} object for the VCALENDAR in which the VTIMEZONE
</ins><span class="cx">             will be created.
</span><span class="cx">         @param rules: the C{dict} containing the set of Rules currently defined.
</span><span class="cx">         @param startYear: a C{int} containing the first year that should be present
</span><span class="lines">@@ -187,11 +187,11 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Get a VTIMEZONE component
</span><del>-        vtz = PyCalendarVTimezone(parent=calendar)
</del><ins>+        vtz = VTimezone(parent=calendar)
</ins><span class="cx"> 
</span><span class="cx">         # Add TZID property
</span><del>-        vtz.addProperty(PyCalendarProperty(definitions.cICalProperty_TZID, self.name))
-        vtz.addProperty(PyCalendarProperty(&quot;X-LIC-LOCATION&quot;, self.name))
</del><ins>+        vtz.addProperty(Property(definitions.cICalProperty_TZID, self.name))
+        vtz.addProperty(Property(&quot;X-LIC-LOCATION&quot;, self.name))
</ins><span class="cx"> 
</span><span class="cx">         transitions = self.expand(rules, minYear, maxYear)
</span><span class="cx"> 
</span><span class="lines">@@ -270,7 +270,7 @@
</span><span class="cx">         RDATEs assuming all other properties are the same.
</span><span class="cx"> 
</span><span class="cx">         @param vtz: the VTIMEZONE object to compress
</span><del>-        @type vtz: L{PyCalendarVTimezone}
</del><ins>+        @type vtz: L{VTimezone}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Map the similar sub-components together
</span><span class="lines">@@ -385,16 +385,16 @@
</span><span class="cx">                 month = int(rule.Rule.MONTH_NAME_TO_POS[splits[1]])
</span><span class="cx">                 if len(splits) &gt; 2 and not splits[2].startswith(&quot;#&quot;):
</span><span class="cx">                     if splits[2] == &quot;lastSun&quot;:
</span><del>-                        dt = PyCalendarDateTime(year=year, month=month, day=1)
-                        dt.setDayOfWeekInMonth(-1, PyCalendarDateTime.SUNDAY)
</del><ins>+                        dt = DateTime(year=year, month=month, day=1)
+                        dt.setDayOfWeekInMonth(-1, DateTime.SUNDAY)
</ins><span class="cx">                         splits[2] = dt.getDay()
</span><span class="cx">                     elif splits[2] == &quot;lastSat&quot;:
</span><del>-                        dt = PyCalendarDateTime(year=year, month=month, day=1)
-                        dt.setDayOfWeekInMonth(-1, PyCalendarDateTime.SATURDAY)
</del><ins>+                        dt = DateTime(year=year, month=month, day=1)
+                        dt.setDayOfWeekInMonth(-1, DateTime.SATURDAY)
</ins><span class="cx">                         splits[2] = dt.getDay()
</span><span class="cx">                     elif splits[2] == &quot;Sun&gt;=1&quot;:
</span><del>-                        dt = PyCalendarDateTime(year=year, month=month, day=1)
-                        dt.setDayOfWeekInMonth(1, PyCalendarDateTime.SUNDAY)
</del><ins>+                        dt = DateTime(year=year, month=month, day=1)
+                        dt.setDayOfWeekInMonth(1, DateTime.SUNDAY)
</ins><span class="cx">                         splits[2] = dt.getDay()
</span><span class="cx">                     day = int(splits[2])
</span><span class="cx">                     if len(splits) &gt; 3 and not splits[3].startswith(&quot;#&quot;):
</span><span class="lines">@@ -408,7 +408,7 @@
</span><span class="cx">                         if len(splits) &gt; 2:
</span><span class="cx">                             seconds = int(splits[2])
</span><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime(year=year, month=month, day=day, hours=hours, minutes=minutes, seconds=seconds)
</del><ins>+        dt = DateTime(year=year, month=month, day=day, hours=hours, minutes=minutes, seconds=seconds)
</ins><span class="cx">         self._cached_until = utils.DateTime(dt, mode)
</span><span class="cx">         return self._cached_until
</span><span class="cx"> 
</span><span class="lines">@@ -493,27 +493,27 @@
</span><span class="cx">     def vtimezone(self, vtz, zonerule, start, end, offsetfrom, offsetto):
</span><span class="cx"> 
</span><span class="cx">         # Determine type of component based on offset
</span><del>-        comp = PyCalendarVTimezoneStandard(parent=vtz)
</del><ins>+        comp = Standard(parent=vtz)
</ins><span class="cx"> 
</span><span class="cx">         # Do offsets
</span><del>-        tzoffsetfrom = PyCalendarUTCOffsetValue(offsetfrom)
-        tzoffsetto = PyCalendarUTCOffsetValue(offsetto)
</del><ins>+        tzoffsetfrom = UTCOffsetValue(offsetfrom)
+        tzoffsetto = UTCOffsetValue(offsetto)
</ins><span class="cx"> 
</span><del>-        comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZOFFSETFROM, tzoffsetfrom))
-        comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZOFFSETTO, tzoffsetto))
</del><ins>+        comp.addProperty(Property(definitions.cICalProperty_TZOFFSETFROM, tzoffsetfrom))
+        comp.addProperty(Property(definitions.cICalProperty_TZOFFSETTO, tzoffsetto))
</ins><span class="cx"> 
</span><span class="cx">         # Do TZNAME
</span><span class="cx">         if self.format.find(&quot;%&quot;) != -1:
</span><span class="cx">             tzname = self.format % (&quot;S&quot;,)
</span><span class="cx">         else:
</span><span class="cx">             tzname = self.format
</span><del>-        comp.addProperty(PyCalendarProperty(definitions.cICalProperty_TZNAME, tzname))
</del><ins>+        comp.addProperty(Property(definitions.cICalProperty_TZNAME, tzname))
</ins><span class="cx"> 
</span><span class="cx">         # Do DTSTART
</span><del>-        comp.addProperty(PyCalendarProperty(definitions.cICalProperty_DTSTART, start))
</del><ins>+        comp.addProperty(Property(definitions.cICalProperty_DTSTART, start))
</ins><span class="cx"> 
</span><span class="cx">         # Recurrence
</span><del>-        comp.addProperty(PyCalendarProperty(definitions.cICalProperty_RDATE, start))
</del><ins>+        comp.addProperty(Property(definitions.cICalProperty_RDATE, start))
</ins><span class="cx"> 
</span><span class="cx">         comp.finalise()
</span><span class="cx">         vtz.addComponent(comp)
</span></span></pre>
</div>
</div>

</body>
</html>