<!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>[12110] CalendarServer/branches/users/gaya/sharedgroupfixes</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/12110">12110</a></dd>
<dt>Author</dt> <dd>gaya@apple.com</dd>
<dt>Date</dt> <dd>2013-12-13 22:28:16 -0800 (Fri, 13 Dec 2013)</dd>
</dl>

<h3>Log Message</h3>
<pre>merge in 11861 to 12016 from trunk</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterREADMEtxt">CalDAVTester/branches/users/gaya/sharedgroupfixestester/README.txt</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterResourceCalDAVprivatecomments32ics">CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/32.ics</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterResourceCalDAVprivatecomments35ics">CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/35.ics</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterResourceCalDAVprivatecomments37ics">CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/37.ics</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptsserverserverinfotemplatexml">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-template.xml</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptsserverserverinfodtd">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo.dtd</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptsserverserverinfoxml">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo.xml</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVcaldavtestdtd">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/caldavtest.dtd</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVimplicitdefaultcalendarxml">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/implicitdefaultcalendar.xml</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVprivatecommentsxml">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/privatecomments.xml</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVsharingnotificationsyncxml">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/sharing-notification-sync.xml</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVsyncreportxml">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/sync-report.xml</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCardDAVcaldavtestdtd">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CardDAV/caldavtest.dtd</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestestersrccaldavtestpy">CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/caldavtest.py</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestestersrcmanagerpy">CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/manager.py</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestestersrcrequestpy">CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/request.py</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestestersrcserverinfopy">CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/serverinfo.py</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestestersrcxmlDefspy">CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/xmlDefs.py</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterverifiersaddressDataMatchpy">CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/addressDataMatch.py</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterverifierscalendarDataMatchpy">CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/calendarDataMatch.py</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterverifiersfreeBusypy">CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/freeBusy.py</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterverifierspostFreeBusypy">CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/postFreeBusy.py</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterverifiersxmlElementMatchpy">CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/xmlElementMatch.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesHACKING">CalendarServer/branches/users/gaya/sharedgroupfixes/HACKING</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesbin_calendarserver_preamblepy">CalendarServer/branches/users/gaya/sharedgroupfixes/bin/_calendarserver_preamble.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushamppushpy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/amppush.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushapplepushpy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/applepush.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushnotifierpy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/notifier.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushtesttest_amppushpy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_amppush.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushtesttest_applepushpy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_applepush.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushtesttest_notifierpy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_notifier.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushutilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertapcaldavpy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tap/caldav.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertaputilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tap/util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsampnotificationspy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/ampnotifications.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsanonymizepy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/anonymize.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolscalverifypy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/calverify.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsdbinspectpy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/dbinspect.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsgatewaypy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/gateway.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsmanagetimezonespy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/managetimezones.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolspurgepy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/purge.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsshelldirectorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/shell/directory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstestdeprovisioncaldavdplist">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/deprovision/caldavd.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstestgatewaycaldavdplist">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/gateway/caldavd.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstestprincipalscaldavdplist">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/principals/caldavd.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstesttest_calverifypy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_calverify.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstesttest_gatewaypy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_gateway.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstesttest_purgepy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_purge.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstesttest_purge_old_eventspy">CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_purge_old_events.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfauthaugmentsdtd">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/augments.dtd</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfcaldavdtestplist">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconflocalserverstestxml">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers-test.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconflocalserversxml">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfremoteserverstestxml">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers-test.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfremoteserversxml">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfresourcescaldavdresourcesplist">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/resources/caldavd-resources.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformanceloadtesticalpy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/ical.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformanceloadtestprofilespy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/profiles.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformanceloadtestsimpy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/sim.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformanceloadtesttest_icalpy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/test_ical.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformancesqlusagerequestsinvitepy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/invite.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformancesqlusagerequestsputpy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/put.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformancesqlusagerequestsquerypy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/query.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformancesqlusagerequestssyncpy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/sync.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformancesqlusagesqlusagepy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/sqlusage.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformancestatspy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/stats.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribperformancetest_statspy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/test_stats.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribtoolsrequest_monitorpy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/tools/request_monitor.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixescontribtoolssortrecurrencespy">CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/tools/sortrecurrences.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixessetuppy">CalendarServer/branches/users/gaya/sharedgroupfixes/setup.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixessupportbuildsh">CalendarServer/branches/users/gaya/sharedgroupfixes/support/build.sh</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixessupportversionpy">CalendarServer/branches/users/gaya/sharedgroupfixes/support/version.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestest">CalendarServer/branches/users/gaya/sharedgroupfixes/test</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextenterprisedalsyntaxpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/dal/syntax.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextenterprisefixturespy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/fixtures.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextenterprisequeuepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/queue.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextenterprisetesttest_queuepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/test/test_queue.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextinternetsendfdportpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/internet/sendfdport.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextprotocolstesttest_memcachepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/protocols/test/test_memcache.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhoaggregatepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/aggregate.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhodirectorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/directory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhoexpressionpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/expression.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhoidirectorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/idirectory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhoindexpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/index.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_aggregatepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_aggregate.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_directorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_directory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_expressionpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_expression.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_utilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_xmlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_xml.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhoutilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhoxmlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/xml.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldav__init__py">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/__init__.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavaccountingpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/accounting.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavauthkerbpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/authkerb.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavbackuppy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/backup.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavcaldavxmlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/caldavxml.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavcarddavxmlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/carddavxml.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavconfigpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/config.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavcustomxmlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/customxml.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdatabasepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/database.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdatafilterscalendardatapy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/datafilters/calendardata.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdateopspy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/dateops.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryaddressbookpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/addressbook.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryaugmentpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/augment.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorycommonpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/common.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorydirectoryprincipalresourcehtml">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/directory-principal-resource.html</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorydirectorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/directory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryidirectorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/idirectory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryldapdirectorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/ldapdirectory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryopendirectorybackerpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/opendirectorybacker.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryprincipalpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/principal.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryresourcepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/resource.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestaugmentstestdefaultxml">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/augments-test-default.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestaugmentstestxml">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/augments-test.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestresourcescaldavdplist">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/resources/caldavd.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_aggregatepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_aggregate.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_augmentpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_augment.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_cachedirectorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_cachedirectory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_digestpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_digest.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_directorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_directory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_guidchangepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_guidchange.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_ldapdirectorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_ldapdirectory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_livedirectorypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_livedirectory.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_modifypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_modify.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_opendirectorybackerpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_opendirectorybacker.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_proxyprincipaldbpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_proxyprincipaldb.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_resourcespy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_resources.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_xmlfilepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_xmlfile.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestutilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryxmlaugmentsparserpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/xmlaugmentsparser.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdropboxpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/dropbox.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavextensionspy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/extensions.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavfreebusyurlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/freebusyurl.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavicalpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/ical.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavicaldavpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/icaldav.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavinstancepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/instance.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavlinkresourcepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/linkresource.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavlocalizationpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/localization.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmemcachelockpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/memcachelock.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmemcachepoolpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/memcachepool.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmethodgetpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/get.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmethodpropfindpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/propfind.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmethodreport_calendar_querypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_calendar_query.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmethodreport_commonpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_common.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmethodreport_freebusypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_freebusy.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmkcolxmlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/mkcolxml.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavnotificationspy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/notifications.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavquerycalendarqueryfilterpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/calendarqueryfilter.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavquerytesttest_calendarquerypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/test/test_calendarquery.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavquerytesttest_queryfilterpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/test/test_queryfilter.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavresourcepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/resource.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavscheduling_storecaldavresourcepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/scheduling_store/caldav/resource.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavsharingpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/sharing.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavsqlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/sql.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavstdconfigpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/stdconfig.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavstorebridgepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/storebridge.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_addressbookmultigetpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_addressbookmultiget.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_caldavxmlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_caldavxml.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_calendarquerypy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_calendarquery.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_configpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_config.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_dateopspy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_dateops.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_icalendarpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_icalendar.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_localizationpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_localization.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_multigetpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_multiget.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_propspy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_props.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_timezonespy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_timezones.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_upgradepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_upgrade.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtimezonespy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezones.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtimezoneservicepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezoneservice.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtimezonestdservicepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezonestdservice.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavupgradepy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/upgrade.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavutilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavvcardpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/vcard.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavxmlutilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/xmlutil.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAfricaCasablancaics">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/Casablanca.ics</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAfricaEl_Aaiunics">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/El_Aaiun.ics</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAfricaTripoliics">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/Tripoli.ics</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAmericaEirunepeics">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Eirunepe.ics</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAmericaPorto_Acreics">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Porto_Acre.ics</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAmericaRio_Brancoics">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Rio_Branco.ics</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoBrazilAcreics">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Brazil/Acre.ics</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoLibyaics">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Libya.ics</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfotimezonesxml">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/timezones.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoversiontxt">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/version.txt</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavbasepropertystorebasepy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/base/propertystore/base.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavbasepropertystoretestbasepy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/base/propertystore/test/base.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastorefilepy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/file.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreindex_filepy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/index_file.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingaddressmappingpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/addressmapping.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingcaldavdeliverypy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/delivery.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingcaldavschedulerpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/scheduler.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingcaldavtesttest_schedulerpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/test/test_scheduler.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingcuaddresspy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/cuaddress.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingfreebusypy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/freebusy.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingicaldiffpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/icaldiff.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingicalsplitterpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/icalsplitter.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingimipoutboundpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/outbound.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingimiptesttest_deliverypy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_delivery.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingimiptesttest_inboundpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_inbound.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingimiptesttest_outboundpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_outbound.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingimplicitpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/implicit.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduledeliverypy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/delivery.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischedulelocalserverspy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/localservers.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduleremoteserverspy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/remoteservers.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduleresourcepy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/resource.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduleschedulerpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/scheduler.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduletesttest_deliverypy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_delivery.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduletesttest_localserverspy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_localservers.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduletesttest_resourcepy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_resource.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingitippy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/itip.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingprocessingpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/processing.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingschedulerpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/scheduler.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingtesttest_freebusypy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_freebusy.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingtesttest_icalsplitterpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_icalsplitter.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingtesttest_implicitpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_implicit.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingtesttest_itippy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_itip.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingtesttest_utilspy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_utils.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingutilspy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/utils.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoresqlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/sql.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretestcommonpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/common.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_attachmentspy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_attachments.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_filepy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_file.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_implicitpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_implicit.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_index_filepy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_index_file.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_sqlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_sql.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_utilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretestutilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreutilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavicalendardirectoryservicepy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/icalendardirectoryservice.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavicalendarstorepy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/icalendarstore.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcarddavdatastoretestcommonpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/carddav/datastore/test/common.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresqlpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_legacypy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_legacy.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemacurrentoracledialectsql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/current-oracle-dialect.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemacurrentsql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/current.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_25_to_26sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_25_to_26.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_25_to_26sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_25_to_26.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoretestutilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/test/util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoreupgradesqlupgradescalendar_upgrade_from_3_to_4py">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_3_to_4.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoreupgradesqlupgradescalendar_upgrade_from_4_to_5py">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_4_to_5.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoreupgradesqlupgradestesttest_upgrade_from_4_to_5py">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_4_to_5.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavidavpy">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/idav.py</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/podding/</li>
<li>CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/polls/</li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptsserverserverinfopodxml">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-pod.xml</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVpollsxml">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/polls.xml</a></li>
<li>CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests-pod/</li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesbintrial">CalendarServer/branches/users/gaya/sharedgroupfixes/bin/trial</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesbintwistd">CalendarServer/branches/users/gaya/sharedgroupfixes/bin/twistd</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfauthaccountstestpodxml">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/accounts-test-pod.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfauthaugmentstestpodxml">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/augments-test-pod.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfauthproxiestestpodxml">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/proxies-test-pod.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfauthresourcestestpodxml">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/resources-test-pod.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfcaldavdtestpodAplist">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test-podA.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfcaldavdtestpodBplist">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test-podB.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconflocalserversdtd">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers.dtd</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfremoteserversdtd">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers.dtd</a></li>
<li>CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/webpoll/</li>
<li>CalendarServer/branches/users/gaya/sharedgroupfixes/twext/application/</li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextprotocolsechopy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/protocols/echo.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_indexpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_index.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedpluginsmasterchildpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twisted/plugins/masterchild.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_utilpy">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_util.py</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldoracledialectv24sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v24.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldoracledialectv26sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v26.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldoracledialectv27sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v27.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldoracledialectv28sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v28.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldpostgresdialectv24sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v24.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldpostgresdialectv26sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v26.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldpostgresdialectv27sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v27.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldpostgresdialectv28sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v28.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_24_to_25sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_24_to_25.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_26_to_27sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_26_to_27.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_27_to_28sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_27_to_28.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_28_to_29sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_28_to_29.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_24_to_25sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_24_to_25.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_26_to_27sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_26_to_27.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_27_to_28sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_27_to_28.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_28_to_29sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_28_to_29.sql</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptsserverserverinfopartitioningxml">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-partitioning.xml</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesbincalendarserver_make_partition">CalendarServer/branches/users/gaya/sharedgroupfixes/bin/calendarserver_make_partition</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfcaldavdpartitioningprimaryplist">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-partitioning-primary.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfcaldavdpartitioningsecondaryplist">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-partitioning-secondary.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfserversdtd">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/servers.dtd</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfservertoserverdtd">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/servertoserver.dtd</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixesconfsudoersplist">CalendarServer/branches/users/gaya/sharedgroupfixes/conf/sudoers.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestsudoersplist">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/sudoers.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestsudoers2plist">CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/sudoers2.plist</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldoracledialectv24sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v24.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldpostgresdialectv24sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v24.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_24_to_25sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_24_to_25.sql</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_24_to_25sql">CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_24_to_25.sql</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestester">CalDAVTester/branches/users/gaya/sharedgroupfixestester/</a></li>
<li><a href="#CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCardDAV">CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CardDAV/</a></li>
<li><a href="#CalendarServerbranchesusersgayasharedgroupfixes">CalendarServer/branches/users/gaya/sharedgroupfixes/</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestester"></a>
<div class="propset"><h4>Property changes: CalDAVTester/branches/users/gaya/sharedgroupfixestester</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4>Modified: svn:mergeinfo</h4></div>
<span class="cx">/CalDAVTester/branches/release/CalDAVTester-4.3-dev:10193
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/attendee-comments-2887:2888-2910
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/better-proxy-3148:3149-3163
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/component-set-fixes:8221-8346
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/conditional-4466:4467-4469
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/implicitauto-2948:2949-2989
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/location-partial-accept-3574:3575-3581
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/managed-attachments:9986-10145
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/normalize-cuaddr-3533:3534-3558
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/pycalendar:7160-7206
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/pycard:7226-7237
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/sharing-5228:5229-5440
</span><span class="cx">/CalDAVTester/branches/users/gaya/sharedgroupstester-3:11181-11204
</span><span class="cx">/CalDAVTester/trunk:11742-11861
</span><span class="cx">   + /CalDAVTester/branches/release/CalDAVTester-3.0-dev:7584
</span><span class="cx">/CalDAVTester/branches/release/CalDAVTester-4.3-dev:10193
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/attendee-comments-2887:2888-2910
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/better-proxy-3148:3149-3163
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/component-set-fixes:8221-8346
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/conditional-4466:4467-4469
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/implicitauto-2948:2949-2989
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/location-partial-accept-3574:3575-3581
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/managed-attachments:9986-10145
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/normalize-cuaddr-3533:3534-3558
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/pycalendar:7160-7206
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/pycard:7226-7237
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/sharing-5228:5229-5440
</span><span class="cx">/CalDAVTester/branches/users/gaya/sharedgroupstester-3:11181-11204
</span><span class="cx">/CalDAVTester/trunk:11742-12016
</span><a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterREADMEtxt"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/README.txt (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/README.txt        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/README.txt        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -791,6 +791,7 @@
</span><span class="cx">         [+text] - node text starts with &quot;text&quot;.
</span><span class="cx">         [^tag] - node has child element &quot;tag&quot;.
</span><span class="cx">         [^tag=text] - node has child element &quot;tag&quot; with text &quot;text&quot;.
</span><ins>+        [|] - node is empty.
</ins><span class="cx">         [json] - node contains valid JSON data.
</span><span class="cx">         [icalendar] - node contains valid iCalendare data.
</span><span class="cx">         
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterResourceCalDAVprivatecomments32ics"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/32.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/32.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/32.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="cx"> CALSCALE:GREGORIAN
</span><del>-PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
</del><ins>+PRODID:-//Example Inc.//Example Calendar//EN
</ins><span class="cx"> BEGIN:VTIMEZONE
</span><span class="cx"> TZID:US/Eastern
</span><span class="cx"> LAST-MODIFIED:20040110T032845Z
</span><span class="lines">@@ -25,11 +25,10 @@
</span><span class="cx"> DTSTART;TZID=US/Eastern:$now.year.1:0101T100000
</span><span class="cx"> DURATION:PT1H
</span><span class="cx"> ATTENDEE;CN=$username1:;PARTSTAT=ACCEPTED;EMAIL=$email1::$cuaddrurn1:
</span><del>-ATTENDEE;CN=$username2:;PARTSTAT=ACCEPTED;EMAIL=$email2::$cuaddrurn2:
</del><ins>+ATTENDEE;CN=$username2:;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0;EMAIL=$email2::$cuaddrurn2:
</ins><span class="cx"> CREATED:20060101T150000Z
</span><span class="cx"> DTSTAMP:20051222T205953Z
</span><del>-ORGANIZER;CN=$username1:;SCHEDULE-STATUS=1.2;EMAIL=$email1::$cuaddrurn1:
</del><ins>+ORGANIZER;CN=$username1:;EMAIL=$email1::$cuaddrurn1:
</ins><span class="cx"> SUMMARY:event 3
</span><del>-X-CALENDARSERVER-PRIVATE-COMMENT:I have accepted.
</del><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterResourceCalDAVprivatecomments35ics"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/35.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/35.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/35.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -31,6 +31,6 @@
</span><span class="cx"> ORGANIZER;CN=$username1:;EMAIL=$email1::$cuaddrurn1:
</span><span class="cx"> SUMMARY:event 3
</span><span class="cx"> X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF=&quot;$cuaddrurn2:
</span><del>- &quot;;X-CALENDARSERVER-DTSTAMP=20080827T171052Z:
</del><ins>+ &quot;;X-CALENDARSERVER-DTSTAMP=20080827T171052Z:I have accepted.
</ins><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterResourceCalDAVprivatecomments37ics"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/37.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/37.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/Resource/CalDAV/privatecomments/37.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -31,6 +31,6 @@
</span><span class="cx"> ORGANIZER;CN=$username1:;EMAIL=$email1::$cuaddrurn1:
</span><span class="cx"> SUMMARY:event 3
</span><span class="cx"> X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF=&quot;$cuaddrurn2:
</span><del>- &quot;;X-CALENDARSERVER-DTSTAMP=20080827T171052Z:
</del><ins>+ &quot;;X-CALENDARSERVER-DTSTAMP=20080827T171052Z:I have accepted.
</ins><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptsserverserverinfopartitioningxml"></a>
<div class="delfile"><h4>Deleted: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-partitioning.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-partitioning.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-partitioning.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,896 +0,0 @@
</span><del>-&lt;?xml version=&quot;1.0&quot; standalone=&quot;no&quot;?&gt;
-
-&lt;!DOCTYPE serverinfo SYSTEM &quot;serverinfo.dtd&quot;&gt;
-
-&lt;!--
- Copyright (c) 2006-2013 Apple Inc. 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.
- --&gt;
-
-&lt;serverinfo&gt;
-        &lt;host&gt;localhost&lt;/host&gt;
-        &lt;nonsslport&gt;8008&lt;/nonsslport&gt;
-        &lt;sslport&gt;8443&lt;/sslport&gt;
-        &lt;authtype&gt;basic&lt;/authtype&gt;
-
-        &lt;features&gt;
-                &lt;!--  Generic WebDAV extensions --&gt;
-                &lt;feature&gt;COPY Method&lt;/feature&gt;                                                        &lt;!-- COPY method --&gt;
-                &lt;feature&gt;MOVE Method&lt;/feature&gt;                                                        &lt;!-- MOVE method --&gt;
-                &lt;feature&gt;Extended MKCOL&lt;/feature&gt;                                                &lt;!-- Extended MKCOL --&gt;
-                
-                &lt;!-- ACL related --&gt;
-                &lt;feature&gt;ACL Method&lt;/feature&gt;                                                        &lt;!-- ACL method --&gt;
-                &lt;feature&gt;acl-principal-prop-set REPORT&lt;/feature&gt;                &lt;!-- ACL acl-principal-prop-set REPORT --&gt;
-                &lt;feature&gt;principal-match REPORT&lt;/feature&gt;                                &lt;!-- ACL principal-match REPORT --&gt;
-                &lt;feature&gt;principal-property-search REPORT&lt;/feature&gt;                &lt;!-- ACL principal-property-search REPORT --&gt;
-                &lt;feature&gt;principal-search-property-set REPORT&lt;/feature&gt;        &lt;!-- ACL principal-search-property-set REPORT --&gt;
-
-                &lt;feature&gt;add-member&lt;/feature&gt;                                        &lt;!-- Add-member used to create resources --&gt;
-                &lt;!-- &lt;feature&gt;auth-on-root&lt;/feature&gt; --&gt;                &lt;!-- Whether the server requires authentication on the root URI --&gt;
-                &lt;feature&gt;brief&lt;/feature&gt;                                            &lt;!-- Brief header for PROPFIND, REPORT --&gt;
-                &lt;feature&gt;bulk-post&lt;/feature&gt;                                        &lt;!-- Bulk POST requests --&gt;
-                &lt;feature&gt;ctag&lt;/feature&gt;                                                        &lt;!-- ctag extension --&gt;
-                &lt;feature&gt;current-user-principal&lt;/feature&gt;                &lt;!-- current-user-principal extension --&gt;
-                &lt;feature&gt;directory listing&lt;/feature&gt;                         &lt;!-- GET on collection --&gt;
-                &lt;feature&gt;extended-principal-search&lt;/feature&gt;        &lt;!-- Extended principal-property-search REPORT extension --&gt;
-                &lt;feature&gt;expand-property&lt;/feature&gt;                                &lt;!-- Expand property REPORT --&gt;
-                &lt;feature&gt;only-proxy-groups&lt;/feature&gt;                        &lt;!-- Group-membership only includes delegated-to groups --&gt;
-                &lt;feature&gt;limits&lt;/feature&gt;                                                &lt;!-- max-collections and max-resources limits --&gt;
-                &lt;feature&gt;prefer&lt;/feature&gt;                                                &lt;!-- Prefer header overall support --&gt;
-                &lt;feature&gt;prefer-minimal&lt;/feature&gt;                                &lt;!-- Prefer header return=minimal --&gt;
-                &lt;feature&gt;prefer-representation&lt;/feature&gt;                &lt;!-- Prefer header return=representation --&gt;
-                &lt;feature&gt;prefer-noroot&lt;/feature&gt;                                &lt;!-- Prefer header depth-noroot --&gt;
-                &lt;feature&gt;quota&lt;/feature&gt;                                                &lt;!-- WebDAV QUOTA --&gt;
-                &lt;!-- &lt;feature&gt;quota-on-resources&lt;/feature&gt; --&gt;        &lt;!-- WebDAV QUOTA on calendar and address book object resources --&gt;
-                &lt;feature&gt;resource-id&lt;/feature&gt;                                        &lt;!-- WebDAV BIND DAV:resource-id property --&gt;
-                &lt;feature&gt;sync-report&lt;/feature&gt;                                        &lt;!-- WebDAV collection sync REPORT --&gt;
-                &lt;!-- &lt;feature&gt;sync-report-limit&lt;/feature&gt; --&gt;        &lt;!-- WebDAV collection sync REPORT DAV:limit support --&gt;
-                &lt;feature&gt;sync-report-home&lt;/feature&gt;                                &lt;!-- WebDAV collection sync REPORT on Homes --&gt;
-                &lt;feature&gt;well-known&lt;/feature&gt;                                        &lt;!-- well-known feature --&gt;
-
-                &lt;!-- &lt;feature&gt;per-object-ACLs&lt;/feature&gt; --&gt;                &lt;!-- ACL for objects in calendar/address books --&gt;
-                &lt;!-- &lt;feature&gt;regular-collection&lt;/feature&gt; --&gt;  &lt;!-- Regular collections allowed in calendar/address book homes --&gt;
-
-                &lt;!-- &lt;feature&gt;json-data&lt;/feature&gt; --&gt;                        &lt;!-- jCal and jCard support --&gt;
-
-                &lt;!-- CalDAV specific extension --&gt;
-                &lt;feature&gt;caldav&lt;/feature&gt;                                            &lt;!-- Basic CalDAV feature enabler --&gt;
-                &lt;feature&gt;attachments-collection&lt;/feature&gt;                &lt;!-- Server uses a collection in same WebDAV tree to store attachments --&gt;
-                &lt;feature&gt;auto-accept&lt;/feature&gt;                                        &lt;!-- Auto-accept for rooms &amp; locations --&gt;
-                &lt;feature&gt;auto-accept-modes&lt;/feature&gt;                        &lt;!-- Auto-accept modes --&gt;
-                &lt;!-- &lt;feature&gt;dropbox&lt;/feature&gt; --&gt;                                &lt;!-- dropbox extension --&gt;
-                &lt;feature&gt;default-alarms&lt;/feature&gt;                                &lt;!-- default alarms extension --&gt;
-                &lt;feature&gt;EMAIL parameter&lt;/feature&gt;                                &lt;!-- Server normalizes cuaddress and adds EMAIL parameter --&gt;
-                &lt;feature&gt;extended-freebusy&lt;/feature&gt;                      &lt;!-- Extended freebusy response --&gt;
-                &lt;feature&gt;implicit-scheduling&lt;/feature&gt;                        &lt;!-- CalDAV scheduling - implicit --&gt;
-                &lt;feature&gt;location-resource-tracking&lt;/feature&gt;   &lt;!-- Server tracks who makes unscheduled changes to locations and resources --&gt;
-                &lt;feature&gt;managed-attachments&lt;/feature&gt;                        &lt;!-- CalDAV Managed Attachments --&gt;
-                &lt;feature&gt;maskuid&lt;/feature&gt;                                                &lt;!-- maskuid extension --&gt;
-                &lt;feature&gt;no-duplicate-uids&lt;/feature&gt;                        &lt;!-- duplicate UIDs in same home not supported --&gt;
-                &lt;feature&gt;partitioning&lt;/feature&gt;                                        &lt;!-- Partitioned server --&gt;
-                &lt;feature&gt;partstat-timestamp&lt;/feature&gt;                        &lt;!-- Time stamps when PARTSTAT changes extension --&gt;
-                &lt;feature&gt;private-comments&lt;/feature&gt;                                &lt;!-- private-comments extension --&gt;
-                &lt;feature&gt;private-events&lt;/feature&gt;                                &lt;!-- private-events extension --&gt;
-                &lt;feature&gt;proxy&lt;/feature&gt;                                                &lt;!-- calendar-user-proxy extension --&gt;
-                &lt;!-- &lt;feature&gt;proxy-authz&lt;/feature&gt; --&gt;                        &lt;!-- sudo user extension --&gt;
-                &lt;feature&gt;remove-duplicate-alarms&lt;/feature&gt;           &lt;!-- Server removes any duplicate alarms on PUT --&gt;
-                &lt;feature&gt;query-extended&lt;/feature&gt;                                &lt;!-- calendar-query-extended extension --&gt;
-                &lt;feature&gt;shared-calendars&lt;/feature&gt;                                &lt;!-- Shared calendars extension --&gt;
-                &lt;feature&gt;schedule-changes&lt;/feature&gt;                                &lt;!-- schedule-changes property extension --&gt;
-                &lt;feature&gt;split-calendars&lt;/feature&gt;                                &lt;!-- Calendars are split by component type --&gt;
-                &lt;feature&gt;supported-component-sets&lt;/feature&gt;                &lt;!-- CALDAV:supported-calendar-component-sets on calendar homes --&gt;
-                &lt;feature&gt;supported-component-sets-one&lt;/feature&gt;        &lt;!-- Only single component calendars allowed to be created --&gt;
-                &lt;feature&gt;timerange-low-limit&lt;/feature&gt;                        &lt;!-- Time-range only valid one year back --&gt;
-                &lt;feature&gt;timerange-high-limit&lt;/feature&gt;                        &lt;!-- Time-range only valid 5 years ahead --&gt;
-                &lt;feature&gt;timezones-by-reference&lt;/feature&gt;                &lt;!-- Timezones by reference enabled --&gt;
-                &lt;feature&gt;timezone-service&lt;/feature&gt;                                &lt;!-- Timezone service extension for Wiki --&gt;
-                &lt;feature&gt;timezone-std-service&lt;/feature&gt;                        &lt;!-- Timezone standard service extension --&gt;
-                &lt;feature&gt;vavailability&lt;/feature&gt;                                &lt;!-- VAVAILABILITY on inbox --&gt;
-                &lt;feature&gt;webcal&lt;/feature&gt;                                                &lt;!-- Internet calendar subscription via GET on calendar collection --&gt;
-
-                &lt;!-- CardDAV specific extension --&gt;
-                &lt;feature&gt;carddav&lt;/feature&gt;                                                 &lt;!-- Basic CardDAV feature enabler --&gt;
-                &lt;feature&gt;default-addressbook&lt;/feature&gt;                         &lt;!-- Default address book behavior --&gt;
-                &lt;!-- &lt;feature&gt;global-addressbook&lt;/feature&gt; --&gt;         &lt;!-- Global address book for each user --&gt;
-                &lt;feature&gt;shared-addressbooks&lt;/feature&gt;                        &lt;!-- Shared address books extension --&gt;
-                &lt;!-- &lt;feature&gt;directory-gateway&lt;/feature&gt; --&gt;        &lt;!-- Directory gateway extension --&gt;
-
-        &lt;/features&gt;
-
-        &lt;substitutions&gt;
-                &lt;!-- Useful xpath shortcuts for verifiers --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$multistatus-response-prefix:&lt;/key&gt;
-                        &lt;value&gt;/{DAV:}multistatus/{DAV:}response&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$multistatus-href-prefix:&lt;/key&gt;
-                        &lt;value&gt;/{DAV:}multistatus/{DAV:}response/{DAV:}href&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$verify-response-prefix:&lt;/key&gt;
-                        &lt;value&gt;{DAV:}response/{DAV:}propstat/{DAV:}prop&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$verify-property-prefix:&lt;/key&gt;
-                        &lt;value&gt;/{DAV:}multistatus/{DAV:}response/{DAV:}propstat/{DAV:}prop&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$verify-bad-response:&lt;/key&gt;
-                        &lt;value&gt;/{DAV:}multistatus/{DAV:}response/{DAV:}status&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$verify-error-response:&lt;/key&gt;
-                        &lt;value&gt;/{DAV:}multistatus/{DAV:}response/{DAV:}error&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$CALDAV:&lt;/key&gt;
-                        &lt;value&gt;urn:ietf:params:xml:ns:caldav&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$CARDDAV:&lt;/key&gt;
-                        &lt;value&gt;urn:ietf:params:xml:ns:carddav&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$CS:&lt;/key&gt;
-                        &lt;value&gt;http://calendarserver.org/ns/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- Server configuration settings --&gt;
-                &lt;!-- $host: and $hostssl: are implicitly added by CalDAVTester based
-                     on the host/nonsslport/sslport values and ssl command line switch --&gt;
-
-                &lt;!-- relative path to caldav root--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$root:&lt;/key&gt;
-                        &lt;value&gt;/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- relative path to main principal collection--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principalcollection:&lt;/key&gt;
-                        &lt;value&gt;$root:principals/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- the core recored type collections--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$uidstype:&lt;/key&gt;
-                        &lt;value&gt;__uids__&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$userstype:&lt;/key&gt;
-                        &lt;value&gt;users&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$groupstype:&lt;/key&gt;
-                        &lt;value&gt;groups&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$locationstype:&lt;/key&gt;
-                        &lt;value&gt;locations&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$resourcestype:&lt;/key&gt;
-                        &lt;value&gt;resources&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- relative path to record type principal collections--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principals_uids:&lt;/key&gt;
-                        &lt;value&gt;$principalcollection:$uidstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principals_users:&lt;/key&gt;
-                        &lt;value&gt;$principalcollection:$userstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principals_groups:&lt;/key&gt;
-                        &lt;value&gt;$principalcollection:$groupstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principals_resources:&lt;/key&gt;
-                        &lt;value&gt;$principalcollection:$resourcestype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principals_locations:&lt;/key&gt;
-                        &lt;value&gt;$principalcollection:$locationstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- relative path to calendars collection--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$calendars:&lt;/key&gt;
-                        &lt;value&gt;$root:calendars/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- relative path to record type calendar collections--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$calendars_uids:&lt;/key&gt;
-                        &lt;value&gt;$calendars:$uidstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$calendars_users:&lt;/key&gt;
-                        &lt;value&gt;$calendars:$userstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$calendars_groups:&lt;/key&gt;
-                        &lt;value&gt;$calendars:$groupstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$calendars_resources:&lt;/key&gt;
-                        &lt;value&gt;$calendars:$resourcestype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$calendars_locations:&lt;/key&gt;
-                        &lt;value&gt;$calendars:$locationstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- primary calendar name--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$calendar:&lt;/key&gt;
-                        &lt;value&gt;calendar&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- primary tasks-only calendar name--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$tasks:&lt;/key&gt;
-                        &lt;value&gt;tasks&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- inbox name--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$inbox:&lt;/key&gt;
-                        &lt;value&gt;inbox&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- outbox name--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$outbox:&lt;/key&gt;
-                        &lt;value&gt;outbox&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- dropbox name--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$dropbox:&lt;/key&gt;
-                        &lt;value&gt;dropbox&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- attachments name--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$attachments:&lt;/key&gt;
-                        &lt;value&gt;dropbox&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- notification name--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$notification:&lt;/key&gt;
-                        &lt;value&gt;notification&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- freebusy name--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$freebusy:&lt;/key&gt;
-                        &lt;value&gt;freebusy&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- server-to-server inbox--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$servertoserver:&lt;/key&gt;
-                        &lt;value&gt;$root:inbox&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- timezone service--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$timezoneservice:&lt;/key&gt;
-                        &lt;value&gt;$root:timezones&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- timezone std service--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$timezonestdservice:&lt;/key&gt;
-                        &lt;value&gt;$root:stdtimezones&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- relative path to addressbooks collection--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$addressbooks:&lt;/key&gt;
-                        &lt;value&gt;$root:addressbooks/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- relative path to record type addressbook collections--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$addressbooks_uids:&lt;/key&gt;
-                        &lt;value&gt;$addressbooks:$uidstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$addressbooks_users:&lt;/key&gt;
-                        &lt;value&gt;$addressbooks:$userstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$addressbooks_groups:&lt;/key&gt;
-                        &lt;value&gt;$addressbooks:$groupstype:/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- primary addressbook name --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$addressbook:&lt;/key&gt;
-                        &lt;value&gt;addressbook&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- directory name --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$directory:&lt;/key&gt;
-                        &lt;value&gt;$root:directory/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- global-addressbook name --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$global_addressbook:&lt;/key&gt;
-                        &lt;value&gt;global-addressbook&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- POST add-member URI suffix --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$add-member:&lt;/key&gt;
-                        &lt;value&gt;;add-member&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- user id for admin user --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$useradmin:&lt;/key&gt;
-                        &lt;value&gt;admin&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- guid for admin user --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$useradminguid:&lt;/key&gt;
-                        &lt;value&gt;admin&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- password for admin user --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$pswdadmin:&lt;/key&gt;
-                        &lt;value&gt;admin&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- relative path to admin principal resource--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principal_admin:&lt;/key&gt;
-                        &lt;value&gt;$principals_users:$useradmin:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principaluri_admin:&lt;/key&gt;
-                        &lt;value&gt;$principals_uids:$useradminguid:/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- user id for apprentice user --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$userapprentice:&lt;/key&gt;
-                        &lt;value&gt;apprentice&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- guid for apprentice user --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$userapprenticeguid:&lt;/key&gt;
-                        &lt;value&gt;apprentice&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- password for admin user --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$pswdapprentice:&lt;/key&gt;
-                        &lt;value&gt;apprentice&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- relative path to apprentice principal resource--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principal_apprentice:&lt;/key&gt;
-                        &lt;value&gt;$principals_users:$userapprentice:/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principaluri_apprentice:&lt;/key&gt;
-                        &lt;value&gt;$principals_uids:$userapprenticeguid:/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- user id for proxy user --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$userproxy:&lt;/key&gt;
-                        &lt;value&gt;superuser&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- password for proxy user --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$pswdproxy:&lt;/key&gt;
-                        &lt;value&gt;superuser&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!--  Forty user accounts --&gt;
-                &lt;repeat count=&quot;40&quot;&gt;
-                        &lt;!-- user id --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$userid%d:&lt;/key&gt;
-                                &lt;value&gt;user%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- user guid --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$userguid%d:&lt;/key&gt;
-                                &lt;value&gt;user%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- user name --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$username%d:&lt;/key&gt;
-                                &lt;value&gt;User %02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- user name URI encoded --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$username-encoded%d:&lt;/key&gt;
-                                &lt;value&gt;User%%20%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- first name --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$firstname%d:&lt;/key&gt;
-                                &lt;value&gt;User&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- last name --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$lastname%d:&lt;/key&gt;
-                                &lt;value&gt;%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- password --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$pswd%d:&lt;/key&gt;
-                                &lt;value&gt;user%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user principal resource--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$principal%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_users:$userid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$principaluri%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_uids:$userguid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$principal%dnoslash:&lt;/key&gt;
-                                &lt;value&gt;$principals_users:$userid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-
-                        &lt;!-- relative path to user calendar home--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$calendarhome%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$userguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user alternate calendar home--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$calendarhomealt%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_users:$userid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user calendar--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$calendarpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendarhome%d:/$calendar:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user alternate calendar--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$calendarpathalt%d:&lt;/key&gt;
-                                &lt;value&gt;$calendarhomealt%d:/$calendar:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user tasks calendar--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$taskspath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendarhome%d:/$tasks:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user inbox--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$inboxpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendarhome%d:/$inbox:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user outbox--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$outboxpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendarhome%d:/$outbox:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user dropbox--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$dropboxpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendarhome%d:/$dropbox:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user notification--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$notificationpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendarhome%d:/$notification:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user freebusy--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$freebusypath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendarhome%d:/$freebusy:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$email%d:&lt;/key&gt;
-                                &lt;value&gt;$userid%d:@example.com&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- calendar user address of user--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$cuaddr%d:&lt;/key&gt;
-                                &lt;value&gt;mailto:$email%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$cuaddralt%d:&lt;/key&gt;
-                                &lt;value&gt;$principaluri%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$cuaddraltnoslash%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_uids:$userguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$cuaddrurn%d:&lt;/key&gt;
-                                &lt;value&gt;urn:uuid:$userguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-
-                        &lt;!-- relative path to user addressbook home--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$addressbookhome%d:&lt;/key&gt;
-                                &lt;value&gt;$addressbooks_uids:$userguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user addressbook--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$addressbookpath%d:&lt;/key&gt;
-                                &lt;value&gt;$addressbooks_uids:$userguid%d:/$addressbook:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                &lt;/repeat&gt;
-
-                &lt;!--  Ten public accounts --&gt;
-                &lt;repeat count=&quot;10&quot;&gt;
-                        &lt;!-- user id --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publicuserid%d:&lt;/key&gt;
-                                &lt;value&gt;public%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- user guid --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publicuserguid%d:&lt;/key&gt;
-                                &lt;value&gt;public%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- user name --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publicusername%d:&lt;/key&gt;
-                                &lt;value&gt;Public %02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- password --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publicpswd%d:&lt;/key&gt;
-                                &lt;value&gt;public%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user principal resource--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publicprincipal%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_users:$publicuserid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publicprincipaluri%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_uids:$publicuserguid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user calendar home--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publiccalendarhome%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$publicuserguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user calendar--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publiccalendarpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$publicuserguid%d:/$calendar:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publicemail%d:&lt;/key&gt;
-                                &lt;value&gt;$publicuserid%d:@example.com&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- calendar user address of user--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publiccuaddr%d:&lt;/key&gt;
-                                &lt;value&gt;mailto:$publicemail%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publiccuaddralt%d:&lt;/key&gt;
-                                &lt;value&gt;$publicprincipaluri%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$publiccuaddrurn%d:&lt;/key&gt;
-                                &lt;value&gt;urn:uuid:$publicuserguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                &lt;/repeat&gt;
-
-                &lt;!--  Twenty resource accounts --&gt;
-                &lt;repeat count=&quot;20&quot;&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$resourceid%d:&lt;/key&gt;
-                                &lt;value&gt;resource%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- resource guid--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$resourceguid%d:&lt;/key&gt;
-                                &lt;value&gt;resource%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- resource name--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$resourcename%d:&lt;/key&gt;
-                                &lt;value&gt;Resource %02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first resource calendar home--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$rcalendarhome%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$resourceguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first resource calendar home--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$rcalendarpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$resourceguid%d:/$calendar:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first resource inbox--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$rinboxpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$resourceguid%d:/$inbox:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first resource outbox--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$routboxpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$resourceguid%d:/$outbox:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first resource principal resource--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$rprincipal%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_resources:$resourceid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$rprincipaluri%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_uids:$resourceguid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$rcuaddralt%d:&lt;/key&gt;
-                                &lt;value&gt;$rprincipaluri%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$rcuaddrurn%d:&lt;/key&gt;
-                                &lt;value&gt;urn:uuid:$resourceguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                &lt;/repeat&gt;
-
-                &lt;!--  Ten Location accounts --&gt;
-                &lt;repeat count=&quot;10&quot;&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$locationid%d:&lt;/key&gt;
-                                &lt;value&gt;location%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- location guid--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$locationguid%d:&lt;/key&gt;
-                                &lt;value&gt;location%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- location name--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$locationname%d:&lt;/key&gt;
-                                &lt;value&gt;Location %02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first location calendar home--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$lcalendarhome%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$locationguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first location calendar home--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$lcalendarpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$locationguid%d:/$calendar:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first location inbox--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$linboxpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$locationguid%d:/$inbox:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first location outbox--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$loutboxpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$locationguid%d:/$outbox:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first location principal resource--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$lprincipal%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_resources:$locationid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$lprincipaluri%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_uids:$locationguid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$lcuaddralt%d:&lt;/key&gt;
-                                &lt;value&gt;$lprincipaluri%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$lcuaddrurn%d:&lt;/key&gt;
-                                &lt;value&gt;urn:uuid:$locationguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                &lt;/repeat&gt;
-
-
-                &lt;!--  Ten Group accounts --&gt;
-                &lt;repeat count=&quot;10&quot;&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$groupid%d:&lt;/key&gt;
-                                &lt;value&gt;group%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- group guid--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$groupguid%d:&lt;/key&gt;
-                                &lt;value&gt;group%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- group name--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$groupname%d:&lt;/key&gt;
-                                &lt;value&gt;Group %02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to first group principal resource--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$gprincipal%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_resources:$groupid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$gprincipaluri%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_uids:$groupguid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$gcuaddralt%d:&lt;/key&gt;
-                                &lt;value&gt;$gprincipaluri%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$gcuaddrurn%d:&lt;/key&gt;
-                                &lt;value&gt;urn:uuid:$groupguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                &lt;/repeat&gt;
-
-                &lt;!--  User with non-ascii name --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$i18nid:&lt;/key&gt;
-                        &lt;value&gt;i18nuser&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- group guid--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$i18nguid:&lt;/key&gt;
-                        &lt;value&gt;i18nuser&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- group name--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$i18nname:&lt;/key&gt;
-                        &lt;value&gt;まだ&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- password --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$i18npswd:&lt;/key&gt;
-                        &lt;value&gt;i18nuser&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- relative path to user calendar--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$i18ncalendarpath:&lt;/key&gt;
-                        &lt;value&gt;$calendars_uids:$i18nguid:/$calendar:&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$i18nemail:&lt;/key&gt;
-                        &lt;value&gt;$i18nid:@example.com&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- CUAddrs --&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$i18ncuaddr:&lt;/key&gt;
-                        &lt;value&gt;mailto:$i18nemail:&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$i18ncuaddrurn:&lt;/key&gt;
-                        &lt;value&gt;urn:uuid:$i18nguid:&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!-- relative path to disabled group principal resource--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principaldisabled:&lt;/key&gt;
-                        &lt;value&gt;$principals_groups:disabledgroup/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$principaluridisabled:&lt;/key&gt;
-                        &lt;value&gt;$principals_uids:disabledgroup/&lt;/value&gt;
-                &lt;/substitution&gt;
-                &lt;!-- calendar user address of disabled group--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$cuaddrdisabled:&lt;/key&gt;
-                        &lt;value&gt;$principals_uids:disabledgroup/&lt;/value&gt;
-                &lt;/substitution&gt;
-
-                &lt;!--  Ten other accounts --&gt;
-                &lt;repeat count=&quot;10&quot;&gt;
-                        &lt;!-- user id --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otherid%d:&lt;/key&gt;
-                                &lt;value&gt;other%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- user guid --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otherguid%d:&lt;/key&gt;
-                                &lt;value&gt;other%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- user name --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otherusername%d:&lt;/key&gt;
-                                &lt;value&gt;Other %02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- password --&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otherpswd%d:&lt;/key&gt;
-                                &lt;value&gt;other%02d&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user principal resource--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otherprincipal%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_users:$otherid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otherprincipaluri%d:&lt;/key&gt;
-                                &lt;value&gt;$principals_uids:$otherguid%d:/&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user calendar home--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$othercalendarhome%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$otherguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user calendar--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$othercalendarpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$otherguid%d:/$calendar:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user inbox--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otherinboxpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$otherguid%d:/$inbox:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user outbox--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otheroutboxpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$otherguid%d:/$outbox:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user dropbox--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otherdropboxpath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$otherguid%d:/$dropbox:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- relative path to user freebusy--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otherfreebusypath%d:&lt;/key&gt;
-                                &lt;value&gt;$calendars_uids:$otherguid%d:/$freebusy:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;!-- calendar user address of user--&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$otheremail%d:&lt;/key&gt;
-                                &lt;value&gt;$otherid%d:@example.com&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$othercuaddr%d:&lt;/key&gt;
-                                &lt;value&gt;mailto:$otheremail%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$othercuaddralt%d:&lt;/key&gt;
-                                &lt;value&gt;$otherprincipaluri%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                        &lt;substitution&gt;
-                                &lt;key&gt;$othercuaddrurn%d:&lt;/key&gt;
-                                &lt;value&gt;urn:uuid:$otherguid%d:&lt;/value&gt;
-                        &lt;/substitution&gt;
-                &lt;/repeat&gt;
-
-                &lt;!--  Override some of the above definitions for special cases --&gt;
-
-                &lt;!-- calendar user address of second user--&gt;
-                &lt;substitution&gt;
-                        &lt;key&gt;$cuaddr2:&lt;/key&gt;
-                        &lt;value&gt;MAILTO:$email2:&lt;/value&gt;
-                &lt;/substitution&gt;
-
-        &lt;/substitutions&gt;
-&lt;/serverinfo&gt;
</del></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptsserverserverinfopodxmlfromrev12016CalDAVTestertrunkscriptsserverserverinfopodxml"></a>
<div class="copfile"><h4>Copied: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-pod.xml (from rev 12016, CalDAVTester/trunk/scripts/server/serverinfo-pod.xml) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-pod.xml                                (rev 0)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-pod.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,652 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; standalone=&quot;no&quot;?&gt;
+
+&lt;!DOCTYPE serverinfo SYSTEM &quot;serverinfo.dtd&quot;&gt;
+
+&lt;!--
+ Copyright (c) 2006-2013 Apple Inc. 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.
+ --&gt;
+
+&lt;serverinfo&gt;
+        &lt;host&gt;localhost&lt;/host&gt;
+        &lt;nonsslport&gt;8008&lt;/nonsslport&gt;
+        &lt;sslport&gt;8443&lt;/sslport&gt;
+
+        &lt;host2&gt;localhost&lt;/host2&gt;
+        &lt;nonsslport2&gt;8108&lt;/nonsslport2&gt;
+        &lt;sslport2&gt;8543&lt;/sslport2&gt;
+
+        &lt;authtype&gt;basic&lt;/authtype&gt;
+
+        &lt;features&gt;
+                &lt;!--  Generic WebDAV extensions --&gt;
+                &lt;feature&gt;COPY Method&lt;/feature&gt;                                                        &lt;!-- COPY method --&gt;
+                &lt;feature&gt;MOVE Method&lt;/feature&gt;                                                        &lt;!-- MOVE method --&gt;
+                &lt;feature&gt;Extended MKCOL&lt;/feature&gt;                                                &lt;!-- Extended MKCOL --&gt;
+                
+                &lt;!-- ACL related --&gt;
+                &lt;feature&gt;ACL Method&lt;/feature&gt;                                                        &lt;!-- ACL method --&gt;
+                &lt;feature&gt;acl-principal-prop-set REPORT&lt;/feature&gt;                &lt;!-- ACL acl-principal-prop-set REPORT --&gt;
+                &lt;feature&gt;principal-match REPORT&lt;/feature&gt;                                &lt;!-- ACL principal-match REPORT --&gt;
+                &lt;feature&gt;principal-property-search REPORT&lt;/feature&gt;                &lt;!-- ACL principal-property-search REPORT --&gt;
+                &lt;feature&gt;principal-search-property-set REPORT&lt;/feature&gt;        &lt;!-- ACL principal-search-property-set REPORT --&gt;
+
+                &lt;feature&gt;add-member&lt;/feature&gt;                                        &lt;!-- Add-member used to create resources --&gt;
+                &lt;!-- &lt;feature&gt;auth-on-root&lt;/feature&gt; --&gt;                &lt;!-- Whether the server requires authentication on the root URI --&gt;
+                &lt;feature&gt;brief&lt;/feature&gt;                                            &lt;!-- Brief header for PROPFIND, REPORT --&gt;
+                &lt;feature&gt;bulk-post&lt;/feature&gt;                                        &lt;!-- Bulk POST requests --&gt;
+                &lt;feature&gt;ctag&lt;/feature&gt;                                                        &lt;!-- ctag extension --&gt;
+                &lt;feature&gt;current-user-principal&lt;/feature&gt;                &lt;!-- current-user-principal extension --&gt;
+                &lt;feature&gt;directory listing&lt;/feature&gt;                         &lt;!-- GET on collection --&gt;
+                &lt;feature&gt;extended-principal-search&lt;/feature&gt;        &lt;!-- Extended principal-property-search REPORT extension --&gt;
+                &lt;feature&gt;expand-property&lt;/feature&gt;                                &lt;!-- Expand property REPORT --&gt;
+                &lt;feature&gt;only-proxy-groups&lt;/feature&gt;                        &lt;!-- Group-membership only includes delegated-to groups --&gt;
+                &lt;feature&gt;limits&lt;/feature&gt;                                                &lt;!-- max-collections and max-resources limits --&gt;
+                &lt;feature&gt;prefer&lt;/feature&gt;                                                &lt;!-- Prefer header overall support --&gt;
+                &lt;feature&gt;prefer-minimal&lt;/feature&gt;                                &lt;!-- Prefer header return=minimal --&gt;
+                &lt;feature&gt;prefer-representation&lt;/feature&gt;                &lt;!-- Prefer header return=representation --&gt;
+                &lt;feature&gt;prefer-noroot&lt;/feature&gt;                                &lt;!-- Prefer header depth-noroot --&gt;
+                &lt;feature&gt;quota&lt;/feature&gt;                                                &lt;!-- WebDAV QUOTA --&gt;
+                &lt;!-- &lt;feature&gt;quota-on-resources&lt;/feature&gt; --&gt;        &lt;!-- WebDAV QUOTA on calendar and address book object resources --&gt;
+                &lt;feature&gt;resource-id&lt;/feature&gt;                                        &lt;!-- WebDAV BIND DAV:resource-id property --&gt;
+                &lt;feature&gt;sync-report&lt;/feature&gt;                                        &lt;!-- WebDAV collection sync REPORT --&gt;
+                &lt;!-- &lt;feature&gt;sync-report-limit&lt;/feature&gt; --&gt;        &lt;!-- WebDAV collection sync REPORT DAV:limit support --&gt;
+                &lt;feature&gt;sync-report-home&lt;/feature&gt;                                &lt;!-- WebDAV collection sync REPORT on Homes --&gt;
+                &lt;feature&gt;well-known&lt;/feature&gt;                                        &lt;!-- well-known feature --&gt;
+
+                &lt;!-- &lt;feature&gt;per-object-ACLs&lt;/feature&gt; --&gt;                &lt;!-- ACL for objects in calendar/address books --&gt;
+                &lt;!-- &lt;feature&gt;regular-collection&lt;/feature&gt; --&gt;  &lt;!-- Regular collections allowed in calendar/address book homes --&gt;
+
+                &lt;!-- &lt;feature&gt;json-data&lt;/feature&gt; --&gt;                        &lt;!-- jCal and jCard support --&gt;
+
+                &lt;!-- CalDAV specific extension --&gt;
+                &lt;feature&gt;caldav&lt;/feature&gt;                                            &lt;!-- Basic CalDAV feature enabler --&gt;
+                &lt;feature&gt;attachments-collection&lt;/feature&gt;                &lt;!-- Server uses a collection in same WebDAV tree to store attachments --&gt;
+                &lt;feature&gt;auto-accept&lt;/feature&gt;                                        &lt;!-- Auto-accept for rooms &amp; locations --&gt;
+                &lt;feature&gt;auto-accept-modes&lt;/feature&gt;                        &lt;!-- Auto-accept modes --&gt;
+                &lt;!-- &lt;feature&gt;dropbox&lt;/feature&gt; --&gt;                                &lt;!-- dropbox extension --&gt;
+                &lt;feature&gt;default-alarms&lt;/feature&gt;                                &lt;!-- default alarms extension --&gt;
+                &lt;feature&gt;EMAIL parameter&lt;/feature&gt;                                &lt;!-- Server normalizes cuaddress and adds EMAIL parameter --&gt;
+                &lt;feature&gt;extended-freebusy&lt;/feature&gt;                      &lt;!-- Extended freebusy response --&gt;
+                &lt;feature&gt;implicit-scheduling&lt;/feature&gt;                        &lt;!-- CalDAV scheduling - implicit --&gt;
+                &lt;feature&gt;location-resource-tracking&lt;/feature&gt;   &lt;!-- Server tracks who makes unscheduled changes to locations and resources --&gt;
+                &lt;feature&gt;managed-attachments&lt;/feature&gt;                        &lt;!-- CalDAV Managed Attachments --&gt;
+                &lt;feature&gt;maskuid&lt;/feature&gt;                                                &lt;!-- maskuid extension --&gt;
+                &lt;feature&gt;no-duplicate-uids&lt;/feature&gt;                        &lt;!-- duplicate UIDs in same home not supported --&gt;
+                &lt;feature&gt;partstat-timestamp&lt;/feature&gt;                        &lt;!-- Time stamps when PARTSTAT changes extension --&gt;
+                &lt;feature&gt;podding&lt;/feature&gt;                                                &lt;!-- Podded server --&gt;
+                &lt;feature&gt;private-comments&lt;/feature&gt;                                &lt;!-- private-comments extension --&gt;
+                &lt;feature&gt;private-events&lt;/feature&gt;                                &lt;!-- private-events extension --&gt;
+                &lt;feature&gt;proxy&lt;/feature&gt;                                                &lt;!-- calendar-user-proxy extension --&gt;
+                &lt;!-- &lt;feature&gt;proxy-authz&lt;/feature&gt; --&gt;                        &lt;!-- sudo user extension --&gt;
+                &lt;feature&gt;remove-duplicate-alarms&lt;/feature&gt;           &lt;!-- Server removes any duplicate alarms on PUT --&gt;
+                &lt;feature&gt;query-extended&lt;/feature&gt;                                &lt;!-- calendar-query-extended extension --&gt;
+                &lt;feature&gt;shared-calendars&lt;/feature&gt;                                &lt;!-- Shared calendars extension --&gt;
+                &lt;feature&gt;schedule-changes&lt;/feature&gt;                                &lt;!-- schedule-changes property extension --&gt;
+                &lt;feature&gt;split-calendars&lt;/feature&gt;                                &lt;!-- Calendars are split by component type --&gt;
+                &lt;feature&gt;supported-component-sets&lt;/feature&gt;                &lt;!-- CALDAV:supported-calendar-component-sets on calendar homes --&gt;
+                &lt;feature&gt;supported-component-sets-one&lt;/feature&gt;        &lt;!-- Only single component calendars allowed to be created --&gt;
+                &lt;feature&gt;timerange-low-limit&lt;/feature&gt;                        &lt;!-- Time-range only valid one year back --&gt;
+                &lt;feature&gt;timerange-high-limit&lt;/feature&gt;                        &lt;!-- Time-range only valid 5 years ahead --&gt;
+                &lt;feature&gt;timezones-by-reference&lt;/feature&gt;                &lt;!-- Timezones by reference enabled --&gt;
+                &lt;feature&gt;timezone-service&lt;/feature&gt;                                &lt;!-- Timezone service extension for Wiki --&gt;
+                &lt;feature&gt;timezone-std-service&lt;/feature&gt;                        &lt;!-- Timezone standard service extension --&gt;
+                &lt;feature&gt;vavailability&lt;/feature&gt;                                &lt;!-- VAVAILABILITY on inbox --&gt;
+                &lt;!-- &lt;feature&gt;vpoll&lt;/feature&gt; --&gt;                                &lt;!-- VPOLL support for store and scheduling --&gt;
+                &lt;feature&gt;webcal&lt;/feature&gt;                                                &lt;!-- Internet calendar subscription via GET on calendar collection --&gt;
+
+                &lt;!-- CardDAV specific extension --&gt;
+                &lt;feature&gt;carddav&lt;/feature&gt;                                                 &lt;!-- Basic CardDAV feature enabler --&gt;
+                &lt;feature&gt;default-addressbook&lt;/feature&gt;                         &lt;!-- Default address book behavior --&gt;
+                &lt;!-- &lt;feature&gt;global-addressbook&lt;/feature&gt; --&gt;         &lt;!-- Global address book for each user --&gt;
+                &lt;feature&gt;shared-addressbooks&lt;/feature&gt;                        &lt;!-- Shared address books extension --&gt;
+                &lt;!-- &lt;feature&gt;directory-gateway&lt;/feature&gt; --&gt;        &lt;!-- Directory gateway extension --&gt;
+
+        &lt;/features&gt;
+
+        &lt;substitutions&gt;
+                &lt;!-- Useful xpath shortcuts for verifiers --&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$multistatus-response-prefix:&lt;/key&gt;
+                        &lt;value&gt;/{DAV:}multistatus/{DAV:}response&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$multistatus-href-prefix:&lt;/key&gt;
+                        &lt;value&gt;/{DAV:}multistatus/{DAV:}response/{DAV:}href&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$verify-response-prefix:&lt;/key&gt;
+                        &lt;value&gt;{DAV:}response/{DAV:}propstat/{DAV:}prop&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$verify-property-prefix:&lt;/key&gt;
+                        &lt;value&gt;/{DAV:}multistatus/{DAV:}response/{DAV:}propstat/{DAV:}prop&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$verify-bad-response:&lt;/key&gt;
+                        &lt;value&gt;/{DAV:}multistatus/{DAV:}response/{DAV:}status&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$verify-error-response:&lt;/key&gt;
+                        &lt;value&gt;/{DAV:}multistatus/{DAV:}response/{DAV:}error&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$CALDAV:&lt;/key&gt;
+                        &lt;value&gt;urn:ietf:params:xml:ns:caldav&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$CARDDAV:&lt;/key&gt;
+                        &lt;value&gt;urn:ietf:params:xml:ns:carddav&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$CS:&lt;/key&gt;
+                        &lt;value&gt;http://calendarserver.org/ns/&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- Server configuration settings --&gt;
+                &lt;!-- $host: and $hostssl: are implicitly added by CalDAVTester based
+                     on the host/nonsslport/sslport values and ssl command line switch --&gt;
+
+                &lt;!-- relative path to caldav root--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$root:&lt;/key&gt;
+                        &lt;value&gt;/&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- relative path to main principal collection--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$principalcollection:&lt;/key&gt;
+                        &lt;value&gt;$root:principals/&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- the core recored type collections--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$uidstype:&lt;/key&gt;
+                        &lt;value&gt;__uids__&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$userstype:&lt;/key&gt;
+                        &lt;value&gt;users&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$groupstype:&lt;/key&gt;
+                        &lt;value&gt;groups&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$locationstype:&lt;/key&gt;
+                        &lt;value&gt;locations&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$resourcestype:&lt;/key&gt;
+                        &lt;value&gt;resources&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- relative path to record type principal collections--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$principals_uids:&lt;/key&gt;
+                        &lt;value&gt;$principalcollection:$uidstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$principals_users:&lt;/key&gt;
+                        &lt;value&gt;$principalcollection:$userstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$principals_groups:&lt;/key&gt;
+                        &lt;value&gt;$principalcollection:$groupstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$principals_resources:&lt;/key&gt;
+                        &lt;value&gt;$principalcollection:$resourcestype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$principals_locations:&lt;/key&gt;
+                        &lt;value&gt;$principalcollection:$locationstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- relative path to calendars collection--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$calendars:&lt;/key&gt;
+                        &lt;value&gt;$root:calendars/&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- relative path to record type calendar collections--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$calendars_uids:&lt;/key&gt;
+                        &lt;value&gt;$calendars:$uidstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$calendars_users:&lt;/key&gt;
+                        &lt;value&gt;$calendars:$userstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$calendars_groups:&lt;/key&gt;
+                        &lt;value&gt;$calendars:$groupstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$calendars_resources:&lt;/key&gt;
+                        &lt;value&gt;$calendars:$resourcestype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$calendars_locations:&lt;/key&gt;
+                        &lt;value&gt;$calendars:$locationstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- primary calendar name--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$calendar:&lt;/key&gt;
+                        &lt;value&gt;calendar&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- primary tasks-only calendar name--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$tasks:&lt;/key&gt;
+                        &lt;value&gt;tasks&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- inbox name--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$inbox:&lt;/key&gt;
+                        &lt;value&gt;inbox&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- outbox name--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$outbox:&lt;/key&gt;
+                        &lt;value&gt;outbox&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- dropbox name--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$dropbox:&lt;/key&gt;
+                        &lt;value&gt;dropbox&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- attachments name--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$attachments:&lt;/key&gt;
+                        &lt;value&gt;dropbox&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- notification name--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$notification:&lt;/key&gt;
+                        &lt;value&gt;notification&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- freebusy name--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$freebusy:&lt;/key&gt;
+                        &lt;value&gt;freebusy&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- server-to-server inbox--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$servertoserver:&lt;/key&gt;
+                        &lt;value&gt;$root:inbox&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- timezone service--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$timezoneservice:&lt;/key&gt;
+                        &lt;value&gt;$root:timezones&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- timezone std service--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$timezonestdservice:&lt;/key&gt;
+                        &lt;value&gt;$root:stdtimezones&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- relative path to addressbooks collection--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$addressbooks:&lt;/key&gt;
+                        &lt;value&gt;$root:addressbooks/&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- relative path to record type addressbook collections--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$addressbooks_uids:&lt;/key&gt;
+                        &lt;value&gt;$addressbooks:$uidstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$addressbooks_users:&lt;/key&gt;
+                        &lt;value&gt;$addressbooks:$userstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$addressbooks_groups:&lt;/key&gt;
+                        &lt;value&gt;$addressbooks:$groupstype:/&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- primary addressbook name --&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$addressbook:&lt;/key&gt;
+                        &lt;value&gt;addressbook&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- directory name --&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$directory:&lt;/key&gt;
+                        &lt;value&gt;$root:directory/&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- global-addressbook name --&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$global_addressbook:&lt;/key&gt;
+                        &lt;value&gt;global-addressbook&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- POST add-member URI suffix --&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$add-member:&lt;/key&gt;
+                        &lt;value&gt;;add-member&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- user id for admin user --&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$useradmin:&lt;/key&gt;
+                        &lt;value&gt;admin&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;!-- guid for admin user --&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$useradminguid:&lt;/key&gt;
+                        &lt;value&gt;admin&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;!-- password for admin user --&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$pswdadmin:&lt;/key&gt;
+                        &lt;value&gt;admin&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!-- relative path to admin principal resource--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$principal_admin:&lt;/key&gt;
+                        &lt;value&gt;$principals_users:$useradmin:/&lt;/value&gt;
+                &lt;/substitution&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$principaluri_admin:&lt;/key&gt;
+                        &lt;value&gt;$principals_uids:$useradminguid:/&lt;/value&gt;
+                &lt;/substitution&gt;
+
+                &lt;!--  Forty podA user accounts --&gt;
+                &lt;repeat count=&quot;40&quot;&gt;
+                        &lt;!-- user id --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$userid%d:&lt;/key&gt;
+                                &lt;value&gt;user%02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- user guid --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$userguid%d:&lt;/key&gt;
+                                &lt;value&gt;user%02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- user name --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$username%d:&lt;/key&gt;
+                                &lt;value&gt;User %02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- user name URI encoded --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$username-encoded%d:&lt;/key&gt;
+                                &lt;value&gt;User%%20%02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- first name --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$firstname%d:&lt;/key&gt;
+                                &lt;value&gt;User&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- last name --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$lastname%d:&lt;/key&gt;
+                                &lt;value&gt;%02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- password --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pswd%d:&lt;/key&gt;
+                                &lt;value&gt;user%02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user principal resource--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$principal%d:&lt;/key&gt;
+                                &lt;value&gt;$principals_users:$userid%d:/&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$principaluri%d:&lt;/key&gt;
+                                &lt;value&gt;$principals_uids:$userguid%d:/&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$principal%dnoslash:&lt;/key&gt;
+                                &lt;value&gt;$principals_users:$userid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+
+                        &lt;!-- relative path to user calendar home--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$calendarhome%d:&lt;/key&gt;
+                                &lt;value&gt;$calendars_uids:$userguid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user alternate calendar home--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$calendarhomealt%d:&lt;/key&gt;
+                                &lt;value&gt;$calendars_users:$userid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user calendar--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$calendarpath%d:&lt;/key&gt;
+                                &lt;value&gt;$calendarhome%d:/$calendar:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user alternate calendar--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$calendarpathalt%d:&lt;/key&gt;
+                                &lt;value&gt;$calendarhomealt%d:/$calendar:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user tasks calendar--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$taskspath%d:&lt;/key&gt;
+                                &lt;value&gt;$calendarhome%d:/$tasks:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user inbox--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$inboxpath%d:&lt;/key&gt;
+                                &lt;value&gt;$calendarhome%d:/$inbox:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user outbox--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$outboxpath%d:&lt;/key&gt;
+                                &lt;value&gt;$calendarhome%d:/$outbox:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user dropbox--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$dropboxpath%d:&lt;/key&gt;
+                                &lt;value&gt;$calendarhome%d:/$dropbox:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user notification--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$notificationpath%d:&lt;/key&gt;
+                                &lt;value&gt;$calendarhome%d:/$notification:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user freebusy--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$freebusypath%d:&lt;/key&gt;
+                                &lt;value&gt;$calendarhome%d:/$freebusy:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$email%d:&lt;/key&gt;
+                                &lt;value&gt;$userid%d:@example.com&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- calendar user address of user--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$cuaddr%d:&lt;/key&gt;
+                                &lt;value&gt;mailto:$email%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$cuaddralt%d:&lt;/key&gt;
+                                &lt;value&gt;$principaluri%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$cuaddraltnoslash%d:&lt;/key&gt;
+                                &lt;value&gt;$principals_uids:$userguid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$cuaddrurn%d:&lt;/key&gt;
+                                &lt;value&gt;urn:uuid:$userguid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+
+                        &lt;!-- relative path to user addressbook home--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$addressbookhome%d:&lt;/key&gt;
+                                &lt;value&gt;$addressbooks_uids:$userguid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user addressbook--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$addressbookpath%d:&lt;/key&gt;
+                                &lt;value&gt;$addressbooks_uids:$userguid%d:/$addressbook:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                &lt;/repeat&gt;
+
+                &lt;!--  Forty podB user accounts --&gt;
+                &lt;repeat count=&quot;40&quot;&gt;
+                        &lt;!-- user id --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$puserid%d:&lt;/key&gt;
+                                &lt;value&gt;puser%02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- user guid --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$puserguid%d:&lt;/key&gt;
+                                &lt;value&gt;puser%02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- user name --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pusername%d:&lt;/key&gt;
+                                &lt;value&gt;Puser %02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- user name URI encoded --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pusername-encoded%d:&lt;/key&gt;
+                                &lt;value&gt;Puser%%20%02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- first name --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pfirstname%d:&lt;/key&gt;
+                                &lt;value&gt;Puser&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- last name --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$plastname%d:&lt;/key&gt;
+                                &lt;value&gt;%02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- password --&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$ppswd%d:&lt;/key&gt;
+                                &lt;value&gt;puser%02d&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user principal resource--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pprincipal%d:&lt;/key&gt;
+                                &lt;value&gt;$principals_users:$puserid%d:/&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pprincipaluri%d:&lt;/key&gt;
+                                &lt;value&gt;$principals_uids:$puserguid%d:/&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pprincipal%dnoslash:&lt;/key&gt;
+                                &lt;value&gt;$principals_users:$puserid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+
+                        &lt;!-- relative path to user calendar home--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pcalendarhome%d:&lt;/key&gt;
+                                &lt;value&gt;$calendars_uids:$puserguid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user alternate calendar home--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pcalendarhomealt%d:&lt;/key&gt;
+                                &lt;value&gt;$calendars_users:$puserid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user calendar--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pcalendarpath%d:&lt;/key&gt;
+                                &lt;value&gt;$pcalendarhome%d:/$calendar:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user alternate calendar--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pcalendarpathalt%d:&lt;/key&gt;
+                                &lt;value&gt;$pcalendarhomealt%d:/$calendar:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user tasks calendar--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$ptaskspath%d:&lt;/key&gt;
+                                &lt;value&gt;$pcalendarhome%d:/$tasks:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user inbox--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pinboxpath%d:&lt;/key&gt;
+                                &lt;value&gt;$pcalendarhome%d:/$inbox:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user outbox--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$poutboxpath%d:&lt;/key&gt;
+                                &lt;value&gt;$pcalendarhome%d:/$outbox:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user dropbox--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pdropboxpath%d:&lt;/key&gt;
+                                &lt;value&gt;$pcalendarhome%d:/$dropbox:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user notification--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pnotificationpath%d:&lt;/key&gt;
+                                &lt;value&gt;$pcalendarhome%d:/$notification:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user freebusy--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pfreebusypath%d:&lt;/key&gt;
+                                &lt;value&gt;$pcalendarhome%d:/$freebusy:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pemail%d:&lt;/key&gt;
+                                &lt;value&gt;$puserid%d:@example.com&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- calendar user address of user--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pcuaddr%d:&lt;/key&gt;
+                                &lt;value&gt;mailto:$pemail%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pcuaddralt%d:&lt;/key&gt;
+                                &lt;value&gt;$pprincipaluri%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pcuaddraltnoslash%d:&lt;/key&gt;
+                                &lt;value&gt;$principals_uids:$puserguid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pcuaddrurn%d:&lt;/key&gt;
+                                &lt;value&gt;urn:uuid:$puserguid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+
+                        &lt;!-- relative path to user addressbook home--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$paddressbookhome%d:&lt;/key&gt;
+                                &lt;value&gt;$addressbooks_uids:$puserguid%d:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                        &lt;!-- relative path to user addressbook--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$paddressbookpath%d:&lt;/key&gt;
+                                &lt;value&gt;$paddressbookhome%d:/$addressbook:&lt;/value&gt;
+                        &lt;/substitution&gt;
+                &lt;/repeat&gt;
+
+        &lt;/substitutions&gt;
+&lt;/serverinfo&gt;
</ins></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptsserverserverinfotemplatexml"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-template.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-template.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo-template.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -79,8 +79,8 @@
</span><span class="cx">                 &lt;feature&gt;managed-attachments&lt;/feature&gt;                        &lt;!-- CalDAV Managed Attachments --&gt;
</span><span class="cx">                 &lt;feature&gt;maskuid&lt;/feature&gt;                                                &lt;!-- maskuid extension --&gt;
</span><span class="cx">                 &lt;feature&gt;no-duplicate-uids&lt;/feature&gt;                        &lt;!-- duplicate UIDs in same home not supported --&gt;
</span><del>-                &lt;!-- &lt;feature&gt;partitioning&lt;/feature&gt; --&gt;                &lt;!-- Partitioned server --&gt;
</del><span class="cx">                 &lt;feature&gt;partstat-timestamp&lt;/feature&gt;                        &lt;!-- Time stamps when PARTSTAT changes extension --&gt;
</span><ins>+                &lt;!-- &lt;feature&gt;podding&lt;/feature&gt; --&gt;                          &lt;!-- Podded server --&gt;
</ins><span class="cx">                 &lt;feature&gt;private-comments&lt;/feature&gt;                                &lt;!-- private-comments extension --&gt;
</span><span class="cx">                 &lt;feature&gt;private-events&lt;/feature&gt;                                &lt;!-- private-events extension --&gt;
</span><span class="cx">                 &lt;feature&gt;proxy&lt;/feature&gt;                                                &lt;!-- calendar-user-proxy extension --&gt;
</span><span class="lines">@@ -98,13 +98,14 @@
</span><span class="cx">                 &lt;feature&gt;timezone-service&lt;/feature&gt;                                &lt;!-- Timezone service extension for Wiki --&gt;
</span><span class="cx">                 &lt;feature&gt;timezone-std-service&lt;/feature&gt;                        &lt;!-- Timezone standard service extension --&gt;
</span><span class="cx">                 &lt;feature&gt;vavailability&lt;/feature&gt;                                &lt;!-- VAVAILABILITY on inbox --&gt;
</span><ins>+                &lt;!-- &lt;feature&gt;vpoll&lt;/feature&gt; --&gt;                                &lt;!-- VPOLL support for store and scheduling --&gt;
</ins><span class="cx">                 &lt;feature&gt;webcal&lt;/feature&gt;                                                &lt;!-- Internet calendar subscription via GET on calendar collection --&gt;
</span><span class="cx"> 
</span><span class="cx">                 &lt;!-- CardDAV specific extension --&gt;
</span><span class="cx">                 &lt;feature&gt;carddav&lt;/feature&gt;                                                 &lt;!-- Basic CardDAV feature enabler --&gt;
</span><span class="cx">                 &lt;feature&gt;default-addressbook&lt;/feature&gt;                         &lt;!-- Default address book behavior --&gt;
</span><span class="cx">                 &lt;!-- &lt;feature&gt;global-addressbook&lt;/feature&gt; --&gt;         &lt;!-- Global address book for each user --&gt;
</span><del>-                &lt;!-- &lt;feature&gt;shared-addressbooks&lt;/feature&gt; --&gt;        &lt;!-- Shared address books extension --&gt;
</del><ins>+                &lt;!-- &lt;feature&gt;shared-addressbooks&lt;/feature&gt; --&gt; &lt;!-- Shared address books extension --&gt;
</ins><span class="cx">                 &lt;!-- &lt;feature&gt;directory-gateway&lt;/feature&gt; --&gt;        &lt;!-- Directory gateway extension --&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;/features&gt;
</span><span class="lines">@@ -539,7 +540,7 @@
</span><span class="cx">                         &lt;!-- relative path to user addressbook--&gt;
</span><span class="cx">                         &lt;substitution&gt;
</span><span class="cx">                                 &lt;key&gt;$addressbookpath%%d:&lt;/key&gt;
</span><del>-                                &lt;value&gt;$addressbooks_uids:$userguid%%d:/$addressbook:&lt;/value&gt;
</del><ins>+                                &lt;value&gt;$addressbookhome%%d:/$addressbook:&lt;/value&gt;
</ins><span class="cx">                         &lt;/substitution&gt;
</span><span class="cx">                 &lt;/repeat&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptsserverserverinfodtd"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo.dtd (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo.dtd        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo.dtd        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -14,11 +14,14 @@
</span><span class="cx">  limitations under the License.
</span><span class="cx">  --&gt;
</span><span class="cx"> 
</span><del>-&lt;!ELEMENT serverinfo (host, nonsslport, sslport, authtype?, waitime?, features?, substitutions)? &gt;
</del><ins>+&lt;!ELEMENT serverinfo (host, nonsslport, sslport, host2?, nonsslport2?, sslport2?, authtype?, waitime?, features?, substitutions)? &gt;
</ins><span class="cx"> 
</span><span class="cx">         &lt;!ELEMENT host                        (#PCDATA)&gt;
</span><span class="cx">         &lt;!ELEMENT nonsslport        (#PCDATA)&gt;
</span><span class="cx">         &lt;!ELEMENT sslport                (#PCDATA)&gt;
</span><ins>+        &lt;!ELEMENT host2                        (#PCDATA)&gt;
+        &lt;!ELEMENT nonsslport2        (#PCDATA)&gt;
+        &lt;!ELEMENT sslport2                (#PCDATA)&gt;
</ins><span class="cx">         &lt;!ELEMENT authtype                (#PCDATA)&gt;
</span><span class="cx">         &lt;!ELEMENT waittime      (#PCDATA)&gt;
</span><span class="cx">         &lt;!ELEMENT features      (feature*)&gt;
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptsserverserverinfoxml"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/server/serverinfo.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -78,9 +78,9 @@
</span><span class="cx">                 &lt;feature&gt;location-resource-tracking&lt;/feature&gt;   &lt;!-- Server tracks who makes unscheduled changes to locations and resources --&gt;
</span><span class="cx">                 &lt;feature&gt;managed-attachments&lt;/feature&gt;                        &lt;!-- CalDAV Managed Attachments --&gt;
</span><span class="cx">                 &lt;feature&gt;maskuid&lt;/feature&gt;                                                &lt;!-- maskuid extension --&gt;
</span><del>-                &lt;!-- &lt;feature&gt;partitioning&lt;/feature&gt; --&gt;                &lt;!-- Partitioned server --&gt;
</del><span class="cx">                 &lt;feature&gt;no-duplicate-uids&lt;/feature&gt;                        &lt;!-- duplicate UIDs in same home not supported --&gt;
</span><span class="cx">                 &lt;feature&gt;partstat-timestamp&lt;/feature&gt;                        &lt;!-- Time stamps when PARTSTAT changes extension --&gt;
</span><ins>+                &lt;!-- &lt;feature&gt;podding&lt;/feature&gt; --&gt;                          &lt;!-- Podded server --&gt;
</ins><span class="cx">                 &lt;feature&gt;private-comments&lt;/feature&gt;                                &lt;!-- private-comments extension --&gt;
</span><span class="cx">                 &lt;feature&gt;private-events&lt;/feature&gt;                                &lt;!-- private-events extension --&gt;
</span><span class="cx">                 &lt;feature&gt;proxy&lt;/feature&gt;                                                &lt;!-- calendar-user-proxy extension --&gt;
</span><span class="lines">@@ -98,6 +98,7 @@
</span><span class="cx">                 &lt;feature&gt;timezone-service&lt;/feature&gt;                                &lt;!-- Timezone service extension for Wiki --&gt;
</span><span class="cx">                 &lt;feature&gt;timezone-std-service&lt;/feature&gt;                        &lt;!-- Timezone standard service extension --&gt;
</span><span class="cx">                 &lt;feature&gt;vavailability&lt;/feature&gt;                                &lt;!-- VAVAILABILITY on inbox --&gt;
</span><ins>+                &lt;!-- &lt;feature&gt;vpoll&lt;/feature&gt; --&gt;                                &lt;!-- VPOLL support for store and scheduling --&gt;
</ins><span class="cx">                 &lt;feature&gt;webcal&lt;/feature&gt;                                                &lt;!-- Internet calendar subscription via GET on calendar collection --&gt;
</span><span class="cx"> 
</span><span class="cx">                 &lt;!-- CardDAV specific extension --&gt;
</span><span class="lines">@@ -248,6 +249,12 @@
</span><span class="cx">                         &lt;value&gt;tasks&lt;/value&gt;
</span><span class="cx">                 &lt;/substitution&gt;
</span><span class="cx"> 
</span><ins>+                &lt;!-- primary polls-only calendar name--&gt;
+                &lt;substitution&gt;
+                        &lt;key&gt;$polls:&lt;/key&gt;
+                        &lt;value&gt;polls&lt;/value&gt;
+                &lt;/substitution&gt;
+
</ins><span class="cx">                 &lt;!-- inbox name--&gt;
</span><span class="cx">                 &lt;substitution&gt;
</span><span class="cx">                         &lt;key&gt;$inbox:&lt;/key&gt;
</span><span class="lines">@@ -302,13 +309,13 @@
</span><span class="cx">                         &lt;value&gt;$root:stdtimezones&lt;/value&gt;
</span><span class="cx">                 &lt;/substitution&gt;
</span><span class="cx"> 
</span><del>-                &lt;!-- relative path to calendars collection--&gt;
</del><ins>+                &lt;!-- relative path to addressbooks collection--&gt;
</ins><span class="cx">                 &lt;substitution&gt;
</span><span class="cx">                         &lt;key&gt;$addressbooks:&lt;/key&gt;
</span><span class="cx">                         &lt;value&gt;$root:addressbooks/&lt;/value&gt;
</span><span class="cx">                 &lt;/substitution&gt;
</span><span class="cx"> 
</span><del>-                &lt;!-- relative path to record type calendar collections--&gt;
</del><ins>+                &lt;!-- relative path to record type addressbook collections--&gt;
</ins><span class="cx">                 &lt;substitution&gt;
</span><span class="cx">                         &lt;key&gt;$addressbooks_uids:&lt;/key&gt;
</span><span class="cx">                         &lt;value&gt;$addressbooks:$uidstype:/&lt;/value&gt;
</span><span class="lines">@@ -485,6 +492,11 @@
</span><span class="cx">                                 &lt;key&gt;$taskspath%d:&lt;/key&gt;
</span><span class="cx">                                 &lt;value&gt;$calendarhome%d:/$tasks:&lt;/value&gt;
</span><span class="cx">                         &lt;/substitution&gt;
</span><ins>+                        &lt;!-- relative path to user polls calendar--&gt;
+                        &lt;substitution&gt;
+                                &lt;key&gt;$pollspath%d:&lt;/key&gt;
+                                &lt;value&gt;$calendarhome%d:/$polls:&lt;/value&gt;
+                        &lt;/substitution&gt;
</ins><span class="cx">                         &lt;!-- relative path to user inbox--&gt;
</span><span class="cx">                         &lt;substitution&gt;
</span><span class="cx">                                 &lt;key&gt;$inboxpath%d:&lt;/key&gt;
</span><span class="lines">@@ -540,7 +552,7 @@
</span><span class="cx">                         &lt;!-- relative path to user addressbook--&gt;
</span><span class="cx">                         &lt;substitution&gt;
</span><span class="cx">                                 &lt;key&gt;$addressbookpath%d:&lt;/key&gt;
</span><del>-                                &lt;value&gt;$addressbooks_uids:$userguid%d:/$addressbook:&lt;/value&gt;
</del><ins>+                                &lt;value&gt;$addressbookhome%d:/$addressbook:&lt;/value&gt;
</ins><span class="cx">                         &lt;/substitution&gt;
</span><span class="cx">                 &lt;/repeat&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVcaldavtestdtd"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/caldavtest.dtd (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/caldavtest.dtd        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/caldavtest.dtd        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -31,7 +31,8 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;!ELEMENT request (require-feature?, exclude-feature?, method, ruri*, header*, data?, verify*,
</span><span class="cx">                                                 graburi?, grabcount?, grabheader*, grabproperty*, grabelement*, grabcalproperty*, grabcalparameter*)&gt;
</span><del>-                &lt;!ATTLIST request auth (yes|no) &quot;yes&quot;
</del><ins>+                &lt;!ATTLIST request host2 (yes|no) &quot;no&quot;
+                                                 auth (yes|no) &quot;yes&quot;
</ins><span class="cx">                                                  user CDATA &quot;&quot;
</span><span class="cx">                                                  pswd CDATA &quot;&quot;
</span><span class="cx">                                                  end-delete (yes|no) &quot;no&quot;
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVimplicitdefaultcalendarxml"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/implicitdefaultcalendar.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/implicitdefaultcalendar.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/implicitdefaultcalendar.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -357,7 +357,7 @@
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><span class="cx">                                                 &lt;name&gt;nohrefs&lt;/name&gt;
</span><del>-                                                &lt;value&gt;events/&lt;/value&gt;
</del><ins>+                                                &lt;value&gt;$calendar:/&lt;/value&gt;
</ins><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                 &lt;/verify&gt;
</span><span class="cx">                         &lt;/request&gt;
</span><span class="lines">@@ -424,7 +424,7 @@
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><del>-                                                &lt;value&gt;events/&lt;/value&gt;
</del><ins>+                                                &lt;value&gt;$calendar:/&lt;/value&gt;
</ins><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                 &lt;/verify&gt;
</span><span class="cx">                         &lt;/request&gt;
</span><span class="lines">@@ -433,7 +433,7 @@
</span><span class="cx">                         &lt;description&gt;Attendee has data&lt;/description&gt;
</span><span class="cx">                         &lt;request user=&quot;$userid10:&quot; pswd=&quot;$pswd10:&quot; print-response='no'&gt;
</span><span class="cx">                                 &lt;method&gt;GETNEW&lt;/method&gt;
</span><del>-                                &lt;ruri&gt;$calendarhome10:/events/&lt;/ruri&gt;
</del><ins>+                                &lt;ruri&gt;$calendarpath10:/&lt;/ruri&gt;
</ins><span class="cx">                                 &lt;verify&gt;
</span><span class="cx">                                         &lt;callback&gt;calendarDataMatch&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><span class="lines">@@ -451,7 +451,7 @@
</span><span class="cx">                         &lt;/request&gt;
</span><span class="cx">                         &lt;request user=&quot;$userid10:&quot; pswd=&quot;$pswd10:&quot;&gt;
</span><span class="cx">                                 &lt;method&gt;DELETEALL&lt;/method&gt;
</span><del>-                                &lt;ruri&gt;$calendarhome10:/events/&lt;/ruri&gt;
</del><ins>+                                &lt;ruri&gt;$calendarpath10:/&lt;/ruri&gt;
</ins><span class="cx">                         &lt;/request&gt;
</span><span class="cx">                         &lt;request user=&quot;$userid1:&quot; pswd=&quot;$pswd1:&quot;&gt;
</span><span class="cx">                                 &lt;method&gt;DELETEALL&lt;/method&gt;
</span><span class="lines">@@ -461,14 +461,6 @@
</span><span class="cx">                                 &lt;method&gt;DELETEALL&lt;/method&gt;
</span><span class="cx">                                 &lt;ruri&gt;$inboxpath10:/&lt;/ruri&gt;
</span><span class="cx">                         &lt;/request&gt;
</span><del>-                        &lt;request user=&quot;$userid10:&quot; pswd=&quot;$pswd10:&quot; print-response='no'&gt;
-                                &lt;method&gt;MKCALENDAR&lt;/method&gt;
-                                &lt;ruri&gt;$calendarpath10:/&lt;/ruri&gt;
-                        &lt;/request&gt;
-                        &lt;request user=&quot;$userid10:&quot; pswd=&quot;$pswd10:&quot;&gt;
-                                &lt;method&gt;DELETE&lt;/method&gt;
-                                &lt;ruri&gt;$calendarhome10:/events/&lt;/ruri&gt;
-                        &lt;/request&gt;
</del><span class="cx">                 &lt;/test&gt;
</span><span class="cx">         &lt;/test-suite&gt;
</span><span class="cx">         
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVpollsxmlfromrev12016CalDAVTestertrunkscriptstestsCalDAVpollsxml"></a>
<div class="copfile"><h4>Copied: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/polls.xml (from rev 12016, CalDAVTester/trunk/scripts/tests/CalDAV/polls.xml) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/polls.xml                                (rev 0)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/polls.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,171 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; standalone=&quot;no&quot;?&gt;
+
+&lt;!DOCTYPE caldavtest SYSTEM &quot;caldavtest.dtd&quot;&gt;
+
+&lt;!--
+ Copyright (c) 2006-2013 Apple Inc. 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.
+ --&gt;
+
+&lt;caldavtest&gt;
+        &lt;description&gt;Test PUT method in CalDAV&lt;/description&gt;
+
+        &lt;require-feature&gt;
+                &lt;feature&gt;caldav&lt;/feature&gt;
+                &lt;feature&gt;vpoll&lt;/feature&gt;
+        &lt;/require-feature&gt;
+
+        &lt;start/&gt;
+
+        &lt;test-suite name='supported-component-set'&gt;
+                &lt;test name='1'&gt;
+                        &lt;require-feature&gt;
+                                &lt;feature&gt;supported-component-sets&lt;/feature&gt;
+                        &lt;/require-feature&gt;
+                        &lt;description&gt;Check calendar home for property&lt;/description&gt;
+                        &lt;request&gt;
+                                &lt;method&gt;PROPFIND&lt;/method&gt;
+                                &lt;ruri&gt;$calendarhome1:/&lt;/ruri&gt;
+                                &lt;header&gt;
+                                        &lt;name&gt;Depth&lt;/name&gt;
+                                        &lt;value&gt;0&lt;/value&gt;
+                                &lt;/header&gt;
+                                &lt;data&gt;
+                                        &lt;content-type&gt;text/xml; charset=utf-8&lt;/content-type&gt;
+                                        &lt;filepath&gt;Resource/CalDAV/polls/supported-component-set/1.xml&lt;/filepath&gt;
+                                &lt;/data&gt;
+                                &lt;verify&gt;
+                                        &lt;exclude-feature&gt;
+                                                &lt;feature&gt;supported-component-sets-one&lt;/feature&gt;
+                                        &lt;/exclude-feature&gt;
+                                        &lt;callback&gt;propfindItems&lt;/callback&gt;
+                                        &lt;arg&gt;
+                                                &lt;name&gt;okprops&lt;/name&gt;
+                                                &lt;value&gt;{urn:ietf:params:xml:ns:caldav}supported-calendar-component-sets$&lt;/value&gt;
+                                        &lt;/arg&gt;
+                                &lt;/verify&gt;
+                                &lt;verify&gt;
+                                        &lt;require-feature&gt;
+                                                &lt;feature&gt;supported-component-sets-one&lt;/feature&gt;
+                                        &lt;/require-feature&gt;
+                                        &lt;callback&gt;xmlElementMatch&lt;/callback&gt;
+                                        &lt;arg&gt;
+                                                &lt;name&gt;exists&lt;/name&gt;
+                                                &lt;value&gt;$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-sets/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set/{urn:ietf:params:xml:ns:caldav}comp[@name=&quot;VEVENT&quot;]&lt;/value&gt;
+                                                &lt;value&gt;$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-sets/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set/{urn:ietf:params:xml:ns:caldav}comp[@name=&quot;VTODO&quot;]&lt;/value&gt;
+                                                &lt;value&gt;$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-sets/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set/{urn:ietf:params:xml:ns:caldav}comp[@name=&quot;VPOLL&quot;]&lt;/value&gt;
+                                        &lt;/arg&gt;
+                                &lt;/verify&gt;
+                        &lt;/request&gt;
+                &lt;/test&gt;
+                &lt;test name='2'&gt;
+                        &lt;description&gt;Check calendar for property&lt;/description&gt;
+                        &lt;request&gt;
+                                &lt;method&gt;PROPFIND&lt;/method&gt;
+                                &lt;ruri&gt;$pollspath1:/&lt;/ruri&gt;
+                                &lt;header&gt;
+                                        &lt;name&gt;Depth&lt;/name&gt;
+                                        &lt;value&gt;0&lt;/value&gt;
+                                &lt;/header&gt;
+                                &lt;data&gt;
+                                        &lt;content-type&gt;text/xml; charset=utf-8&lt;/content-type&gt;
+                                        &lt;filepath&gt;Resource/CalDAV/polls/supported-component-set/2.xml&lt;/filepath&gt;
+                                &lt;/data&gt;
+                                &lt;verify&gt;
+                                        &lt;require-feature&gt;
+                                                &lt;feature&gt;exclude-calendars&lt;/feature&gt;
+                                        &lt;/require-feature&gt;
+                                        &lt;callback&gt;xmlElementMatch&lt;/callback&gt;
+                                        &lt;arg&gt;
+                                                &lt;name&gt;exists&lt;/name&gt;
+                                                &lt;value&gt;$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set/{urn:ietf:params:xml:ns:caldav}comp[@name=&quot;VEVENT&quot;]&lt;/value&gt;
+                                                &lt;value&gt;$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set/{urn:ietf:params:xml:ns:caldav}comp[@name=&quot;VTODO&quot;]&lt;/value&gt;
+                                                &lt;value&gt;$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set/{urn:ietf:params:xml:ns:caldav}comp[@name=&quot;VPOLL&quot;]&lt;/value&gt;
+                                        &lt;/arg&gt;
+                                &lt;/verify&gt;
+                                &lt;verify&gt;
+                                        &lt;require-feature&gt;
+                                                &lt;feature&gt;split-calendars&lt;/feature&gt;
+                                        &lt;/require-feature&gt;
+                                        &lt;callback&gt;xmlElementMatch&lt;/callback&gt;
+                                        &lt;arg&gt;
+                                                &lt;name&gt;exists&lt;/name&gt;
+                                                &lt;value&gt;$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set/{urn:ietf:params:xml:ns:caldav}comp[@name=&quot;VPOLL&quot;]&lt;/value&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
+                                                &lt;name&gt;notexists&lt;/name&gt;
+                                                &lt;value&gt;$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set/{urn:ietf:params:xml:ns:caldav}comp[@name=&quot;VEVENT&quot;]&lt;/value&gt;
+                                                &lt;value&gt;$verify-property-prefix:/{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set/{urn:ietf:params:xml:ns:caldav}comp[@name=&quot;VTODO&quot;]&lt;/value&gt;
+                                        &lt;/arg&gt;
+                                &lt;/verify&gt;
+                        &lt;/request&gt;
+                &lt;/test&gt;
+        &lt;/test-suite&gt;
+
+        &lt;test-suite name='PUT VPOLL' ignore='no'&gt;
+                &lt;test name='1' ignore='no'&gt;
+                        &lt;description&gt;PUT unscheduled empty poll&lt;/description&gt;
+                        &lt;request end-delete='yes'&gt;
+                                &lt;method&gt;PUT&lt;/method&gt;
+                                &lt;ruri&gt;$pollspath1:/1.ics&lt;/ruri&gt;
+                                &lt;data&gt;
+                                        &lt;content-type&gt;text/calendar; charset=utf-8&lt;/content-type&gt;
+                                        &lt;filepath&gt;Resource/CalDAV/polls/put/1.ics&lt;/filepath&gt;
+                                &lt;/data&gt;
+                                &lt;verify&gt;
+                                        &lt;callback&gt;statusCode&lt;/callback&gt;
+                                &lt;/verify&gt;
+                        &lt;/request&gt;
+                        &lt;request&gt;
+                                &lt;method&gt;GET&lt;/method&gt;
+                                &lt;ruri&gt;$pollspath1:/1.ics&lt;/ruri&gt;
+                                &lt;verify&gt;
+                                        &lt;callback&gt;calendarDataMatch&lt;/callback&gt;
+                                        &lt;arg&gt;
+                                                &lt;name&gt;filepath&lt;/name&gt;
+                                                &lt;value&gt;Resource/CalDAV/polls/put/2.ics&lt;/value&gt;
+                                        &lt;/arg&gt;
+                                &lt;/verify&gt;
+                        &lt;/request&gt;
+                &lt;/test&gt;
+                &lt;test name='2' ignore='no'&gt;
+                        &lt;description&gt;PUT unscheduled event poll&lt;/description&gt;
+                        &lt;request end-delete='yes'&gt;
+                                &lt;method&gt;PUT&lt;/method&gt;
+                                &lt;ruri&gt;$pollspath1:/2.ics&lt;/ruri&gt;
+                                &lt;data&gt;
+                                        &lt;content-type&gt;text/calendar; charset=utf-8&lt;/content-type&gt;
+                                        &lt;filepath&gt;Resource/CalDAV/polls/put/3.ics&lt;/filepath&gt;
+                                &lt;/data&gt;
+                                &lt;verify&gt;
+                                        &lt;callback&gt;statusCode&lt;/callback&gt;
+                                &lt;/verify&gt;
+                        &lt;/request&gt;
+                        &lt;request&gt;
+                                &lt;method&gt;GET&lt;/method&gt;
+                                &lt;ruri&gt;$pollspath1:/2.ics&lt;/ruri&gt;
+                                &lt;verify&gt;
+                                        &lt;callback&gt;calendarDataMatch&lt;/callback&gt;
+                                        &lt;arg&gt;
+                                                &lt;name&gt;filepath&lt;/name&gt;
+                                                &lt;value&gt;Resource/CalDAV/polls/put/4.ics&lt;/value&gt;
+                                        &lt;/arg&gt;
+                                &lt;/verify&gt;
+                        &lt;/request&gt;
+                &lt;/test&gt;
+        &lt;/test-suite&gt;
+        
+        &lt;end/&gt;
+        
+&lt;/caldavtest&gt;
</ins></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVprivatecommentsxml"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/privatecomments.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/privatecomments.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/privatecomments.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1006,55 +1006,34 @@
</span><span class="cx">                         &lt;/request&gt;
</span><span class="cx">                 &lt;/test&gt;
</span><span class="cx">                 &lt;test name='8'&gt;
</span><del>-                        &lt;description&gt;Attendee removes comment property entirely&lt;/description&gt;
-                        &lt;request user=&quot;$userid2:&quot; pswd=&quot;$pswd2:&quot; print-response='no'&gt;
-                                &lt;method&gt;GETNEW&lt;/method&gt;
-                                &lt;ruri&gt;$calendarpath2:/&lt;/ruri&gt;
-                                &lt;verify&gt;
-                                        &lt;callback&gt;statusCode&lt;/callback&gt;
-                                &lt;/verify&gt;
</del><ins>+                        &lt;description&gt;Organizer Inbox Item&lt;/description&gt;
+                        &lt;request print-response='no'&gt;
+                                &lt;method&gt;WAITDELETEALL 1&lt;/method&gt;
+                                &lt;ruri&gt;$inboxpath1:/&lt;/ruri&gt;
</ins><span class="cx">                         &lt;/request&gt;
</span><del>-                        &lt;request user=&quot;$userid2:&quot; pswd=&quot;$pswd2:&quot; print-response='no'&gt;
-                                &lt;method&gt;PUT&lt;/method&gt;
-                                &lt;ruri&gt;$&lt;/ruri&gt;
-                                &lt;data&gt;
-                                        &lt;content-type&gt;text/calendar; charset=utf-8&lt;/content-type&gt;
-                                        &lt;filepath&gt;Resource/CalDAV/privatecomments/31.ics&lt;/filepath&gt;
-                                &lt;/data&gt;
-                                &lt;verify&gt;
-                                        &lt;callback&gt;statusCode&lt;/callback&gt;
-                                &lt;/verify&gt;
-                        &lt;/request&gt;
</del><span class="cx">                 &lt;/test&gt;
</span><span class="cx">                 &lt;test name='9'&gt;
</span><del>-                        &lt;description&gt;Attendee has data with comment preserved&lt;/description&gt;
-                        &lt;request user=&quot;$userid2:&quot; pswd=&quot;$pswd2:&quot; print-response='no'&gt;
-                                &lt;method&gt;GETNEW&lt;/method&gt;
-                                &lt;ruri&gt;$calendarpath2:/&lt;/ruri&gt;
</del><ins>+                        &lt;description&gt;Organizer data changed&lt;/description&gt;
+                        &lt;request print-response='no'&gt;
+                                &lt;method&gt;GET&lt;/method&gt;
+                                &lt;ruri&gt;$calendarpath1:/3.ics&lt;/ruri&gt;
</ins><span class="cx">                                 &lt;verify&gt;
</span><span class="cx">                                         &lt;callback&gt;calendarDataMatch&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><span class="cx">                                                 &lt;name&gt;filepath&lt;/name&gt;
</span><del>-                                                &lt;value&gt;Resource/CalDAV/privatecomments/32.ics&lt;/value&gt;
</del><ins>+                                                &lt;value&gt;Resource/CalDAV/privatecomments/35.ics&lt;/value&gt;
</ins><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                 &lt;/verify&gt;
</span><span class="cx">                         &lt;/request&gt;
</span><span class="cx">                 &lt;/test&gt;
</span><span class="cx">                 &lt;test name='10'&gt;
</span><del>-                        &lt;description&gt;Attendee changes comment&lt;/description&gt;
-                        &lt;request user=&quot;$userid2:&quot; pswd=&quot;$pswd2:&quot; print-response='no'&gt;
-                                &lt;method&gt;GETNEW&lt;/method&gt;
-                                &lt;ruri&gt;$calendarpath2:/&lt;/ruri&gt;
-                                &lt;verify&gt;
-                                        &lt;callback&gt;statusCode&lt;/callback&gt;
-                                &lt;/verify&gt;
-                        &lt;/request&gt;
-                        &lt;request user=&quot;$userid2:&quot; pswd=&quot;$pswd2:&quot; print-response='no'&gt;
</del><ins>+                        &lt;description&gt;Organizer removes comments entirely&lt;/description&gt;
+                        &lt;request print-response='no'&gt;
</ins><span class="cx">                                 &lt;method&gt;PUT&lt;/method&gt;
</span><del>-                                &lt;ruri&gt;$&lt;/ruri&gt;
</del><ins>+                                &lt;ruri&gt;$calendarpath1:/3.ics&lt;/ruri&gt;
</ins><span class="cx">                                 &lt;data&gt;
</span><span class="cx">                                         &lt;content-type&gt;text/calendar; charset=utf-8&lt;/content-type&gt;
</span><del>-                                        &lt;filepath&gt;Resource/CalDAV/privatecomments/33.ics&lt;/filepath&gt;
</del><ins>+                                        &lt;filepath&gt;Resource/CalDAV/privatecomments/36.ics&lt;/filepath&gt;
</ins><span class="cx">                                 &lt;/data&gt;
</span><span class="cx">                                 &lt;verify&gt;
</span><span class="cx">                                         &lt;callback&gt;statusCode&lt;/callback&gt;
</span><span class="lines">@@ -1062,55 +1041,34 @@
</span><span class="cx">                         &lt;/request&gt;
</span><span class="cx">                 &lt;/test&gt;
</span><span class="cx">                 &lt;test name='11'&gt;
</span><del>-                        &lt;description&gt;Attendee has data with comment preserved&lt;/description&gt;
-                        &lt;request user=&quot;$userid2:&quot; pswd=&quot;$pswd2:&quot; print-response='no'&gt;
-                                &lt;method&gt;GETNEW&lt;/method&gt;
-                                &lt;ruri&gt;$calendarpath2:/&lt;/ruri&gt;
-                                &lt;verify&gt;
-                                        &lt;callback&gt;calendarDataMatch&lt;/callback&gt;
-                                        &lt;arg&gt;
-                                                &lt;name&gt;filepath&lt;/name&gt;
-                                                &lt;value&gt;Resource/CalDAV/privatecomments/34.ics&lt;/value&gt;
-                                        &lt;/arg&gt;
-                                &lt;/verify&gt;
-                        &lt;/request&gt;
-                &lt;/test&gt;
-                &lt;test name='12'&gt;
-                        &lt;description&gt;Organizer Inbox Items&lt;/description&gt;
</del><ins>+                        &lt;description&gt;Organizer checks data&lt;/description&gt;
</ins><span class="cx">                         &lt;request print-response='no'&gt;
</span><del>-                                &lt;method&gt;WAITDELETEALL 2&lt;/method&gt;
-                                &lt;ruri&gt;$inboxpath1:/&lt;/ruri&gt;
-                        &lt;/request&gt;
-                &lt;/test&gt;
-                &lt;test name='13'&gt;
-                        &lt;description&gt;Organizer data changed&lt;/description&gt;
-                        &lt;request print-response='no'&gt;
</del><span class="cx">                                 &lt;method&gt;GET&lt;/method&gt;
</span><span class="cx">                                 &lt;ruri&gt;$calendarpath1:/3.ics&lt;/ruri&gt;
</span><span class="cx">                                 &lt;verify&gt;
</span><span class="cx">                                         &lt;callback&gt;calendarDataMatch&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><span class="cx">                                                 &lt;name&gt;filepath&lt;/name&gt;
</span><del>-                                                &lt;value&gt;Resource/CalDAV/privatecomments/35.ics&lt;/value&gt;
</del><ins>+                                                &lt;value&gt;Resource/CalDAV/privatecomments/37.ics&lt;/value&gt;
</ins><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                 &lt;/verify&gt;
</span><span class="cx">                         &lt;/request&gt;
</span><span class="cx">                 &lt;/test&gt;
</span><del>-                &lt;test name='15'&gt;
-                        &lt;description&gt;Organizer removes comments entirely&lt;/description&gt;
</del><ins>+                &lt;test name='12'&gt;
+                        &lt;description&gt;Organizer changes comment&lt;/description&gt;
</ins><span class="cx">                         &lt;request print-response='no'&gt;
</span><span class="cx">                                 &lt;method&gt;PUT&lt;/method&gt;
</span><span class="cx">                                 &lt;ruri&gt;$calendarpath1:/3.ics&lt;/ruri&gt;
</span><span class="cx">                                 &lt;data&gt;
</span><span class="cx">                                         &lt;content-type&gt;text/calendar; charset=utf-8&lt;/content-type&gt;
</span><del>-                                        &lt;filepath&gt;Resource/CalDAV/privatecomments/36.ics&lt;/filepath&gt;
</del><ins>+                                        &lt;filepath&gt;Resource/CalDAV/privatecomments/38.ics&lt;/filepath&gt;
</ins><span class="cx">                                 &lt;/data&gt;
</span><span class="cx">                                 &lt;verify&gt;
</span><span class="cx">                                         &lt;callback&gt;statusCode&lt;/callback&gt;
</span><span class="cx">                                 &lt;/verify&gt;
</span><span class="cx">                         &lt;/request&gt;
</span><span class="cx">                 &lt;/test&gt;
</span><del>-                &lt;test name='16'&gt;
</del><ins>+                &lt;test name='13'&gt;
</ins><span class="cx">                         &lt;description&gt;Organizer checks data&lt;/description&gt;
</span><span class="cx">                         &lt;request print-response='no'&gt;
</span><span class="cx">                                 &lt;method&gt;GET&lt;/method&gt;
</span><span class="lines">@@ -1119,35 +1077,49 @@
</span><span class="cx">                                         &lt;callback&gt;calendarDataMatch&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><span class="cx">                                                 &lt;name&gt;filepath&lt;/name&gt;
</span><del>-                                                &lt;value&gt;Resource/CalDAV/privatecomments/37.ics&lt;/value&gt;
</del><ins>+                                                &lt;value&gt;Resource/CalDAV/privatecomments/38.ics&lt;/value&gt;
</ins><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                 &lt;/verify&gt;
</span><span class="cx">                         &lt;/request&gt;
</span><span class="cx">                 &lt;/test&gt;
</span><del>-                &lt;test name='17'&gt;
-                        &lt;description&gt;Organizer changes comment&lt;/description&gt;
-                        &lt;request print-response='no'&gt;
</del><ins>+                &lt;test name='14'&gt;
+                        &lt;description&gt;Attendee removes comment property entirely&lt;/description&gt;
+                        &lt;request user=&quot;$userid2:&quot; pswd=&quot;$pswd2:&quot; print-response='no'&gt;
+                                &lt;method&gt;GETNEW&lt;/method&gt;
+                                &lt;ruri&gt;$calendarpath2:/&lt;/ruri&gt;
+                                &lt;verify&gt;
+                                        &lt;callback&gt;statusCode&lt;/callback&gt;
+                                &lt;/verify&gt;
+                        &lt;/request&gt;
+                        &lt;request user=&quot;$userid2:&quot; pswd=&quot;$pswd2:&quot; print-response='no'&gt;
</ins><span class="cx">                                 &lt;method&gt;PUT&lt;/method&gt;
</span><del>-                                &lt;ruri&gt;$calendarpath1:/3.ics&lt;/ruri&gt;
</del><ins>+                                &lt;ruri&gt;$&lt;/ruri&gt;
</ins><span class="cx">                                 &lt;data&gt;
</span><span class="cx">                                         &lt;content-type&gt;text/calendar; charset=utf-8&lt;/content-type&gt;
</span><del>-                                        &lt;filepath&gt;Resource/CalDAV/privatecomments/38.ics&lt;/filepath&gt;
</del><ins>+                                        &lt;filepath&gt;Resource/CalDAV/privatecomments/31.ics&lt;/filepath&gt;
</ins><span class="cx">                                 &lt;/data&gt;
</span><span class="cx">                                 &lt;verify&gt;
</span><span class="cx">                                         &lt;callback&gt;statusCode&lt;/callback&gt;
</span><span class="cx">                                 &lt;/verify&gt;
</span><span class="cx">                         &lt;/request&gt;
</span><span class="cx">                 &lt;/test&gt;
</span><del>-                &lt;test name='18'&gt;
-                        &lt;description&gt;Organizer checks data&lt;/description&gt;
</del><ins>+                &lt;test name='15'&gt;
+                        &lt;description&gt;Organizer Inbox Item&lt;/description&gt;
</ins><span class="cx">                         &lt;request print-response='no'&gt;
</span><ins>+                                &lt;method&gt;WAITDELETEALL 1&lt;/method&gt;
+                                &lt;ruri&gt;$inboxpath1:/&lt;/ruri&gt;
+                        &lt;/request&gt;
+                &lt;/test&gt;
+                &lt;test name='16'&gt;
+                        &lt;description&gt;Organizer data changed&lt;/description&gt;
+                        &lt;request print-response='no'&gt;
</ins><span class="cx">                                 &lt;method&gt;GET&lt;/method&gt;
</span><span class="cx">                                 &lt;ruri&gt;$calendarpath1:/3.ics&lt;/ruri&gt;
</span><span class="cx">                                 &lt;verify&gt;
</span><span class="cx">                                         &lt;callback&gt;calendarDataMatch&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><span class="cx">                                                 &lt;name&gt;filepath&lt;/name&gt;
</span><del>-                                                &lt;value&gt;Resource/CalDAV/privatecomments/38.ics&lt;/value&gt;
</del><ins>+                                                &lt;value&gt;Resource/CalDAV/privatecomments/32.ics&lt;/value&gt;
</ins><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                 &lt;/verify&gt;
</span><span class="cx">                         &lt;/request&gt;
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVsharingnotificationsyncxml"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/sharing-notification-sync.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/sharing-notification-sync.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/sharing-notification-sync.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -239,36 +239,12 @@
</span><span class="cx">                                         &lt;filepath&gt;Resource/CalDAV/sharing/notification-sync/2.xml&lt;/filepath&gt;
</span><span class="cx">                                 &lt;/data&gt;
</span><span class="cx">                                 &lt;verify&gt;
</span><del>-                                        &lt;exclude-feature&gt;
-                                                &lt;feature&gt;split-calendars&lt;/feature&gt;
-                                        &lt;/exclude-feature&gt;
</del><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><del>-                                                &lt;name&gt;okhrefs&lt;/name&gt;
-                                                &lt;value&gt;$calendar:/&lt;/value&gt;
-                                                &lt;value&gt;$inbox:/&lt;/value&gt;
-                                                &lt;value&gt;$outbox:/&lt;/value&gt;
-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
-                                                &lt;value&gt;shared/&lt;/value&gt;
</del><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
</ins><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><del>-                                                &lt;name&gt;badhrefs&lt;/name&gt;
-                                                &lt;value&gt;$dropbox:/&lt;/value&gt;
-                                        &lt;/arg&gt;
-                                &lt;/verify&gt;
-                                &lt;verify&gt;
-                                        &lt;require-feature&gt;
-                                                &lt;feature&gt;split-calendars&lt;/feature&gt;
-                                        &lt;/require-feature&gt;
-                                        &lt;callback&gt;multistatusItems&lt;/callback&gt;
-                                        &lt;arg&gt;
</del><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><del>-                                                &lt;value&gt;$calendar:/&lt;/value&gt;
-                                                &lt;value&gt;$tasks:/&lt;/value&gt;
-                                                &lt;value&gt;$inbox:/&lt;/value&gt;
-                                                &lt;value&gt;$outbox:/&lt;/value&gt;
-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;$notification:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;shared/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -300,35 +276,12 @@
</span><span class="cx">                                         &lt;filepath&gt;Resource/CalDAV/sharing/notification-sync/2.xml&lt;/filepath&gt;
</span><span class="cx">                                 &lt;/data&gt;
</span><span class="cx">                                 &lt;verify&gt;
</span><del>-                                        &lt;exclude-feature&gt;
-                                                &lt;feature&gt;split-calendars&lt;/feature&gt;
-                                        &lt;/exclude-feature&gt;
</del><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><del>-                                                &lt;name&gt;okhrefs&lt;/name&gt;
-                                                &lt;value&gt;$calendar:/&lt;/value&gt;
-                                                &lt;value&gt;$inbox:/&lt;/value&gt;
-                                                &lt;value&gt;$outbox:/&lt;/value&gt;
-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
</ins><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><del>-                                                &lt;name&gt;badhrefs&lt;/name&gt;
-                                                &lt;value&gt;$dropbox:/&lt;/value&gt;
-                                        &lt;/arg&gt;
-                                &lt;/verify&gt;
-                                &lt;verify&gt;
-                                        &lt;require-feature&gt;
-                                                &lt;feature&gt;split-calendars&lt;/feature&gt;
-                                        &lt;/require-feature&gt;
-                                        &lt;callback&gt;multistatusItems&lt;/callback&gt;
-                                        &lt;arg&gt;
</del><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><del>-                                                &lt;value&gt;$calendar:/&lt;/value&gt;
-                                                &lt;value&gt;$tasks:/&lt;/value&gt;
-                                                &lt;value&gt;$inbox:/&lt;/value&gt;
-                                                &lt;value&gt;$outbox:/&lt;/value&gt;
-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;$notification:/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCalDAVsyncreportxml"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/sync-report.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/sync-report.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CalDAV/sync-report.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -262,12 +262,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -282,13 +283,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -321,12 +323,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -341,13 +344,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -380,12 +384,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -400,13 +405,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -439,12 +445,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -463,13 +470,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -506,12 +514,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -530,13 +539,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -573,12 +583,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -597,13 +608,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -841,12 +853,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -861,13 +874,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -900,12 +914,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -924,13 +939,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -1005,12 +1021,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -1025,13 +1042,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -1064,12 +1082,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -1089,13 +1108,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -1166,12 +1186,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -1186,13 +1207,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -1225,12 +1247,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -1249,13 +1272,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -1329,12 +1353,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -1349,13 +1374,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar2/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -1388,12 +1414,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -1412,13 +1439,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar1/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar1/2.ics&lt;/value&gt;
</span><span class="lines">@@ -2063,12 +2091,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/2.ics&lt;/value&gt;
</span><span class="lines">@@ -2087,13 +2116,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/2.ics&lt;/value&gt;
</span><span class="lines">@@ -2298,12 +2328,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/2.ics&lt;/value&gt;
</span><span class="lines">@@ -2322,13 +2353,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/2.ics&lt;/value&gt;
</span><span class="lines">@@ -2579,12 +2611,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/2.ics&lt;/value&gt;
</span><span class="lines">@@ -2603,13 +2636,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/1.ics&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar3/2.ics&lt;/value&gt;
</span><span class="lines">@@ -2795,12 +2829,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -2815,13 +2850,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -3012,12 +3048,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -3032,13 +3069,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -3275,12 +3313,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -3295,13 +3334,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -3481,12 +3521,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/1.ics&lt;/value&gt;
</span><span class="lines">@@ -3503,13 +3544,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/1.ics&lt;/value&gt;
</span><span class="lines">@@ -3639,12 +3681,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -3659,13 +3702,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -3794,12 +3838,13 @@
</span><span class="cx">                                         &lt;/exclude-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span><span class="lines">@@ -3814,13 +3859,14 @@
</span><span class="cx">                                         &lt;/require-feature&gt;
</span><span class="cx">                                         &lt;callback&gt;multistatusItems&lt;/callback&gt;
</span><span class="cx">                                         &lt;arg&gt;
</span><ins>+                                                &lt;name&gt;ignoremissing&lt;/name&gt;
+                                        &lt;/arg&gt;
+                                        &lt;arg&gt;
</ins><span class="cx">                                                 &lt;name&gt;okhrefs&lt;/name&gt;
</span><span class="cx">                                                 &lt;value&gt;$calendar:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$tasks:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$inbox:/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;$outbox:/&lt;/value&gt;
</span><del>-                                                &lt;value&gt;$freebusy:&lt;/value&gt;
-                                                &lt;value&gt;$notification:/&lt;/value&gt;
</del><span class="cx">                                                 &lt;value&gt;synccalendar3/&lt;/value&gt;
</span><span class="cx">                                                 &lt;value&gt;synccalendar4/&lt;/value&gt;
</span><span class="cx">                                         &lt;/arg&gt;
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCardDAV"></a>
<div class="propset"><h4>Property changes: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CardDAV</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4>Modified: svn:mergeinfo</h4></div>
<span class="cx">/CalDAVTester/branches/release/CalDAVTester-4.3-dev/scripts/tests/CardDAV:10193
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/attendee-comments-2887/scripts/tests/CardDAV:2888-2910
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/better-proxy-3148/scripts/tests/CardDAV:3149-3163
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/component-set-fixes/scripts/tests/CardDAV:8221-8346
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/conditional-4466/scripts/tests/CardDAV:4467-4469
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/implicitauto-2948/scripts/tests/CardDAV:2949-2989
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/location-partial-accept-3574/scripts/tests/CardDAV:3575-3581
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/managed-attachments/scripts/tests/CardDAV:9986-10145
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/normalize-cuaddr-3533/scripts/tests/CardDAV:3534-3558
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/pycalendar/scripts/tests/CardDAV:7160-7206
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/pycard/scripts/tests/CardDAV:7226-7237
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/sharing-5228/scripts/tests/CardDAV:5229-5440
</span><span class="cx">/CalDAVTester/branches/users/gaya/sharedgroupstester-2/scripts/tests/CardDAV:11078-11181
</span><span class="cx">/CalDAVTester/branches/users/gaya/sharedgroupstester-3/scripts/tests/CardDAV:11181-11204
</span><span class="cx">/CalDAVTester/trunk/scripts/tests/CardDAV:11742-11861
</span><span class="cx">   + /CalDAVTester/branches/release/CalDAVTester-3.0-dev/scripts/tests/CardDAV:7584
</span><span class="cx">/CalDAVTester/branches/release/CalDAVTester-4.3-dev/scripts/tests/CardDAV:10193
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/attendee-comments-2887/scripts/tests/CardDAV:2888-2910
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/better-proxy-3148/scripts/tests/CardDAV:3149-3163
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/component-set-fixes/scripts/tests/CardDAV:8221-8346
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/conditional-4466/scripts/tests/CardDAV:4467-4469
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/implicitauto-2948/scripts/tests/CardDAV:2949-2989
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/location-partial-accept-3574/scripts/tests/CardDAV:3575-3581
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/managed-attachments/scripts/tests/CardDAV:9986-10145
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/normalize-cuaddr-3533/scripts/tests/CardDAV:3534-3558
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/pycalendar/scripts/tests/CardDAV:7160-7206
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/pycard/scripts/tests/CardDAV:7226-7237
</span><span class="cx">/CalDAVTester/branches/users/cdaboo/sharing-5228/scripts/tests/CardDAV:5229-5440
</span><span class="cx">/CalDAVTester/branches/users/gaya/sharedgroupstester-2/scripts/tests/CardDAV:11078-11181
</span><span class="cx">/CalDAVTester/branches/users/gaya/sharedgroupstester-3/scripts/tests/CardDAV:11181-11204
</span><span class="cx">/CalDAVTester/trunk/scripts/tests/CardDAV:11742-12016
</span><a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterscriptstestsCardDAVcaldavtestdtd"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CardDAV/caldavtest.dtd (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CardDAV/caldavtest.dtd        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/scripts/tests/CardDAV/caldavtest.dtd        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -31,7 +31,8 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;!ELEMENT request (require-feature?, exclude-feature?, method, ruri*, header*, data?, verify*,
</span><span class="cx">                                                 graburi?, grabcount?, grabheader*, grabproperty*, grabelement*, grabcalproperty*, grabcalparameter*)&gt;
</span><del>-                &lt;!ATTLIST request auth (yes|no) &quot;yes&quot;
</del><ins>+                &lt;!ATTLIST request host2 (yes|no) &quot;no&quot;
+                                                 auth (yes|no) &quot;yes&quot;
</ins><span class="cx">                                                  user CDATA &quot;&quot;
</span><span class="cx">                                                  pswd CDATA &quot;&quot;
</span><span class="cx">                                                  end-delete (yes|no) &quot;no&quot;
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestestersrccaldavtestpy"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/caldavtest.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/caldavtest.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/caldavtest.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -19,7 +19,7 @@
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> from cStringIO import StringIO
</span><del>-from pycalendar.calendar import PyCalendar
</del><ins>+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> from src.httpshandler import SmartHTTPConnection
</span><span class="cx"> from src.manager import manager
</span><span class="cx"> from src.request import data, pause
</span><span class="lines">@@ -583,7 +583,7 @@
</span><span class="cx">             stats.startTimer()
</span><span class="cx"> 
</span><span class="cx">         # Do the http request
</span><del>-        http = SmartHTTPConnection(self.manager.server_info.host, self.manager.server_info.port, self.manager.server_info.ssl)
</del><ins>+        http = SmartHTTPConnection(req.host, req.port, self.manager.server_info.ssl)
</ins><span class="cx"> 
</span><span class="cx">         if not 'User-Agent' in headers and label is not None:
</span><span class="cx">             headers['User-Agent'] = label.encode(&quot;utf-8&quot;)
</span><span class="lines">@@ -916,7 +916,7 @@
</span><span class="cx">         prop = self._calProperty(propertyname, respdata)
</span><span class="cx"> 
</span><span class="cx">         try:
</span><del>-            return prop.getAttributeValue(pname) if prop else None
</del><ins>+            return prop.getParameterValue(pname) if prop else None
</ins><span class="cx">         except KeyError:
</span><span class="cx">             return None
</span><span class="cx"> 
</span><span class="lines">@@ -924,7 +924,7 @@
</span><span class="cx">     def _calProperty(self, propertyname, respdata):
</span><span class="cx"> 
</span><span class="cx">         try:
</span><del>-            cal = PyCalendar.parseText(respdata)
</del><ins>+            cal = Calendar.parseText(respdata)
</ins><span class="cx">         except Exception:
</span><span class="cx">             return None
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestestersrcmanagerpy"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/manager.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/manager.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/manager.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -100,12 +100,22 @@
</span><span class="cx">         # Setup ssl stuff
</span><span class="cx">         self.server_info.ssl = ssl
</span><span class="cx">         self.server_info.port = self.server_info.sslport if ssl else self.server_info.nonsslport
</span><ins>+        self.server_info.port2 = self.server_info.sslport2 if ssl else self.server_info.nonsslport2
+
</ins><span class="cx">         moresubs[&quot;$host:&quot;] = &quot;%s://%s:%d&quot; % (
</span><span class="cx">             &quot;https&quot; if ssl else &quot;http&quot;,
</span><span class="cx">             self.server_info.host,
</span><span class="cx">             self.server_info.port,
</span><span class="cx">         )
</span><span class="cx">         moresubs[&quot;$hostssl:&quot;] = &quot;https://%s:%d&quot; % (self.server_info.host, self.server_info.sslport,)
</span><ins>+
+        moresubs[&quot;$host2:&quot;] = &quot;%s://%s:%d&quot; % (
+            &quot;https&quot; if ssl else &quot;http&quot;,
+            self.server_info.host2,
+            self.server_info.port2,
+        )
+        moresubs[&quot;$hostssl2:&quot;] = &quot;https://%s:%d&quot; % (self.server_info.host2, self.server_info.sslport2,)
+
</ins><span class="cx">         self.server_info.addsubs(moresubs)
</span><span class="cx"> 
</span><span class="cx">         for testfile in testfiles:
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestestersrcrequestpy"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/request.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/request.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/request.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -142,6 +142,8 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, manager):
</span><span class="cx">         self.manager = manager
</span><ins>+        self.host = self.manager.server_info.host
+        self.port = self.manager.server_info.port
</ins><span class="cx">         self.auth = True
</span><span class="cx">         self.user = &quot;&quot;
</span><span class="cx">         self.pswd = &quot;&quot;
</span><span class="lines">@@ -345,6 +347,10 @@
</span><span class="cx">         self.iterate_data = getYesNoAttributeValue(node, src.xmlDefs.ATTR_ITERATE_DATA)
</span><span class="cx">         self.wait_for_success = getYesNoAttributeValue(node, src.xmlDefs.ATTR_WAIT_FOR_SUCCESS)
</span><span class="cx"> 
</span><ins>+        if node.get(src.xmlDefs.ATTR_HOST2, src.xmlDefs.ATTR_VALUE_NO) == src.xmlDefs.ATTR_VALUE_YES:
+            self.host = self.manager.server_info.host2
+            self.port = self.manager.server_info.port2
+
</ins><span class="cx">         for child in node.getchildren():
</span><span class="cx">             if child.tag == src.xmlDefs.ELEMENT_REQUIRE_FEATURE:
</span><span class="cx">                 self.parseFeatures(child, require=True)
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestestersrcserverinfopy"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/serverinfo.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/serverinfo.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/serverinfo.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -30,6 +30,9 @@
</span><span class="cx">         self.host = &quot;&quot;
</span><span class="cx">         self.nonsslport = 80
</span><span class="cx">         self.sslport = 443
</span><ins>+        self.host2 = &quot;&quot;
+        self.nonsslport2 = 80
+        self.sslport2 = 443
</ins><span class="cx">         self.authtype = &quot;basic&quot;
</span><span class="cx">         self.features = set()
</span><span class="cx">         self.user = &quot;&quot;
</span><span class="lines">@@ -131,6 +134,15 @@
</span><span class="cx">                 self.nonsslport = int(child.text)
</span><span class="cx">             elif child.tag == src.xmlDefs.ELEMENT_SSLPORT:
</span><span class="cx">                 self.sslport = int(child.text)
</span><ins>+            elif child.tag == src.xmlDefs.ELEMENT_HOST2:
+                try:
+                    self.host2 = child.text.encode(&quot;utf-8&quot;)
+                except:
+                    self.host2 = &quot;localhost&quot;
+            elif child.tag == src.xmlDefs.ELEMENT_NONSSLPORT2:
+                self.nonsslport2 = int(child.text)
+            elif child.tag == src.xmlDefs.ELEMENT_SSLPORT2:
+                self.sslport2 = int(child.text)
</ins><span class="cx">             elif child.tag == src.xmlDefs.ELEMENT_AUTHTYPE:
</span><span class="cx">                 self.authtype = child.text.encode(&quot;utf-8&quot;)
</span><span class="cx">             elif child.tag == src.xmlDefs.ELEMENT_WAITTIME:
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestestersrcxmlDefspy"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/xmlDefs.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/xmlDefs.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/src/xmlDefs.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> ELEMENT_GRABURI = &quot;graburi&quot;
</span><span class="cx"> ELEMENT_HEADER = &quot;header&quot;
</span><span class="cx"> ELEMENT_HOST = &quot;host&quot;
</span><ins>+ELEMENT_HOST2 = &quot;host2&quot;
</ins><span class="cx"> ELEMENT_KEY = &quot;key&quot;
</span><span class="cx"> ELEMENT_LOGGING = &quot;logging&quot;
</span><span class="cx"> ELEMENT_MAILFROM = &quot;mailfrom&quot;
</span><span class="lines">@@ -46,6 +47,7 @@
</span><span class="cx"> ELEMENT_METHOD = &quot;method&quot;
</span><span class="cx"> ELEMENT_NAME = &quot;name&quot;
</span><span class="cx"> ELEMENT_NONSSLPORT = &quot;nonsslport&quot;
</span><ins>+ELEMENT_NONSSLPORT2 = &quot;nonsslport2&quot;
</ins><span class="cx"> ELEMENT_NOTIFY = &quot;notify&quot;
</span><span class="cx"> ELEMENT_PARENT = &quot;parent&quot;
</span><span class="cx"> ELEMENT_PAUSE = &quot;pause&quot;
</span><span class="lines">@@ -59,6 +61,7 @@
</span><span class="cx"> ELEMENT_SERVERINFO = &quot;serverinfo&quot;
</span><span class="cx"> ELEMENT_SPREAD = &quot;spread&quot;
</span><span class="cx"> ELEMENT_SSLPORT = &quot;sslport&quot;
</span><ins>+ELEMENT_SSLPORT2 = &quot;sslport2&quot;
</ins><span class="cx"> ELEMENT_START = &quot;start&quot;
</span><span class="cx"> ELEMENT_SUBJECT = &quot;subject&quot;
</span><span class="cx"> ELEMENT_SUBSTITUTIONS = &quot;substitutions&quot;
</span><span class="lines">@@ -75,6 +78,7 @@
</span><span class="cx"> ELEMENT_WAITTIME = &quot;waittime&quot;
</span><span class="cx"> ELEMENT_WARNINGTIME = &quot;warningtime&quot;
</span><span class="cx"> 
</span><ins>+ATTR_HOST2 = &quot;host2&quot;
</ins><span class="cx"> ATTR_AUTH = &quot;auth&quot;
</span><span class="cx"> ATTR_COUNT = &quot;count&quot;
</span><span class="cx"> ATTR_DETAILS = &quot;details&quot;
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterverifiersaddressDataMatchpy"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/addressDataMatch.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/addressDataMatch.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/addressDataMatch.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -73,8 +73,8 @@
</span><span class="cx">                     if &quot;:&quot; in filter:
</span><span class="cx">                         propname, parameter = filter.split(&quot;:&quot;)
</span><span class="cx">                         if property.getName() == propname:
</span><del>-                            if property.hasAttribute(parameter):
-                                property.removeAttributes(parameter)
</del><ins>+                            if property.hasParameter(parameter):
+                                property.removeParameters(parameter)
</ins><span class="cx">                     else:
</span><span class="cx">                         if property.getName() == filter:
</span><span class="cx">                             component.removeProperty(property)
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterverifierscalendarDataMatchpy"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/calendarDataMatch.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/calendarDataMatch.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/calendarDataMatch.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -15,8 +15,8 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> from difflib import unified_diff
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.attribute import PyCalendarAttribute
</del><ins>+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.parameter import Parameter
</ins><span class="cx"> 
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> Verifier that checks the response body for a semantic match to data in a file.
</span><span class="lines">@@ -99,25 +99,25 @@
</span><span class="cx">             for property in allProps:
</span><span class="cx">                 # Always reset DTSTAMP on these properties
</span><span class="cx">                 if property.getName() in (&quot;ATTENDEE&quot;, &quot;X-CALENDARSERVER-ATTENDEE-COMMENT&quot;):
</span><del>-                    if property.hasAttribute(&quot;X-CALENDARSERVER-DTSTAMP&quot;):
-                        property.replaceAttribute(PyCalendarAttribute(&quot;X-CALENDARSERVER-DTSTAMP&quot;, &quot;20080101T000000Z&quot;))
</del><ins>+                    if property.hasParameter(&quot;X-CALENDARSERVER-DTSTAMP&quot;):
+                        property.replaceParameter(Parameter(&quot;X-CALENDARSERVER-DTSTAMP&quot;, &quot;20080101T000000Z&quot;))
</ins><span class="cx"> 
</span><span class="cx">                 for filter in filters:
</span><span class="cx">                     if &quot;:&quot; in filter:
</span><span class="cx">                         propname, parameter = filter.split(&quot;:&quot;)
</span><span class="cx">                         if property.getName() == propname:
</span><del>-                            if property.hasAttribute(parameter):
-                                property.removeAttributes(parameter)
</del><ins>+                            if property.hasParameter(parameter):
+                                property.removeParameters(parameter)
</ins><span class="cx">                     else:
</span><span class="cx">                         if property.getName() == filter:
</span><span class="cx">                             component.removeProperty(property)
</span><span class="cx"> 
</span><span class="cx">         try:
</span><del>-            resp_calendar = PyCalendar.parseText(respdata)
</del><ins>+            resp_calendar = Calendar.parseText(respdata)
</ins><span class="cx">             removePropertiesParameters(resp_calendar)
</span><span class="cx">             respdata = resp_calendar.getText()
</span><span class="cx"> 
</span><del>-            data_calendar = PyCalendar.parseText(data)
</del><ins>+            data_calendar = Calendar.parseText(data)
</ins><span class="cx">             removePropertiesParameters(data_calendar)
</span><span class="cx">             data = data_calendar.getText()
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterverifiersfreeBusypy"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/freeBusy.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/freeBusy.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/freeBusy.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,8 +18,8 @@
</span><span class="cx"> Verifier that checks the response of a free-busy-query.
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.exceptions import PyCalendarInvalidData
</del><ins>+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.exceptions import InvalidData
</ins><span class="cx"> 
</span><span class="cx"> class Verifier(object):
</span><span class="cx"> 
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> 
</span><span class="cx">         # Parse data as calendar object
</span><span class="cx">         try:
</span><del>-            calendar = PyCalendar.parseText(respdata)
</del><ins>+            calendar = Calendar.parseText(respdata)
</ins><span class="cx"> 
</span><span class="cx">             # Check for calendar
</span><span class="cx">             if calendar is None:
</span><span class="lines">@@ -61,8 +61,8 @@
</span><span class="cx">                     periods[i].getValue().setUseDuration(False)
</span><span class="cx">                 # Check param
</span><span class="cx">                 fbtype = &quot;BUSY&quot;
</span><del>-                if fp.hasAttribute(&quot;FBTYPE&quot;):
-                    fbtype = fp.getAttributeValue(&quot;FBTYPE&quot;)
</del><ins>+                if fp.hasParameter(&quot;FBTYPE&quot;):
+                    fbtype = fp.getParameterValue(&quot;FBTYPE&quot;)
</ins><span class="cx">                 if fbtype == &quot;BUSY&quot;:
</span><span class="cx">                     busyp.extend(periods)
</span><span class="cx">                 elif fbtype == &quot;BUSY-TENTATIVE&quot;:
</span><span class="lines">@@ -97,7 +97,7 @@
</span><span class="cx">             elif len(unavailablep.symmetric_difference(unavailable)):
</span><span class="cx">                 raise ValueError(&quot;Busy-unavailable periods do not match&quot;)
</span><span class="cx"> 
</span><del>-        except PyCalendarInvalidData:
</del><ins>+        except InvalidData:
</ins><span class="cx">             return False, &quot;        HTTP response data is not a calendar&quot;
</span><span class="cx">         except ValueError, txt:
</span><span class="cx">             return False, &quot;        HTTP response data is invalid: %s&quot; % (txt,)
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterverifierspostFreeBusypy"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/postFreeBusy.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/postFreeBusy.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/postFreeBusy.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,8 +18,8 @@
</span><span class="cx"> Verifier that checks the response of a free-busy-query.
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.exceptions import PyCalendarInvalidData
</del><ins>+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.exceptions import InvalidData
</ins><span class="cx"> from xml.etree.ElementTree import ElementTree
</span><span class="cx"> from xml.parsers.expat import ExpatError
</span><span class="cx"> import StringIO
</span><span class="lines">@@ -47,7 +47,7 @@
</span><span class="cx">         for calendar in tree.findall(&quot;./{urn:ietf:params:xml:ns:caldav}response/{urn:ietf:params:xml:ns:caldav}calendar-data&quot;):
</span><span class="cx">             # Parse data as calendar object
</span><span class="cx">             try:
</span><del>-                calendar = PyCalendar.parseText(calendar.text)
</del><ins>+                calendar = Calendar.parseText(calendar.text)
</ins><span class="cx"> 
</span><span class="cx">                 # Check for calendar
</span><span class="cx">                 if calendar is None:
</span><span class="lines">@@ -80,8 +80,8 @@
</span><span class="cx">                         periods[i].getValue().setUseDuration(False)
</span><span class="cx">                     # Check param
</span><span class="cx">                     fbtype = &quot;BUSY&quot;
</span><del>-                    if fp.hasAttribute(&quot;FBTYPE&quot;):
-                        fbtype = fp.getAttributeValue(&quot;FBTYPE&quot;)
</del><ins>+                    if fp.hasParameter(&quot;FBTYPE&quot;):
+                        fbtype = fp.getParameterValue(&quot;FBTYPE&quot;)
</ins><span class="cx">                     if fbtype == &quot;BUSY&quot;:
</span><span class="cx">                         busyp.extend(periods)
</span><span class="cx">                     elif fbtype == &quot;BUSY-TENTATIVE&quot;:
</span><span class="lines">@@ -118,7 +118,7 @@
</span><span class="cx"> 
</span><span class="cx">                 break
</span><span class="cx"> 
</span><del>-            except PyCalendarInvalidData:
</del><ins>+            except InvalidData:
</ins><span class="cx">                 return False, &quot;        HTTP response data is not a calendar&quot;
</span><span class="cx">             except ValueError, txt:
</span><span class="cx">                 return False, &quot;        HTTP response data is invalid: %s&quot; % (txt,)
</span></span></pre></div>
<a id="CalDAVTesterbranchesusersgayasharedgroupfixestesterverifiersxmlElementMatchpy"></a>
<div class="modfile"><h4>Modified: CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/xmlElementMatch.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/xmlElementMatch.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalDAVTester/branches/users/gaya/sharedgroupfixestester/verifiers/xmlElementMatch.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -19,7 +19,7 @@
</span><span class="cx"> Verifier that checks the response body for an exact match to data in a file.
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
</del><ins>+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> from xml.etree.ElementTree import ElementTree
</span><span class="cx"> import json
</span><span class="cx"> import StringIO
</span><span class="lines">@@ -141,6 +141,9 @@
</span><span class="cx">                         for child in node.getchildren():
</span><span class="cx">                             if child.tag == element and (value is None or child.text == value):
</span><span class="cx">                                 results.append(node)
</span><ins>+                    elif test[0] == '|':
+                        if node.text is None and len(node.getchildren()) == 0:
+                            results.append(node)
</ins><span class="cx">         else:
</span><span class="cx">             results = nodes
</span><span class="cx"> 
</span><span class="lines">@@ -222,7 +225,7 @@
</span><span class="cx">                         # Try to parse as iCalendar
</span><span class="cx">                         elif test == 'icalendar':
</span><span class="cx">                             try:
</span><del>-                                PyCalendar.parseText(node.text)
</del><ins>+                                Calendar.parseText(node.text)
</ins><span class="cx">                             except:
</span><span class="cx">                                 result = &quot;        Incorrect value returned in iCalendar for %s\n&quot; % (path,)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixes"></a>
<div class="propset"><h4>Property changes: CalendarServer/branches/users/gaya/sharedgroupfixes</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4>Modified: svn:mergeinfo</h4></div>
<span class="cx">/CalendarServer/branches/config-separation:4379-4443
</span><span class="cx">/CalendarServer/branches/egg-info-351:4589-4625
</span><span class="cx">/CalendarServer/branches/generic-sqlstore:6167-6191
</span><span class="cx">/CalendarServer/branches/new-store:5594-5934
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile:5911-5935
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-4.3-dev:10180-10190,10192
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-5.1-dev:11846
</span><span class="cx">/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
</span><span class="cx">/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
</span><span class="cx">/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
</span><span class="cx">/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
</span><span class="cx">/CalendarServer/branches/users/cdaboo/fix-no-ischedule:11612
</span><span class="cx">/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
</span><span class="cx">/CalendarServer/branches/users/cdaboo/ischedule-dkim:9747-9979
</span><span class="cx">/CalendarServer/branches/users/cdaboo/managed-attachments:9985-10145
</span><span class="cx">/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
</span><span class="cx">/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
</span><span class="cx">/CalendarServer/branches/users/cdaboo/performance-tweaks:11824-11836
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pods:7297-7377
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycard:7227-7237
</span><span class="cx">/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
</span><span class="cx">/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
</span><span class="cx">/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
</span><span class="cx">/CalendarServer/branches/users/cdaboo/store-scheduling:10876-11129
</span><span class="cx">/CalendarServer/branches/users/cdaboo/timezones:7443-7699
</span><span class="cx">/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
</span><span class="cx">/CalendarServer/branches/users/gaya/sharedgroups-3:11088-11204
</span><span class="cx">/CalendarServer/branches/users/glyph/always-abort-txn-on-error:9958-9969
</span><span class="cx">/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
</span><span class="cx">/CalendarServer/branches/users/glyph/conn-limit:6574-6577
</span><span class="cx">/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
</span><span class="cx">/CalendarServer/branches/users/glyph/dalify:6932-7023
</span><span class="cx">/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
</span><span class="cx">/CalendarServer/branches/users/glyph/deploybuild:7563-7572
</span><span class="cx">/CalendarServer/branches/users/glyph/digest-auth-redux:10624-10635
</span><span class="cx">/CalendarServer/branches/users/glyph/disable-quota:7718-7727
</span><span class="cx">/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
</span><span class="cx">/CalendarServer/branches/users/glyph/enforce-max-requests:11640-11643
</span><span class="cx">/CalendarServer/branches/users/glyph/hang-fix:11465-11491
</span><span class="cx">/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
</span><span class="cx">/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
</span><span class="cx">/CalendarServer/branches/users/glyph/launchd-wrapper-bis:11413-11436
</span><span class="cx">/CalendarServer/branches/users/glyph/linux-tests:6893-6900
</span><span class="cx">/CalendarServer/branches/users/glyph/log-cleanups:11691-11731
</span><span class="cx">/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
</span><span class="cx">/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
</span><span class="cx">/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
</span><span class="cx">/CalendarServer/branches/users/glyph/new-export:7444-7485
</span><span class="cx">/CalendarServer/branches/users/glyph/one-home-list-api:10048-10073
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle:7106-7155
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
</span><span class="cx">/CalendarServer/branches/users/glyph/other-html:8062-8091
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
</span><span class="cx">/CalendarServer/branches/users/glyph/q:9560-9688
</span><span class="cx">/CalendarServer/branches/users/glyph/queue-locking-and-timing:10204-10289
</span><span class="cx">/CalendarServer/branches/users/glyph/quota:7604-7637
</span><span class="cx">/CalendarServer/branches/users/glyph/sendfdport:5388-5424
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
</span><span class="cx">/CalendarServer/branches/users/glyph/sharedpool:6490-6550
</span><span class="cx">/CalendarServer/branches/users/glyph/sharing-api:9192-9205
</span><span class="cx">/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
</span><span class="cx">/CalendarServer/branches/users/glyph/sql-store:5929-6073
</span><span class="cx">/CalendarServer/branches/users/glyph/start-service-start-loop:11060-11065
</span><span class="cx">/CalendarServer/branches/users/glyph/subtransactions:7248-7258
</span><span class="cx">/CalendarServer/branches/users/glyph/table-alias:8651-8664
</span><span class="cx">/CalendarServer/branches/users/glyph/uidexport:7673-7676
</span><span class="cx">/CalendarServer/branches/users/glyph/unshare-when-access-revoked:10562-10595
</span><span class="cx">/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
</span><span class="cx">/CalendarServer/branches/users/glyph/uuid-normalize:9268-9296
</span><span class="cx">/CalendarServer/branches/users/glyph/warning-cleanups:11347-11357
</span><span class="cx">/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
</span><span class="cx">/CalendarServer/branches/users/sagen/applepush:8126-8184
</span><span class="cx">/CalendarServer/branches/users/sagen/inboxitems:7380-7381
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources:5032-5051
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
</span><span class="cx">/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
</span><span class="cx">/CalendarServer/branches/users/sagen/resources-2:5084-5093
</span><span class="cx">/CalendarServer/branches/users/sagen/testing:10827-10851,10853-10855
</span><span class="cx">/CalendarServer/branches/users/wsanchez/transations:5515-5593
</span><span class="cx">/CalendarServer/trunk:11632-11860
</span><span class="cx">   + /CalDAVTester/trunk:11193-11198
</span><span class="cx">/CalendarServer/branches/config-separation:4379-4443
</span><span class="cx">/CalendarServer/branches/egg-info-351:4589-4625
</span><span class="cx">/CalendarServer/branches/generic-sqlstore:6167-6191
</span><span class="cx">/CalendarServer/branches/new-store:5594-5934
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile:5911-5935
</span><span class="cx">/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-4.3-dev:10180-10190,10192
</span><span class="cx">/CalendarServer/branches/release/CalendarServer-5.1-dev:11846
</span><span class="cx">/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
</span><span class="cx">/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
</span><span class="cx">/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
</span><span class="cx">/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
</span><span class="cx">/CalendarServer/branches/users/cdaboo/fix-no-ischedule:11607-11871
</span><span class="cx">/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
</span><span class="cx">/CalendarServer/branches/users/cdaboo/ischedule-dkim:9747-9979
</span><span class="cx">/CalendarServer/branches/users/cdaboo/json:11622-11912
</span><span class="cx">/CalendarServer/branches/users/cdaboo/managed-attachments:9985-10145
</span><span class="cx">/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
</span><span class="cx">/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
</span><span class="cx">/CalendarServer/branches/users/cdaboo/performance-tweaks:11824-11836
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pods:7297-7377
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
</span><span class="cx">/CalendarServer/branches/users/cdaboo/pycard:7227-7237
</span><span class="cx">/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
</span><span class="cx">/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
</span><span class="cx">/CalendarServer/branches/users/cdaboo/reverse-proxy-pods:11875-11900
</span><span class="cx">/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
</span><span class="cx">/CalendarServer/branches/users/cdaboo/store-scheduling:10876-11129
</span><span class="cx">/CalendarServer/branches/users/cdaboo/timezones:7443-7699
</span><span class="cx">/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
</span><span class="cx">/CalendarServer/branches/users/gaya/sharedgroups-3:11088-11204
</span><span class="cx">/CalendarServer/branches/users/glyph/always-abort-txn-on-error:9958-9969
</span><span class="cx">/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
</span><span class="cx">/CalendarServer/branches/users/glyph/conn-limit:6574-6577
</span><span class="cx">/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
</span><span class="cx">/CalendarServer/branches/users/glyph/dalify:6932-7023
</span><span class="cx">/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
</span><span class="cx">/CalendarServer/branches/users/glyph/deploybuild:7563-7572
</span><span class="cx">/CalendarServer/branches/users/glyph/digest-auth-redux:10624-10635
</span><span class="cx">/CalendarServer/branches/users/glyph/disable-quota:7718-7727
</span><span class="cx">/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
</span><span class="cx">/CalendarServer/branches/users/glyph/enforce-max-requests:11640-11643
</span><span class="cx">/CalendarServer/branches/users/glyph/hang-fix:11465-11491
</span><span class="cx">/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
</span><span class="cx">/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
</span><span class="cx">/CalendarServer/branches/users/glyph/launchd-wrapper-bis:11413-11436
</span><span class="cx">/CalendarServer/branches/users/glyph/linux-tests:6893-6900
</span><span class="cx">/CalendarServer/branches/users/glyph/log-cleanups:11691-11731
</span><span class="cx">/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
</span><span class="cx">/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
</span><span class="cx">/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
</span><span class="cx">/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
</span><span class="cx">/CalendarServer/branches/users/glyph/new-export:7444-7485
</span><span class="cx">/CalendarServer/branches/users/glyph/one-home-list-api:10048-10073
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle:7106-7155
</span><span class="cx">/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
</span><span class="cx">/CalendarServer/branches/users/glyph/other-html:8062-8091
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
</span><span class="cx">/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
</span><span class="cx">/CalendarServer/branches/users/glyph/q:9560-9688
</span><span class="cx">/CalendarServer/branches/users/glyph/queue-locking-and-timing:10204-10289
</span><span class="cx">/CalendarServer/branches/users/glyph/quota:7604-7637
</span><span class="cx">/CalendarServer/branches/users/glyph/sendfdport:5388-5424
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
</span><span class="cx">/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
</span><span class="cx">/CalendarServer/branches/users/glyph/sharedpool:6490-6550
</span><span class="cx">/CalendarServer/branches/users/glyph/sharing-api:9192-9205
</span><span class="cx">/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
</span><span class="cx">/CalendarServer/branches/users/glyph/sql-store:5929-6073
</span><span class="cx">/CalendarServer/branches/users/glyph/start-service-start-loop:11060-11065
</span><span class="cx">/CalendarServer/branches/users/glyph/subtransactions:7248-7258
</span><span class="cx">/CalendarServer/branches/users/glyph/table-alias:8651-8664
</span><span class="cx">/CalendarServer/branches/users/glyph/uidexport:7673-7676
</span><span class="cx">/CalendarServer/branches/users/glyph/unshare-when-access-revoked:10562-10595
</span><span class="cx">/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
</span><span class="cx">/CalendarServer/branches/users/glyph/uuid-normalize:9268-9296
</span><span class="cx">/CalendarServer/branches/users/glyph/warning-cleanups:11347-11357
</span><span class="cx">/CalendarServer/branches/users/glyph/whenNotProposed:11881-11897
</span><span class="cx">/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
</span><span class="cx">/CalendarServer/branches/users/sagen/applepush:8126-8184
</span><span class="cx">/CalendarServer/branches/users/sagen/inboxitems:7380-7381
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources:5032-5051
</span><span class="cx">/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
</span><span class="cx">/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
</span><span class="cx">/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
</span><span class="cx">/CalendarServer/branches/users/sagen/resources-2:5084-5093
</span><span class="cx">/CalendarServer/branches/users/sagen/testing:10827-10851,10853-10855
</span><span class="cx">/CalendarServer/branches/users/wsanchez/transations:5515-5593
</span><span class="cx">/CalendarServer/trunk:11632-11860,11862-12016
</span><a id="CalendarServerbranchesusersgayasharedgroupfixesHACKING"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/HACKING (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/HACKING        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/HACKING        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -144,10 +144,6 @@
</span><span class="cx"> 
</span><span class="cx"> PEP-8 items we do not follow:
</span><span class="cx"> 
</span><del>- * Lines need not be limited to 79 spaces, but longer lines are
-   undesirable.  If you can easily do so, try to keep lines under 80
-   columns.
-
</del><span class="cx">  * PEP-8 recommends using a backslash to break long lines up:
</span><span class="cx"> 
</span><span class="cx">    ::
</span><span class="lines">@@ -181,14 +177,6 @@
</span><span class="cx"> 
</span><span class="cx">    Because that's just silly.
</span><span class="cx"> 
</span><del>- * Lining up assignments is OK, within reason:
-
-   ::
-
-     cars       =  4
-     motorbikes =  8
-     bicycles   = 18
-
</del><span class="cx"> Additions:
</span><span class="cx"> 
</span><span class="cx">  * Close parentheses and brackets such as ``()``, ``[]`` and ``{}`` at the
</span><span class="lines">@@ -248,9 +236,8 @@
</span><span class="cx"> 
</span><span class="cx">      process = subprocess.Popen(...)
</span><span class="cx"> 
</span><del>-   This makes code shorter and removes the runtime indirection (which
-   can be relevant in tight loops). It also makes it easier to replace
-   one implementation with another.
</del><ins>+   This makes code shorter and makes it easier to replace one implementation
+   with another.
</ins><span class="cx"> 
</span><span class="cx">  * All files should have an ``__all__`` specification.  Put them at the
</span><span class="cx">    top of the file, before imports (PEP-8 puts them at the top, but
</span><span class="lines">@@ -259,8 +246,8 @@
</span><span class="cx"> 
</span><span class="cx">  * It is more important that symbol names are meaningful than it is
</span><span class="cx">    that they be concise.  ``x`` is rarely an appropriate name for a
</span><del>-   variable.  ``transmogrifierStatus`` is more useful to the reader
-   than ``trmgStat``; avoid contractions.
</del><ins>+   variable.  Avoid contractions: ``transmogrifierStatus`` is more useful
+   to the reader than ``trmgStat``.
</ins><span class="cx"> 
</span><span class="cx">  * A deferred that will be immediately returned may be called ``d``:
</span><span class="cx"> 
</span><span class="lines">@@ -271,9 +258,7 @@
</span><span class="cx">      d.addErrback(onError)
</span><span class="cx">      return d
</span><span class="cx"> 
</span><del>- * We prefer ``inlineCallbacks`` over ``deferredGenerator``.
-   ``inlineCallbacks`` are more readable, and we do not support Python
-   versions old enough that ``deferredGenerator`` would be necessary.
</del><ins>+ * Do not use ``deferredGenerator``.  Use ``inlineCallbacks`` instead.
</ins><span class="cx"> 
</span><span class="cx">  * That said, avoid using ``inlineCallbacks`` when chaining deferreds
</span><span class="cx">    is straightforward, as they are more expensive.  Use
</span><span class="lines">@@ -306,17 +291,29 @@
</span><span class="cx">    Use of underscores is reserved for implied dispatching and the like
</span><span class="cx">    (eg. ``http_FOO()``).  See the Twisted Coding Standard for details.
</span><span class="cx"> 
</span><del>- * Always use a tuple when using ``%``-formatting, even when only one
-   value is being provided:
</del><ins>+ * Do not use ``%``-formatting:
</ins><span class="cx"> 
</span><span class="cx">    ::
</span><span class="cx"> 
</span><span class="cx">      error = &quot;Unexpected value: %s&quot; % (value,)
</span><span class="cx"> 
</span><del>-   Do not use the non-tuple form:
</del><ins>+   Use PEP-3101 formatting instead:
</ins><span class="cx"> 
</span><span class="cx">    ::
</span><span class="cx"> 
</span><ins>+     error = &quot;Unexpected value: {value}&quot;.format(value=value)
+
+ * If you must use ``%``-formatting for some reason, always use a tuple as
+   the format argument, even when only one value is being provided:
+
+   ::
+
+     error = &quot;Unexpected value: %s&quot; % (value,)
+
+   Never use the non-tuple form:
+
+   ::
+
</ins><span class="cx">      error = &quot;Unexpected value: %s&quot; % value
</span><span class="cx"> 
</span><span class="cx">    Which is allowed in Python, but results in a programming error if
</span><span class="lines">@@ -329,8 +326,9 @@
</span><span class="cx">      numbers = (1,2,3,) # No
</span><span class="cx">      numbers = (1,2,3)  # Yes
</span><span class="cx"> 
</span><del>-   It's desirable on multiple lines, though, as that makes re-ordering
-   items easy, and avoids a diff on the last line when adding another:
</del><ins>+   The trailing comma is desirable on multiple lines, though, as that makes
+   re-ordering items easy, and avoids a diff on the last line when adding
+   another:
</ins><span class="cx"> 
</span><span class="cx">    ::
</span><span class="cx"> 
</span><span class="lines">@@ -368,11 +366,11 @@
</span><span class="cx"> ==============
</span><span class="cx"> 
</span><span class="cx">  * If a callable is going to return a Deferred some of the time, it
</span><del>-   should probably return a deferred all of the time.  Return
-   ``succeed(value)`` instead of ``value`` if necessary.  This avoids
-   forcing the caller to check as to whether the value is a deferred
-   or not (eg. by using ``maybeDeferred()``), which is both annoying
-   to code and potentially expensive at runtime.
</del><ins>+   should return a deferred all of the time.  Return ``succeed(value)``
+   instead of ``value`` if necessary.  This avoids forcing the caller
+   to check as to whether the value is a deferred or not (eg. by using
+   ``maybeDeferred()``), which is both annoying to code and potentially
+   expensive at runtime.
</ins><span class="cx"> 
</span><span class="cx">  * Be proactive about closing files and file-like objects.
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesbin_calendarserver_preamblepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/bin/_calendarserver_preamble.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/bin/_calendarserver_preamble.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/bin/_calendarserver_preamble.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -60,11 +60,11 @@
</span><span class="cx">     noConfigOption = [
</span><span class="cx">         &quot;calendarserver_bootstrap_database&quot;,
</span><span class="cx">         &quot;calendarserver_load_augmentdb&quot;,
</span><del>-        &quot;calendarserver_make_partition&quot;,
</del><span class="cx">         &quot;calendarserver_manage_augments&quot;,
</span><span class="cx">         &quot;calendarserver_manage_postgres&quot;,
</span><span class="cx">         &quot;calendarserver_manage_timezones&quot;,
</span><span class="cx">         &quot;icalendar_split&quot;,
</span><ins>+        &quot;twistd&quot;, &quot;trial&quot;,
</ins><span class="cx">     ]
</span><span class="cx"> 
</span><span class="cx">     if split(sys.argv[0])[-1] not in noConfigOption:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesbincalendarserver_make_partition"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/bin/calendarserver_make_partition (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/bin/calendarserver_make_partition        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/bin/calendarserver_make_partition        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,32 +0,0 @@
</span><del>-#!/usr/bin/env python
-##
-# Copyright (c) 2010-2013 Apple Inc. 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 sys
-
-#PYTHONPATH
-
-if __name__ == &quot;__main__&quot;:
-    if &quot;PYTHONPATH&quot; in globals():
-        sys.path.insert(0, PYTHONPATH)
-    else:
-        try:
-            import _calendarserver_preamble
-        except ImportError:
-            sys.exc_clear()
-
-    from calendarserver.tools.makepartition import main
-    main()
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesbintrialfromrev12016CalendarServertrunkbintrial"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/bin/trial (from rev 12016, CalendarServer/trunk/bin/trial) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/bin/trial                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/bin/trial        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+#!/usr/bin/env python
+
+##
+# Copyright (c) 2006-2013 Apple Inc. 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 sys
+
+#PYTHONPATH
+
+if __name__ == &quot;__main__&quot;:
+    if &quot;PYTHONPATH&quot; in globals():
+        sys.path.insert(0, PYTHONPATH)
+    else:
+        try:
+            import _calendarserver_preamble
+        except ImportError:
+            sys.exc_clear()
+
+    from twisted.scripts.trial import run
+    run()
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesbintwistdfromrev12016CalendarServertrunkbintwistd"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/bin/twistd (from rev 12016, CalendarServer/trunk/bin/twistd) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/bin/twistd                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/bin/twistd        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+#!/usr/bin/env python
+
+##
+# Copyright (c) 2006-2013 Apple Inc. 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 sys
+
+#PYTHONPATH
+
+if __name__ == &quot;__main__&quot;:
+    if &quot;PYTHONPATH&quot; in globals():
+        sys.path.insert(0, PYTHONPATH)
+    else:
+        try:
+            import _calendarserver_preamble
+        except ImportError:
+            sys.exc_clear()
+
+    from twisted.scripts.twistd import run
+    run()
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushamppushpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/amppush.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/amppush.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/amppush.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -23,7 +23,9 @@
</span><span class="cx"> import time
</span><span class="cx"> import uuid
</span><span class="cx"> 
</span><ins>+from calendarserver.push.util import PushPriority
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -49,7 +51,8 @@
</span><span class="cx"> 
</span><span class="cx"> class NotificationForID(amp.Command):
</span><span class="cx">     arguments = [('id', amp.String()),
</span><del>-                 ('dataChangedTimestamp', amp.Integer(optional=True))]
</del><ins>+                 ('dataChangedTimestamp', amp.Integer(optional=True)),
+                 ('priority', amp.Integer(optional=True))]
</ins><span class="cx">     response = [('status', amp.String())]
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -82,12 +85,14 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def enqueue(self, transaction, id, dataChangedTimestamp=None):
</del><ins>+    def enqueue(self, transaction, id, dataChangedTimestamp=None,
+        priority=PushPriority.high):
</ins><span class="cx">         if dataChangedTimestamp is None:
</span><span class="cx">             dataChangedTimestamp = int(time.time())
</span><span class="cx">         for protocol in self.protocols:
</span><span class="cx">             yield protocol.callRemote(NotificationForID, id=id,
</span><del>-                dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+                dataChangedTimestamp=dataChangedTimestamp,
+                priority=priority.value)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -103,10 +108,12 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @NotificationForID.responder
</span><del>-    def enqueueFromWorker(self, id, dataChangedTimestamp=None):
</del><ins>+    def enqueueFromWorker(self, id, dataChangedTimestamp=None,
+        priority=PushPriority.high.value):
</ins><span class="cx">         if dataChangedTimestamp is None:
</span><span class="cx">             dataChangedTimestamp = int(time.time())
</span><del>-        self.master.enqueue(None, id, dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+        self.master.enqueue(None, id, dataChangedTimestamp=dataChangedTimestamp,
+            priority=PushPriority.lookupByValue(priority))
</ins><span class="cx">         return {&quot;status&quot; : &quot;OK&quot;}
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -167,7 +174,8 @@
</span><span class="cx">         self.subscribers.remove(p)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def enqueue(self, transaction, pushKey, dataChangedTimestamp=None):
</del><ins>+    def enqueue(self, transaction, pushKey, dataChangedTimestamp=None,
+        priority=PushPriority.high):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Sends an AMP push notification to any clients subscribing to this pushKey.
</span><span class="cx"> 
</span><span class="lines">@@ -192,23 +200,26 @@
</span><span class="cx">             if token is not None:
</span><span class="cx">                 tokens.append(token)
</span><span class="cx">         if tokens:
</span><del>-            return self.scheduleNotifications(tokens, pushKey, dataChangedTimestamp)
</del><ins>+            return self.scheduleNotifications(tokens, pushKey,
+                dataChangedTimestamp, priority)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def sendNotification(self, token, id, dataChangedTimestamp):
</del><ins>+    def sendNotification(self, token, id, dataChangedTimestamp, priority):
</ins><span class="cx">         for subscriber in self.subscribers:
</span><span class="cx">             if subscriber.subscribedToID(id):
</span><del>-                yield subscriber.notify(token, id, dataChangedTimestamp)
</del><ins>+                yield subscriber.notify(token, id, dataChangedTimestamp,
+                    priority)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def scheduleNotifications(self, tokens, id, dataChangedTimestamp):
</del><ins>+    def scheduleNotifications(self, tokens, id, dataChangedTimestamp, priority):
</ins><span class="cx">         if self.scheduler is not None:
</span><del>-            self.scheduler.schedule(tokens, id, dataChangedTimestamp)
</del><ins>+            self.scheduler.schedule(tokens, id, dataChangedTimestamp, priority)
</ins><span class="cx">         else:
</span><span class="cx">             for token in tokens:
</span><del>-                yield self.sendNotification(token, id, dataChangedTimestamp)
</del><ins>+                yield self.sendNotification(token, id, dataChangedTimestamp,
+                    priority)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -238,11 +249,12 @@
</span><span class="cx">         return {&quot;status&quot; : &quot;OK&quot;}
</span><span class="cx">     UnsubscribeFromID.responder(unsubscribe)
</span><span class="cx"> 
</span><del>-    def notify(self, token, id, dataChangedTimestamp):
</del><ins>+    def notify(self, token, id, dataChangedTimestamp, priority):
</ins><span class="cx">         if self.subscribedToID(id) == token:
</span><span class="cx">             self.log.debug(&quot;Sending notification for %s to %s&quot; % (id, token))
</span><span class="cx">             return self.callRemote(NotificationForID, id=id,
</span><del>-                dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+                dataChangedTimestamp=dataChangedTimestamp,
+                priority=priority.value)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def subscribedToID(self, id):
</span><span class="lines">@@ -288,8 +300,8 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def notificationForID(self, id, dataChangedTimestamp):
-        yield self.callback(id, dataChangedTimestamp)
</del><ins>+    def notificationForID(self, id, dataChangedTimestamp, priority):
+        yield self.callback(id, dataChangedTimestamp, PushPriority.lookupByValue(priority))
</ins><span class="cx">         returnValue({&quot;status&quot; : &quot;OK&quot;})
</span><span class="cx"> 
</span><span class="cx">     NotificationForID.responder(notificationForID)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushapplepushpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/applepush.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/applepush.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/applepush.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -36,16 +36,27 @@
</span><span class="cx"> import struct
</span><span class="cx"> import time
</span><span class="cx"> from txdav.common.icommondatastore import InvalidSubscriptionValues
</span><del>-
-from calendarserver.push.util import validToken, TokenHistory, PushScheduler
-
</del><ins>+from calendarserver.push.util import (
+    validToken, TokenHistory, PushScheduler, PushPriority
+)
</ins><span class="cx"> from twext.internet.adaptendpoint import connect
</span><span class="cx"> from twext.internet.gaiendpoint import GAIEndpoint
</span><ins>+from twisted.python.constants import Values, ValueConstant
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+class ApplePushPriority(Values):
+    &quot;&quot;&quot;
+    Maps calendarserver.push.util.PushPriority values to APNS-specific values
+    &quot;&quot;&quot;
+    low    = ValueConstant(PushPriority.low.value)
+    medium = ValueConstant(PushPriority.medium.value)
+    high   = ValueConstant(PushPriority.high.value)
+
+
+
</ins><span class="cx"> class ApplePushNotifierService(service.MultiService):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     ApplePushNotifierService is a MultiService responsible for
</span><span class="lines">@@ -55,7 +66,7 @@
</span><span class="cx"> 
</span><span class="cx">     The Apple Push Notification protocol is described here:
</span><span class="cx"> 
</span><del>-    http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingWIthAPS/CommunicatingWIthAPS.html
</del><ins>+    https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/CommunicatingWIthAPS.html
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -177,7 +188,8 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def enqueue(self, transaction, pushKey, dataChangedTimestamp=None):
</del><ins>+    def enqueue(self, transaction, pushKey, dataChangedTimestamp=None,
+        priority=PushPriority.high):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Sends an Apple Push Notification to any device token subscribed to
</span><span class="cx">         this pushKey.
</span><span class="lines">@@ -191,6 +203,8 @@
</span><span class="cx">         @param dataChangedTimestamp: Timestamp (epoch seconds) for the data change
</span><span class="cx">             which triggered this notification (Only used for unit tests)
</span><span class="cx">         @type key: C{int}
</span><ins>+        @param priority: the priority level
+        @type priority: L{PushPriority}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         try:
</span><span class="lines">@@ -219,7 +233,8 @@
</span><span class="cx">                     if token and uid:
</span><span class="cx">                         tokens.append(token)
</span><span class="cx">                 if tokens:
</span><del>-                    provider.scheduleNotifications(tokens, pushKey, dataChangedTimestamp)
</del><ins>+                    provider.scheduleNotifications(tokens, pushKey,
+                        dataChangedTimestamp, priority)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -230,8 +245,7 @@
</span><span class="cx">     log = Logger()
</span><span class="cx"> 
</span><span class="cx">     # Sent by provider
</span><del>-    COMMAND_SIMPLE = 0
-    COMMAND_ENHANCED = 1
</del><ins>+    COMMAND_PROVIDER = 2
</ins><span class="cx"> 
</span><span class="cx">     # Received by provider
</span><span class="cx">     COMMAND_ERROR = 8
</span><span class="lines">@@ -333,7 +347,7 @@
</span><span class="cx">                 yield txn.commit()
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def sendNotification(self, token, key, dataChangedTimestamp):
</del><ins>+    def sendNotification(self, token, key, dataChangedTimestamp, priority):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Sends a push notification message for the key to the device associated
</span><span class="cx">         with the token.
</span><span class="lines">@@ -357,6 +371,7 @@
</span><span class="cx">             return
</span><span class="cx"> 
</span><span class="cx">         identifier = self.history.add(token)
</span><ins>+        apnsPriority = ApplePushPriority.lookupByValue(priority.value).value
</ins><span class="cx">         payload = json.dumps(
</span><span class="cx">             {
</span><span class="cx">                 &quot;key&quot; : key,
</span><span class="lines">@@ -365,23 +380,79 @@
</span><span class="cx">             }
</span><span class="cx">         )
</span><span class="cx">         payloadLength = len(payload)
</span><del>-        self.log.debug(&quot;Sending APNS notification to {token}: id={id} payload={payload}&quot;,
-            token=token, id=identifier, payload=payload)
</del><ins>+        self.log.debug(&quot;Sending APNS notification to {token}: id={id} payload={payload} priority={priority}&quot;,
+            token=token, id=identifier, payload=payload, priority=apnsPriority)
</ins><span class="cx"> 
</span><ins>+        &quot;&quot;&quot;
+        Notification format
+
+        Top level:  Command (1 byte), Frame length (4 bytes), Frame data (variable)
+        Within Frame data:  Item ...
+        Item: Item number (1 byte), Item data length (2 bytes), Item data (variable)
+        Item 1: Device token (32 bytes)
+        Item 2: Payload (variable length) in JSON format, not null-terminated
+        Item 3: Notification ID (4 bytes) an opaque value used for reporting errors
+        Item 4: Expiration date (4 bytes) UNIX epoch in secondcs UTC
+        Item 5: Priority (1 byte): 10 (push sent immediately) or 5 (push sent
+            at a time that conservces power on the device receiving it)
+        &quot;&quot;&quot;
+
+                                                    # Frame struct.pack format
+                                                    # ! Network byte order
+        command = self.COMMAND_PROVIDER             # B
+        frameLength = (                             # I
+            # Item 1 (Device token)
+            1 +  # Item number                      # B
+            2 +  # Item length                      # H
+            32 + # device token                     # 32s
+            # Item 2 (Payload)
+            1 +  # Item number                      # B
+            2 +  # Item length                      # H
+            payloadLength + # the JSON payload      # %d s
+            # Item 3 (Notification ID)
+            1 +  # Item number                      # B    
+            2 +  # Item length                      # H
+            4 +  # Notification ID                  # I
+            # Item 4 (Expiration)
+            1 +  # Item number                      # B
+            2 +  # Item length                      # H
+            4 +  # Expiration seconds since epoch   # I
+            # Item 5 (Priority)
+            1 +  # Item number                      # B
+            2 +  # Item length                      # H
+            1    # Priority                         # B
+        )
+
</ins><span class="cx">         self.transport.write(
</span><del>-            struct.pack(&quot;!BIIH32sH%ds&quot; % (payloadLength,),
-                self.COMMAND_ENHANCED,           # Command
-                identifier,                      # Identifier
-                int(time.time()) + 72 * 60 * 60, # Expires in 72 hours
</del><ins>+            struct.pack(&quot;!BIBH32sBH%dsBHIBHIBHB&quot; % (payloadLength,),
+
+                command,                         # Command
+                frameLength,                     # Frame length
+
+                1,                               # Item 1 (Device token)
</ins><span class="cx">                 32,                              # Token Length
</span><span class="cx">                 binaryToken,                     # Token
</span><del>-                payloadLength,                   # Payload Length
-                payload,                         # Payload in JSON format
</del><ins>+
+                2,                               # Item 2 (Payload)
+                payloadLength,                   # Payload length
+                payload,                         # Payload
+
+                3,                               # Item 3 (Notification ID)
+                4,                               # Notification ID Length
+                identifier,                      # Notification ID
+
+                4,                               # Item 4 (Expiration)
+                4,                               # Expiration length
+                int(time.time()) + 72 * 60 * 60, # Expires in 72 hours
+
+                5,                               # Item 5 (Priority)
+                1,                               # Priority length
+                apnsPriority,                    # Priority
+
</ins><span class="cx">             )
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> class APNProviderFactory(ReconnectingClientFactory):
</span><span class="cx">     log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -509,12 +580,13 @@
</span><span class="cx">             # sent will be put back into the queue.
</span><span class="cx">             queued = list(self.queue)
</span><span class="cx">             self.queue = []
</span><del>-            for (token, key), dataChangedTimestamp in queued:
-                if token and key and dataChangedTimestamp:
-                    self.sendNotification(token, key, dataChangedTimestamp)
</del><ins>+            for (token, key), dataChangedTimestamp, priority in queued:
+                if token and key and dataChangedTimestamp and priority:
+                    self.sendNotification(token, key, dataChangedTimestamp,
+                        priority)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def scheduleNotifications(self, tokens, key, dataChangedTimestamp):
</del><ins>+    def scheduleNotifications(self, tokens, key, dataChangedTimestamp, priority):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         The starting point for getting notifications to the APNS server.  If there is
</span><span class="cx">         a connection to the APNS server, these notifications are scheduled (or directly
</span><span class="lines">@@ -533,15 +605,15 @@
</span><span class="cx">         connection = getattr(self.factory, &quot;connection&quot;, None)
</span><span class="cx">         if connection is not None:
</span><span class="cx">             if self.scheduler is not None:
</span><del>-                self.scheduler.schedule(tokens, key, dataChangedTimestamp)
</del><ins>+                self.scheduler.schedule(tokens, key, dataChangedTimestamp, priority)
</ins><span class="cx">             else:
</span><span class="cx">                 for token in tokens:
</span><del>-                    self.sendNotification(token, key, dataChangedTimestamp)
</del><ins>+                    self.sendNotification(token, key, dataChangedTimestamp, priority)
</ins><span class="cx">         else:
</span><del>-            self._saveForWhenConnected(tokens, key, dataChangedTimestamp)
</del><ins>+            self._saveForWhenConnected(tokens, key, dataChangedTimestamp, priority)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def _saveForWhenConnected(self, tokens, key, dataChangedTimestamp):
</del><ins>+    def _saveForWhenConnected(self, tokens, key, dataChangedTimestamp, priority):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Called in order to save notifications that can't be sent now because there
</span><span class="cx">         is no connection to the APNS server.  (token, key) tuples are appended to
</span><span class="lines">@@ -557,16 +629,16 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         for token in tokens:
</span><span class="cx">             tokenKeyPair = (token, key)
</span><del>-            for existingPair, ignored in self.queue:
</del><ins>+            for existingPair, timstamp, priority in self.queue:
</ins><span class="cx">                 if tokenKeyPair == existingPair:
</span><span class="cx">                     self.log.debug(&quot;APNProviderService has no connection; skipping duplicate: %s %s&quot; % (token, key))
</span><span class="cx">                     break # Already scheduled
</span><span class="cx">             else:
</span><span class="cx">                 self.log.debug(&quot;APNProviderService has no connection; queuing: %s %s&quot; % (token, key))
</span><del>-                self.queue.append(((token, key), dataChangedTimestamp))
</del><ins>+                self.queue.append(((token, key), dataChangedTimestamp, priority))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def sendNotification(self, token, key, dataChangedTimestamp):
</del><ins>+    def sendNotification(self, token, key, dataChangedTimestamp, priority):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         If there is a connection the notification is sent right away, otherwise
</span><span class="cx">         the notification is saved for later.
</span><span class="lines">@@ -579,15 +651,15 @@
</span><span class="cx">             which triggered this notification
</span><span class="cx">         @type key: C{int}
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        if not (token and key and dataChangedTimestamp):
</del><ins>+        if not (token and key and dataChangedTimestamp, priority):
</ins><span class="cx">             return
</span><span class="cx"> 
</span><span class="cx">         # Service has reference to factory has reference to protocol instance
</span><span class="cx">         connection = getattr(self.factory, &quot;connection&quot;, None)
</span><span class="cx">         if connection is None:
</span><del>-            self._saveForWhenConnected([token], key, dataChangedTimestamp)
</del><ins>+            self._saveForWhenConnected([token], key, dataChangedTimestamp, priority)
</ins><span class="cx">         else:
</span><del>-            connection.sendNotification(token, key, dataChangedTimestamp)
</del><ins>+            connection.sendNotification(token, key, dataChangedTimestamp, priority)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushnotifierpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/notifier.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/notifier.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/notifier.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -19,7 +19,7 @@
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> from twext.enterprise.dal.record import fromTable
</span><del>-from twext.enterprise.dal.syntax import Delete
</del><ins>+from twext.enterprise.dal.syntax import Delete, Select, Parameter
</ins><span class="cx"> from twext.enterprise.queue import WorkItem
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx"> 
</span><span class="lines">@@ -32,10 +32,13 @@
</span><span class="cx"> 
</span><span class="cx"> import datetime
</span><span class="cx"> 
</span><ins>+from calendarserver.push.util import PushPriority
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class PushNotificationWork(WorkItem, fromTable(schema.PUSH_NOTIFICATION_WORK)):
</span><span class="cx"> 
</span><span class="cx">     group = property(lambda self: self.pushID)
</span><span class="lines">@@ -43,14 +46,35 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def doWork(self):
</span><span class="cx"> 
</span><del>-        # Delete all other work items with the same pushID
-        yield Delete(From=self.table,
-                     Where=self.table.PUSH_ID == self.pushID
-                    ).on(self.transaction)
</del><ins>+        # Find all work items with the same push ID and find the highest
+        # priority.  Delete matching work items.
+        results = (yield Select([self.table.WORK_ID, self.table.PRIORITY],
+            From=self.table, Where=self.table.PUSH_ID == self.pushID).on(
+            self.transaction))
</ins><span class="cx"> 
</span><ins>+        maxPriority = self.priority
+
+        # If there are other enqueued work items for this push ID, find the
+        # highest priority one and use that value
+        if results:
+            workIDs = []
+            for workID, priority in results:
+                if priority &gt; maxPriority:
+                    maxPriority = priority
+                workIDs.append(workID)
+
+            # Delete the work items we selected
+            yield Delete(From=self.table,
+                         Where=self.table.WORK_ID.In(
+                            Parameter(&quot;workIDs&quot;, len(workIDs)))
+                        ).on(self.transaction, workIDs=workIDs)
+
</ins><span class="cx">         pushDistributor = self.transaction._pushDistributor
</span><span class="cx">         if pushDistributor is not None:
</span><del>-            yield pushDistributor.enqueue(self.transaction, self.pushID)
</del><ins>+            # Convert the integer priority value back into a constant
+            priority = PushPriority.lookupByValue(maxPriority)
+            yield pushDistributor.enqueue(self.transaction, self.pushID,
+                priority=priority)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -84,13 +108,15 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def notify(self, txn):
</del><ins>+    def notify(self, txn, priority=PushPriority.high):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Send the notification. For a home object we just push using the home id. For a home
</span><span class="cx">         child we push both the owner home id and the owned home child id.
</span><span class="cx"> 
</span><span class="cx">         @param txn: The transaction to create the work item with
</span><span class="cx">         @type txn: L{CommonStoreTransaction}
</span><ins>+        @param priority: the priority level
+        @type priority: L{PushPriority}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         # Push ids from the store objects are a tuple of (prefix, name,) and we need to compose that
</span><span class="cx">         # into a single token.
</span><span class="lines">@@ -102,10 +128,13 @@
</span><span class="cx"> 
</span><span class="cx">         for prefix, id in ids:
</span><span class="cx">             if self._notify:
</span><del>-                self.log.debug(&quot;Notifications are enabled: %s %s/%s&quot; % (self._storeObject, prefix, id,))
-                yield self._notifierFactory.send(prefix, id, txn)
</del><ins>+                self.log.debug(&quot;Notifications are enabled: %s %s/%s priority=%d&quot; %
+                    (self._storeObject, prefix, id, priority.value))
+                yield self._notifierFactory.send(prefix, id, txn,
+                    priority=priority)
</ins><span class="cx">             else:
</span><del>-                self.log.debug(&quot;Skipping notification for: %s %s/%s&quot; % (self._storeObject, prefix, id,))
</del><ins>+                self.log.debug(&quot;Skipping notification for: %s %s/%s&quot; %
+                    (self._storeObject, prefix, id,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def clone(self, storeObject):
</span><span class="lines">@@ -150,12 +179,14 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def send(self, prefix, id, txn):
</del><ins>+    def send(self, prefix, id, txn, priority=PushPriority.high):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Enqueue a push notification work item on the provided transaction.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         notBefore = datetime.datetime.utcnow() + datetime.timedelta(seconds=self.coalesceSeconds)
</span><del>-        yield txn.enqueue(PushNotificationWork, pushID=self.pushKeyForId(prefix, id), notBefore=notBefore)
</del><ins>+        yield txn.enqueue(PushNotificationWork,
+            pushID=self.pushKeyForId(prefix, id), notBefore=notBefore,
+            priority=priority.value)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def newNotifier(self, storeObject):
</span><span class="lines">@@ -212,7 +243,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def enqueue(self, transaction, pushKey):
</del><ins>+    def enqueue(self, transaction, pushKey, priority=PushPriority.high):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Pass along enqueued pushKey to any observers
</span><span class="cx"> 
</span><span class="lines">@@ -221,6 +252,10 @@
</span><span class="cx"> 
</span><span class="cx">         @param pushKey: the push key to distribute to the observers
</span><span class="cx">         @type pushKey: C{str}
</span><ins>+
+        @param priority: the priority level
+        @type priority: L{PushPriority}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         for observer in self.observers:
</span><del>-            yield observer.enqueue(transaction, pushKey)
</del><ins>+            yield observer.enqueue(transaction, pushKey,
+                dataChangedTimestamp=None, priority=priority)
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushtesttest_amppushpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_amppush.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_amppush.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_amppush.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,6 +18,7 @@
</span><span class="cx"> from calendarserver.push.amppush import NotificationForID
</span><span class="cx"> from twistedcaldav.test.util import StoreTestCase
</span><span class="cx"> from twisted.internet.task import Clock
</span><ins>+from calendarserver.push.util import PushPriority
</ins><span class="cx"> 
</span><span class="cx"> class AMPPushMasterTests(StoreTestCase):
</span><span class="cx"> 
</span><span class="lines">@@ -57,27 +58,81 @@
</span><span class="cx">         self.assertTrue(client3.subscribedToID(&quot;/CalDAV/localhost/user03/&quot;))
</span><span class="cx"> 
</span><span class="cx">         dataChangedTimestamp = 1354815999
</span><del>-        service.enqueue(None, &quot;/CalDAV/localhost/user01/&quot;, dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+        service.enqueue(None, &quot;/CalDAV/localhost/user01/&quot;,
+            dataChangedTimestamp=dataChangedTimestamp,
+            priority=PushPriority.high)
</ins><span class="cx">         self.assertEquals(len(client1.history), 0)
</span><span class="cx">         self.assertEquals(len(client2.history), 0)
</span><span class="cx">         self.assertEquals(len(client3.history), 0)
</span><span class="cx">         clock.advance(1)
</span><del>-        self.assertEquals(client1.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp': 1354815999})])
</del><ins>+        self.assertEquals(
+            client1.history,
+            [
+                (
+                    NotificationForID,
+                    {
+                        'id'                   : '/CalDAV/localhost/user01/',
+                        'dataChangedTimestamp' : 1354815999,
+                        'priority'             : PushPriority.high.value,
+                    }
+                )
+            ]
+        )
</ins><span class="cx">         self.assertEquals(len(client2.history), 0)
</span><span class="cx">         self.assertEquals(len(client3.history), 0)
</span><span class="cx">         clock.advance(3)
</span><del>-        self.assertEquals(client2.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp': 1354815999})])
</del><ins>+        self.assertEquals(
+            client2.history,
+            [
+                (
+                    NotificationForID,
+                    {
+                        'id'                   : '/CalDAV/localhost/user01/',
+                        'dataChangedTimestamp' : 1354815999,
+                        'priority'             : PushPriority.high.value,
+                    }
+                )
+            ]
+        )
+
</ins><span class="cx">         self.assertEquals(len(client3.history), 0)
</span><span class="cx">         clock.advance(3)
</span><del>-        self.assertEquals(client3.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp': 1354815999})])
</del><ins>+        self.assertEquals(
+            client3.history,
+            [
+                (
+                    NotificationForID,
+                    {
+                        'id'                   : '/CalDAV/localhost/user01/',
+                        'dataChangedTimestamp' : 1354815999,
+                        'priority'             : PushPriority.high.value,
+                    }
+                )
+            ]
+        )
</ins><span class="cx"> 
</span><span class="cx">         client1.reset()
</span><span class="cx">         client2.reset()
</span><span class="cx">         client2.unsubscribe(&quot;token2&quot;, &quot;/CalDAV/localhost/user01/&quot;)
</span><del>-        service.enqueue(None, &quot;/CalDAV/localhost/user01/&quot;, dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+        service.enqueue(None, &quot;/CalDAV/localhost/user01/&quot;,
+            dataChangedTimestamp=dataChangedTimestamp,
+            priority=PushPriority.low)
</ins><span class="cx">         self.assertEquals(len(client1.history), 0)
</span><span class="cx">         clock.advance(1)
</span><del>-        self.assertEquals(client1.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp' : 1354815999})])
</del><ins>+        self.assertEquals(
+            client1.history,
+            [
+                (
+                    NotificationForID,
+                    {
+                        'id'                   : '/CalDAV/localhost/user01/',
+                        'dataChangedTimestamp' : 1354815999,
+                        'priority'             : PushPriority.low.value,
+                    }
+                )
+            ]
+        )
+
</ins><span class="cx">         self.assertEquals(len(client2.history), 0)
</span><span class="cx">         clock.advance(3)
</span><span class="cx">         self.assertEquals(len(client2.history), 0)
</span><span class="lines">@@ -87,9 +142,35 @@
</span><span class="cx">         client1.reset()
</span><span class="cx">         client2.reset()
</span><span class="cx">         client2.subscribe(&quot;token2&quot;, &quot;/CalDAV/localhost/user01/&quot;)
</span><del>-        service.enqueue(None, &quot;/CalDAV/localhost/user01/&quot;, dataChangedTimestamp=dataChangedTimestamp)
-        self.assertEquals(client1.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp' : 1354815999})])
-        self.assertEquals(client2.history, [(NotificationForID, {'id': '/CalDAV/localhost/user01/', 'dataChangedTimestamp' : 1354815999})])
</del><ins>+        service.enqueue(None, &quot;/CalDAV/localhost/user01/&quot;,
+            dataChangedTimestamp=dataChangedTimestamp,
+            priority=PushPriority.medium)
+        self.assertEquals(
+            client1.history,
+            [
+                (
+                    NotificationForID,
+                    {
+                        'id'                   : '/CalDAV/localhost/user01/',
+                        'dataChangedTimestamp' : 1354815999,
+                        'priority'             : PushPriority.medium.value,
+                    }
+                )
+            ]
+        )
+        self.assertEquals(
+            client2.history,
+            [
+                (
+                    NotificationForID,
+                    {
+                        'id'                   : '/CalDAV/localhost/user01/',
+                        'dataChangedTimestamp' : 1354815999,
+                        'priority'             : PushPriority.medium.value,
+                    }
+                )
+            ]
+        )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushtesttest_applepushpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_applepush.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_applepush.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_applepush.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,14 +18,15 @@
</span><span class="cx"> import struct
</span><span class="cx"> import time
</span><span class="cx"> from calendarserver.push.applepush import (
</span><del>-    ApplePushNotifierService, APNProviderProtocol
</del><ins>+    ApplePushNotifierService, APNProviderProtocol, ApplePushPriority
</ins><span class="cx"> )
</span><del>-from calendarserver.push.util import validToken, TokenHistory
</del><ins>+from calendarserver.push.util import validToken, TokenHistory, PushPriority
</ins><span class="cx"> from twistedcaldav.test.util import StoreTestCase
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, succeed
</span><span class="cx"> from twisted.internet.task import Clock
</span><span class="cx"> from txdav.common.icommondatastore import InvalidSubscriptionValues
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class ApplePushNotifierServiceTests(StoreTestCase):
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -120,12 +121,14 @@
</span><span class="cx">         dataChangedTimestamp = 1354815999
</span><span class="cx">         txn = self._sqlCalendarStore.newTransaction()
</span><span class="cx">         yield service.enqueue(txn, &quot;/CalDAV/calendars.example.com/user01/calendar/&quot;,
</span><del>-            dataChangedTimestamp=dataChangedTimestamp)
</del><ins>+            dataChangedTimestamp=dataChangedTimestamp, priority=PushPriority.high)
</ins><span class="cx">         yield txn.commit()
</span><span class="cx"> 
</span><span class="cx">         # The notifications should be in the queue
</span><del>-        self.assertTrue(((token, key1), dataChangedTimestamp) in service.providers[&quot;CalDAV&quot;].queue)
-        self.assertTrue(((token2, key1), dataChangedTimestamp) in service.providers[&quot;CalDAV&quot;].queue)
</del><ins>+        self.assertTrue(((token, key1), dataChangedTimestamp, PushPriority.high)
+            in service.providers[&quot;CalDAV&quot;].queue)
+        self.assertTrue(((token2, key1), dataChangedTimestamp, PushPriority.high)
+            in service.providers[&quot;CalDAV&quot;].queue)
</ins><span class="cx"> 
</span><span class="cx">         # Start the service, making the connection which should service the
</span><span class="cx">         # queue
</span><span class="lines">@@ -137,17 +140,40 @@
</span><span class="cx">         # Verify data sent to APN
</span><span class="cx">         providerConnector = service.providers[&quot;CalDAV&quot;].testConnector
</span><span class="cx">         rawData = providerConnector.transport.data
</span><del>-        self.assertEquals(len(rawData), 183)
-        data = struct.unpack(&quot;!BIIH32sH&quot;, rawData[:45])
-        self.assertEquals(data[0], 1) # command
-        self.assertEquals(data[4].encode(&quot;hex&quot;), token.replace(&quot; &quot;, &quot;&quot;)) # token
-        payloadLength = data[5]
-        payload = struct.unpack(&quot;%ds&quot; % (payloadLength,),
-            rawData[45:])
</del><ins>+        self.assertEquals(len(rawData), 199)
+        data = struct.unpack(&quot;!BI&quot;, rawData[:5])
+        self.assertEquals(data[0], 2) # command
+        self.assertEquals(data[1], 194) # frame length
+        # Item 1 (device token)
+        data = struct.unpack(&quot;!BH32s&quot;, rawData[5:40])
+        self.assertEquals(data[0], 1)
+        self.assertEquals(data[1], 32)
+        self.assertEquals(data[2].encode(&quot;hex&quot;), token.replace(&quot; &quot;, &quot;&quot;)) # token
+        # Item 2 (payload)
+        data = struct.unpack(&quot;!BH&quot;, rawData[40:43])
+        self.assertEquals(data[0], 2)
+        payloadLength = data[1]
+        self.assertEquals(payloadLength, 138)
+        payload = struct.unpack(&quot;!%ds&quot; % (payloadLength,), rawData[43:181])
</ins><span class="cx">         payload = json.loads(payload[0])
</span><span class="cx">         self.assertEquals(payload[&quot;key&quot;], u&quot;/CalDAV/calendars.example.com/user01/calendar/&quot;)
</span><span class="cx">         self.assertEquals(payload[&quot;dataChangedTimestamp&quot;], dataChangedTimestamp)
</span><span class="cx">         self.assertTrue(&quot;pushRequestSubmittedTimestamp&quot; in payload)
</span><ins>+        # Item 3 (notification id)
+        data = struct.unpack(&quot;!BHI&quot;, rawData[181:188])
+        self.assertEquals(data[0], 3)
+        self.assertEquals(data[1], 4)
+        self.assertEquals(data[2], 2)
+        # Item 4 (expiration)
+        data = struct.unpack(&quot;!BHI&quot;, rawData[188:195])
+        self.assertEquals(data[0], 4)
+        self.assertEquals(data[1], 4)
+        # Item 5 (priority)
+        data = struct.unpack(&quot;!BHB&quot;, rawData[195:199])
+        self.assertEquals(data[0], 5)
+        self.assertEquals(data[1], 1)
+        self.assertEquals(data[2], ApplePushPriority.high.value)
+
</ins><span class="cx">         # Verify token history is updated
</span><span class="cx">         self.assertTrue(token in [t for (_ignore_i, t) in providerConnector.service.protocol.history.history])
</span><span class="cx">         self.assertTrue(token2 in [t for (_ignore_i, t) in providerConnector.service.protocol.history.history])
</span><span class="lines">@@ -160,14 +186,21 @@
</span><span class="cx">         providerConnector.transport.data = None
</span><span class="cx">         # Send notification while service is connected
</span><span class="cx">         txn = self._sqlCalendarStore.newTransaction()
</span><del>-        yield service.enqueue(txn, &quot;/CalDAV/calendars.example.com/user01/calendar/&quot;)
</del><ins>+        yield service.enqueue(txn, &quot;/CalDAV/calendars.example.com/user01/calendar/&quot;,
+            priority=PushPriority.low)
</ins><span class="cx">         yield txn.commit()
</span><span class="cx">         clock.advance(1) # so that first push is sent
</span><del>-        self.assertEquals(len(providerConnector.transport.data), 183)
</del><ins>+        self.assertEquals(len(providerConnector.transport.data), 199)
+        # Ensure that the priority is &quot;low&quot;
+        data = struct.unpack(&quot;!BHB&quot;, providerConnector.transport.data[195:199])
+        self.assertEquals(data[0], 5)
+        self.assertEquals(data[1], 1)
+        self.assertEquals(data[2], ApplePushPriority.low.value)
+
</ins><span class="cx">         # Reset sent data
</span><span class="cx">         providerConnector.transport.data = None
</span><span class="cx">         clock.advance(3) # so that second push is sent
</span><del>-        self.assertEquals(len(providerConnector.transport.data), 183)
</del><ins>+        self.assertEquals(len(providerConnector.transport.data), 199)
</ins><span class="cx"> 
</span><span class="cx">         history = []
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushtesttest_notifierpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_notifier.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_notifier.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/test/test_notifier.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,12 +18,13 @@
</span><span class="cx"> from calendarserver.push.notifier import PushDistributor
</span><span class="cx"> from calendarserver.push.notifier import getPubSubAPSConfiguration
</span><span class="cx"> from calendarserver.push.notifier import PushNotificationWork
</span><del>-from twisted.internet.defer import inlineCallbacks, succeed
</del><ins>+from twisted.internet.defer import inlineCallbacks, succeed, gatherResults
</ins><span class="cx"> from twistedcaldav.config import ConfigDict
</span><span class="cx"> from txdav.common.datastore.test.util import populateCalendarsFrom
</span><span class="cx"> from txdav.common.datastore.sql_tables import _BIND_MODE_WRITE
</span><ins>+from calendarserver.push.util import PushPriority
+from txdav.idav import ChangeCategory
</ins><span class="cx"> 
</span><del>-
</del><span class="cx"> class StubService(object):
</span><span class="cx">     def __init__(self):
</span><span class="cx">         self.reset()
</span><span class="lines">@@ -33,8 +34,9 @@
</span><span class="cx">         self.history = []
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def enqueue(self, transaction, id):
-        self.history.append(id)
</del><ins>+    def enqueue(self, transaction, id, dataChangedTimestamp=None,
+        priority=None):
+        self.history.append((id, priority))
</ins><span class="cx">         return(succeed(None))
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -45,8 +47,8 @@
</span><span class="cx">     def test_enqueue(self):
</span><span class="cx">         stub = StubService()
</span><span class="cx">         dist = PushDistributor([stub])
</span><del>-        yield dist.enqueue(None, &quot;testing&quot;)
-        self.assertEquals(stub.history, [&quot;testing&quot;])
</del><ins>+        yield dist.enqueue(None, &quot;testing&quot;, PushPriority.high)
+        self.assertEquals(stub.history, [(&quot;testing&quot;, PushPriority.high)])
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_getPubSubAPSConfiguration(self):
</span><span class="lines">@@ -91,11 +93,12 @@
</span><span class="cx">         self.history = []
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def enqueue(self, transaction, pushID):
-        self.history.append(pushID)
</del><ins>+    def enqueue(self, transaction, pushID, dataChangedTimestamp=None,
+        priority=None):
+        self.history.append((pushID, priority))
+        return(succeed(None))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> class PushNotificationWorkTests(StoreTestCase):
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -111,35 +114,71 @@
</span><span class="cx">         txn = self._sqlCalendarStore.newTransaction()
</span><span class="cx">         wp = (yield txn.enqueue(PushNotificationWork,
</span><span class="cx">             pushID=&quot;/CalDAV/localhost/foo/&quot;,
</span><ins>+            priority=PushPriority.high.value
</ins><span class="cx">         ))
</span><span class="cx">         yield txn.commit()
</span><span class="cx">         yield wp.whenExecuted()
</span><del>-        self.assertEquals(pushDistributor.history, [&quot;/CalDAV/localhost/foo/&quot;])
</del><ins>+        self.assertEquals(pushDistributor.history,
+            [(&quot;/CalDAV/localhost/foo/&quot;, PushPriority.high)])
</ins><span class="cx"> 
</span><span class="cx">         pushDistributor.reset()
</span><span class="cx">         txn = self._sqlCalendarStore.newTransaction()
</span><del>-        wp = (yield txn.enqueue(PushNotificationWork,
</del><ins>+        proposals = []
+        wp = txn.enqueue(PushNotificationWork,
</ins><span class="cx">             pushID=&quot;/CalDAV/localhost/bar/&quot;,
</span><del>-        ))
-        wp = (yield txn.enqueue(PushNotificationWork,
</del><ins>+            priority=PushPriority.high.value
+        )
+        proposals.append(wp.whenExecuted())
+        wp = txn.enqueue(PushNotificationWork,
</ins><span class="cx">             pushID=&quot;/CalDAV/localhost/bar/&quot;,
</span><del>-        ))
-        wp = (yield txn.enqueue(PushNotificationWork,
</del><ins>+            priority=PushPriority.high.value
+        )
+        proposals.append(wp.whenExecuted())
+        wp = txn.enqueue(PushNotificationWork,
</ins><span class="cx">             pushID=&quot;/CalDAV/localhost/bar/&quot;,
</span><del>-        ))
</del><ins>+            priority=PushPriority.high.value
+        )
+        proposals.append(wp.whenExecuted())
</ins><span class="cx">         # Enqueue a different pushID to ensure those are not grouped with
</span><span class="cx">         # the others:
</span><del>-        wp = (yield txn.enqueue(PushNotificationWork,
</del><ins>+        wp = txn.enqueue(PushNotificationWork,
</ins><span class="cx">             pushID=&quot;/CalDAV/localhost/baz/&quot;,
</span><del>-        ))
</del><ins>+            priority=PushPriority.high.value
+        )
+        proposals.append(wp.whenExecuted())
</ins><span class="cx"> 
</span><span class="cx">         yield txn.commit()
</span><del>-        yield wp.whenExecuted()
</del><ins>+        yield gatherResults(proposals)
+        self.assertEquals(set(pushDistributor.history),
+            set([(&quot;/CalDAV/localhost/bar/&quot;, PushPriority.high),
+             (&quot;/CalDAV/localhost/baz/&quot;, PushPriority.high)]))
+
+        # Ensure only the high-water-mark priority push goes out, by
+        # enqueuing low, medium, and high notifications
+        pushDistributor.reset()
+        txn = self._sqlCalendarStore.newTransaction()
+        proposals = []
+        wp = txn.enqueue(PushNotificationWork,
+            pushID=&quot;/CalDAV/localhost/bar/&quot;,
+            priority=PushPriority.low.value
+        )
+        proposals.append(wp.whenExecuted())
+        wp = txn.enqueue(PushNotificationWork,
+            pushID=&quot;/CalDAV/localhost/bar/&quot;,
+            priority=PushPriority.high.value
+        )
+        proposals.append(wp.whenExecuted())
+        wp = txn.enqueue(PushNotificationWork,
+            pushID=&quot;/CalDAV/localhost/bar/&quot;,
+            priority=PushPriority.medium.value
+        )
+        proposals.append(wp.whenExecuted())
+        yield txn.commit()
+        yield gatherResults(proposals)
</ins><span class="cx">         self.assertEquals(pushDistributor.history,
</span><del>-            [&quot;/CalDAV/localhost/bar/&quot;, &quot;/CalDAV/localhost/baz/&quot;])
</del><ins>+            [(&quot;/CalDAV/localhost/bar/&quot;, PushPriority.high)])
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> class NotifierFactory(StoreTestCase):
</span><span class="cx"> 
</span><span class="cx">     requirements = {
</span><span class="lines">@@ -168,8 +207,9 @@
</span><span class="cx">     def test_homeNotifier(self):
</span><span class="cx"> 
</span><span class="cx">         home = yield self.homeUnderTest()
</span><del>-        yield home.notifyChanged()
-        self.assertEquals(self.notifierFactory.history, [&quot;/CalDAV/example.com/home1/&quot;])
</del><ins>+        yield home.notifyChanged(category=ChangeCategory.default)
+        self.assertEquals(self.notifierFactory.history,
+            [(&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high)])
</ins><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -177,10 +217,12 @@
</span><span class="cx">     def test_calendarNotifier(self):
</span><span class="cx"> 
</span><span class="cx">         calendar = yield self.calendarUnderTest()
</span><del>-        yield calendar.notifyChanged()
</del><ins>+        yield calendar.notifyChanged(category=ChangeCategory.default)
</ins><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><del>-            set([&quot;/CalDAV/example.com/home1/&quot;, &quot;/CalDAV/example.com/home1/calendar_1/&quot;])
</del><ins>+            set([
+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/calendar_1/&quot;, PushPriority.high)])
</ins><span class="cx">         )
</span><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="lines">@@ -194,9 +236,9 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CalDAV/example.com/home1/&quot;,
-                &quot;/CalDAV/example.com/home1/calendar_1/&quot;,
-                &quot;/CalDAV/example.com/home2/&quot;
</del><ins>+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/calendar_1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home2/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx">         yield self.commit()
</span><span class="lines">@@ -207,9 +249,9 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CalDAV/example.com/home1/&quot;,
-                &quot;/CalDAV/example.com/home1/calendar_1/&quot;,
-                &quot;/CalDAV/example.com/home2/&quot;
</del><ins>+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/calendar_1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home2/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx">         yield self.commit()
</span><span class="lines">@@ -225,10 +267,12 @@
</span><span class="cx">         self.notifierFactory.reset()
</span><span class="cx"> 
</span><span class="cx">         shared = yield self.calendarUnderTest(home=&quot;home2&quot;, name=shareName)
</span><del>-        yield shared.notifyChanged()
</del><ins>+        yield shared.notifyChanged(category=ChangeCategory.default)
</ins><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><del>-            set([&quot;/CalDAV/example.com/home1/&quot;, &quot;/CalDAV/example.com/home1/calendar_1/&quot;])
</del><ins>+            set([
+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/calendar_1/&quot;, PushPriority.high)])
</ins><span class="cx">         )
</span><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="lines">@@ -237,9 +281,11 @@
</span><span class="cx">     def test_notificationNotifier(self):
</span><span class="cx"> 
</span><span class="cx">         notifications = yield self.transactionUnderTest().notificationsWithUID(&quot;home1&quot;)
</span><del>-        yield notifications.notifyChanged()
</del><ins>+        yield notifications.notifyChanged(category=ChangeCategory.default)
</ins><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><del>-            set([&quot;/CalDAV/example.com/home1/&quot;, &quot;/CalDAV/example.com/home1/notification/&quot;])
</del><ins>+            set([
+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/notification/&quot;, PushPriority.high)])
</ins><span class="cx">         )
</span><span class="cx">         yield self.commit()
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarserverpushutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/util.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/util.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/push/util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,7 +16,20 @@
</span><span class="cx"> 
</span><span class="cx"> from OpenSSL import crypto
</span><span class="cx"> from twext.python.log import Logger
</span><ins>+from twisted.python.constants import Values, ValueConstant
</ins><span class="cx"> 
</span><ins>+
+
+class PushPriority(Values):
+    &quot;&quot;&quot;
+    Constants to use for push priorities
+    &quot;&quot;&quot;
+    low    = ValueConstant(1)
+    medium = ValueConstant(5)
+    high   = ValueConstant(10)
+
+
+
</ins><span class="cx"> def getAPNTopicFromCertificate(certPath):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Given the path to a certificate, extract the UID value portion of the
</span><span class="lines">@@ -128,7 +141,7 @@
</span><span class="cx">         self.staggerSeconds = staggerSeconds
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def schedule(self, tokens, key, dataChangedTimestamp):
</del><ins>+    def schedule(self, tokens, key, dataChangedTimestamp, priority):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Schedules a batch of notifications for the given tokens, staggered
</span><span class="cx">         with self.staggerSeconds between each one.  Duplicates are ignored,
</span><span class="lines">@@ -151,13 +164,14 @@
</span><span class="cx">                     (internalKey,))
</span><span class="cx">             else:
</span><span class="cx">                 self.outstanding[internalKey] = self.reactor.callLater(
</span><del>-                    scheduleTime, self.send, token, key, dataChangedTimestamp)
</del><ins>+                    scheduleTime, self.send, token, key, dataChangedTimestamp,
+                    priority)
</ins><span class="cx">                 self.log.debug(&quot;PushScheduler scheduled: %s in %.0f sec&quot; %
</span><span class="cx">                     (internalKey, scheduleTime))
</span><span class="cx">                 scheduleTime += self.staggerSeconds
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def send(self, token, key, dataChangedTimestamp):
</del><ins>+    def send(self, token, key, dataChangedTimestamp, priority):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         This method is what actually gets scheduled.  Its job is to remove
</span><span class="cx">         its corresponding entry from the outstanding dict and call the
</span><span class="lines">@@ -173,7 +187,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         self.log.debug(&quot;PushScheduler fired for %s %s %d&quot; % (token, key, dataChangedTimestamp))
</span><span class="cx">         del self.outstanding[(token, key)]
</span><del>-        return self.callback(token, key, dataChangedTimestamp)
</del><ins>+        return self.callback(token, key, dataChangedTimestamp, priority)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def stop(self):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertapcaldavpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tap/caldav.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tap/caldav.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tap/caldav.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -401,6 +401,14 @@
</span><span class="cx">         print(&quot;Reading configuration from file: %s&quot; % (self[&quot;config&quot;],))
</span><span class="cx"> 
</span><span class="cx">         config.load(self[&quot;config&quot;])
</span><ins>+
+        for path in config.getProvider().importedFiles:
+            print(&quot;Imported configuration from file: '%s'&quot; % (path,))
+        for path in config.getProvider().includedFiles:
+            print(&quot;Adding configuration from file: '%s'&quot; % (path,))
+        for path in config.getProvider().missingFiles:
+            print(&quot;Missing configuration file: '%s'&quot; % (path,))
+
</ins><span class="cx">         config.updateDefaults(self.overrides)
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertaputilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tap/util.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tap/util.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tap/util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -636,11 +636,23 @@
</span><span class="cx">             addSystemEventTrigger(&quot;after&quot;, &quot;startup&quot;, timezoneStdService.onStartup)
</span><span class="cx"> 
</span><span class="cx">     #
</span><del>-    # iSchedule service
</del><ins>+    # iSchedule service for podding
</ins><span class="cx">     #
</span><ins>+    if config.Servers.Enabled:
+        log.info(&quot;Setting up iSchedule podding inbox resource: {cls}&quot;, cls=iScheduleResourceClass)
+
+        ischedule = iScheduleResourceClass(
+            root,
+            newStore,
+            podding=True
+        )
+        root.putChild(config.Servers.InboxName, ischedule)
+
+    #
+    # iSchedule service (not used for podding)
+    #
</ins><span class="cx">     if config.Scheduling.iSchedule.Enabled:
</span><del>-        log.info(&quot;Setting up iSchedule inbox resource: {cls}&quot;,
-                      cls=iScheduleResourceClass)
</del><ins>+        log.info(&quot;Setting up iSchedule inbox resource: {cls}&quot;, cls=iScheduleResourceClass)
</ins><span class="cx"> 
</span><span class="cx">         ischedule = iScheduleResourceClass(
</span><span class="cx">             root,
</span><span class="lines">@@ -651,8 +663,7 @@
</span><span class="cx">         # Do DomainKey resources
</span><span class="cx">         DKIMUtils.validConfiguration(config)
</span><span class="cx">         if config.Scheduling.iSchedule.DKIM.Enabled:
</span><del>-            log.info(&quot;Setting up domainkey resource: {res}&quot;,
-                res=DomainKeyResource)
</del><ins>+            log.info(&quot;Setting up domainkey resource: {res}&quot;, res=DomainKeyResource)
</ins><span class="cx">             domain = config.Scheduling.iSchedule.DKIM.Domain if config.Scheduling.iSchedule.DKIM.Domain else config.ServerHostName
</span><span class="cx">             dk = DomainKeyResource(
</span><span class="cx">                 domain,
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsampnotificationspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/ampnotifications.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/ampnotifications.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/ampnotifications.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -141,8 +141,8 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-def notificationCallback(id, dataChangedTimestamp):
-    print(&quot;Received notification for:&quot;, id)
</del><ins>+def notificationCallback(id, dataChangedTimestamp, priority):
+    print(&quot;Received notification for:&quot;, id, &quot;Priority&quot;, priority)
</ins><span class="cx">     return succeed(True)
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsanonymizepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/anonymize.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/anonymize.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/anonymize.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -33,8 +33,8 @@
</span><span class="cx"> 
</span><span class="cx"> from twext.python.plistlib import readPlistFromString
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.attribute import PyCalendarAttribute
</del><ins>+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.parameter import Parameter
</ins><span class="cx"> 
</span><span class="cx"> COPY_CAL_XATTRS = (
</span><span class="cx">     'WebDAV:{DAV:}resourcetype',
</span><span class="lines">@@ -67,6 +67,8 @@
</span><span class="cx">     else:
</span><span class="cx">         sys.exit(0)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def main():
</span><span class="cx"> 
</span><span class="cx">     try:
</span><span class="lines">@@ -83,8 +85,6 @@
</span><span class="cx">     # Get configuration
</span><span class="cx">     #
</span><span class="cx">     directoryNode = &quot;/Search&quot;
</span><del>-    sourceDirectory = None
-    destDirectory = None
</del><span class="cx"> 
</span><span class="cx">     for opt, arg in optargs:
</span><span class="cx">         if opt in (&quot;-h&quot;, &quot;--help&quot;):
</span><span class="lines">@@ -107,6 +107,7 @@
</span><span class="cx">     directoryMap.dumpDsImports(os.path.join(destDirectory, &quot;dsimports&quot;))
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def anonymizeRoot(directoryMap, sourceDirectory, destDirectory):
</span><span class="cx">     # sourceDirectory and destDirectory are DocumentRoots
</span><span class="cx"> 
</span><span class="lines">@@ -244,12 +245,10 @@
</span><span class="cx"> 
</span><span class="cx">                     resources += 1
</span><span class="cx"> 
</span><del>-
</del><span class="cx">                 # Store new ctag on calendar
</span><span class="cx">                 xml = &quot;&lt;?xml version='1.0' encoding='UTF-8'?&gt;\r\n&lt;getctag xmlns='http://calendarserver.org/ns/'&gt;%s&lt;/getctag&gt;\r\n&quot; % (str(datetime.datetime.now()),)
</span><span class="cx">                 xattr.setxattr(destCal, &quot;WebDAV:{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag&quot;, zlib.compress(xml))
</span><span class="cx"> 
</span><del>-
</del><span class="cx">             # Calendar home quota
</span><span class="cx">             xml = &quot;&lt;?xml version='1.0' encoding='UTF-8'?&gt;\r\n&lt;quota-used xmlns='http://twistedmatrix.com/xml_namespace/dav/private/'&gt;%d&lt;/quota-used&gt;\r\n&quot; % (quotaUsed,)
</span><span class="cx">             xattr.setxattr(destHome, &quot;WebDAV:{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2Fprivate%2F}quota-used&quot;, zlib.compress(xml))
</span><span class="lines">@@ -280,9 +279,10 @@
</span><span class="cx">     print(&quot;&quot;)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def anonymizeData(directoryMap, data):
</span><span class="cx">     try:
</span><del>-        pyobj = PyCalendar.parseText(data)
</del><ins>+        pyobj = Calendar.parseText(data)
</ins><span class="cx">     except Exception, e:
</span><span class="cx">         print(&quot;Failed to parse (%s): %s&quot; % (e, data))
</span><span class="cx">         return None
</span><span class="lines">@@ -309,13 +309,13 @@
</span><span class="cx">                             comp.removeProperty(prop)
</span><span class="cx">                             continue
</span><span class="cx">                     prop.setValue(&quot;urn:uuid:%s&quot; % (record['guid'],))
</span><del>-                    if prop.hasAttribute('X-CALENDARSERVER-EMAIL'):
-                        prop.replaceAttribute(PyCalendarAttribute('X-CALENDARSERVER-EMAIL', record['email']))
</del><ins>+                    if prop.hasParameter('X-CALENDARSERVER-EMAIL'):
+                        prop.replaceParameter(Parameter('X-CALENDARSERVER-EMAIL', record['email']))
</ins><span class="cx">                     else:
</span><del>-                        prop.removeAttributes('EMAIL')
-                        prop.addAttribute(PyCalendarAttribute('EMAIL', record['email']))
-                    prop.removeAttributes('CN')
-                    prop.addAttribute(PyCalendarAttribute('CN', record['name']))
</del><ins>+                        prop.removeParameters('EMAIL')
+                        prop.addParameter(Parameter('EMAIL', record['email']))
+                    prop.removeParameters('CN')
+                    prop.addParameter(Parameter('CN', record['name']))
</ins><span class="cx">             except KeyError:
</span><span class="cx">                 pass
</span><span class="cx"> 
</span><span class="lines">@@ -345,11 +345,12 @@
</span><span class="cx">     return pyobj.getText(includeTimezones=True)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class DirectoryMap(object):
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, node):
</span><span class="cx"> 
</span><del>-        self.map = { }
</del><ins>+        self.map = {}
</ins><span class="cx">         self.byType = {
</span><span class="cx">             'users' : [],
</span><span class="cx">             'groups' : [],
</span><span class="lines">@@ -373,10 +374,10 @@
</span><span class="cx"> 
</span><span class="cx">         print(&quot;Fetching records from directory: %s&quot; % (node,))
</span><span class="cx"> 
</span><del>-        for internalType, (recordType, friendlyType) in self.strings.iteritems():
</del><ins>+        for internalType, (recordType, _ignore_friendlyType) in self.strings.iteritems():
</ins><span class="cx">             print(&quot; %s...&quot; % (internalType,))
</span><span class="cx">             child = Popen(
</span><del>-                args = [
</del><ins>+                args=[
</ins><span class="cx">                     &quot;/usr/bin/dscl&quot;, &quot;-plist&quot;, node, &quot;-readall&quot;,
</span><span class="cx">                     &quot;/%s&quot; % (recordType,),
</span><span class="cx">                     &quot;GeneratedUID&quot;, &quot;RecordName&quot;, &quot;EMailAddress&quot;, &quot;GroupMembers&quot;
</span><span class="lines">@@ -405,6 +406,7 @@
</span><span class="cx">         print(&quot;Done.&quot;)
</span><span class="cx">         print(&quot;&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def addRecord(self, internalType=&quot;users&quot;, guid=None, names=None,
</span><span class="cx">         emails=None, members=None, cua=None):
</span><span class="cx"> 
</span><span class="lines">@@ -458,6 +460,7 @@
</span><span class="cx">                 keys.append(email)
</span><span class="cx">         return keys
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def cua2key(self, cua):
</span><span class="cx">         key = cua.lower()
</span><span class="cx"> 
</span><span class="lines">@@ -473,10 +476,11 @@
</span><span class="cx"> 
</span><span class="cx">         return key
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def lookupCUA(self, cua):
</span><span class="cx">         key = self.cua2key(cua)
</span><span class="cx"> 
</span><del>-        if key and self.map.has_key(key):
</del><ins>+        if key and key in self.map:
</ins><span class="cx">             return self.map[key]
</span><span class="cx">         else:
</span><span class="cx">             return None
</span><span class="lines">@@ -491,6 +495,7 @@
</span><span class="cx">         if unknown:
</span><span class="cx">             print(&quot; Principals not found in directory: %d&quot; % (unknown,))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def dumpDsImports(self, dirPath):
</span><span class="cx">         if not os.path.exists(dirPath):
</span><span class="cx">             os.makedirs(dirPath)
</span><span class="lines">@@ -567,6 +572,8 @@
</span><span class="cx">     Error trying to access dscl
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class DatabaseError(Exception):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Error trying to access sqlite3
</span><span class="lines">@@ -574,8 +581,6 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
-
</del><span class="cx"> def anonymize(text):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Return a string whose value is the hex digest of text, repeated as needed
</span><span class="lines">@@ -592,19 +597,18 @@
</span><span class="cx">     h = hashlib.md5(text)
</span><span class="cx">     h = h.hexdigest()
</span><span class="cx">     l = len(text)
</span><del>-    return (h*((l/32)+1))[:-(32-(l%32))]
</del><ins>+    return (h * ((l / 32) + 1))[:-(32 - (l % 32))]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> nameChars = &quot;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;
</span><span class="cx"> def randomName(length):
</span><span class="cx">     l = []
</span><del>-    for i in xrange(length):
</del><ins>+    for _ignore in xrange(length):
</ins><span class="cx">         l.append(random.choice(nameChars))
</span><span class="cx">     return &quot;&quot;.join(l)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> if __name__ == &quot;__main__&quot;:
</span><span class="cx">     main()
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolscalverifypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/calverify.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/calverify.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/calverify.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -47,12 +47,12 @@
</span><span class="cx"> import traceback
</span><span class="cx"> import uuid
</span><span class="cx"> 
</span><del>-from pycalendar import definitions
-from pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.exceptions import PyCalendarError
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.icalendar import definitions
+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.datetime import DateTime
+from pycalendar.exceptions import ErrorBase
+from pycalendar.period import Period
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twisted.application.service import Service
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, returnValue
</span><span class="lines">@@ -543,7 +543,7 @@
</span><span class="cx">         tr = schema.TIME_RANGE
</span><span class="cx">         kwds = {
</span><span class="cx">             &quot;Start&quot; : pyCalendarTodatetime(start),
</span><del>-            &quot;Max&quot;   : pyCalendarTodatetime(PyCalendarDateTime(1900, 1, 1, 0, 0, 0))
</del><ins>+            &quot;Max&quot;   : pyCalendarTodatetime(DateTime(1900, 1, 1, 0, 0, 0))
</ins><span class="cx">         }
</span><span class="cx">         rows = (yield Select(
</span><span class="cx">             [ch.OWNER_UID, co.RESOURCE_ID, co.ICALENDAR_UID, cb.CALENDAR_RESOURCE_NAME, co.MD5, co.ORGANIZER, co.CREATED, co.MODIFIED],
</span><span class="lines">@@ -596,7 +596,7 @@
</span><span class="cx">         tr = schema.TIME_RANGE
</span><span class="cx">         kwds = {
</span><span class="cx">             &quot;Start&quot; : pyCalendarTodatetime(start),
</span><del>-            &quot;Max&quot;   : pyCalendarTodatetime(PyCalendarDateTime(1900, 1, 1, 0, 0, 0)),
</del><ins>+            &quot;Max&quot;   : pyCalendarTodatetime(DateTime(1900, 1, 1, 0, 0, 0)),
</ins><span class="cx">             &quot;UUID&quot; : uuid,
</span><span class="cx">         }
</span><span class="cx">         rows = (yield Select(
</span><span class="lines">@@ -626,7 +626,7 @@
</span><span class="cx"> 
</span><span class="cx">         kwds = {
</span><span class="cx">             &quot;Start&quot; : pyCalendarTodatetime(start),
</span><del>-            &quot;Max&quot;   : pyCalendarTodatetime(PyCalendarDateTime(1900, 1, 1, 0, 0, 0)),
</del><ins>+            &quot;Max&quot;   : pyCalendarTodatetime(DateTime(1900, 1, 1, 0, 0, 0)),
</ins><span class="cx">             &quot;UUID&quot; : uuid,
</span><span class="cx">         }
</span><span class="cx">         rows = (yield Select(
</span><span class="lines">@@ -704,8 +704,8 @@
</span><span class="cx">             ),
</span><span class="cx">         ).on(self.txn, **kwds))
</span><span class="cx">         try:
</span><del>-            caldata = PyCalendar.parseText(rows[0][0]) if rows else None
-        except PyCalendarError:
</del><ins>+            caldata = Calendar.parseText(rows[0][0]) if rows else None
+        except ErrorBase:
</ins><span class="cx">             caltxt = rows[0][0] if rows else None
</span><span class="cx">             if caltxt:
</span><span class="cx">                 caltxt = caltxt.replace(&quot;\r\n &quot;, &quot;&quot;)
</span><span class="lines">@@ -713,8 +713,8 @@
</span><span class="cx">                     if doFix:
</span><span class="cx">                         caltxt = (yield self.fixBadOldCua(resid, caltxt))
</span><span class="cx">                         try:
</span><del>-                            caldata = PyCalendar.parseText(caltxt) if rows else None
-                        except PyCalendarError:
</del><ins>+                            caldata = Calendar.parseText(caltxt) if rows else None
+                        except ErrorBase:
</ins><span class="cx">                             self.parseError = &quot;No fix bad CALENDARSERVER-OLD-CUA&quot;
</span><span class="cx">                             returnValue(None)
</span><span class="cx">                     else:
</span><span class="lines">@@ -746,8 +746,8 @@
</span><span class="cx">         ).on(self.txn, **kwds))
</span><span class="cx"> 
</span><span class="cx">         try:
</span><del>-            caldata = PyCalendar.parseText(rows[0][0]) if rows else None
-        except PyCalendarError:
</del><ins>+            caldata = Calendar.parseText(rows[0][0]) if rows else None
+        except ErrorBase:
</ins><span class="cx">             returnValue((None, None, None, None,))
</span><span class="cx"> 
</span><span class="cx">         returnValue((caldata, rows[0][1], rows[0][2], rows[0][3],) if rows else (None, None, None, None,))
</span><span class="lines">@@ -1056,14 +1056,14 @@
</span><span class="cx"> 
</span><span class="cx">         self.output.write(&quot;\n---- Scanning calendar data ----\n&quot;)
</span><span class="cx"> 
</span><del>-        self.now = PyCalendarDateTime.getNowUTC()
-        self.start = PyCalendarDateTime.getToday()
</del><ins>+        self.now = DateTime.getNowUTC()
+        self.start = DateTime.getToday()
</ins><span class="cx">         self.start.setDateOnly(False)
</span><span class="cx">         self.end = self.start.duplicate()
</span><span class="cx">         self.end.offsetYear(1)
</span><span class="cx">         self.fix = self.options[&quot;fix&quot;]
</span><span class="cx"> 
</span><del>-        self.tzid = PyCalendarTimezone(tzid=self.options[&quot;tzid&quot;] if self.options[&quot;tzid&quot;] else &quot;America/Los_Angeles&quot;)
</del><ins>+        self.tzid = Timezone(tzid=self.options[&quot;tzid&quot;] if self.options[&quot;tzid&quot;] else &quot;America/Los_Angeles&quot;)
</ins><span class="cx"> 
</span><span class="cx">         self.txn = self.store.newTransaction()
</span><span class="cx"> 
</span><span class="lines">@@ -1426,14 +1426,14 @@
</span><span class="cx"> 
</span><span class="cx">         self.output.write(&quot;\n---- Scanning calendar data ----\n&quot;)
</span><span class="cx"> 
</span><del>-        self.now = PyCalendarDateTime.getNowUTC()
-        self.start = self.options[&quot;start&quot;] if &quot;start&quot; in self.options else PyCalendarDateTime.getToday()
</del><ins>+        self.now = DateTime.getNowUTC()
+        self.start = self.options[&quot;start&quot;] if &quot;start&quot; in self.options else DateTime.getToday()
</ins><span class="cx">         self.start.setDateOnly(False)
</span><span class="cx">         self.end = self.start.duplicate()
</span><span class="cx">         self.end.offsetYear(1)
</span><span class="cx">         self.fix = self.options[&quot;fix&quot;]
</span><span class="cx"> 
</span><del>-        self.tzid = PyCalendarTimezone(tzid=self.options[&quot;tzid&quot;] if self.options[&quot;tzid&quot;] else &quot;America/Los_Angeles&quot;)
</del><ins>+        self.tzid = Timezone(tzid=self.options[&quot;tzid&quot;] if self.options[&quot;tzid&quot;] else &quot;America/Los_Angeles&quot;)
</ins><span class="cx"> 
</span><span class="cx">         self.txn = self.store.newTransaction()
</span><span class="cx"> 
</span><span class="lines">@@ -2028,7 +2028,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Return the master iCal component in this calendar.
</span><span class="cx"> 
</span><del>-        @return: the L{PyCalendarComponent} for the master component,
</del><ins>+        @return: the L{Component} for the master component,
</ins><span class="cx">             or C{None} if there isn't one.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         for component in calendar.getComponents(definitions.cICalComponent_VEVENT):
</span><span class="lines">@@ -2042,7 +2042,7 @@
</span><span class="cx">         # Expand events into instances in the start/end range
</span><span class="cx">         results = []
</span><span class="cx">         calendar.getVEvents(
</span><del>-            PyCalendarPeriod(
</del><ins>+            Period(
</ins><span class="cx">                 start=start,
</span><span class="cx">                 end=end,
</span><span class="cx">             ),
</span><span class="lines">@@ -2082,10 +2082,10 @@
</span><span class="cx">                 if cancelled:
</span><span class="cx">                     partstat = &quot;CANCELLED&quot;
</span><span class="cx">                 else:
</span><del>-                    if not prop.hasAttribute(definitions.cICalAttribute_PARTSTAT):
-                        partstat = definitions.cICalAttribute_PARTSTAT_NEEDSACTION
</del><ins>+                    if not prop.hasParameter(definitions.cICalParameter_PARTSTAT):
+                        partstat = definitions.cICalParameter_PARTSTAT_NEEDSACTION
</ins><span class="cx">                     else:
</span><del>-                        partstat = prop.getAttributeValue(definitions.cICalAttribute_PARTSTAT)
</del><ins>+                        partstat = prop.getParameterValue(definitions.cICalParameter_PARTSTAT)
</ins><span class="cx"> 
</span><span class="cx">                 attendees.setdefault(caladdr, set()).add((instance_id, partstat))
</span><span class="cx"> 
</span><span class="lines">@@ -2140,9 +2140,9 @@
</span><span class="cx"> 
</span><span class="cx">         self.output.write(&quot;\n---- Scanning calendar data ----\n&quot;)
</span><span class="cx"> 
</span><del>-        self.tzid = PyCalendarTimezone(tzid=self.options[&quot;tzid&quot;] if self.options[&quot;tzid&quot;] else &quot;America/Los_Angeles&quot;)
-        self.now = PyCalendarDateTime.getNowUTC()
-        self.start = PyCalendarDateTime.getToday()
</del><ins>+        self.tzid = Timezone(tzid=self.options[&quot;tzid&quot;] if self.options[&quot;tzid&quot;] else &quot;America/Los_Angeles&quot;)
+        self.now = DateTime.getNowUTC()
+        self.start = DateTime.getToday()
</ins><span class="cx">         self.start.setDateOnly(False)
</span><span class="cx">         self.start.setTimezone(self.tzid)
</span><span class="cx">         self.end = self.start.duplicate()
</span><span class="lines">@@ -2328,7 +2328,7 @@
</span><span class="cx">                     continue
</span><span class="cx">                 dtstart = instance.component.propertyValue(&quot;DTSTART&quot;)
</span><span class="cx">                 if tzid is None and dtstart.getTimezoneID():
</span><del>-                    tzid = PyCalendarTimezone(tzid=dtstart.getTimezoneID())
</del><ins>+                    tzid = Timezone(tzid=dtstart.getTimezoneID())
</ins><span class="cx">                 hasFloating |= dtstart.isDateOnly() or dtstart.floating()
</span><span class="cx"> 
</span><span class="cx">                 details.append(InstanceDetails(resid, uid, instance.start, instance.end, instance.component.getOrganizer(), instance.component.propertyValue(&quot;SUMMARY&quot;)))
</span><span class="lines">@@ -2369,7 +2369,7 @@
</span><span class="cx"> 
</span><span class="cx">         # Adjust floating and sort
</span><span class="cx">         if hasFloating and tzid is not None:
</span><del>-            utc = PyCalendarTimezone(utc=True)
</del><ins>+            utc = Timezone(utc=True)
</ins><span class="cx">             for item in details:
</span><span class="cx">                 if item.start.floating():
</span><span class="cx">                     item.start.setTimezone(tzid)
</span><span class="lines">@@ -2449,9 +2449,9 @@
</span><span class="cx"> 
</span><span class="cx">         self.output.write(&quot;\n---- Scanning calendar data ----\n&quot;)
</span><span class="cx"> 
</span><del>-        self.tzid = PyCalendarTimezone(tzid=self.options[&quot;tzid&quot;] if self.options[&quot;tzid&quot;] else &quot;America/Los_Angeles&quot;)
-        self.now = PyCalendarDateTime.getNowUTC()
-        self.start = self.options[&quot;start&quot;] if &quot;start&quot; in self.options else PyCalendarDateTime.getToday()
</del><ins>+        self.tzid = Timezone(tzid=self.options[&quot;tzid&quot;] if self.options[&quot;tzid&quot;] else &quot;America/Los_Angeles&quot;)
+        self.now = DateTime.getNowUTC()
+        self.start = self.options[&quot;start&quot;] if &quot;start&quot; in self.options else DateTime.getToday()
</ins><span class="cx">         self.start.setDateOnly(False)
</span><span class="cx">         self.start.setTimezone(self.tzid)
</span><span class="cx">         self.fix = self.options[&quot;fix&quot;]
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsdbinspectpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/dbinspect.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/dbinspect.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/dbinspect.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -24,7 +24,7 @@
</span><span class="cx"> 
</span><span class="cx"> from calendarserver.tools import tables
</span><span class="cx"> from calendarserver.tools.cmdline import utilityMain
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> from twext.enterprise.dal.syntax import Select, Parameter, Count, Delete, \
</span><span class="cx">     Constant
</span><span class="cx"> from twisted.application.service import Service
</span><span class="lines">@@ -715,12 +715,12 @@
</span><span class="cx">             end += &quot;T000000Z&quot;
</span><span class="cx"> 
</span><span class="cx">         try:
</span><del>-            start = PyCalendarDateTime.parseText(start)
</del><ins>+            start = DateTime.parseText(start)
</ins><span class="cx">         except ValueError:
</span><span class="cx">             print(&quot;Invalid start value&quot;)
</span><span class="cx">             returnValue(None)
</span><span class="cx">         try:
</span><del>-            end = PyCalendarDateTime.parseText(end)
</del><ins>+            end = DateTime.parseText(end)
</ins><span class="cx">         except ValueError:
</span><span class="cx">             print(&quot;Invalid end value&quot;)
</span><span class="cx">             returnValue(None)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsgatewaypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/gateway.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/gateway.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/gateway.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -36,9 +36,9 @@
</span><span class="cx"> from calendarserver.tools.purge import WorkerService, PurgeOldEventsService, DEFAULT_BATCH_SIZE, DEFAULT_RETAIN_DAYS
</span><span class="cx"> from calendarserver.tools.cmdline import utilityMain
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><del>-from twistedcaldav.config import config, ConfigDict 
</del><ins>+from twistedcaldav.config import config, ConfigDict
</ins><span class="cx"> 
</span><span class="cx"> from calendarserver.tools.config import WRITABLE_CONFIG_KEYS, setKeyPath, getKeyPath, flattenDictionary, WritableConfig
</span><span class="cx"> 
</span><span class="lines">@@ -156,6 +156,7 @@
</span><span class="cx">     'ZIP' : { 'extras' : True, 'attr' : 'zip', },
</span><span class="cx">     'Country' : { 'extras' : True, 'attr' : 'country', },
</span><span class="cx">     'Phone' : { 'extras' : True, 'attr' : 'phone', },
</span><ins>+    'Geo' : { 'extras' : True, 'attr' : 'geo', },
</ins><span class="cx">     'AutoSchedule' : { 'attr' : 'autoSchedule', },
</span><span class="cx">     'AutoAcceptGroup' : { 'attr' : 'autoAcceptGroup', },
</span><span class="cx"> }
</span><span class="lines">@@ -373,7 +374,7 @@
</span><span class="cx">             return
</span><span class="cx">         self.respondWithRecordsOfTypes(self.dir, command, [&quot;resources&quot;])
</span><span class="cx"> 
</span><del>-        
</del><ins>+
</ins><span class="cx">     def command_getLocationAndResourceList(self, command):
</span><span class="cx">         self.respondWithRecordsOfTypes(self.dir, command, [&quot;locations&quot;, &quot;resources&quot;])
</span><span class="cx"> 
</span><span class="lines">@@ -424,10 +425,8 @@
</span><span class="cx">             self.command_readConfig(command)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     # Proxies
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     @inlineCallbacks
</span><span class="cx">     def command_listWriteProxies(self, command):
</span><span class="cx">         principal = principalForPrincipalID(command['Principal'], directory=self.dir)
</span><span class="lines">@@ -538,14 +537,13 @@
</span><span class="cx">         @type command: C{dict}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         retainDays = command.get(&quot;RetainDays&quot;, DEFAULT_RETAIN_DAYS)
</span><del>-        cutoff = PyCalendarDateTime.getToday()
</del><ins>+        cutoff = DateTime.getToday()
</ins><span class="cx">         cutoff.setDateOnly(False)
</span><span class="cx">         cutoff.offsetDay(-retainDays)
</span><span class="cx">         eventCount = (yield PurgeOldEventsService.purgeOldEvents(self.store, cutoff, DEFAULT_BATCH_SIZE))
</span><span class="cx">         self.respond(command, {'EventsRemoved' : eventCount, &quot;RetainDays&quot; : retainDays})
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     @inlineCallbacks
</span><span class="cx">     def respondWithProxies(self, directory, command, principal, proxyType):
</span><span class="cx">         proxies = []
</span><span class="lines">@@ -562,7 +560,6 @@
</span><span class="cx">         })
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     def respondWithRecordsOfTypes(self, directory, command, recordTypes):
</span><span class="cx">         result = []
</span><span class="cx">         for recordType in recordTypes:
</span><span class="lines">@@ -572,7 +569,6 @@
</span><span class="cx">         self.respond(command, result)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     def respond(self, command, result):
</span><span class="cx">         self.output.write(writePlistToString({'command' : command['command'], 'result' : result}))
</span><span class="cx"> 
</span><span class="lines">@@ -581,6 +577,7 @@
</span><span class="cx">         self.output.write(writePlistToString({'error' : msg, }))
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def recordToDict(record):
</span><span class="cx">     recordDict = {}
</span><span class="cx">     for key, info in attrMap.iteritems():
</span><span class="lines">@@ -596,6 +593,8 @@
</span><span class="cx">             pass
</span><span class="cx">     return recordDict
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def respondWithError(msg, status=1):
</span><span class="cx">     sys.stdout.write(writePlistToString({'error' : msg, }))
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsmanagetimezonespy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/managetimezones.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/managetimezones.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/managetimezones.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,8 +16,8 @@
</span><span class="cx"> ##
</span><span class="cx"> from __future__ import print_function
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> from twext.python.log import StandardIOObserver
</span><span class="lines">@@ -95,11 +95,11 @@
</span><span class="cx">         pass
</span><span class="cx"> 
</span><span class="cx">     if not tzvers:
</span><del>-        tzvers = PyCalendarDateTime.getToday().getText()
</del><ins>+        tzvers = DateTime.getToday().getText()
</ins><span class="cx">     print(&quot;Converting data (version: %s) at: %s&quot; % (tzvers, zonedir,))
</span><span class="cx">     startYear = 1800
</span><del>-    endYear = PyCalendarDateTime.getToday().getYear() + 10
-    PyCalendar.sProdID = &quot;-//calendarserver.org//Zonal//EN&quot;
</del><ins>+    endYear = DateTime.getToday().getYear() + 10
+    Calendar.sProdID = &quot;-//calendarserver.org//Zonal//EN&quot;
</ins><span class="cx">     zonefiles = &quot;northamerica&quot;, &quot;southamerica&quot;, &quot;europe&quot;, &quot;africa&quot;, &quot;asia&quot;, &quot;australasia&quot;, &quot;antarctica&quot;, &quot;etcetera&quot;, &quot;backward&quot;
</span><span class="cx">     parser = tzconvert()
</span><span class="cx">     for file in zonefiles:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolspurgepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/purge.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/purge.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/purge.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -23,7 +23,7 @@
</span><span class="cx"> 
</span><span class="cx"> from getopt import getopt, GetoptError
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx"> 
</span><span class="lines">@@ -147,7 +147,7 @@
</span><span class="cx">         if dryrun:
</span><span class="cx">             verbose = True
</span><span class="cx"> 
</span><del>-        cutoff = PyCalendarDateTime.getToday()
</del><ins>+        cutoff = DateTime.getToday()
</ins><span class="cx">         cutoff.setDateOnly(False)
</span><span class="cx">         cutoff.offsetDay(-days)
</span><span class="cx">         cls.cutoff = cutoff
</span><span class="lines">@@ -328,7 +328,7 @@
</span><span class="cx"> 
</span><span class="cx">         cls.uuid = uuid
</span><span class="cx">         if days &gt; 0:
</span><del>-            cutoff = PyCalendarDateTime.getToday()
</del><ins>+            cutoff = DateTime.getToday()
</ins><span class="cx">             cutoff.setDateOnly(False)
</span><span class="cx">             cutoff.offsetDay(-days)
</span><span class="cx">             cls.cutoff = cutoff
</span><span class="lines">@@ -352,7 +352,7 @@
</span><span class="cx">         service = cls(store)
</span><span class="cx">         service.uuid = uuid
</span><span class="cx">         if days &gt; 0:
</span><del>-            cutoff = PyCalendarDateTime.getToday()
</del><ins>+            cutoff = DateTime.getToday()
</ins><span class="cx">             cutoff.setDateOnly(False)
</span><span class="cx">             cutoff.offsetDay(-days)
</span><span class="cx">             service.cutoff = cutoff
</span><span class="lines">@@ -732,7 +732,7 @@
</span><span class="cx">     def _purgeUID(self, uid):
</span><span class="cx"> 
</span><span class="cx">         if self.when is None:
</span><del>-            self.when = PyCalendarDateTime.getNowUTC()
</del><ins>+            self.when = DateTime.getNowUTC()
</ins><span class="cx"> 
</span><span class="cx">         # Does the record exist?
</span><span class="cx">         record = self.directory.recordWithUID(uid)
</span><span class="lines">@@ -1020,7 +1020,7 @@
</span><span class="cx">         @type event: L{twistedcaldav.ical.Component}
</span><span class="cx"> 
</span><span class="cx">         @param when: the cutoff date (anything after which is removed)
</span><del>-        @type when: PyCalendarDateTime
</del><ins>+        @type when: DateTime
</ins><span class="cx"> 
</span><span class="cx">         @param cua: Calendar User Address of principal being purged, to compare
</span><span class="cx">             to see if it's the organizer of the event or just an attendee
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolsshelldirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/shell/directory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/shell/directory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/shell/directory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx">     returnValue(sorted(records, key=operator.attrgetter(&quot;fullName&quot;)))
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @inlineCallbacks
</span><span class="cx"> def recordInfo(directory, record):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -58,8 +59,9 @@
</span><span class="cx">     add(&quot;Proxy access&quot;     , (yield recordProxyAccessInfo(directory, record)))
</span><span class="cx"> 
</span><span class="cx">     returnValue(&quot;\n&quot;.join(info))
</span><del>-        
</del><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def recordBasicInfo(directory, record):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Basic information for a record.
</span><span class="lines">@@ -87,15 +89,15 @@
</span><span class="cx">     for cua in record.calendarUserAddresses:
</span><span class="cx">         add(&quot;Calendar User Address&quot;, cua)
</span><span class="cx"> 
</span><del>-    add(&quot;Server ID&quot;           , record.serverID              )
-    add(&quot;Partition ID&quot;        , record.partitionID           )
-    add(&quot;Enabled&quot;             , record.enabled               )
-    add(&quot;Enabled for Calendar&quot;, record.enabledForCalendaring )
</del><ins>+    add(&quot;Server ID&quot;           , record.serverID)
+    add(&quot;Enabled&quot;             , record.enabled)
+    add(&quot;Enabled for Calendar&quot;, record.enabledForCalendaring)
</ins><span class="cx">     add(&quot;Enabled for Contacts&quot;, record.enabledForAddressBooks)
</span><span class="cx"> 
</span><span class="cx">     return succeed(table.toString())
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def recordGroupMembershipInfo(directory, record):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Group membership info for a record.
</span><span class="lines">@@ -109,7 +111,7 @@
</span><span class="cx">         return succeed(None)
</span><span class="cx"> 
</span><span class="cx">     rows = sorted(rows,
</span><del>-        key = lambda row: (row[1], row[2])
</del><ins>+        key=lambda row: (row[1], row[2])
</ins><span class="cx">     )
</span><span class="cx"> 
</span><span class="cx">     table = Table()
</span><span class="lines">@@ -120,6 +122,7 @@
</span><span class="cx">     return succeed(table.toString())
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @inlineCallbacks
</span><span class="cx"> def recordProxyAccessInfo(directory, record):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -154,7 +157,7 @@
</span><span class="cx">         returnValue(None)
</span><span class="cx"> 
</span><span class="cx">     rows = sorted(rows,
</span><del>-        key = lambda row: (row[1], row[2], row[4])
</del><ins>+        key=lambda row: (row[1], row[2], row[4])
</ins><span class="cx">     )
</span><span class="cx"> 
</span><span class="cx">     table = Table()
</span><span class="lines">@@ -165,6 +168,7 @@
</span><span class="cx">     returnValue(table.toString())
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def summarizeRecords(directory, records):
</span><span class="cx">     table = Table()
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstestdeprovisioncaldavdplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/deprovision/caldavd.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/deprovision/caldavd.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/deprovision/caldavd.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -191,7 +191,6 @@
</span><span class="cx">         Augments for the directory service records to add calendar specific attributes.
</span><span class="cx"> 
</span><span class="cx">         A variety of augment services are available for use.
</span><del>-        When using a partitioned server, a service that can be accessed from each host will be needed.
</del><span class="cx">       --&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;!-- XML File Augment Service --&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstestgatewaycaldavdplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/gateway/caldavd.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/gateway/caldavd.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/gateway/caldavd.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -203,7 +203,6 @@
</span><span class="cx">         Augments for the directory service records to add calendar specific attributes.
</span><span class="cx"> 
</span><span class="cx">         A variety of augment services are available for use.
</span><del>-        When using a partitioned server, a service that can be accessed from each host will be needed.
</del><span class="cx">       --&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;!-- XML File Augment Service --&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstestprincipalscaldavdplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/principals/caldavd.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/principals/caldavd.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/principals/caldavd.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -195,7 +195,6 @@
</span><span class="cx">         Augments for the directory service records to add calendar specific attributes.
</span><span class="cx"> 
</span><span class="cx">         A variety of augment services are available for use.
</span><del>-        When using a partitioned server, a service that can be accessed from each host will be needed.
</del><span class="cx">       --&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;!-- XML File Augment Service --&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstesttest_calverifypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_calverify.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_calverify.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_calverify.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -22,7 +22,7 @@
</span><span class="cx"> from calendarserver.tools.calverify import BadDataService, \
</span><span class="cx">     SchedulingMismatchService, DoubleBookingService, DarkPurgeService
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from twisted.internet import reactor
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks
</span><span class="lines">@@ -511,7 +511,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         sync_token_old = (yield (yield self.calendarUnderTest()).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: True,
</span><span class="lines">@@ -555,7 +555,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         sync_token_old = (yield (yield self.calendarUnderTest()).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: True,
</span><span class="lines">@@ -627,7 +627,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         sync_token_old = (yield (yield self.calendarUnderTest()).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -667,7 +667,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         sync_token_old = (yield (yield self.calendarUnderTest()).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -969,7 +969,7 @@
</span><span class="cx">         self.notifierFactory.reset()
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-now = PyCalendarDateTime.getToday()
</del><ins>+now = DateTime.getToday()
</ins><span class="cx"> now.setDay(1)
</span><span class="cx"> now.offsetMonth(2)
</span><span class="cx"> nowYear = now.getYear()
</span><span class="lines">@@ -1404,7 +1404,7 @@
</span><span class="cx"> 
</span><span class="cx">         home = (yield self.homeUnderTest(name=self.uuid3))
</span><span class="cx">         calendar = (yield self.calendarUnderTest(name=&quot;calendar2&quot;, home=self.uuid3))
</span><del>-        yield home.setDefaultCalendar(calendar)
</del><ins>+        yield home.setDefaultCalendar(calendar, &quot;VEVENT&quot;)
</ins><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1418,7 +1418,7 @@
</span><span class="cx">         sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name=&quot;calendar&quot;)).syncToken())
</span><span class="cx">         sync_token_old2 = (yield (yield self.calendarUnderTest(home=self.uuid2, name=&quot;calendar&quot;)).syncToken())
</span><span class="cx">         sync_token_old3 = (yield (yield self.calendarUnderTest(home=self.uuid3, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -1431,7 +1431,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;tzid&quot;: &quot;&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">         }
</span><span class="cx">         output = StringIO()
</span><span class="cx">         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="lines">@@ -1485,7 +1485,7 @@
</span><span class="cx">         sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name=&quot;calendar&quot;)).syncToken())
</span><span class="cx">         sync_token_old2 = (yield (yield self.calendarUnderTest(home=self.uuid2, name=&quot;calendar&quot;)).syncToken())
</span><span class="cx">         sync_token_old3 = (yield (yield self.calendarUnderTest(home=self.uuid3, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -1498,7 +1498,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;tzid&quot;: &quot;&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">         }
</span><span class="cx">         output = StringIO()
</span><span class="cx">         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="lines">@@ -1576,7 +1576,7 @@
</span><span class="cx">         self.assertNotEqual(sync_token_old3, sync_token_new3)
</span><span class="cx"> 
</span><span class="cx">         # Re-scan after changes to make sure there are no errors
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx">         options[&quot;fix&quot;] = False
</span><span class="cx">         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="cx">         yield calverify.doAction()
</span><span class="lines">@@ -1694,7 +1694,7 @@
</span><span class="cx"> 
</span><span class="cx">         sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name=&quot;calendar&quot;)).syncToken())
</span><span class="cx">         sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -1707,7 +1707,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;tzid&quot;: &quot;&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">         }
</span><span class="cx">         output = StringIO()
</span><span class="cx">         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="lines">@@ -1745,7 +1745,7 @@
</span><span class="cx"> 
</span><span class="cx">         sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name=&quot;calendar&quot;)).syncToken())
</span><span class="cx">         sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -1758,7 +1758,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;tzid&quot;: &quot;&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">         }
</span><span class="cx">         output = StringIO()
</span><span class="cx">         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="lines">@@ -1803,7 +1803,7 @@
</span><span class="cx">         self.assertNotEqual(sync_token_oldl1, sync_token_newl1)
</span><span class="cx"> 
</span><span class="cx">         # Re-scan after changes to make sure there are no errors
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx">         options[&quot;fix&quot;] = False
</span><span class="cx">         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="cx">         yield calverify.doAction()
</span><span class="lines">@@ -1921,7 +1921,7 @@
</span><span class="cx"> 
</span><span class="cx">         sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name=&quot;calendar&quot;)).syncToken())
</span><span class="cx">         sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -1934,7 +1934,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: CalVerifyMismatchTestsBase.uuidl1,
</span><span class="cx">             &quot;tzid&quot;: &quot;&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">         }
</span><span class="cx">         output = StringIO()
</span><span class="cx">         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="lines">@@ -1970,7 +1970,7 @@
</span><span class="cx"> 
</span><span class="cx">         sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name=&quot;calendar&quot;)).syncToken())
</span><span class="cx">         sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -1983,7 +1983,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: CalVerifyMismatchTestsBase.uuidl1,
</span><span class="cx">             &quot;tzid&quot;: &quot;&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">         }
</span><span class="cx">         output = StringIO()
</span><span class="cx">         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="lines">@@ -2021,7 +2021,7 @@
</span><span class="cx">         self.assertNotEqual(sync_token_oldl1, sync_token_newl1)
</span><span class="cx"> 
</span><span class="cx">         # Re-scan after changes to make sure there are no errors
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx">         options[&quot;fix&quot;] = False
</span><span class="cx">         options[&quot;uuid&quot;] = CalVerifyMismatchTestsBase.uuidl1
</span><span class="cx">         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="lines">@@ -2430,7 +2430,7 @@
</span><span class="cx"> 
</span><span class="cx">         sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name=&quot;calendar&quot;)).syncToken())
</span><span class="cx">         sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -2446,7 +2446,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: self.uuidl1,
</span><span class="cx">             &quot;tzid&quot;: &quot;utc&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">         }
</span><span class="cx">         output = StringIO()
</span><span class="cx">         calverify = DoubleBookingService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="lines">@@ -2592,7 +2592,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -2609,7 +2609,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: self.uuidl1,
</span><span class="cx">             &quot;tzid&quot;: &quot;utc&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">             &quot;no-organizer&quot;: False,
</span><span class="cx">             &quot;invalid-organizer&quot;: False,
</span><span class="cx">             &quot;disabled-organizer&quot;: False,
</span><span class="lines">@@ -2639,7 +2639,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -2656,7 +2656,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: self.uuidl1,
</span><span class="cx">             &quot;tzid&quot;: &quot;utc&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">             &quot;no-organizer&quot;: False,
</span><span class="cx">             &quot;invalid-organizer&quot;: False,
</span><span class="cx">             &quot;disabled-organizer&quot;: False,
</span><span class="lines">@@ -2678,7 +2678,7 @@
</span><span class="cx">         self.assertNotEqual(sync_token_oldl1, sync_token_newl1)
</span><span class="cx"> 
</span><span class="cx">         # Re-scan after changes to make sure there are no errors
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx">         options[&quot;fix&quot;] = False
</span><span class="cx">         options[&quot;uuid&quot;] = self.uuidl1
</span><span class="cx">         calverify = DarkPurgeService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="lines">@@ -2698,7 +2698,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -2715,7 +2715,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: self.uuidl1,
</span><span class="cx">             &quot;tzid&quot;: &quot;utc&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">             &quot;no-organizer&quot;: True,
</span><span class="cx">             &quot;invalid-organizer&quot;: False,
</span><span class="cx">             &quot;disabled-organizer&quot;: False,
</span><span class="lines">@@ -2737,7 +2737,7 @@
</span><span class="cx">         self.assertNotEqual(sync_token_oldl1, sync_token_newl1)
</span><span class="cx"> 
</span><span class="cx">         # Re-scan after changes to make sure there are no errors
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx">         options[&quot;fix&quot;] = False
</span><span class="cx">         options[&quot;uuid&quot;] = self.uuidl1
</span><span class="cx">         calverify = DarkPurgeService(self._sqlCalendarStore, options, output, reactor, config)
</span><span class="lines">@@ -2757,7 +2757,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name=&quot;calendar&quot;)).syncToken())
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx"> 
</span><span class="cx">         options = {
</span><span class="cx">             &quot;ical&quot;: False,
</span><span class="lines">@@ -2774,7 +2774,7 @@
</span><span class="cx">             &quot;uid&quot;: &quot;&quot;,
</span><span class="cx">             &quot;uuid&quot;: self.uuidl1,
</span><span class="cx">             &quot;tzid&quot;: &quot;utc&quot;,
</span><del>-            &quot;start&quot;: PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
</del><ins>+            &quot;start&quot;: DateTime(nowYear, 1, 1, 0, 0, 0),
</ins><span class="cx">             &quot;no-organizer&quot;: True,
</span><span class="cx">             &quot;invalid-organizer&quot;: True,
</span><span class="cx">             &quot;disabled-organizer&quot;: True,
</span><span class="lines">@@ -2796,7 +2796,7 @@
</span><span class="cx">         self.assertNotEqual(sync_token_oldl1, sync_token_newl1)
</span><span class="cx"> 
</span><span class="cx">         # Re-scan after changes to make sure there are no errors
</span><del>-        self.commit()
</del><ins>+        yield self.commit()
</ins><span class="cx">         options[&quot;fix&quot;] = False
</span><span class="cx">         options[&quot;uuid&quot;] = self.uuidl1
</span><span class="cx">         calverify = DarkPurgeService(self._sqlCalendarStore, options, output, reactor, config)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstesttest_gatewaypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_gateway.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_gateway.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_gateway.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -193,6 +193,7 @@
</span><span class="cx">         self.assertEquals(record.extras[&quot;zip&quot;], &quot;95014&quot;)
</span><span class="cx">         self.assertEquals(record.extras[&quot;country&quot;], &quot;USA&quot;)
</span><span class="cx">         self.assertEquals(record.extras[&quot;phone&quot;], &quot;(408) 555-1212&quot;)
</span><ins>+        self.assertEquals(record.extras[&quot;geo&quot;], &quot;geo:37.331,-122.030&quot;)
</ins><span class="cx"> 
</span><span class="cx">         results = yield self.runCommand(command_getLocationAttributes)
</span><span class="cx">         self.assertEquals(set(results[&quot;result&quot;][&quot;ReadProxies&quot;]), set(['user03', 'user04']))
</span><span class="lines">@@ -424,6 +425,8 @@
</span><span class="cx">         &lt;string&gt;USA&lt;/string&gt;
</span><span class="cx">         &lt;key&gt;Phone&lt;/key&gt;
</span><span class="cx">         &lt;string&gt;(408) 555-1212&lt;/string&gt;
</span><ins>+        &lt;key&gt;Geo&lt;/key&gt;
+        &lt;string&gt;geo:37.331,-122.030&lt;/string&gt;
</ins><span class="cx">         &lt;key&gt;ReadProxies&lt;/key&gt;
</span><span class="cx">         &lt;array&gt;
</span><span class="cx">             &lt;string&gt;users:user03&lt;/string&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstesttest_purgepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_purge.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_purge.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_purge.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -21,8 +21,8 @@
</span><span class="cx"> from twistedcaldav.ical import Component
</span><span class="cx"> from twistedcaldav.test.util import StoreTestCase
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks
</span><span class="cx"> from txdav.common.datastore.test.util import populateCalendarsFrom
</span><span class="lines">@@ -33,11 +33,11 @@
</span><span class="cx"> import os
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-future = PyCalendarDateTime.getNowUTC()
</del><ins>+future = DateTime.getNowUTC()
</ins><span class="cx"> future.offsetDay(1)
</span><span class="cx"> future = future.getText()
</span><span class="cx"> 
</span><del>-past = PyCalendarDateTime.getNowUTC()
</del><ins>+past = DateTime.getNowUTC()
</ins><span class="cx"> past.offsetDay(-1)
</span><span class="cx"> past = past.getText()
</span><span class="cx"> 
</span><span class="lines">@@ -230,7 +230,7 @@
</span><span class="cx">     def test_cancelRepeating(self):
</span><span class="cx">         # A repeating event where purged CUA is organizer
</span><span class="cx">         event = Component.fromString(REPEATING_1_ICS_BEFORE)
</span><del>-        action = PurgePrincipalService._cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+        action = PurgePrincipalService._cancelEvent(event, DateTime(2010, 12, 6, 12, 0, 0, Timezone(utc=True)),
</ins><span class="cx">             &quot;urn:uuid:0F168477-CF3D-45D3-AE60-9875EA02C4D1&quot;)
</span><span class="cx">         self.assertEquals(action, PurgePrincipalService.CANCELEVENT_MODIFIED)
</span><span class="cx">         self.assertEquals(str(event), REPEATING_1_ICS_AFTER)
</span><span class="lines">@@ -239,7 +239,7 @@
</span><span class="cx">     def test_cancelAllDayRepeating(self):
</span><span class="cx">         # A repeating All Day event where purged CUA is organizer
</span><span class="cx">         event = Component.fromString(REPEATING_2_ICS_BEFORE)
</span><del>-        action = PurgePrincipalService._cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+        action = PurgePrincipalService._cancelEvent(event, DateTime(2010, 12, 6, 12, 0, 0, Timezone(utc=True)),
</ins><span class="cx">             &quot;urn:uuid:0F168477-CF3D-45D3-AE60-9875EA02C4D1&quot;)
</span><span class="cx">         self.assertEquals(action, PurgePrincipalService.CANCELEVENT_MODIFIED)
</span><span class="cx">         self.assertEquals(str(event), REPEATING_2_ICS_AFTER)
</span><span class="lines">@@ -248,7 +248,7 @@
</span><span class="cx">     def test_cancelFutureEvent(self):
</span><span class="cx">         # A future event
</span><span class="cx">         event = Component.fromString(FUTURE_EVENT_ICS)
</span><del>-        action = PurgePrincipalService._cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+        action = PurgePrincipalService._cancelEvent(event, DateTime(2010, 12, 6, 12, 0, 0, Timezone(utc=True)),
</ins><span class="cx">             &quot;urn:uuid:0F168477-CF3D-45D3-AE60-9875EA02C4D1&quot;)
</span><span class="cx">         self.assertEquals(action, PurgePrincipalService.CANCELEVENT_SHOULD_DELETE)
</span><span class="cx"> 
</span><span class="lines">@@ -256,7 +256,7 @@
</span><span class="cx">     def test_cancelNonMeeting(self):
</span><span class="cx">         # A repeating non-meeting event
</span><span class="cx">         event = Component.fromString(REPEATING_NON_MEETING_ICS)
</span><del>-        action = PurgePrincipalService._cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+        action = PurgePrincipalService._cancelEvent(event, DateTime(2010, 12, 6, 12, 0, 0, Timezone(utc=True)),
</ins><span class="cx">             &quot;urn:uuid:0F168477-CF3D-45D3-AE60-9875EA02C4D1&quot;)
</span><span class="cx">         self.assertEquals(action, PurgePrincipalService.CANCELEVENT_SHOULD_DELETE)
</span><span class="cx"> 
</span><span class="lines">@@ -264,7 +264,7 @@
</span><span class="cx">     def test_cancelAsAttendee(self):
</span><span class="cx">         # A repeating meeting event where purged CUA is an attendee
</span><span class="cx">         event = Component.fromString(REPEATING_ATTENDEE_MEETING_ICS)
</span><del>-        action = PurgePrincipalService._cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+        action = PurgePrincipalService._cancelEvent(event, DateTime(2010, 12, 6, 12, 0, 0, Timezone(utc=True)),
</ins><span class="cx">             &quot;urn:uuid:0F168477-CF3D-45D3-AE60-9875EA02C4D1&quot;)
</span><span class="cx">         self.assertEquals(action, PurgePrincipalService.CANCELEVENT_SHOULD_DELETE)
</span><span class="cx"> 
</span><span class="lines">@@ -273,7 +273,7 @@
</span><span class="cx">         # A repeating meeting occurrence with no master, where purged CUA is
</span><span class="cx">         # an attendee
</span><span class="cx">         event = Component.fromString(INVITED_TO_OCCURRENCE_ICS)
</span><del>-        action = PurgePrincipalService._cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+        action = PurgePrincipalService._cancelEvent(event, DateTime(2010, 12, 6, 12, 0, 0, Timezone(utc=True)),
</ins><span class="cx">             &quot;urn:uuid:9DC04A71-E6DD-11DF-9492-0800200C9A66&quot;)
</span><span class="cx">         self.assertEquals(action, PurgePrincipalService.CANCELEVENT_SHOULD_DELETE)
</span><span class="cx"> 
</span><span class="lines">@@ -282,7 +282,7 @@
</span><span class="cx">         # Multiple meeting occurrences with no master, where purged CUA is
</span><span class="cx">         # an attendee
</span><span class="cx">         event = Component.fromString(INVITED_TO_MULTIPLE_OCCURRENCES_ICS)
</span><del>-        action = PurgePrincipalService._cancelEvent(event, PyCalendarDateTime(2010, 12, 6, 12, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+        action = PurgePrincipalService._cancelEvent(event, DateTime(2010, 12, 6, 12, 0, 0, Timezone(utc=True)),
</ins><span class="cx">             &quot;urn:uuid:9DC04A71-E6DD-11DF-9492-0800200C9A66&quot;)
</span><span class="cx">         self.assertEquals(action, PurgePrincipalService.CANCELEVENT_SHOULD_DELETE)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescalendarservertoolstesttest_purge_old_eventspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_purge_old_events.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_purge_old_events.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/calendarserver/tools/test/test_purge_old_events.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -21,8 +21,8 @@
</span><span class="cx"> from calendarserver.tools.purge import PurgeOldEventsService, PurgeAttachmentsService, \
</span><span class="cx">     PurgePrincipalService
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twext.enterprise.dal.syntax import Update, Delete
</span><span class="cx"> from twext.web2.http_headers import MimeType
</span><span class="lines">@@ -39,7 +39,7 @@
</span><span class="cx"> import os
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-now = PyCalendarDateTime.getToday().getYear()
</del><ins>+now = DateTime.getToday().getYear()
</ins><span class="cx"> 
</span><span class="cx"> OLD_ICS = &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="lines">@@ -443,7 +443,7 @@
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_eventsOlderThan(self):
</span><del>-        cutoff = PyCalendarDateTime(now, 4, 1, 0, 0, 0)
</del><ins>+        cutoff = DateTime(now, 4, 1, 0, 0, 0)
</ins><span class="cx">         txn = self._sqlCalendarStore.newTransaction()
</span><span class="cx"> 
</span><span class="cx">         # Query for all old events
</span><span class="lines">@@ -475,7 +475,7 @@
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_removeOldEvents(self):
</span><del>-        cutoff = PyCalendarDateTime(now, 4, 1, 0, 0, 0)
</del><ins>+        cutoff = DateTime(now, 4, 1, 0, 0, 0)
</ins><span class="cx">         txn = self._sqlCalendarStore.newTransaction()
</span><span class="cx"> 
</span><span class="cx">         # Remove oldest event - except we don't know what that is because of the dummy timestamps
</span><span class="lines">@@ -598,7 +598,7 @@
</span><span class="cx">         self.assertTrue(os.path.exists(mattachmentPath2))
</span><span class="cx"> 
</span><span class="cx">         # Delete all old events (including the event containing the attachment)
</span><del>-        cutoff = PyCalendarDateTime(now, 4, 1, 0, 0, 0)
</del><ins>+        cutoff = DateTime(now, 4, 1, 0, 0, 0)
</ins><span class="cx">         count = (yield self.transactionUnderTest().removeOldEvents(cutoff))
</span><span class="cx"> 
</span><span class="cx">         # See which events have gone and which exist
</span><span class="lines">@@ -633,7 +633,7 @@
</span><span class="cx">         # Dry run
</span><span class="cx">         total = (yield PurgeOldEventsService.purgeOldEvents(
</span><span class="cx">             self._sqlCalendarStore,
</span><del>-            PyCalendarDateTime(now, 4, 1, 0, 0, 0),
</del><ins>+            DateTime(now, 4, 1, 0, 0, 0),
</ins><span class="cx">             2,
</span><span class="cx">             dryrun=True,
</span><span class="cx">             verbose=False
</span><span class="lines">@@ -643,7 +643,7 @@
</span><span class="cx">         # Actually remove
</span><span class="cx">         total = (yield PurgeOldEventsService.purgeOldEvents(
</span><span class="cx">             self._sqlCalendarStore,
</span><del>-            PyCalendarDateTime(now, 4, 1, 0, 0, 0),
</del><ins>+            DateTime(now, 4, 1, 0, 0, 0),
</ins><span class="cx">             2,
</span><span class="cx">             verbose=False
</span><span class="cx">         ))
</span><span class="lines">@@ -652,7 +652,7 @@
</span><span class="cx">         # There should be no more left
</span><span class="cx">         total = (yield PurgeOldEventsService.purgeOldEvents(
</span><span class="cx">             self._sqlCalendarStore,
</span><del>-            PyCalendarDateTime(now, 4, 1, 0, 0, 0),
</del><ins>+            DateTime(now, 4, 1, 0, 0, 0),
</ins><span class="cx">             2,
</span><span class="cx">             verbose=False
</span><span class="cx">         ))
</span><span class="lines">@@ -681,7 +681,7 @@
</span><span class="cx">         # Purge home1
</span><span class="cx">         total, ignored = (yield PurgePrincipalService.purgeUIDs(self._sqlCalendarStore, self.directory,
</span><span class="cx">             self.rootResource, (&quot;home1&quot;,), verbose=False, proxies=False,
</span><del>-            when=PyCalendarDateTime(now, 4, 1, 12, 0, 0, 0, PyCalendarTimezone(utc=True))))
</del><ins>+            when=DateTime(now, 4, 1, 12, 0, 0, 0, Timezone(utc=True))))
</ins><span class="cx"> 
</span><span class="cx">         # 4 items deleted: 3 events and 1 vcard
</span><span class="cx">         self.assertEquals(total, 4)
</span><span class="lines">@@ -768,7 +768,7 @@
</span><span class="cx">         # Remove old events first
</span><span class="cx">         total = (yield PurgeOldEventsService.purgeOldEvents(
</span><span class="cx">             self._sqlCalendarStore,
</span><del>-            PyCalendarDateTime(now, 4, 1, 0, 0, 0),
</del><ins>+            DateTime(now, 4, 1, 0, 0, 0),
</ins><span class="cx">             2,
</span><span class="cx">             verbose=False
</span><span class="cx">         ))
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfauthaccountstestpodxmlfromrev12016CalendarServertrunkconfauthaccountstestpodxml"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/accounts-test-pod.xml (from rev 12016, CalendarServer/trunk/conf/auth/accounts-test-pod.xml) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/accounts-test-pod.xml                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/accounts-test-pod.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+
+&lt;accounts realm=&quot;Test Realm&quot;&gt;
+  &lt;user&gt;
+    &lt;uid&gt;admin&lt;/uid&gt;
+    &lt;guid&gt;admin&lt;/guid&gt;
+    &lt;password&gt;admin&lt;/password&gt;
+    &lt;name&gt;Super User&lt;/name&gt;
+    &lt;first-name&gt;Super&lt;/first-name&gt;
+    &lt;last-name&gt;User&lt;/last-name&gt;
+  &lt;/user&gt;
+  &lt;user repeat=&quot;101&quot;&gt;
+    &lt;uid&gt;user%02d&lt;/uid&gt;
+    &lt;uid&gt;User %02d&lt;/uid&gt;
+    &lt;guid&gt;user%02d&lt;/guid&gt;
+    &lt;password&gt;user%02d&lt;/password&gt;
+    &lt;name&gt;User %02d&lt;/name&gt;
+    &lt;first-name&gt;User&lt;/first-name&gt;
+    &lt;last-name&gt;%02d&lt;/last-name&gt;
+    &lt;email-address&gt;user%02d@example.com&lt;/email-address&gt;
+  &lt;/user&gt;
+  &lt;user repeat=&quot;101&quot;&gt;
+    &lt;uid&gt;puser%02d&lt;/uid&gt;
+    &lt;uid&gt;Puser %02d&lt;/uid&gt;
+    &lt;guid&gt;puser%02d&lt;/guid&gt;
+    &lt;password&gt;puser%02d&lt;/password&gt;
+    &lt;name&gt;Puser %02d&lt;/name&gt;
+    &lt;first-name&gt;Puser&lt;/first-name&gt;
+    &lt;last-name&gt;%02d&lt;/last-name&gt;
+    &lt;email-address&gt;puser%02d@example.com&lt;/email-address&gt;
+  &lt;/user&gt;
+&lt;/accounts&gt;
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfauthaugmentstestpodxmlfromrev12016CalendarServertrunkconfauthaugmentstestpodxml"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/augments-test-pod.xml (from rev 12016, CalendarServer/trunk/conf/auth/augments-test-pod.xml) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/augments-test-pod.xml                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/augments-test-pod.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;!DOCTYPE augments SYSTEM &quot;augments.dtd&quot;&gt;
+
+&lt;augments&gt;
+  &lt;record&gt;
+    &lt;uid&gt;Default&lt;/uid&gt;
+    &lt;enable&gt;true&lt;/enable&gt;
+    &lt;server-id&gt;A&lt;/server-id&gt;
+    &lt;enable-calendar&gt;true&lt;/enable-calendar&gt;
+    &lt;enable-addressbook&gt;true&lt;/enable-addressbook&gt;
+  &lt;/record&gt;
+  &lt;record repeat=&quot;101&quot;&gt;
+    &lt;uid&gt;puser%02d&lt;/uid&gt;
+    &lt;enable&gt;true&lt;/enable&gt;
+    &lt;server-id&gt;B&lt;/server-id&gt;
+    &lt;enable-calendar&gt;true&lt;/enable-calendar&gt;
+    &lt;enable-addressbook&gt;true&lt;/enable-addressbook&gt;
+  &lt;/record&gt;
+&lt;/augments&gt;
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfauthaugmentsdtd"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/augments.dtd (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/augments.dtd        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/augments.dtd        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -19,7 +19,7 @@
</span><span class="cx">   &lt;!ELEMENT record (
</span><span class="cx">                   uid,
</span><span class="cx">                   enable,
</span><del>-                  (server-id, partition-id?)?,
</del><ins>+                  server-id?,
</ins><span class="cx">                   enable-calendar?,
</span><span class="cx">                   enable-addressbook?,
</span><span class="cx">                   enable-login?,
</span><span class="lines">@@ -32,7 +32,6 @@
</span><span class="cx">   &lt;!ELEMENT uid                (#PCDATA)&gt;
</span><span class="cx">   &lt;!ELEMENT enable             (#PCDATA)&gt;
</span><span class="cx">   &lt;!ELEMENT server-id          (#PCDATA)&gt;
</span><del>-  &lt;!ELEMENT partition-id       (#PCDATA)&gt;
</del><span class="cx">   &lt;!ELEMENT enable-calendar    (#PCDATA)&gt;
</span><span class="cx">   &lt;!ELEMENT enable-addressbook (#PCDATA)&gt;
</span><span class="cx">   &lt;!ELEMENT enable-login       (#PCDATA)&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfauthproxiestestpodxmlfromrev12016CalendarServertrunkconfauthproxiestestpodxml"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/proxies-test-pod.xml (from rev 12016, CalendarServer/trunk/conf/auth/proxies-test-pod.xml) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/proxies-test-pod.xml                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/proxies-test-pod.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+
+&lt;!--
+Copyright (c) 2009-2013 Apple Inc. 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.
+ --&gt;
+
+&lt;!DOCTYPE proxies SYSTEM &quot;proxies.dtd&quot;&gt;
+
+&lt;proxies&gt;
+&lt;/proxies&gt;
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfauthresourcestestpodxmlfromrev12016CalendarServertrunkconfauthresourcestestpodxml"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/resources-test-pod.xml (from rev 12016, CalendarServer/trunk/conf/auth/resources-test-pod.xml) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/resources-test-pod.xml                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/auth/resources-test-pod.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+
+&lt;accounts realm=&quot;Test Realm&quot;&gt;
+&lt;/accounts&gt;
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfcaldavdpartitioningprimaryplist"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-partitioning-primary.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-partitioning-primary.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-partitioning-primary.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,85 +0,0 @@
</span><del>-&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-
-&lt;!--
-    Copyright (c) 2006-2013 Apple Inc. 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.
-  --&gt;
-
-&lt;!DOCTYPE plist PUBLIC &quot;-//Apple Computer//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
-&lt;plist version=&quot;1.0&quot;&gt;
-  &lt;dict&gt;
-
-    &lt;!--  Servers --&gt;
-    &lt;key&gt;Servers&lt;/key&gt;
-    &lt;dict&gt;
-            &lt;key&gt;Enabled&lt;/key&gt;
-            &lt;true/&gt;
-            &lt;key&gt;ConfigFile&lt;/key&gt;
-            &lt;string&gt;localservers.xml&lt;/string&gt;
-            &lt;key&gt;MaxClients&lt;/key&gt;
-            &lt;integer&gt;5&lt;/integer&gt;
-        &lt;/dict&gt;
-    &lt;key&gt;ServerPartitionID&lt;/key&gt;
-    &lt;string&gt;00001&lt;/string&gt;
-
-    &lt;!-- PostgreSQL ProxyDB Service --&gt;
-    &lt;key&gt;ProxyDBService&lt;/key&gt;
-    &lt;dict&gt;
-      &lt;key&gt;type&lt;/key&gt;
-      &lt;string&gt;twistedcaldav.directory.calendaruserproxy.ProxyPostgreSQLDB&lt;/string&gt;
-      
-      &lt;key&gt;params&lt;/key&gt;
-      &lt;dict&gt;
-        &lt;key&gt;host&lt;/key&gt;
-        &lt;string&gt;localhost&lt;/string&gt;
-        &lt;key&gt;database&lt;/key&gt;
-        &lt;string&gt;proxies&lt;/string&gt;
-      &lt;/dict&gt;
-    &lt;/dict&gt;
-
-    &lt;!-- Support for Memcached --&gt;
-    &lt;key&gt;Memcached&lt;/key&gt;
-    &lt;dict&gt;
-          &lt;key&gt;Pools&lt;/key&gt;
-                &lt;dict&gt;
-                  &lt;key&gt;CommonToAllNodes&lt;/key&gt;
-                  &lt;dict&gt;
-                    &lt;key&gt;ClientEnabled&lt;/key&gt;
-                    &lt;true/&gt;
-                    &lt;key&gt;ServerEnabled&lt;/key&gt;
-                    &lt;true/&gt;
-                    &lt;key&gt;BindAddress&lt;/key&gt;
-                    &lt;string&gt;localhost&lt;/string&gt;
-                    &lt;key&gt;Port&lt;/key&gt;
-                    &lt;integer&gt;11311&lt;/integer&gt;
-                    &lt;key&gt;HandleCacheTypes&lt;/key&gt;
-                    &lt;array&gt;
-                      &lt;string&gt;ProxyDB&lt;/string&gt;
-                      &lt;string&gt;PrincipalToken&lt;/string&gt;
-                      &lt;string&gt;DIGESTCREDENTIALS&lt;/string&gt;
-                    &lt;/array&gt;
-                  &lt;/dict&gt;
-                &lt;/dict&gt;
-      &lt;key&gt;MaxClients&lt;/key&gt;
-      &lt;integer&gt;5&lt;/integer&gt;
-      &lt;key&gt;memcached&lt;/key&gt;
-      &lt;string&gt;../memcached/_root/bin/memcached&lt;/string&gt; &lt;!-- Find in PATH --&gt;
-      &lt;key&gt;Options&lt;/key&gt;
-      &lt;array&gt;
-        &lt;!--&lt;string&gt;-vv&lt;/string&gt;--&gt;
-      &lt;/array&gt;
-    &lt;/dict&gt;
-
-  &lt;/dict&gt;
-&lt;/plist&gt;
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfcaldavdpartitioningsecondaryplist"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-partitioning-secondary.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-partitioning-secondary.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-partitioning-secondary.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,85 +0,0 @@
</span><del>-&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-
-&lt;!--
-    Copyright (c) 2006-2013 Apple Inc. 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.
-  --&gt;
-
-&lt;!DOCTYPE plist PUBLIC &quot;-//Apple Computer//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
-&lt;plist version=&quot;1.0&quot;&gt;
-  &lt;dict&gt;
-
-    &lt;!--  Servers --&gt;
-    &lt;key&gt;Servers&lt;/key&gt;
-    &lt;dict&gt;
-            &lt;key&gt;Enabled&lt;/key&gt;
-            &lt;true/&gt;
-            &lt;key&gt;ConfigFile&lt;/key&gt;
-            &lt;string&gt;localservers.xml&lt;/string&gt;
-            &lt;key&gt;MaxClients&lt;/key&gt;
-            &lt;integer&gt;5&lt;/integer&gt;
-        &lt;/dict&gt;
-    &lt;key&gt;ServerPartitionID&lt;/key&gt;
-    &lt;string&gt;00002&lt;/string&gt;
-
-    &lt;!-- PostgreSQL ProxyDB Service --&gt;
-    &lt;key&gt;ProxyDBService&lt;/key&gt;
-    &lt;dict&gt;
-      &lt;key&gt;type&lt;/key&gt;
-      &lt;string&gt;twistedcaldav.directory.calendaruserproxy.ProxyPostgreSQLDB&lt;/string&gt;
-      
-      &lt;key&gt;params&lt;/key&gt;
-      &lt;dict&gt;
-        &lt;key&gt;host&lt;/key&gt;
-        &lt;string&gt;localhost&lt;/string&gt;
-        &lt;key&gt;database&lt;/key&gt;
-        &lt;string&gt;proxies&lt;/string&gt;
-      &lt;/dict&gt;
-    &lt;/dict&gt;
-
-    &lt;!-- Support for Memcached --&gt;
-    &lt;key&gt;Memcached&lt;/key&gt;
-    &lt;dict&gt;
-          &lt;key&gt;Pools&lt;/key&gt;
-                &lt;dict&gt;
-                  &lt;key&gt;CommonToAllNodes&lt;/key&gt;
-                  &lt;dict&gt;
-                    &lt;key&gt;ClientEnabled&lt;/key&gt;
-                    &lt;true/&gt;
-                    &lt;key&gt;ServerEnabled&lt;/key&gt;
-                    &lt;false/&gt;
-                    &lt;key&gt;BindAddress&lt;/key&gt;
-                    &lt;string&gt;localhost&lt;/string&gt;
-                    &lt;key&gt;Port&lt;/key&gt;
-                    &lt;integer&gt;11311&lt;/integer&gt;
-                    &lt;key&gt;HandleCacheTypes&lt;/key&gt;
-                    &lt;array&gt;
-                      &lt;string&gt;ProxyDB&lt;/string&gt;
-                      &lt;string&gt;PrincipalToken&lt;/string&gt;
-                      &lt;string&gt;DIGESTCREDENTIALS&lt;/string&gt;
-                    &lt;/array&gt;
-                  &lt;/dict&gt;
-                &lt;/dict&gt;
-      &lt;key&gt;MaxClients&lt;/key&gt;
-      &lt;integer&gt;5&lt;/integer&gt;
-      &lt;key&gt;memcached&lt;/key&gt;
-      &lt;string&gt;../memcached/_root/bin/memcached&lt;/string&gt; &lt;!-- Find in PATH --&gt;
-      &lt;key&gt;Options&lt;/key&gt;
-      &lt;array&gt;
-        &lt;!--&lt;string&gt;-vv&lt;/string&gt;--&gt;
-      &lt;/array&gt;
-    &lt;/dict&gt;
-
-  &lt;/dict&gt;
-&lt;/plist&gt;
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfcaldavdtestpodAplistfromrev12016CalendarServertrunkconfcaldavdtestpodAplist"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test-podA.plist (from rev 12016, CalendarServer/trunk/conf/caldavd-test-podA.plist) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test-podA.plist                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test-podA.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,158 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
+
+&lt;!--
+    Copyright (c) 2006-2009 Apple Inc. 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.
+  --&gt;
+
+&lt;!DOCTYPE plist PUBLIC &quot;-//Apple Computer//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
+&lt;plist version=&quot;1.0&quot;&gt;
+  &lt;dict&gt;
+
+    &lt;!-- Import a parent config before this one --&gt;
+    &lt;key&gt;ImportConfig&lt;/key&gt;
+    &lt;string&gt;./conf/caldavd-test.plist&lt;/string&gt;
+
+    &lt;!-- HTTP port [0 = disable HTTP] --&gt;
+    &lt;key&gt;HTTPPort&lt;/key&gt;
+    &lt;integer&gt;8008&lt;/integer&gt;
+
+    &lt;!-- SSL port [0 = disable HTTPS] --&gt;
+    &lt;!-- (Must also configure SSLCertificate and SSLPrivateKey below) --&gt;
+    &lt;key&gt;SSLPort&lt;/key&gt;
+    &lt;integer&gt;8443&lt;/integer&gt;
+
+    &lt;!-- List of port numbers to bind to for HTTP [empty = same as &quot;Port&quot;] --&gt;
+    &lt;key&gt;BindHTTPPorts&lt;/key&gt;
+    &lt;array&gt;
+    &lt;/array&gt;
+
+    &lt;!-- List of port numbers to bind to for SSL [empty = same as &quot;SSLPort&quot;] --&gt;
+    &lt;key&gt;BindSSLPorts&lt;/key&gt;
+    &lt;array&gt;
+    &lt;/array&gt;
+
+    &lt;!-- Server root --&gt;
+    &lt;key&gt;ServerRoot&lt;/key&gt;
+    &lt;string&gt;./data/podA&lt;/string&gt;
+
+    &lt;!-- Configuration root --&gt;
+    &lt;key&gt;ConfigRoot&lt;/key&gt;
+    &lt;string&gt;./conf&lt;/string&gt;
+
+    &lt;!-- XML File Directory Service --&gt;
+    &lt;key&gt;DirectoryService&lt;/key&gt;
+    &lt;dict&gt;
+      &lt;key&gt;type&lt;/key&gt;
+      &lt;string&gt;twistedcaldav.directory.xmlfile.XMLDirectoryService&lt;/string&gt;
+      
+      &lt;key&gt;params&lt;/key&gt;
+      &lt;dict&gt;
+        &lt;key&gt;xmlFile&lt;/key&gt;
+        &lt;string&gt;./conf/auth/accounts-test-pod.xml&lt;/string&gt;
+      &lt;/dict&gt;
+    &lt;/dict&gt;
+    
+    &lt;!-- Resource and Location Service --&gt;
+    &lt;key&gt;ResourceService&lt;/key&gt;
+    &lt;dict&gt;
+      &lt;key&gt;Enabled&lt;/key&gt;
+      &lt;true/&gt;
+      &lt;key&gt;type&lt;/key&gt;
+      &lt;string&gt;twistedcaldav.directory.xmlfile.XMLDirectoryService&lt;/string&gt;
+      
+      &lt;key&gt;params&lt;/key&gt;
+      &lt;dict&gt;
+        &lt;key&gt;xmlFile&lt;/key&gt;
+        &lt;string&gt;./conf/auth/resources-test-pod.xml&lt;/string&gt;
+      &lt;/dict&gt;
+    &lt;/dict&gt;
+
+    &lt;!-- XML File Augment Service --&gt;
+    &lt;key&gt;AugmentService&lt;/key&gt;
+    &lt;dict&gt;
+      &lt;key&gt;type&lt;/key&gt;
+      &lt;string&gt;twistedcaldav.directory.augment.AugmentXMLDB&lt;/string&gt;
+      
+      &lt;key&gt;params&lt;/key&gt;
+      &lt;dict&gt;
+        &lt;key&gt;xmlFiles&lt;/key&gt;
+        &lt;array&gt;
+              &lt;string&gt;./conf/auth/augments-test-pod.xml&lt;/string&gt;
+        &lt;/array&gt;
+      &lt;/dict&gt;
+    &lt;/dict&gt;
+
+    &lt;key&gt;ProxyLoadFromFile&lt;/key&gt;
+    &lt;string&gt;./conf/auth/proxies-test-pod.xml&lt;/string&gt;
+
+    &lt;!--  Servers --&gt;
+    &lt;key&gt;Servers&lt;/key&gt;
+    &lt;dict&gt;
+            &lt;key&gt;Enabled&lt;/key&gt;
+            &lt;true/&gt;
+            &lt;key&gt;ConfigFile&lt;/key&gt;
+            &lt;string&gt;./conf/localservers-test.xml&lt;/string&gt;
+            &lt;key&gt;MaxClients&lt;/key&gt;
+            &lt;integer&gt;5&lt;/integer&gt;
+            &lt;key&gt;InboxName&lt;/key&gt;
+            &lt;string&gt;podding&lt;/string&gt;
+        &lt;/dict&gt;
+
+    &lt;!-- Support for Memcached --&gt;
+    &lt;key&gt;Memcached&lt;/key&gt;
+    &lt;dict&gt;
+          &lt;key&gt;Pools&lt;/key&gt;
+                &lt;dict&gt;
+                  &lt;key&gt;Default&lt;/key&gt;
+                  &lt;dict&gt;
+                    &lt;key&gt;ClientEnabled&lt;/key&gt;
+                    &lt;true/&gt;
+                    &lt;key&gt;ServerEnabled&lt;/key&gt;
+                    &lt;true/&gt;
+                    &lt;key&gt;BindAddress&lt;/key&gt;
+                    &lt;string&gt;localhost&lt;/string&gt;
+                    &lt;key&gt;Port&lt;/key&gt;
+                    &lt;integer&gt;11211&lt;/integer&gt;
+                  &lt;/dict&gt;
+                  &lt;key&gt;ProxyDB&lt;/key&gt;
+                  &lt;dict&gt;
+                    &lt;key&gt;ClientEnabled&lt;/key&gt;
+                    &lt;true/&gt;
+                    &lt;key&gt;ServerEnabled&lt;/key&gt;
+                    &lt;true/&gt;
+                    &lt;key&gt;BindAddress&lt;/key&gt;
+                    &lt;string&gt;localhost&lt;/string&gt;
+                    &lt;key&gt;Port&lt;/key&gt;
+                    &lt;integer&gt;11311&lt;/integer&gt;
+                    &lt;key&gt;HandleCacheTypes&lt;/key&gt;
+                    &lt;array&gt;
+                      &lt;string&gt;ProxyDB&lt;/string&gt;
+                      &lt;string&gt;PrincipalToken&lt;/string&gt;
+                      &lt;string&gt;DIGESTCREDENTIALS&lt;/string&gt;
+                    &lt;/array&gt;
+                  &lt;/dict&gt;
+                &lt;/dict&gt;
+      &lt;key&gt;MaxClients&lt;/key&gt;
+      &lt;integer&gt;5&lt;/integer&gt;
+      &lt;key&gt;memcached&lt;/key&gt;
+      &lt;string&gt;../memcached/_root/bin/memcached&lt;/string&gt; &lt;!-- Find in PATH --&gt;
+      &lt;key&gt;Options&lt;/key&gt;
+      &lt;array&gt;
+        &lt;!--&lt;string&gt;-vv&lt;/string&gt;--&gt;
+      &lt;/array&gt;
+    &lt;/dict&gt;
+
+  &lt;/dict&gt;
+&lt;/plist&gt;
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfcaldavdtestpodBplistfromrev12016CalendarServertrunkconfcaldavdtestpodBplist"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test-podB.plist (from rev 12016, CalendarServer/trunk/conf/caldavd-test-podB.plist) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test-podB.plist                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test-podB.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,158 @@
</span><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
+
+&lt;!--
+    Copyright (c) 2006-2009 Apple Inc. 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.
+  --&gt;
+
+&lt;!DOCTYPE plist PUBLIC &quot;-//Apple Computer//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
+&lt;plist version=&quot;1.0&quot;&gt;
+  &lt;dict&gt;
+
+    &lt;!-- Import a parent config before this one --&gt;
+    &lt;key&gt;ImportConfig&lt;/key&gt;
+    &lt;string&gt;./conf/caldavd-test.plist&lt;/string&gt;
+
+    &lt;!-- HTTP port [0 = disable HTTP] --&gt;
+    &lt;key&gt;HTTPPort&lt;/key&gt;
+    &lt;integer&gt;8108&lt;/integer&gt;
+
+    &lt;!-- SSL port [0 = disable HTTPS] --&gt;
+    &lt;!-- (Must also configure SSLCertificate and SSLPrivateKey below) --&gt;
+    &lt;key&gt;SSLPort&lt;/key&gt;
+    &lt;integer&gt;8543&lt;/integer&gt;
+
+    &lt;!-- List of port numbers to bind to for HTTP [empty = same as &quot;Port&quot;] --&gt;
+    &lt;key&gt;BindHTTPPorts&lt;/key&gt;
+    &lt;array&gt;
+    &lt;/array&gt;
+
+    &lt;!-- List of port numbers to bind to for SSL [empty = same as &quot;SSLPort&quot;] --&gt;
+    &lt;key&gt;BindSSLPorts&lt;/key&gt;
+    &lt;array&gt;
+    &lt;/array&gt;
+
+    &lt;!-- Server root --&gt;
+    &lt;key&gt;ServerRoot&lt;/key&gt;
+    &lt;string&gt;./data/podB&lt;/string&gt;
+
+    &lt;!-- Configuration root --&gt;
+    &lt;key&gt;ConfigRoot&lt;/key&gt;
+    &lt;string&gt;./conf&lt;/string&gt;
+
+    &lt;!-- XML File Directory Service --&gt;
+    &lt;key&gt;DirectoryService&lt;/key&gt;
+    &lt;dict&gt;
+      &lt;key&gt;type&lt;/key&gt;
+      &lt;string&gt;twistedcaldav.directory.xmlfile.XMLDirectoryService&lt;/string&gt;
+      
+      &lt;key&gt;params&lt;/key&gt;
+      &lt;dict&gt;
+        &lt;key&gt;xmlFile&lt;/key&gt;
+        &lt;string&gt;./conf/auth/accounts-test-pod.xml&lt;/string&gt;
+      &lt;/dict&gt;
+    &lt;/dict&gt;
+    
+    &lt;!-- Resource and Location Service --&gt;
+    &lt;key&gt;ResourceService&lt;/key&gt;
+    &lt;dict&gt;
+      &lt;key&gt;Enabled&lt;/key&gt;
+      &lt;true/&gt;
+      &lt;key&gt;type&lt;/key&gt;
+      &lt;string&gt;twistedcaldav.directory.xmlfile.XMLDirectoryService&lt;/string&gt;
+      
+      &lt;key&gt;params&lt;/key&gt;
+      &lt;dict&gt;
+        &lt;key&gt;xmlFile&lt;/key&gt;
+        &lt;string&gt;./conf/auth/resources-test-pod.xml&lt;/string&gt;
+      &lt;/dict&gt;
+    &lt;/dict&gt;
+
+    &lt;!-- XML File Augment Service --&gt;
+    &lt;key&gt;AugmentService&lt;/key&gt;
+    &lt;dict&gt;
+      &lt;key&gt;type&lt;/key&gt;
+      &lt;string&gt;twistedcaldav.directory.augment.AugmentXMLDB&lt;/string&gt;
+      
+      &lt;key&gt;params&lt;/key&gt;
+      &lt;dict&gt;
+        &lt;key&gt;xmlFiles&lt;/key&gt;
+        &lt;array&gt;
+              &lt;string&gt;./conf/auth/augments-test-pod.xml&lt;/string&gt;
+        &lt;/array&gt;
+      &lt;/dict&gt;
+    &lt;/dict&gt;
+
+    &lt;key&gt;ProxyLoadFromFile&lt;/key&gt;
+    &lt;string&gt;./conf/auth/proxies-test-pod.xml&lt;/string&gt;
+
+    &lt;!--  Servers --&gt;
+    &lt;key&gt;Servers&lt;/key&gt;
+    &lt;dict&gt;
+            &lt;key&gt;Enabled&lt;/key&gt;
+            &lt;true/&gt;
+            &lt;key&gt;ConfigFile&lt;/key&gt;
+            &lt;string&gt;./conf/localservers-test.xml&lt;/string&gt;
+            &lt;key&gt;MaxClients&lt;/key&gt;
+            &lt;integer&gt;5&lt;/integer&gt;
+            &lt;key&gt;InboxName&lt;/key&gt;
+            &lt;string&gt;podding&lt;/string&gt;
+        &lt;/dict&gt;
+
+    &lt;!-- Support for Memcached --&gt;
+    &lt;key&gt;Memcached&lt;/key&gt;
+    &lt;dict&gt;
+          &lt;key&gt;Pools&lt;/key&gt;
+                &lt;dict&gt;
+                  &lt;key&gt;Default&lt;/key&gt;
+                  &lt;dict&gt;
+                    &lt;key&gt;ClientEnabled&lt;/key&gt;
+                    &lt;true/&gt;
+                    &lt;key&gt;ServerEnabled&lt;/key&gt;
+                    &lt;true/&gt;
+                    &lt;key&gt;BindAddress&lt;/key&gt;
+                    &lt;string&gt;localhost&lt;/string&gt;
+                    &lt;key&gt;Port&lt;/key&gt;
+                    &lt;integer&gt;11411&lt;/integer&gt;
+                  &lt;/dict&gt;
+                  &lt;key&gt;ProxyDB&lt;/key&gt;
+                  &lt;dict&gt;
+                    &lt;key&gt;ClientEnabled&lt;/key&gt;
+                    &lt;true/&gt;
+                    &lt;key&gt;ServerEnabled&lt;/key&gt;
+                    &lt;true/&gt;
+                    &lt;key&gt;BindAddress&lt;/key&gt;
+                    &lt;string&gt;localhost&lt;/string&gt;
+                    &lt;key&gt;Port&lt;/key&gt;
+                    &lt;integer&gt;11311&lt;/integer&gt;
+                    &lt;key&gt;HandleCacheTypes&lt;/key&gt;
+                    &lt;array&gt;
+                      &lt;string&gt;ProxyDB&lt;/string&gt;
+                      &lt;string&gt;PrincipalToken&lt;/string&gt;
+                      &lt;string&gt;DIGESTCREDENTIALS&lt;/string&gt;
+                    &lt;/array&gt;
+                  &lt;/dict&gt;
+                &lt;/dict&gt;
+      &lt;key&gt;MaxClients&lt;/key&gt;
+      &lt;integer&gt;5&lt;/integer&gt;
+      &lt;key&gt;memcached&lt;/key&gt;
+      &lt;string&gt;../memcached/_root/bin/memcached&lt;/string&gt; &lt;!-- Find in PATH --&gt;
+      &lt;key&gt;Options&lt;/key&gt;
+      &lt;array&gt;
+        &lt;!--&lt;string&gt;-vv&lt;/string&gt;--&gt;
+      &lt;/array&gt;
+    &lt;/dict&gt;
+
+  &lt;/dict&gt;
+&lt;/plist&gt;
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfcaldavdtestplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/caldavd-test.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -895,9 +895,10 @@
</span><span class="cx">     &lt;key&gt;EnableWebAdmin&lt;/key&gt;
</span><span class="cx">     &lt;true/&gt;
</span><span class="cx"> 
</span><del>-    &lt;!-- Support for Content-Encoding compression options as specified in RFC2616 Section 3.5 --&gt;
</del><ins>+    &lt;!-- Support for Content-Encoding compression --&gt;
</ins><span class="cx">     &lt;key&gt;ResponseCompression&lt;/key&gt;
</span><del>-    &lt;false/&gt;
</del><ins>+    &lt;false/&gt;  &lt;!-- Off for testing, as debugging is easier that way. --&gt;
+
</ins><span class="cx">     
</span><span class="cx">     &lt;!-- The retry-after value (in seconds) to return with a 503 error. --&gt;
</span><span class="cx">     &lt;key&gt;HTTPRetryAfter&lt;/key&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconflocalserverstestxml"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers-test.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers-test.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers-test.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,21 +16,19 @@
</span><span class="cx"> limitations under the License.
</span><span class="cx">  --&gt;
</span><span class="cx"> 
</span><del>-&lt;!DOCTYPE servers SYSTEM &quot;servers.dtd&quot;&gt;
</del><ins>+&lt;!DOCTYPE servers SYSTEM &quot;localservers.dtd&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;servers&gt;
</span><span class="cx">   &lt;server&gt;
</span><del>-    &lt;id&gt;00001&lt;/id&gt;
</del><ins>+    &lt;id&gt;A&lt;/id&gt;
</ins><span class="cx">     &lt;uri&gt;http://localhost:8008&lt;/uri&gt;
</span><del>-    &lt;partitions&gt;
-            &lt;partition&gt;
-                    &lt;id&gt;00001&lt;/id&gt;
-                    &lt;uri&gt;http://localhost:8008&lt;/uri&gt;
-            &lt;/partition&gt;
-            &lt;partition&gt;
-                    &lt;id&gt;00002&lt;/id&gt;
-                    &lt;uri&gt;http://localhost:8108&lt;/uri&gt;
-            &lt;/partition&gt;
-    &lt;/partitions&gt;
</del><ins>+    &lt;allowed-from&gt;localhost&lt;/allowed-from&gt;
+    &lt;shared-secret&gt;A&lt;/shared-secret&gt;
</ins><span class="cx">   &lt;/server&gt;
</span><ins>+  &lt;server&gt;
+    &lt;id&gt;B&lt;/id&gt;
+    &lt;uri&gt;http://localhost:8108&lt;/uri&gt;
+    &lt;allowed-from&gt;localhost&lt;/allowed-from&gt;
+    &lt;shared-secret&gt;B&lt;/shared-secret&gt;
+  &lt;/server&gt;
</ins><span class="cx"> &lt;/servers&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconflocalserversdtdfromrev12016CalendarServertrunkconflocalserversdtd"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers.dtd (from rev 12016, CalendarServer/trunk/conf/localservers.dtd) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers.dtd                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers.dtd        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,25 @@
</span><ins>+&lt;!--
+Copyright (c) 2011-2013 Apple Inc. 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.
+--&gt;
+
+&lt;!ELEMENT servers (server*) &gt;
+
+        &lt;!ELEMENT server (id, uri, allowed-from*, shared-secret?) &gt;
+                &lt;!ATTLIST server implicit (yes|no) &quot;yes&quot;&gt;
+
+                &lt;!ELEMENT id  (#PCDATA) &gt;
+                &lt;!ELEMENT uri (#PCDATA) &gt;
+                &lt;!ELEMENT allowed-from (#PCDATA) &gt;
+                &lt;!ELEMENT shared-secret (#PCDATA) &gt;
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconflocalserversxml"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/localservers.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx"> limitations under the License.
</span><span class="cx">  --&gt;
</span><span class="cx"> 
</span><del>-&lt;!DOCTYPE servers SYSTEM &quot;servers.dtd&quot;&gt;
</del><ins>+&lt;!DOCTYPE servers SYSTEM &quot;localservers.dtd&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;servers&gt;
</span><span class="cx">   &lt;!--
</span><span class="lines">@@ -30,16 +30,6 @@
</span><span class="cx">     &lt;allowed-from&gt;127.0.0.1&lt;/allowed-from&gt;
</span><span class="cx">     &lt;allowed-from&gt;example.local&lt;/allowed-from&gt;
</span><span class="cx">     &lt;shared-secret&gt;ABC&lt;/shared-secret&gt;
</span><del>-    &lt;partitions&gt;
-            &lt;partition&gt;
-                    &lt;id&gt;00001&lt;/id&gt;
-                    &lt;url&gt;https://machine1.example.com:8443&lt;/url&gt;
-            &lt;/partition&gt;
-            &lt;partition&gt;
-                    &lt;id&gt;00002&lt;/id&gt;
-                    &lt;url&gt;https://machine2.example.com:8443&lt;/url&gt;
-            &lt;/partition&gt;
-    &lt;/partitions&gt;
</del><span class="cx">   &lt;/server&gt;
</span><span class="cx">   --&gt;
</span><span class="cx"> &lt;/servers&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfremoteserverstestxml"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers-test.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers-test.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers-test.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx"> limitations under the License.
</span><span class="cx">  --&gt;
</span><span class="cx"> 
</span><del>-&lt;!DOCTYPE servers SYSTEM &quot;servertoserver.dtd&quot;&gt;
</del><ins>+&lt;!DOCTYPE servers SYSTEM &quot;remoteservers.dtd&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;servers&gt;
</span><span class="cx">   &lt;server&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfremoteserversdtdfromrev12016CalendarServertrunkconfremoteserversdtd"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers.dtd (from rev 12016, CalendarServer/trunk/conf/remoteservers.dtd) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers.dtd                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers.dtd        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+&lt;!--
+Copyright (c) 2006-2013 Apple Inc. 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.
+--&gt;
+
+&lt;!ELEMENT servers (server*) &gt;
+
+        &lt;!ELEMENT server (uri, authentication?, allow-requests-from, allow-requests-to, domains?, hosts?) &gt;
+
+                &lt;!ELEMENT uri (#PCDATA) &gt;
+                &lt;!ELEMENT authentication (user, password) &gt;
+                    &lt;!ATTLIST authentication type (basic) &quot;&quot;&gt;
+                    &lt;!ELEMENT user (#PCDATA) &gt;
+                    &lt;!ELEMENT password (#PCDATA) &gt;
+
+                &lt;!ELEMENT allow-requests-from EMPTY &gt;
+                &lt;!ELEMENT allow-requests-to EMPTY &gt;
+                &lt;!ELEMENT domains (domain*) &gt;
+                        &lt;!ELEMENT domain (#PCDATA) &gt;
+                &lt;!ELEMENT hosts (host*) &gt;
+                        &lt;!ELEMENT host (#PCDATA) &gt;
+                        
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfremoteserversxml"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/remoteservers.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx"> limitations under the License.
</span><span class="cx">  --&gt;
</span><span class="cx"> 
</span><del>-&lt;!DOCTYPE servers SYSTEM &quot;servertoserver.dtd&quot;&gt;
</del><ins>+&lt;!DOCTYPE servers SYSTEM &quot;remoteservers.dtd&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;servers&gt;
</span><span class="cx">   &lt;!--
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfresourcescaldavdresourcesplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/resources/caldavd-resources.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/resources/caldavd-resources.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/resources/caldavd-resources.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -174,7 +174,6 @@
</span><span class="cx">         Augments for the directory service records to add calendar specific attributes.
</span><span class="cx"> 
</span><span class="cx">         A variety of augment services are available for use.
</span><del>-        When using a partitioned server, a service that can be accessed from each host will be needed.
</del><span class="cx">       --&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;!-- XML File Augment Service --&gt;
</span><span class="lines">@@ -670,7 +669,7 @@
</span><span class="cx">     &lt;key&gt;EnableWebAdmin&lt;/key&gt;
</span><span class="cx">     &lt;true/&gt;
</span><span class="cx"> 
</span><del>-    &lt;!-- Support for Content-Encoding compression options as specified in RFC2616 Section 3.5 --&gt;
</del><ins>+    &lt;!-- Support for Content-Encoding compression --&gt;
</ins><span class="cx">     &lt;key&gt;ResponseCompression&lt;/key&gt;
</span><span class="cx">     &lt;false/&gt;
</span><span class="cx">     
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfserversdtd"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/servers.dtd (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/servers.dtd        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/servers.dtd        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,28 +0,0 @@
</span><del>-&lt;!--
-Copyright (c) 2011-2013 Apple Inc. 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.
---&gt;
-
-&lt;!ELEMENT servers (server*) &gt;
-
-        &lt;!ELEMENT server (id, uri, allowed-from*, shared-secret?, partitions?) &gt;
-                &lt;!ATTLIST server implicit (yes|no) &quot;yes&quot;&gt;
-
-                &lt;!ELEMENT id  (#PCDATA) &gt;
-                &lt;!ELEMENT uri (#PCDATA) &gt;
-                &lt;!ELEMENT allowed-from (#PCDATA) &gt;
-                &lt;!ELEMENT shared-secret (#PCDATA) &gt;
-
-                &lt;!ELEMENT partitions (partition*) &gt;
-                        &lt;!ELEMENT partition (id, uri) &gt;
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfservertoserverdtd"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/servertoserver.dtd (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/servertoserver.dtd        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/servertoserver.dtd        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,33 +0,0 @@
</span><del>-&lt;!--
-Copyright (c) 2006-2013 Apple Inc. 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.
---&gt;
-
-&lt;!ELEMENT servers (server*) &gt;
-
-        &lt;!ELEMENT server (uri, authentication?, allow-requests-from, allow-requests-to, domains?, hosts?) &gt;
-
-                &lt;!ELEMENT uri (#PCDATA) &gt;
-                &lt;!ELEMENT authentication (user, password) &gt;
-                    &lt;!ATTLIST authentication type (basic) &quot;&quot;&gt;
-                    &lt;!ELEMENT user (#PCDATA) &gt;
-                    &lt;!ELEMENT password (#PCDATA) &gt;
-
-                &lt;!ELEMENT allow-requests-from EMPTY &gt;
-                &lt;!ELEMENT allow-requests-to EMPTY &gt;
-                &lt;!ELEMENT domains (domain*) &gt;
-                        &lt;!ELEMENT domain (#PCDATA) &gt;
-                &lt;!ELEMENT hosts (host*) &gt;
-                        &lt;!ELEMENT host (#PCDATA) &gt;
-                        
</del><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixesconfsudoersplist"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/conf/sudoers.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/conf/sudoers.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/conf/sudoers.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,42 +0,0 @@
</span><del>-&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE plist PUBLIC &quot;-//Apple Computer//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
-&lt;plist version=&quot;1.0&quot;&gt;
-&lt;dict&gt;
-&lt;key&gt;users&lt;/key&gt;
-&lt;array&gt;
-&lt;!-- Sudo user definitions --&gt;
-&lt;!-- With the exception of username and password none of the following
-     elements are used in the current implementation. --&gt;
-&lt;!--
-  &lt;dict&gt;
-    &lt;key&gt;authorize-as&lt;/key&gt;
-    &lt;dict&gt;
-      &lt;key&gt;allow&lt;/key&gt;
-      &lt;true/&gt;
-      &lt;key&gt;principals&lt;/key&gt;
-      &lt;array&gt;
-        &lt;string&gt;all&lt;/string&gt;
-        &lt;string&gt;/principals/user/wsanchez&lt;/string&gt;
-      &lt;/array&gt;
-    &lt;/dict&gt;
-    &lt;key&gt;authorize-from&lt;/key&gt;
-    &lt;array&gt;
-      &lt;string&gt;127.0.0.1&lt;/string&gt;
-    &lt;/array&gt;
-
-    &lt;key&gt;username&lt;/key&gt;
-    &lt;string&gt;&lt;/string&gt;
-
-    &lt;key&gt;password&lt;/key&gt;
-    &lt;string&gt;&lt;/string&gt;
-  &lt;/dict&gt;
---&gt;
-  &lt;dict&gt;
-    &lt;key&gt;username&lt;/key&gt;
-    &lt;string&gt;superuser&lt;/string&gt;
-    &lt;key&gt;password&lt;/key&gt;
-    &lt;string&gt;superuser&lt;/string&gt;
-  &lt;/dict&gt;
-&lt;/array&gt;
-&lt;/dict&gt;
-&lt;/plist&gt;
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformanceloadtesticalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/ical.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/ical.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/ical.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -29,9 +29,9 @@
</span><span class="cx"> from contrib.performance.httpclient import StringProducer, readBody
</span><span class="cx"> from contrib.performance.loadtest.subscribe import Periodical
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twext.internet.adaptendpoint import connect
</span><span class="cx"> from twext.internet.gaiendpoint import GAIEndpoint
</span><span class="lines">@@ -1199,7 +1199,7 @@
</span><span class="cx">         connect(GAIEndpoint(self.reactor, host, port), factory)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def _receivedPush(self, inboundID, dataChangedTimestamp):
</del><ins>+    def _receivedPush(self, inboundID, dataChangedTimestamp, priority=5):
</ins><span class="cx">         for href, id in self.ampPushKeys.iteritems():
</span><span class="cx">             if inboundID == id:
</span><span class="cx">                 self._checkCalendarsForEvents(href, push=True)
</span><span class="lines">@@ -1609,13 +1609,13 @@
</span><span class="cx">             msg(&quot;Availability request spanning multiple days (%r to %r), &quot;
</span><span class="cx">                 &quot;dropping the end date.&quot; % (start, end))
</span><span class="cx"> 
</span><del>-        start.setTimezone(PyCalendarTimezone(utc=True))
</del><ins>+        start.setTimezone(Timezone(utc=True))
</ins><span class="cx">         start.setHHMMSS(0, 0, 0)
</span><del>-        end = start + PyCalendarDuration(hours=24)
</del><ins>+        end = start + Duration(hours=24)
</ins><span class="cx"> 
</span><span class="cx">         start = start.getText()
</span><span class="cx">         end = end.getText()
</span><del>-        now = PyCalendarDateTime.getNowUTC().getText()
</del><ins>+        now = DateTime.getNowUTC().getText()
</ins><span class="cx"> 
</span><span class="cx">         label_suffix = &quot;small&quot;
</span><span class="cx">         if len(users) &gt; 5:
</span><span class="lines">@@ -1919,7 +1919,7 @@
</span><span class="cx">         # the sim can fire a PUT between the PROPFIND and when process the removals.
</span><span class="cx">         old_hrefs = set([calendar.url + child for child in calendar.events.keys()])
</span><span class="cx"> 
</span><del>-        now = PyCalendarDateTime.getNowUTC()
</del><ins>+        now = DateTime.getNowUTC()
</ins><span class="cx">         now.setDateOnly(True)
</span><span class="cx">         now.offsetMonth(-1) # 1 month back default
</span><span class="cx">         result = yield self._report(
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformanceloadtestprofilespy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/profiles.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/profiles.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/profiles.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -42,8 +42,8 @@
</span><span class="cx"> from contrib.performance.loadtest.logger import SummarizingMixin
</span><span class="cx"> from contrib.performance.loadtest.ical import IncorrectResponseCode
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
</ins><span class="cx"> 
</span><span class="cx"> class ProfileBase(object):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -407,9 +407,9 @@
</span><span class="cx">             vevent = vcalendar.mainComponent()
</span><span class="cx">             uid = str(uuid4())
</span><span class="cx">             dtstart = self._eventStartDistribution.sample()
</span><del>-            dtend = dtstart + PyCalendarDuration(seconds=self._eventDurationDistribution.sample())
-            vevent.replaceProperty(Property(&quot;CREATED&quot;, PyCalendarDateTime.getNowUTC()))
-            vevent.replaceProperty(Property(&quot;DTSTAMP&quot;, PyCalendarDateTime.getNowUTC()))
</del><ins>+            dtend = dtstart + Duration(seconds=self._eventDurationDistribution.sample())
+            vevent.replaceProperty(Property(&quot;CREATED&quot;, DateTime.getNowUTC()))
+            vevent.replaceProperty(Property(&quot;DTSTAMP&quot;, DateTime.getNowUTC()))
</ins><span class="cx">             vevent.replaceProperty(Property(&quot;DTSTART&quot;, dtstart))
</span><span class="cx">             vevent.replaceProperty(Property(&quot;DTEND&quot;, dtend))
</span><span class="cx">             vevent.replaceProperty(Property(&quot;UID&quot;, uid))
</span><span class="lines">@@ -650,9 +650,9 @@
</span><span class="cx">             vevent = vcalendar.mainComponent()
</span><span class="cx">             uid = str(uuid4())
</span><span class="cx">             dtstart = self._eventStartDistribution.sample()
</span><del>-            dtend = dtstart + PyCalendarDuration(seconds=self._eventDurationDistribution.sample())
-            vevent.replaceProperty(Property(&quot;CREATED&quot;, PyCalendarDateTime.getNowUTC()))
-            vevent.replaceProperty(Property(&quot;DTSTAMP&quot;, PyCalendarDateTime.getNowUTC()))
</del><ins>+            dtend = dtstart + Duration(seconds=self._eventDurationDistribution.sample())
+            vevent.replaceProperty(Property(&quot;CREATED&quot;, DateTime.getNowUTC()))
+            vevent.replaceProperty(Property(&quot;DTSTAMP&quot;, DateTime.getNowUTC()))
</ins><span class="cx">             vevent.replaceProperty(Property(&quot;DTSTART&quot;, dtstart))
</span><span class="cx">             vevent.replaceProperty(Property(&quot;DTEND&quot;, dtend))
</span><span class="cx">             vevent.replaceProperty(Property(&quot;UID&quot;, uid))
</span><span class="lines">@@ -719,8 +719,8 @@
</span><span class="cx">             vtodo = vcalendar.mainComponent()
</span><span class="cx">             uid = str(uuid4())
</span><span class="cx">             due = self._taskStartDistribution.sample()
</span><del>-            vtodo.replaceProperty(Property(&quot;CREATED&quot;, PyCalendarDateTime.getNowUTC()))
-            vtodo.replaceProperty(Property(&quot;DTSTAMP&quot;, PyCalendarDateTime.getNowUTC()))
</del><ins>+            vtodo.replaceProperty(Property(&quot;CREATED&quot;, DateTime.getNowUTC()))
+            vtodo.replaceProperty(Property(&quot;DTSTAMP&quot;, DateTime.getNowUTC()))
</ins><span class="cx">             vtodo.replaceProperty(Property(&quot;DUE&quot;, due))
</span><span class="cx">             vtodo.replaceProperty(Property(&quot;UID&quot;, uid))
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformanceloadtestsimpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/sim.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/sim.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/sim.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -346,6 +346,7 @@
</span><span class="cx">         if 'serverStats' in config:
</span><span class="cx">             if config['serverStats']['enabled']:
</span><span class="cx">                 serverStats = config['serverStats']
</span><ins>+                serverStats['server'] = config['server'] if 'server' in config else ''
</ins><span class="cx"> 
</span><span class="cx">         observers = []
</span><span class="cx">         if 'observers' in config:
</span><span class="lines">@@ -483,7 +484,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         if self.serverStats is not None:
</span><del>-            _ignore_scheme, hostname, _ignore_path, _ignore_query, _ignore_fragment = urlsplit(self.server)
</del><ins>+            _ignore_scheme, hostname, _ignore_path, _ignore_query, _ignore_fragment = urlsplit(self.serverStats[&quot;server&quot;])
</ins><span class="cx">             data = self.readStatsSock((hostname.split(&quot;:&quot;)[0], self.serverStats[&quot;Port&quot;],), True)
</span><span class="cx">             if &quot;Failed&quot; not in data:
</span><span class="cx">                 data = data[&quot;5 Minutes&quot;]
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformanceloadtesttest_icalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/test_ical.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/test_ical.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/loadtest/test_ical.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -24,8 +24,8 @@
</span><span class="cx"> from contrib.performance.loadtest.ical import XMPPPush, Event, Calendar, OS_X_10_6
</span><span class="cx"> from contrib.performance.loadtest.sim import _DirectoryRecord
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twisted.internet.defer import Deferred, inlineCallbacks, returnValue
</span><span class="cx"> from twisted.internet.protocol import ProtocolToConsumerAdapter
</span><span class="lines">@@ -1957,8 +1957,8 @@
</span><span class="cx">         self.client.outbox = &quot;/calendars/__uids__/%s/outbox/&quot; % (self.record.uid,)
</span><span class="cx">         requests = self.interceptRequests()
</span><span class="cx"> 
</span><del>-        start = PyCalendarDateTime(2011, 6, 10, 10, 45, 0, tzid=PyCalendarTimezone(utc=True))
-        end = PyCalendarDateTime(2011, 6, 10, 11, 15, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        start = DateTime(2011, 6, 10, 10, 45, 0, tzid=Timezone(utc=True))
+        end = DateTime(2011, 6, 10, 11, 15, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         d = self.client.requestAvailability(
</span><span class="cx">             start, end, [u&quot;urn:uuid:user05&quot;, u&quot;urn:uuid:user10&quot;])
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformancesqlusagerequestsinvitepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/invite.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/invite.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/invite.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx"> 
</span><span class="cx"> from caldavclientlibrary.protocol.url import URL
</span><span class="cx"> from contrib.performance.sqlusage.requests.httpTests import HTTPTestBase
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> from twext.web2.dav.util import joinURL
</span><span class="cx"> from caldavclientlibrary.protocol.webdav.definitions import davxml
</span><span class="cx"> 
</span><span class="lines">@@ -67,7 +67,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Invite as user02
</span><del>-        now = PyCalendarDateTime.getNowUTC()
</del><ins>+        now = DateTime.getNowUTC()
</ins><span class="cx">         href = joinURL(self.sessions[1].calendarHref, &quot;organizer.ics&quot;)
</span><span class="cx">         self.sessions[1].writeData(URL(path=href), ICAL % (now.getYear() + 1,), &quot;text/calendar&quot;)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformancesqlusagerequestsputpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/put.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/put.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/put.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx"> 
</span><span class="cx"> from caldavclientlibrary.protocol.url import URL
</span><span class="cx"> from contrib.performance.sqlusage.requests.httpTests import HTTPTestBase
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> from twext.web2.dav.util import joinURL
</span><span class="cx"> 
</span><span class="cx"> ICAL = &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="lines">@@ -62,7 +62,7 @@
</span><span class="cx">         Execute the actual HTTP request.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        now = PyCalendarDateTime.getNowUTC()
</del><ins>+        now = DateTime.getNowUTC()
</ins><span class="cx">         href = joinURL(self.sessions[0].calendarHref, &quot;put.ics&quot;)
</span><span class="cx">         self.sessions[0].writeData(URL(path=href), ICAL % (now.getYear() + 1,), &quot;text/calendar&quot;)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformancesqlusagerequestsquerypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/query.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/query.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/query.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> from caldavclientlibrary.protocol.webdav.definitions import davxml, statuscodes
</span><span class="cx"> from contrib.performance.sqlusage.requests.httpTests import HTTPTestBase
</span><span class="cx"> from twext.web2.dav.util import joinURL
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> from caldavclientlibrary.protocol.caldav.query import QueryVEVENTTimeRange
</span><span class="cx"> from caldavclientlibrary.protocol.http.data.string import ResponseDataString
</span><span class="cx"> 
</span><span class="lines">@@ -70,7 +70,7 @@
</span><span class="cx">         Do some setup prior to the real request.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         # Add resources to create required number of changes
</span><del>-        self.start = PyCalendarDateTime.getNowUTC()
</del><ins>+        self.start = DateTime.getNowUTC()
</ins><span class="cx">         self.start.setHHMMSS(12, 0, 0)
</span><span class="cx">         self.end = self.start.duplicate()
</span><span class="cx">         self.end.offsetHours(1)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformancesqlusagerequestssyncpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/sync.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/sync.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/requests/sync.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> from caldavclientlibrary.protocol.webdav.definitions import davxml
</span><span class="cx"> from contrib.performance.sqlusage.requests.httpTests import HTTPTestBase
</span><span class="cx"> from twext.web2.dav.util import joinURL
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> ICAL = &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> CALSCALE:GREGORIAN
</span><span class="lines">@@ -75,7 +75,7 @@
</span><span class="cx">             self.synctoken = results[davxml.sync_token]
</span><span class="cx"> 
</span><span class="cx">             # Add resources to create required number of changes
</span><del>-            now = PyCalendarDateTime.getNowUTC()
</del><ins>+            now = DateTime.getNowUTC()
</ins><span class="cx">             for i in range(self.count):
</span><span class="cx">                 href = joinURL(self.sessions[0].calendarHref, &quot;sync-collection-%d.ics&quot; % (i + 1,))
</span><span class="cx">                 self.sessions[0].writeData(URL(path=href), ICAL % (now.getYear() + 1, i + 1,), &quot;text/calendar&quot;)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformancesqlusagesqlusagepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/sqlusage.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/sqlusage.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/sqlusage/sqlusage.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -27,7 +27,7 @@
</span><span class="cx"> from contrib.performance.sqlusage.requests.put import PutTest
</span><span class="cx"> from contrib.performance.sqlusage.requests.query import QueryTest
</span><span class="cx"> from contrib.performance.sqlusage.requests.sync import SyncTest
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> from twext.web2.dav.util import joinURL
</span><span class="cx"> import getopt
</span><span class="cx"> import itertools
</span><span class="lines">@@ -183,7 +183,7 @@
</span><span class="cx">         @param n: number of events
</span><span class="cx">         @type n: C{int}
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        now = PyCalendarDateTime.getNowUTC()
</del><ins>+        now = DateTime.getNowUTC()
</ins><span class="cx">         for i in range(n - self.currentCount):
</span><span class="cx">             index = self.currentCount + i + 1
</span><span class="cx">             href = joinURL(calendarhref, &quot;%d.ics&quot; % (index,))
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformancestatspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/stats.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/stats.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/stats.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,10 +16,10 @@
</span><span class="cx"> 
</span><span class="cx"> from __future__ import print_function
</span><span class="cx"> from math import log, sqrt
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.property import PyCalendarProperty
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration as PyDuration
+from pycalendar.icalendar.property import Property
+from pycalendar.timezone import Timezone
</ins><span class="cx"> from twisted.python.util import FancyEqMixin
</span><span class="cx"> from zope.interface import Interface, implements
</span><span class="cx"> import random
</span><span class="lines">@@ -338,7 +338,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def sample(self):
</span><del>-        now = PyCalendarDateTime.getNowUTC()
</del><ins>+        now = DateTime.getNowUTC()
</ins><span class="cx">         now.offsetSeconds(int(self._offset.sample()))
</span><span class="cx">         return now
</span><span class="cx"> 
</span><span class="lines">@@ -390,7 +390,7 @@
</span><span class="cx">             60 * 60 * 8 * 6,
</span><span class="cx">             # Standard deviation of 4 workdays
</span><span class="cx">             60 * 60 * 8 * 4)
</span><del>-        self.now = PyCalendarDateTime.getNow
</del><ins>+        self.now = DateTime.getNow
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def astimestamp(self, dt):
</span><span class="lines">@@ -406,7 +406,7 @@
</span><span class="cx">         # Find a workday that follows the timestamp
</span><span class="cx">         weekday = when.getDayOfWeek()
</span><span class="cx">         for i in range(NUM_WEEKDAYS):
</span><del>-            day = when + PyCalendarDuration(days=i)
</del><ins>+            day = when + PyDuration(days=i)
</ins><span class="cx">             if (weekday + i) % NUM_WEEKDAYS in self._daysOfWeek:
</span><span class="cx">                 # Joy, a day on which work might occur.  Find the first hour on
</span><span class="cx">                 # this day when work may start.
</span><span class="lines">@@ -419,8 +419,8 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def sample(self):
</span><del>-        offset = PyCalendarDuration(seconds=int(self._helperDistribution.sample()))
-        beginning = self.now(PyCalendarTimezone(tzid=self._tzname))
</del><ins>+        offset = PyDuration(seconds=int(self._helperDistribution.sample()))
+        beginning = self.now(Timezone(tzid=self._tzname))
</ins><span class="cx">         while offset:
</span><span class="cx">             start, end = self._findWorkAfter(beginning)
</span><span class="cx">             if end - start &gt; offset:
</span><span class="lines">@@ -463,8 +463,7 @@
</span><span class="cx">             index = self._helperDistribution.sample()
</span><span class="cx">             rrule = self._rrules[index]
</span><span class="cx">             if rrule:
</span><del>-                prop = PyCalendarProperty()
-                prop.parse(rrule)
</del><ins>+                prop = Property.parseText(rrule)
</ins><span class="cx">                 return prop
</span><span class="cx"> 
</span><span class="cx">         return None
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribperformancetest_statspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/test_stats.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/test_stats.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/performance/test_stats.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -20,8 +20,8 @@
</span><span class="cx">     SQLDuration, LogNormalDistribution, UniformDiscreteDistribution,
</span><span class="cx">     UniformIntegerDistribution, WorkDistribution, quantize,
</span><span class="cx">     RecurrenceDistribution)
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> class SQLDurationTests(TestCase):
</span><span class="cx">     def setUp(self):
</span><span class="lines">@@ -90,21 +90,21 @@
</span><span class="cx">         tzname = &quot;US/Eastern&quot;
</span><span class="cx">         dist = WorkDistribution([&quot;mon&quot;, &quot;wed&quot;, &quot;thu&quot;, &quot;sat&quot;], 10, 20, tzname)
</span><span class="cx">         dist._helperDistribution = UniformDiscreteDistribution([35 * 60 * 60 + 30 * 60])
</span><del>-        dist.now = lambda tzname = None: PyCalendarDateTime(2011, 5, 29, 18, 5, 36, tzid=tzname)
</del><ins>+        dist.now = lambda tzname = None: DateTime(2011, 5, 29, 18, 5, 36, tzid=tzname)
</ins><span class="cx">         value = dist.sample()
</span><span class="cx">         self.assertEqual(
</span><span class="cx">             # Move past three workdays - monday, wednesday, thursday - using 30
</span><span class="cx">             # of the hours, and then five and a half hours into the fourth
</span><span class="cx">             # workday, saturday.  Workday starts at 10am, so the sample value
</span><span class="cx">             # is 3:30pm, ie 1530 hours.
</span><del>-            PyCalendarDateTime(2011, 6, 4, 15, 30, 0, tzid=PyCalendarTimezone(tzid=tzname)),
</del><ins>+            DateTime(2011, 6, 4, 15, 30, 0, tzid=Timezone(tzid=tzname)),
</ins><span class="cx">             value
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         dist = WorkDistribution([&quot;mon&quot;, &quot;tue&quot;, &quot;wed&quot;, &quot;thu&quot;, &quot;fri&quot;], 10, 20, tzname)
</span><span class="cx">         dist._helperDistribution = UniformDiscreteDistribution([35 * 60 * 60 + 30 * 60])
</span><span class="cx">         value = dist.sample()
</span><del>-        self.assertTrue(isinstance(value, PyCalendarDateTime))
</del><ins>+        self.assertTrue(isinstance(value, DateTime))
</ins><span class="cx"> 
</span><span class="cx">     # twisted.trial.unittest.FailTest: not equal:
</span><span class="cx">     # a = datetime.datetime(2011, 6, 4, 15, 30, tzinfo=&lt;DstTzInfo 'US/Eastern' EST-1 day, 19:00:00 STD&gt;)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribtoolsrequest_monitorpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/tools/request_monitor.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/tools/request_monitor.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/tools/request_monitor.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -303,8 +303,6 @@
</span><span class="cx">     print(&quot;--procs N  specifies how many python processes are expected in the log file (default: 80)&quot;)
</span><span class="cx">     print(&quot;--top N    how many long requests to print (default: 10)&quot;)
</span><span class="cx">     print(&quot;--users N  how many top users to print (default: 5)&quot;)
</span><del>-    print(&quot;--router   analyze a partition server router node&quot;)
-    print(&quot;--worker   analyze a partition server worker node&quot;)
</del><span class="cx">     print(&quot;&quot;)
</span><span class="cx">     print(&quot;Version: 5&quot;)
</span><span class="cx"> 
</span><span class="lines">@@ -313,19 +311,13 @@
</span><span class="cx"> numTop = 10
</span><span class="cx"> numUsers = 5
</span><span class="cx"> lineRange = None
</span><del>-router = False
-worker = False
-options, args = getopt.getopt(sys.argv[1:], &quot;h&quot;, [&quot;debug&quot;, &quot;router&quot;, &quot;worker&quot;, &quot;lines=&quot;, &quot;range=&quot;, &quot;procs=&quot;, &quot;top=&quot;, &quot;users=&quot;])
</del><ins>+options, args = getopt.getopt(sys.argv[1:], &quot;h&quot;, [&quot;debug&quot;, &quot;lines=&quot;, &quot;range=&quot;, &quot;procs=&quot;, &quot;top=&quot;, &quot;users=&quot;])
</ins><span class="cx"> for option, value in options:
</span><span class="cx">     if option == &quot;-h&quot;:
</span><span class="cx">         usage()
</span><span class="cx">         sys.exit(0)
</span><span class="cx">     elif option == &quot;--debug&quot;:
</span><span class="cx">         debug = True
</span><del>-    elif option == &quot;--router&quot;:
-        router = True
-    elif option == &quot;--worker&quot;:
-        worker = True
</del><span class="cx">     elif option == &quot;--lines&quot;:
</span><span class="cx">         numLines = int(value)
</span><span class="cx">     elif option == &quot;--range&quot;:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixescontribtoolssortrecurrencespy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/tools/sortrecurrences.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/tools/sortrecurrences.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/contrib/tools/sortrecurrences.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -20,7 +20,7 @@
</span><span class="cx"> import os
</span><span class="cx"> import sys
</span><span class="cx"> import traceback
</span><del>-from pycalendar.calendar import PyCalendar
</del><ins>+from pycalendar.icalendar.calendar import Calendar
</ins><span class="cx"> 
</span><span class="cx"> def usage(error_msg=None):
</span><span class="cx">     if error_msg:
</span><span class="lines">@@ -72,7 +72,7 @@
</span><span class="cx">                 print(&quot;Path does not exist: '%s'. Ignoring.&quot; % (arg,))
</span><span class="cx">                 continue
</span><span class="cx"> 
</span><del>-            cal = PyCalendar()
</del><ins>+            cal = Calendar()
</ins><span class="cx">             cal.parse(open(arg))
</span><span class="cx">             print(str(cal.serialize()))
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixessetuppy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/setup.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/setup.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/setup.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -145,7 +145,6 @@
</span><span class="cx">                              &quot;bin/calendarserver_export&quot;,
</span><span class="cx">                             #&quot;bin/calendarserver_icalendar_validate&quot;,
</span><span class="cx">                             #&quot;bin/calendarserver_load_augmentdb&quot;,
</span><del>-                            #&quot;bin/calendarserver_make_partition&quot;,
</del><span class="cx">                             #&quot;bin/calendarserver_manage_postgres&quot;,
</span><span class="cx">                              &quot;bin/calendarserver_manage_principals&quot;,
</span><span class="cx">                              &quot;bin/calendarserver_manage_push&quot;,
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixessupportbuildsh"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/support/build.sh (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/support/build.sh        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/support/build.sh        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -40,11 +40,67 @@
</span><span class="cx">   fi;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Checks for presence of a C header, optionally with a version comparison.
+# With only a header file name, try to include it, returning nonzero if absent.
+# With 3 params, also attempt a version check, returning nonzero if too old.
+# Param 2 is a minimum acceptable version number
+# Param 3 is a #define from the source that holds the installed version number
+# Examples:
+#   Assert that ldap.h is present
+#     find_header &quot;ldap.h&quot;
+#   Assert that ldap.h is present with a version &gt;= 20344
+#     find_header &quot;ldap.h&quot; 20344 &quot;LDAP_VENDOR_VERSION&quot;
</ins><span class="cx"> find_header () {
</span><del>-  local sysheader=&quot;$1&quot;; shift;
-  echo &quot;#include &lt;${sysheader}&gt;&quot; | cc -x c -c - -o /dev/null 2&gt; /dev/null;
-  return &quot;$?&quot;;
-}
</del><ins>+  ARGS=&quot;$@&quot;;
+  ret=1;  # default to a failed check, forcing a fetch of the depencency
+  i=0;
+  for a in $ARGS; do
+    [ $i -eq 0 ] &amp;&amp; local sysheader=&quot;$1&quot;;
+    [ $i -eq 1 ] &amp;&amp; local minver=&quot;$2&quot;;
+    [ $i -eq 2 ] &amp;&amp; local def=&quot;$3&quot;;
+    i=$(($i+1));
+  done;
+  [ ! $sysheader ] &amp;&amp; return 1;
+  # Check for presence of a header. We use the &quot;-c&quot; cc option because we don't
+  # need to emit a file; cc exits nonzero if it can't find the header
+  if [ $# -lt 2 ]; then
+    echo &quot;#include &lt;${sysheader}&gt;&quot; | cc -x c -c - -o /dev/null 2&gt; /dev/null;
+    return &quot;$?&quot;;
+  # Check for presence of a header of specified version
+  else
+    found='';
+    local aout=$(mktemp -t ccXXXXXX); # compiled executable file path
+    local prog=$(mktemp -t ccXXXXXX); # C source file path
+    cat &lt;&lt;DOC &gt; ${prog}
+#include &lt;${sysheader}&gt;
+#include &lt;stdio.h&gt;
+#define STR(x)   #x
+#define SHOW_DEFINE(x) printf(&quot;%s&quot;, STR(x))
+int main()
+{
+    if (${def})
+    {
+        SHOW_DEFINE(${def});
+        return 0;
+    };
+    return 1;
+};
+DOC
+    cc -x c -o ${aout} ${prog} &amp;&gt; /dev/null;
+    if [ $? -eq 0 ] &amp;&amp; [ -e ${aout} ] ; then
+      found=$(${aout});
+    fi;
+    if [ $? -eq 0 ] &amp;&amp; [ ! -z ${found} ] ; then
+      cmp_version $minver $found;
+      ret=$?;
+    else
+      ret=1;   #cc exited nonzero or didn't emit a file
+    fi;
+    rm -f &quot;${aout}&quot;;
+    rm -f &quot;${prog}&quot;;
+  fi;
+  return $ret;
+};
</ins><span class="cx"> 
</span><span class="cx"> # Initialize all the global state required to use this library.
</span><span class="cx"> init_build () {
</span><span class="lines">@@ -213,10 +269,13 @@
</span><span class="cx">   if &quot;${force_setup}&quot; || [ ! -d &quot;${path}&quot; ]; then
</span><span class="cx">     local ext=&quot;$(echo &quot;${url}&quot; | sed 's|^.*\.\([^.]*\)$|\1|')&quot;;
</span><span class="cx"> 
</span><ins>+    untar () { tar -xvf -; }
+    unzipstream () { tmp=&quot;$(mktemp -t ccsXXXXX)&quot;; cat &gt; &quot;${tmp}&quot;; unzip &quot;${tmp}&quot;; rm &quot;${tmp}&quot;; }
</ins><span class="cx">     case &quot;${ext}&quot; in
</span><del>-      gz|tgz) decompress=&quot;gzip -d -c&quot;; ;;
-      bz2)    decompress=&quot;bzip2 -d -c&quot;; ;;
-      tar)    decompress=&quot;cat&quot;; ;;
</del><ins>+      gz|tgz) decompress=&quot;gzip -d -c&quot;; unpack=&quot;untar&quot;; ;;
+      bz2)    decompress=&quot;bzip2 -d -c&quot;; unpack=&quot;untar&quot;; ;;
+      tar)    decompress=&quot;untar&quot;; unpack=&quot;untar&quot;; ;;
+      zip)    decompress=&quot;cat&quot;; unpack=&quot;unzipstream&quot;; ;;
</ins><span class="cx">       *)
</span><span class="cx">         echo &quot;Error in www_get of URL ${url}: Unknown extension ${ext}&quot;;
</span><span class="cx">         exit 1;
</span><span class="lines">@@ -228,7 +287,7 @@
</span><span class="cx">     if [ -n &quot;${cache_deps}&quot; ] &amp;&amp; [ -n &quot;${hash}&quot; ]; then
</span><span class="cx">       mkdir -p &quot;${cache_deps}&quot;;
</span><span class="cx"> 
</span><del>-      local cache_basename=&quot;${name}-$(echo &quot;${url}&quot; | hash)-$(basename &quot;${url}&quot;)&quot;;
</del><ins>+      local cache_basename=&quot;$(echo ${name} | tr '[ ]' '_')-$(echo &quot;${url}&quot; | hash)-$(basename &quot;${url}&quot;)&quot;;
</ins><span class="cx">       local cache_file=&quot;${cache_deps}/${cache_basename}&quot;;
</span><span class="cx"> 
</span><span class="cx">       check_hash () {
</span><span class="lines">@@ -327,7 +386,7 @@
</span><span class="cx"> 
</span><span class="cx">     rm -rf &quot;${path}&quot;;
</span><span class="cx">     cd &quot;$(dirname &quot;${path}&quot;)&quot;;
</span><del>-    get | ${decompress} | tar -xvf -;
</del><ins>+    get | ${decompress} | ${unpack};
</ins><span class="cx">     apply_patches &quot;${name}&quot; &quot;${path}&quot;;
</span><span class="cx">     cd /;
</span><span class="cx">   fi;
</span><span class="lines">@@ -670,12 +729,12 @@
</span><span class="cx">   if type -P memcached &gt; /dev/null; then
</span><span class="cx">     using_system &quot;memcached&quot;;
</span><span class="cx">   else
</span><del>-    local le=&quot;libevent-2.0.17-stable&quot;;
-    local mc=&quot;memcached-1.4.13&quot;;
-    c_dependency -m &quot;dad64aaaaff16b5fbec25160c06fee9a&quot; \
</del><ins>+    local le=&quot;libevent-2.0.21-stable&quot;;
+    local mc=&quot;memcached-1.4.15&quot;;
+    c_dependency -m &quot;b2405cc9ebf264aa47ff615d9de527a2&quot; \
</ins><span class="cx">       &quot;libevent&quot; &quot;${le}&quot; \
</span><del>-      &quot;https://github.com/downloads/libevent/libevent/${le}.tar.gz&quot;;
-    c_dependency -m &quot;6d18c6d25da945442fcc1187b3b63b7f&quot; \
</del><ins>+      &quot;http://github.com/downloads/libevent/libevent/${le}.tar.gz&quot;;
+    c_dependency -m &quot;36ea966f5a29655be1746bf4949f7f69&quot; \
</ins><span class="cx">       &quot;memcached&quot; &quot;${mc}&quot; \
</span><span class="cx">       &quot;http://memcached.googlecode.com/files/${mc}.tar.gz&quot;;
</span><span class="cx">   fi;
</span><span class="lines">@@ -683,8 +742,9 @@
</span><span class="cx">   if type -P postgres &gt; /dev/null; then
</span><span class="cx">     using_system &quot;Postgres&quot;;
</span><span class="cx">   else
</span><del>-    local pgv=&quot;9.2.4&quot;;
-    local pg=&quot;postgresql-${pgv}&quot;;
</del><ins>+    local v=&quot;9.3.1&quot;;
+    local n=&quot;postgresql&quot;;
+    local p=&quot;${n}-${v}&quot;;
</ins><span class="cx"> 
</span><span class="cx">     if type -P dtrace &gt; /dev/null; then
</span><span class="cx">       local enable_dtrace=&quot;--enable-dtrace&quot;;
</span><span class="lines">@@ -692,19 +752,22 @@
</span><span class="cx">       local enable_dtrace=&quot;&quot;;
</span><span class="cx">     fi;
</span><span class="cx"> 
</span><del>-    c_dependency -m &quot;52df0a9e288f02d7e6e0af89ed4dcfc6&quot; \
-      &quot;PostgreSQL&quot; &quot;${pg}&quot; \
-      &quot;ftp://ftp5.us.postgresql.org/pub/PostgreSQL/source/v${pgv}/${pg}.tar.gz&quot; \
</del><ins>+    c_dependency -m &quot;c003d871f712d4d3895956b028a96e74&quot; \
+      &quot;PostgreSQL&quot; &quot;${p}&quot; \
+      &quot;http://ftp.postgresql.org/pub/source/v${v}/${p}.tar.bz2&quot; \
</ins><span class="cx">       --with-python ${enable_dtrace};
</span><span class="cx">     :;
</span><span class="cx">   fi;
</span><span class="cx"> 
</span><del>-  if find_header ldap.h; then
</del><ins>+  if find_header ldap.h 20428 LDAP_VENDOR_VERSION; then
</ins><span class="cx">     using_system &quot;OpenLDAP&quot;;
</span><span class="cx">   else
</span><del>-    c_dependency -m &quot;ec63f9c2add59f323a0459128846905b&quot; \
-      &quot;OpenLDAP&quot; &quot;openldap-2.4.25&quot; \
-      &quot;http://www.openldap.org/software/download/OpenLDAP/openldap-release/openldap-2.4.25.tgz&quot; \
</del><ins>+    local v=&quot;2.4.38&quot;;
+    local n=&quot;openldap&quot;;
+    local p=&quot;${n}-${v}&quot;;
+    c_dependency -m &quot;39831848c731bcaef235a04e0d14412f&quot; \
+      &quot;OpenLDAP&quot; &quot;${p}&quot; \
+      &quot;http://www.openldap.org/software/download/OpenLDAP/${n}-release/${p}.tgz&quot; \
</ins><span class="cx">       --disable-bdb --disable-hdb;
</span><span class="cx">   fi;
</span><span class="cx"> 
</span><span class="lines">@@ -726,24 +789,24 @@
</span><span class="cx"> 
</span><span class="cx">   # Sourceforge mirror hostname.
</span><span class="cx">   local sf=&quot;superb-sea2.dl.sourceforge.net&quot;;
</span><del>-  local st=&quot;setuptools-0.6c11&quot;;
</del><ins>+  local st=&quot;setuptools-1.4&quot;;
</ins><span class="cx">   local pypi=&quot;http://pypi.python.org/packages/source&quot;;
</span><span class="cx"> 
</span><del>-  py_dependency -m &quot;7df2a529a074f613b509fb44feefe74e&quot; \
</del><ins>+  py_dependency -v 1 -m &quot;5710464bc5a61d75f5087f15ce63cfe0&quot; \
</ins><span class="cx">     &quot;setuptools&quot; &quot;setuptools&quot; &quot;${st}&quot; \
</span><span class="cx">     &quot;$pypi/s/setuptools/${st}.tar.gz&quot;;
</span><span class="cx"> 
</span><del>-  local v=&quot;4.0.3&quot;;
</del><ins>+  local v=&quot;4.0.5&quot;;
</ins><span class="cx">   local n=&quot;zope.interface&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -v 4 -m &quot;1ddd308f2c83703accd1696158c300eb&quot; \
</del><ins>+  py_dependency -v 4 -m &quot;caf26025ae1b02da124a58340e423dfe&quot; \
</ins><span class="cx">     &quot;Zope Interface&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><del>-    &quot;http://pypi.python.org/packages/source/z/${n}/${p}.tar.gz&quot;;
</del><ins>+    &quot;http://pypi.python.org/packages/source/z/${n}/${p}.zip&quot;;
</ins><span class="cx"> 
</span><del>-  local v=&quot;0.10&quot;;
</del><ins>+  local v=&quot;0.12&quot;;
</ins><span class="cx">   local n=&quot;pyOpenSSL&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -v 0.9 -m &quot;34db8056ec53ce80c7f5fc58bee9f093&quot; \
</del><ins>+  py_dependency -v 0.12 -m &quot;60a7bbb6160950823eddcbba2cbcb0d6&quot; \
</ins><span class="cx">     &quot;${n}&quot; &quot;OpenSSL&quot; &quot;${p}&quot; \
</span><span class="cx">     &quot;http://pypi.python.org/packages/source/p/${n}/${p}.tar.gz&quot;;
</span><span class="cx"> 
</span><span class="lines">@@ -754,18 +817,18 @@
</span><span class="cx">       &quot;${svn_uri_base}/${n}/trunk&quot;;
</span><span class="cx">   fi;
</span><span class="cx"> 
</span><del>-  local v=&quot;0.6.1&quot;;
</del><ins>+  local v=&quot;0.6.4&quot;;
</ins><span class="cx">   local n=&quot;xattr&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -v 0.5 -r 1038 \
-    &quot;${n}&quot; &quot;${n}&quot; &quot;${n}&quot; \
-    &quot;http://svn.red-bean.com/bob/${n}/releases/${p}/&quot;;
</del><ins>+  py_dependency -v 0.6 -m &quot;1bef31afb7038800f8d5cfa2f4562b37&quot; \
+    &quot;${n}&quot; &quot;${n}&quot; &quot;${p}&quot; \
+    &quot;${pypi}/x/${n}/${n}-${v}.tar.gz&quot;;
</ins><span class="cx"> 
</span><span class="cx">   if [ -n &quot;${ORACLE_HOME:-}&quot; ]; then
</span><del>-    local v=&quot;5.1&quot;;
</del><ins>+    local v=&quot;5.1.2&quot;;
</ins><span class="cx">     local n=&quot;cx_Oracle&quot;;
</span><span class="cx">     local p=&quot;${n}-${v}&quot;;
</span><del>-    py_dependency -v &quot;${v}&quot; -m &quot;d2697493a40c9d46c9b7c1c210b61671&quot; \
</del><ins>+    py_dependency -v &quot;${v}&quot; -m &quot;462f309e00f7bff7100e2077fc43172c&quot; \
</ins><span class="cx">       &quot;${n}&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><span class="cx">       &quot;http://${sf}/project/cx-oracle/${v}/${p}.tar.gz&quot;;
</span><span class="cx">   fi;
</span><span class="lines">@@ -779,10 +842,10 @@
</span><span class="cx"> 
</span><span class="cx">   # Maintenance note: next time the Twisted dependency gets updated, check out
</span><span class="cx">   # twext/patches.py.
</span><del>-  local v=&quot;12.3.0&quot;;
</del><ins>+  local v=&quot;13.2.0&quot;;
</ins><span class="cx">   local n=&quot;Twisted&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -v 12.2 -m &quot;6e289825f3bf5591cfd670874cc0862d&quot; \
</del><ins>+  py_dependency -v 13.2 -m &quot;83fe6c0c911cc1602dbffb036be0ba79&quot; \
</ins><span class="cx">     &quot;${n}&quot; &quot;twisted&quot; &quot;${p}&quot; \
</span><span class="cx">     &quot;${pypi}/T/${n}/${p}.tar.bz2&quot;;
</span><span class="cx"> 
</span><span class="lines">@@ -793,22 +856,22 @@
</span><span class="cx">     &quot;${n}&quot; &quot;dateutil&quot; &quot;${p}&quot; \
</span><span class="cx">     &quot;http://www.labix.org/download/${n}/${p}.tar.gz&quot;;
</span><span class="cx"> 
</span><del>-  local v=&quot;0.6.1&quot;;
</del><ins>+  local v=&quot;1.2.0&quot;;
</ins><span class="cx">   local n=&quot;psutil&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -m &quot;3cfcbfb8525f6e4c70110e44a85e907e&quot; \
</del><ins>+  py_dependency -m &quot;f8ae906249e65db21f17d873ae07e584&quot; \
</ins><span class="cx">     &quot;${n}&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><del>-    &quot;http://${n}.googlecode.com/files/${p}.tar.gz&quot;;
</del><ins>+    &quot;${pypi}/p/${n}/${p}.tar.gz&quot;;
</ins><span class="cx"> 
</span><del>-  local v=&quot;2.3.13&quot;;
</del><ins>+  local v=&quot;2.4.13&quot;;
</ins><span class="cx">   local n=&quot;python-ldap&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -v &quot;${v}&quot; -m &quot;895223d32fa10bbc29aa349bfad59175&quot; \
</del><ins>+  py_dependency -v &quot;${v}&quot; -m &quot;74b7b50267761540451eade44b2049ee&quot; \
</ins><span class="cx">     &quot;Python-LDAP&quot; &quot;ldap&quot; &quot;${p}&quot; \
</span><span class="cx">     &quot;${pypi}/p/${n}/${p}.tar.gz&quot;;
</span><span class="cx"> 
</span><span class="cx">   # XXX actually PyCalendar should be imported in-place.
</span><del>-  py_dependency -fe -i &quot;src&quot; -r 11458 \
</del><ins>+  py_dependency -fe -i &quot;src&quot; -r 11947 \
</ins><span class="cx">     &quot;PyCalendar&quot; &quot;pycalendar&quot; &quot;pycalendar&quot; \
</span><span class="cx">     &quot;${svn_uri_base}/PyCalendar/trunk&quot;;
</span><span class="cx"> 
</span><span class="lines">@@ -840,44 +903,45 @@
</span><span class="cx">     &quot;${svn_uri_base}/CalDAVClientLibrary/trunk&quot;;
</span><span class="cx"> 
</span><span class="cx">   # Can't add &quot;-v 2011g&quot; to args because the version check expects numbers.
</span><ins>+  local v=&quot;2013.8&quot;;
</ins><span class="cx">   local n=&quot;pytz&quot;;
</span><del>-  local p=&quot;${n}-2011n&quot;;
-  py_dependency -m &quot;75ffdc113a4bcca8096ab953df746391&quot; \
</del><ins>+  local p=&quot;${n}-${v}&quot;;
+  py_dependency -m &quot;37750ca749ed3a52523b9682b0b7e381&quot; \
</ins><span class="cx">     &quot;${n}&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><span class="cx">     &quot;${pypi}/p/${n}/${p}.tar.gz&quot;;
</span><span class="cx"> 
</span><del>-  local v=&quot;2.5&quot;;
</del><ins>+  local v=&quot;2.6.1&quot;;
</ins><span class="cx">   local n=&quot;pycrypto&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -v &quot;${v}&quot; -m &quot;783e45d4a1a309e03ab378b00f97b291&quot; \
</del><ins>+  py_dependency -v &quot;${v}&quot; -m &quot;55a61a054aa66812daf5161a0d5d7eda&quot; \
</ins><span class="cx">     &quot;PyCrypto&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><span class="cx">     &quot;http://ftp.dlitz.net/pub/dlitz/crypto/${n}/${p}.tar.gz&quot;;
</span><span class="cx"> 
</span><del>-  local v=&quot;0.1.2&quot;;
</del><ins>+  local v=&quot;0.1.7&quot;;
</ins><span class="cx">   local n=&quot;pyasn1&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -v &quot;${v}&quot; -m &quot;a7c67f5880a16a347a4d3ce445862a47&quot; \
</del><ins>+  py_dependency -v &quot;${v}&quot; -m &quot;2cbd80fcd4c7b1c82180d3d76fee18c8&quot; \
</ins><span class="cx">     &quot;${n}&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><span class="cx">     &quot;${pypi}/p/${n}/${p}.tar.gz&quot;;
</span><span class="cx"> 
</span><del>-  local v=&quot;1.1.6&quot;;
</del><ins>+  local v=&quot;1.1.8&quot;;
</ins><span class="cx">   local n=&quot;setproctitle&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -v &quot;1.0&quot; -m &quot;1e42e43b440214b971f4b33c21eac369&quot; \
</del><ins>+  py_dependency -v &quot;1.0&quot; -m &quot;728f4c8c6031bbe56083a48594027edd&quot; \
</ins><span class="cx">     &quot;${n}&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><span class="cx">     &quot;${pypi}/s/${n}/${p}.tar.gz&quot;;
</span><span class="cx"> 
</span><del>-  local v=&quot;0.6&quot;;
</del><ins>+  local v=&quot;0.8&quot;;
</ins><span class="cx">   local n=&quot;cffi&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -v &quot;0.6&quot; -m &quot;5be33b1ab0247a984d42b27344519337&quot; \
</del><ins>+  py_dependency -v &quot;0.6&quot; -m &quot;e61deb0515311bb42d5d58b9403bc923&quot; \
</ins><span class="cx">     &quot;${n}&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><span class="cx">     &quot;${pypi}/c/${n}/${p}.tar.gz&quot;;
</span><span class="cx"> 
</span><del>-  local v=&quot;2.09.1&quot;;
</del><ins>+  local v=&quot;2.10&quot;;
</ins><span class="cx">   local n=&quot;pycparser&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -v &quot;0.6&quot; -m &quot;74aa075fc28b7c24a4426574d1ac91e0&quot; \
</del><ins>+  py_dependency -v &quot;0.6&quot; -m &quot;d87aed98c8a9f386aa56d365fe4d515f&quot; \
</ins><span class="cx">     &quot;${n}&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><span class="cx">     &quot;${pypi}/p/${n}/${p}.tar.gz&quot;;
</span><span class="cx"> 
</span><span class="lines">@@ -889,21 +953,21 @@
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><span class="cx">   py_dependency -o -m &quot;36407974bd5da2af00bf90ca27feeb44&quot; \
</span><span class="cx">     &quot;Epydoc&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><del>-    &quot;https://pypi.python.org/packages/source/e/${n}/${p}.tar.gz&quot;;
</del><ins>+    &quot;${pypi}/e/${n}/${p}.tar.gz&quot;;
</ins><span class="cx"> 
</span><span class="cx">   local v=&quot;0.10.0&quot;;
</span><span class="cx">   local n=&quot;Nevow&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><span class="cx">   py_dependency -o -m &quot;66dda2ad88f42dea05911add15f4d1b2&quot; \
</span><span class="cx">     &quot;${n}&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><del>-    &quot;https://pypi.python.org/packages/source/N/${n}/${p}.tar.gz&quot;;
</del><ins>+    &quot;${pypi}/N/${n}/${p}.tar.gz&quot;;
</ins><span class="cx"> 
</span><del>-  local v=&quot;0.4&quot;;
</del><ins>+  local v=&quot;0.5b1&quot;;
</ins><span class="cx">   local n=&quot;pydoctor&quot;;
</span><span class="cx">   local p=&quot;${n}-${v}&quot;;
</span><del>-  py_dependency -o -m &quot;b7564e12b5d35d4cb529a2c220b25d3a&quot; \
</del><ins>+  py_dependency -o -m &quot;c4fb33672f37624116cc7a0606f74f28&quot; \
</ins><span class="cx">     &quot;${n}&quot; &quot;${n}&quot; &quot;${p}&quot; \
</span><del>-    &quot;https://pypi.python.org/packages/source/p/${n}/${p}.tar.gz&quot;;
</del><ins>+    &quot;{$pypi}/p/${n}/${p}.tar.gz&quot;;
</ins><span class="cx"> 
</span><span class="cx">   if &quot;${do_setup}&quot;; then
</span><span class="cx">     cd &quot;${caldav}&quot;;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixessupportversionpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/support/version.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/support/version.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/support/version.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -26,7 +26,7 @@
</span><span class="cx">     # Compute the version number.
</span><span class="cx">     #
</span><span class="cx"> 
</span><del>-    base_version = &quot;5.2&quot;
</del><ins>+    base_version = &quot;6.0&quot;
</ins><span class="cx"> 
</span><span class="cx">     branches = tuple(
</span><span class="cx">         branch.format(version=base_version)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestest"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/test (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/test        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/test        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -21,7 +21,7 @@
</span><span class="cx"> 
</span><span class="cx"> wd=&quot;$(cd &quot;$(dirname &quot;$0&quot;)&quot; &amp;&amp; pwd -L)&quot;;
</span><span class="cx"> 
</span><del>-. &quot;${wd}/support/build.sh&quot;;
</del><ins>+#. &quot;${wd}/support/build.sh&quot;;
</ins><span class="cx"> 
</span><span class="cx"> do_setup=&quot;false&quot;;
</span><span class="cx"> do_get=&quot;false&quot;;
</span><span class="lines">@@ -74,9 +74,6 @@
</span><span class="cx"> 
</span><span class="cx"> export PYTHONPATH=&quot;${wd}:${PYTHONPATH:-}&quot;;
</span><span class="cx"> 
</span><del>-dependencies;
-trial=&quot;$(type -p trial)&quot;;
-
</del><span class="cx"> if [ $# -gt 0 ]; then
</span><span class="cx">   test_modules=&quot;$@&quot;;
</span><span class="cx">   flaky=true;
</span><span class="lines">@@ -88,7 +85,7 @@
</span><span class="cx"> find &quot;${wd}&quot; -name \*.pyc -print0 | xargs -0 rm;
</span><span class="cx"> 
</span><span class="cx"> mkdir -p &quot;${wd}/data&quot;;
</span><del>-cd &quot;${wd}&quot; &amp;&amp; &quot;${python}&quot; &quot;${trial}&quot; --temp-directory=&quot;${wd}/data/trial&quot; --rterrors ${reactor} ${random} ${until_fail} ${no_colour} ${coverage} ${numjobs} ${test_modules};
</del><ins>+cd &quot;${wd}&quot; &amp;&amp; &quot;${wd}/bin/trial&quot; --temp-directory=&quot;${wd}/data/trial&quot; --rterrors ${reactor} ${random} ${until_fail} ${no_colour} ${coverage} ${numjobs} ${test_modules};
</ins><span class="cx"> 
</span><span class="cx"> if ${flaky}; then
</span><span class="cx">   echo &quot;&quot;;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextenterprisedalsyntaxpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/dal/syntax.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/dal/syntax.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/dal/syntax.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1686,6 +1686,7 @@
</span><span class="cx">             SQLFragment(' in %s mode' % (self.mode,)))
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class DatabaseLock(_LockingStatement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     An SQL exclusive session level advisory lock
</span><span class="lines">@@ -1706,6 +1707,7 @@
</span><span class="cx">         return succeed(None)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class DatabaseUnlock(_LockingStatement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     An SQL exclusive session level advisory lock
</span><span class="lines">@@ -1726,6 +1728,7 @@
</span><span class="cx">         return succeed(None)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class Savepoint(_LockingStatement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     An SQL 'savepoint' statement.
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextenterprisefixturespy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/fixtures.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/fixtures.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/fixtures.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -76,8 +76,8 @@
</span><span class="cx"> 
</span><span class="cx"> def resultOf(deferred, propagate=False):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Add a callback and errback which will capture the result of a L{Deferred} in
-    a list, and return that list.  If 'propagate' is True, pass through the
</del><ins>+    Add a callback and errback which will capture the result of a L{Deferred}
+    in a list, and return that list.  If 'propagate' is True, pass through the
</ins><span class="cx">     results.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     results = []
</span><span class="lines">@@ -194,7 +194,6 @@
</span><span class="cx">         No implementation.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     def callFromThread(self, thunk, *a, **kw):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         No implementation.
</span><span class="lines">@@ -223,14 +222,16 @@
</span><span class="cx">             self.factory = ConnectionFactory()
</span><span class="cx">             connect = self.factory.connect
</span><span class="cx">         self.connect = connect
</span><del>-        self.paused             = False
-        self.holders            = []
-        self.pool               = ConnectionPool(connect,
-                                                 maxConnections=2,
-                                                 dialect=self.dialect,
-                                                 paramstyle=self.paramstyle)
</del><ins>+        self.paused = False
+        self.holders = []
+        self.pool = ConnectionPool(
+            connect,
+            maxConnections=2,
+            dialect=self.dialect,
+            paramstyle=self.paramstyle
+        )
</ins><span class="cx">         self.pool._createHolder = self.makeAHolder
</span><del>-        self.clock              = self.pool.reactor = ClockWithThreads()
</del><ins>+        self.clock = self.pool.reactor = ClockWithThreads()
</ins><span class="cx">         self.pool.startService()
</span><span class="cx">         test.addCleanup(self.flushHolders)
</span><span class="cx"> 
</span><span class="lines">@@ -239,7 +240,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Flush all pending C{submit}s since C{pauseHolders} was called.  This
</span><span class="cx">         makes sure the service is stopped and the fake ThreadHolders are all
</span><del>-        executing their queues so failed tsets can exit cleanly.
</del><ins>+        executing their queues so failed tests can exit cleanly.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         self.paused = False
</span><span class="cx">         for holder in self.holders:
</span><span class="lines">@@ -551,6 +552,21 @@
</span><span class="cx">         self._connectResultQueue.append(thunk)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def willConnectTo(self):
+        &quot;&quot;&quot;
+        Queue a successful result for connect() and immediately add it as a
+        child to this L{ConnectionFactory}.
+
+        @return: a connection object
+        @rtype: L{FakeConnection}
+        &quot;&quot;&quot;
+        aConnection = FakeConnection(self)
+        def thunk():
+            return aConnection
+        self._connectResultQueue.append(thunk)
+        return aConnection
+
+
</ins><span class="cx">     def willFail(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Used by tests to queue a successful result for connect().
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextenterprisequeuepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/queue.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/queue.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/queue.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -115,7 +115,7 @@
</span><span class="cx">     (in the worst case) pass from worker-&gt;controller-&gt;controller-&gt;worker.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def performWork(table, workID):
</del><ins>+    def performWork(table, workID): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param table: The table where work is waiting.
</span><span class="cx">         @type table: L{TableSyntax}
</span><span class="lines">@@ -149,7 +149,8 @@
</span><span class="cx">     NodeTable.addColumn(&quot;PORT&quot;, SQLType(&quot;integer&quot;, None))
</span><span class="cx">     NodeTable.addColumn(&quot;TIME&quot;, SQLType(&quot;timestamp&quot;, None)).setDefaultValue(
</span><span class="cx">         # Note: in the real data structure, this is actually a not-cleaned-up
</span><del>-        # sqlparse internal data structure, but it *should* look closer to this.
</del><ins>+        # sqlparse internal data structure, but it *should* look closer to
+        # this.
</ins><span class="cx">         ProcedureCall(&quot;timezone&quot;, [&quot;UTC&quot;, NamedValue('CURRENT_TIMESTAMP')])
</span><span class="cx">     )
</span><span class="cx">     for column in NodeTable.columns:
</span><span class="lines">@@ -370,7 +371,6 @@
</span><span class="cx">         will be taken care of by the job queueing machinery.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     @classmethod
</span><span class="cx">     def forTable(cls, table):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -677,8 +677,8 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, peerPool, boxReceiver=None, locator=None):
</span><del>-        super(ConnectionFromWorker, self).__init__(peerPool.schema, boxReceiver,
-                                                   locator)
</del><ins>+        super(ConnectionFromWorker, self).__init__(peerPool.schema,
+                                                   boxReceiver, locator)
</ins><span class="cx">         self.peerPool = peerPool
</span><span class="cx">         self._load = 0
</span><span class="cx"> 
</span><span class="lines">@@ -830,9 +830,9 @@
</span><span class="cx">             workItem = yield workItemClass.load(txn, workID)
</span><span class="cx">             if workItem.group is not None:
</span><span class="cx">                 yield NamedLock.acquire(txn, workItem.group)
</span><del>-            # TODO: what if we fail?  error-handling should be recorded someplace,
-            # the row should probably be marked, re-tries should be triggerable
-            # administratively.
</del><ins>+            # TODO: what if we fail?  error-handling should be recorded
+            # someplace, the row should probably be marked, re-tries should be
+            # triggerable administratively.
</ins><span class="cx">             yield workItem.delete()
</span><span class="cx">             # TODO: verify that workID is the primary key someplace.
</span><span class="cx">             yield workItem.doWork()
</span><span class="lines">@@ -865,9 +865,6 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
-
-
</del><span class="cx"> class WorkerFactory(Factory, object):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Factory, to be used as the client to connect from the worker to the
</span><span class="lines">@@ -950,7 +947,7 @@
</span><span class="cx">         waiting for the transaction where that addition was completed to
</span><span class="cx">         commit, and asking the local node controller process to do the work.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        @passthru(self.workItemType.create(self.txn, **self.kw).addCallback)
</del><ins>+        created = self.workItemType.create(self.txn, **self.kw)
</ins><span class="cx">         def whenCreated(item):
</span><span class="cx">             self._whenProposed.callback(self)
</span><span class="cx">             @self.txn.postCommit
</span><span class="lines">@@ -967,12 +964,15 @@
</span><span class="cx">                         self._whenExecuted.errback(why)
</span><span class="cx">                 reactor = self._chooser.reactor
</span><span class="cx">                 when = max(0, astimestamp(item.notBefore) - reactor.seconds())
</span><del>-                # TODO: Track the returned DelayedCall so it can be stopped when
-                # the service stops.
</del><ins>+                # TODO: Track the returned DelayedCall so it can be stopped
+                # when the service stops.
</ins><span class="cx">                 self._chooser.reactor.callLater(when, maybeLater)
</span><span class="cx">             @self.txn.postAbort
</span><span class="cx">             def whenFailed():
</span><span class="cx">                 self._whenCommitted.errback(TransactionFailed)
</span><ins>+        def whenNotCreated(failure):
+            self._whenProposed.errback(failure)
+        created.addCallbacks(whenCreated, whenNotCreated)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def whenExecuted(self):
</span><span class="lines">@@ -1023,6 +1023,8 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return _cloneDeferred(self._whenCommitted)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class _BaseQueuer(object):
</span><span class="cx">     implements(IQueuer)
</span><span class="cx"> 
</span><span class="lines">@@ -1030,13 +1032,16 @@
</span><span class="cx">         super(_BaseQueuer, self).__init__()
</span><span class="cx">         self.proposalCallbacks = set()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def callWithNewProposals(self, callback):
</span><del>-        self.proposalCallbacks.add(callback);
</del><ins>+        self.proposalCallbacks.add(callback)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def transferProposalCallbacks(self, newQueuer):
</span><span class="cx">         newQueuer.proposalCallbacks = self.proposalCallbacks
</span><span class="cx">         return newQueuer
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def enqueueWork(self, txn, workItemType, **kw):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         There is some work to do.  Do it, someplace else, ideally in parallel.
</span><span class="lines">@@ -1061,6 +1066,7 @@
</span><span class="cx">         return wp
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class PeerConnectionPool(_BaseQueuer, MultiService, object):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Each node has a L{PeerConnectionPool} connecting it to all the other nodes
</span><span class="lines">@@ -1140,7 +1146,7 @@
</span><span class="cx">         self.mappedPeers = {}
</span><span class="cx">         self.schema = schema
</span><span class="cx">         self._startingUp = None
</span><del>-        self._listeningPortObject = None
</del><ins>+        self._listeningPort = None
</ins><span class="cx">         self._lastSeenTotalNodes = 1
</span><span class="cx">         self._lastSeenNodeIndex = 1
</span><span class="cx"> 
</span><span class="lines">@@ -1197,7 +1203,8 @@
</span><span class="cx">         A peer has requested us to perform some work; choose a work performer
</span><span class="cx">         local to this node, and then execute it.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        return self.choosePerformer(onlyLocally=True).performWork(table, workID)
</del><ins>+        performer = self.choosePerformer(onlyLocally=True)
+        return performer.performWork(table, workID)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def allWorkItemTypes(self):
</span><span class="lines">@@ -1225,8 +1232,8 @@
</span><span class="cx"> 
</span><span class="cx">         @return: the maximum number of other L{PeerConnectionPool} instances
</span><span class="cx">             that may be connected to the database described by
</span><del>-            C{self.transactionFactory}.  Note that this is not the current count
-            by connectivity, but the count according to the database.
</del><ins>+            C{self.transactionFactory}.  Note that this is not the current
+            count by connectivity, but the count according to the database.
</ins><span class="cx">         @rtype: L{int}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         # TODO
</span><span class="lines">@@ -1277,7 +1284,6 @@
</span><span class="cx">                                            overdueItem.workID)
</span><span class="cx">         return inTransaction(self.transactionFactory, workCheck)
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     _currentWorkDeferred = None
</span><span class="cx">     _lostWorkCheckCall = None
</span><span class="cx"> 
</span><span class="lines">@@ -1315,10 +1321,10 @@
</span><span class="cx">         @inlineCallbacks
</span><span class="cx">         def startup(txn):
</span><span class="cx">             endpoint = TCP4ServerEndpoint(self.reactor, self.ampPort)
</span><del>-            # If this fails, the failure mode is going to be ugly, just like all
-            # conflicted-port failures.  But, at least it won't proceed.
-            self._listeningPortObject = yield endpoint.listen(self.peerFactory())
-            self.ampPort = self._listeningPortObject.getHost().port
</del><ins>+            # If this fails, the failure mode is going to be ugly, just like
+            # all conflicted-port failures.  But, at least it won't proceed.
+            self._listeningPort = yield endpoint.listen(self.peerFactory())
+            self.ampPort = self._listeningPort.getHost().port
</ins><span class="cx">             yield Lock.exclusive(NodeInfo.table).on(txn)
</span><span class="cx">             nodes = yield self.activeNodes(txn)
</span><span class="cx">             selves = [node for node in nodes
</span><span class="lines">@@ -1354,8 +1360,8 @@
</span><span class="cx">         yield super(PeerConnectionPool, self).stopService()
</span><span class="cx">         if self._startingUp is not None:
</span><span class="cx">             yield self._startingUp
</span><del>-        if self._listeningPortObject is not None:
-            yield self._listeningPortObject.stopListening()
</del><ins>+        if self._listeningPort is not None:
+            yield self._listeningPort.stopListening()
</ins><span class="cx">         if self._lostWorkCheckCall is not None:
</span><span class="cx">             self._lostWorkCheckCall.cancel()
</span><span class="cx">         if self._currentWorkDeferred is not None:
</span><span class="lines">@@ -1430,8 +1436,6 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
-
</del><span class="cx"> class LocalQueuer(_BaseQueuer):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     When work is enqueued with this queuer, it is just executed locally.
</span><span class="lines">@@ -1458,7 +1462,8 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Implementor of C{performWork} that doesn't actual perform any work.  This
</span><span class="cx">     is used in the case where you want to be able to enqueue work for someone
</span><del>-    else to do, but not take on any work yourself (such as a command line tool).
</del><ins>+    else to do, but not take on any work yourself (such as a command line
+    tool).
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     implements(_IWorkPerformer)
</span><span class="cx"> 
</span><span class="lines">@@ -1469,6 +1474,7 @@
</span><span class="cx">         return succeed(None)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class NonPerformingQueuer(_BaseQueuer):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     When work is enqueued with this queuer, it is never executed locally.
</span><span class="lines">@@ -1487,4 +1493,4 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Choose to perform the work locally.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        return NonPerformer()
</del><span class="cx">\ No newline at end of file
</span><ins>+        return NonPerformer()
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextenterprisetesttest_queuepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/test/test_queue.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/test/test_queue.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/enterprise/test/test_queue.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> from twisted.trial.unittest import TestCase
</span><ins>+from twisted.python.failure import Failure
</ins><span class="cx"> from twisted.internet.defer import (
</span><span class="cx">     Deferred, inlineCallbacks, gatherResults, passthru#, returnValue
</span><span class="cx"> )
</span><span class="lines">@@ -55,6 +56,8 @@
</span><span class="cx"> from twisted.test.proto_helpers import StringTransport, MemoryReactor
</span><span class="cx"> from twext.enterprise.fixtures import SteppablePoolHelper
</span><span class="cx"> from twisted.internet.defer import returnValue
</span><ins>+from twext.enterprise.queue import LocalQueuer
+from twext.enterprise.fixtures import ConnectionPoolHelper
</ins><span class="cx"> 
</span><span class="cx"> from twext.enterprise.queue import _BaseQueuer, NonPerformingQueuer
</span><span class="cx"> import twext.enterprise.queue
</span><span class="lines">@@ -67,7 +70,7 @@
</span><span class="cx"> 
</span><span class="cx">     def callLater(self, _seconds, _f, *args, **kw):
</span><span class="cx">         if _seconds &lt; 0:
</span><del>-            raise ValueError(&quot;%s&lt;0: &quot;%(_seconds,))
</del><ins>+            raise ValueError(&quot;%s&lt;0: &quot; % (_seconds,))
</ins><span class="cx">         return super(Clock, self).callLater(_seconds, _f, *args, **kw)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -267,6 +270,56 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+class WorkProposalTests(TestCase):
+    &quot;&quot;&quot;
+    Tests for L{WorkProposal}.
+    &quot;&quot;&quot;
+
+    def test_whenProposedSuccess(self):
+        &quot;&quot;&quot;
+        The L{Deferred} returned by L{WorkProposal.whenProposed} fires when the
+        SQL sent to the database has completed.
+        &quot;&quot;&quot;
+        cph = ConnectionPoolHelper()
+        cph.setUp(test=self)
+        cph.pauseHolders()
+        lq = LocalQueuer(cph.createTransaction)
+        enqTxn = cph.createTransaction()
+        wp = lq.enqueueWork(enqTxn, DummyWorkItem, a=3, b=4)
+        d = wp.whenProposed()
+        r = cph.resultOf(d)
+        self.assertEquals(r, [])
+        cph.flushHolders()
+        self.assertEquals(len(r), 1)
+
+
+    def test_whenProposedFailure(self):
+        &quot;&quot;&quot;
+        The L{Deferred} returned by L{WorkProposal.whenProposed} fails with an
+        errback when the SQL executed to create the WorkItem row fails.
+        &quot;&quot;&quot;
+        cph = ConnectionPoolHelper()
+        cph.setUp(self)
+        cph.pauseHolders()
+        firstConnection = cph.factory.willConnectTo()
+        enqTxn = cph.createTransaction()
+        # Execute some SQL on the connection before enqueueing the work-item so
+        # that we don't get the initial-statement.
+        enqTxn.execSQL(&quot;some sql&quot;)
+        lq = LocalQueuer(cph.createTransaction)
+        cph.flushHolders()
+        cph.pauseHolders()
+        wp = lq.enqueueWork(enqTxn, DummyWorkItem, a=3, b=4)
+        firstConnection.executeWillFail(lambda: RuntimeError(&quot;foo&quot;))
+        d = wp.whenProposed()
+        r = cph.resultOf(d)
+        self.assertEquals(r, [])
+        cph.flushHolders()
+        self.assertEquals(len(r), 1)
+        self.assertIsInstance(r[0], Failure)
+
+
+
</ins><span class="cx"> class PeerConnectionPoolUnitTests(TestCase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     L{PeerConnectionPool} has many internal components.
</span><span class="lines">@@ -393,7 +446,8 @@
</span><span class="cx">             # Next, create one that's actually far enough into the past to run.
</span><span class="cx">             yield DummyWorkItem.create(
</span><span class="cx">                 txn, a=3, b=4, notBefore=(
</span><del>-                    # Schedule it in the past so that it should have already run.
</del><ins>+                    # Schedule it in the past so that it should have already
+                    # run.
</ins><span class="cx">                     fakeNow - datetime.timedelta(
</span><span class="cx">                         seconds=qpool.queueProcessTimeout + 20
</span><span class="cx">                     )
</span><span class="lines">@@ -509,8 +563,8 @@
</span><span class="cx">             t = StringTransport()
</span><span class="cx">             p.makeConnection(t)
</span><span class="cx">             return p, t
</span><del>-        worker1, trans1 = peer()
-        worker2, trans2 = peer()
</del><ins>+        worker1, _ignore_trans1 = peer()
+        worker2, _ignore_trans2 = peer()
</ins><span class="cx">         # Ask the worker to do something.
</span><span class="cx">         worker1.performWork(schema.DUMMY_WORK_ITEM, 1)
</span><span class="cx">         self.assertEquals(worker1.currentLoad, 1)
</span><span class="lines">@@ -619,11 +673,12 @@
</span><span class="cx">         self.receiver, self.sender = self.sender, self.receiver
</span><span class="cx">         return result
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def flush(self, turns=10):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Keep relaying data until there's no more.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        for x in range(turns):
</del><ins>+        for _ignore_x in range(turns):
</ins><span class="cx">             if not (self.pump() or self.pump()):
</span><span class="cx">                 return
</span><span class="cx"> 
</span><span class="lines">@@ -718,7 +773,7 @@
</span><span class="cx">         def op2(txn):
</span><span class="cx">             return Select([schema.DUMMY_WORK_DONE.WORK_ID,
</span><span class="cx">                            schema.DUMMY_WORK_DONE.A_PLUS_B],
</span><del>-                           From=schema.DUMMY_WORK_DONE).on(txn)
</del><ins>+                          From=schema.DUMMY_WORK_DONE).on(txn)
</ins><span class="cx">         rows = yield inTransaction(self.store.newTransaction, op2)
</span><span class="cx">         self.assertEquals(rows, [[4321, 7]])
</span><span class="cx"> 
</span><span class="lines">@@ -729,7 +784,7 @@
</span><span class="cx">         When a L{WorkItem} is concurrently deleted by another transaction, it
</span><span class="cx">         should I{not} perform its work.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        # Provide access to a method called 'concurrently' everything using 
</del><ins>+        # Provide access to a method called 'concurrently' everything using
</ins><span class="cx">         original = self.store.newTransaction
</span><span class="cx">         def decorate(*a, **k):
</span><span class="cx">             result = original(*a, **k)
</span><span class="lines">@@ -746,13 +801,13 @@
</span><span class="cx">         # Sanity check on the concurrent deletion.
</span><span class="cx">         def op2(txn):
</span><span class="cx">             return Select([schema.DUMMY_WORK_ITEM.WORK_ID],
</span><del>-                           From=schema.DUMMY_WORK_ITEM).on(txn)
</del><ins>+                          From=schema.DUMMY_WORK_ITEM).on(txn)
</ins><span class="cx">         rows = yield inTransaction(self.store.newTransaction, op2)
</span><span class="cx">         self.assertEquals(rows, [])
</span><span class="cx">         def op3(txn):
</span><span class="cx">             return Select([schema.DUMMY_WORK_DONE.WORK_ID,
</span><span class="cx">                            schema.DUMMY_WORK_DONE.A_PLUS_B],
</span><del>-                           From=schema.DUMMY_WORK_DONE).on(txn)
</del><ins>+                          From=schema.DUMMY_WORK_DONE).on(txn)
</ins><span class="cx">         rows = yield inTransaction(self.store.newTransaction, op3)
</span><span class="cx">         self.assertEquals(rows, [])
</span><span class="cx"> 
</span><span class="lines">@@ -763,18 +818,23 @@
</span><span class="cx">     def __init__(self, *ignored):
</span><span class="cx">         pass
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _start(self):
</span><span class="cx">         pass
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class BaseQueuerTests(TestCase):
</span><span class="cx"> 
</span><span class="cx">     def setUp(self):
</span><span class="cx">         self.proposal = None
</span><span class="cx">         self.patch(twext.enterprise.queue, &quot;WorkProposal&quot;, DummyProposal)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _proposalCallback(self, proposal):
</span><span class="cx">         self.proposal = proposal
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_proposalCallbacks(self):
</span><span class="cx">         queuer = _BaseQueuer()
</span><span class="cx">         queuer.callWithNewProposals(self._proposalCallback)
</span><span class="lines">@@ -783,6 +843,7 @@
</span><span class="cx">         self.assertNotEqual(self.proposal, None)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class NonPerformingQueuerTests(TestCase):
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -791,5 +852,3 @@
</span><span class="cx">         performer = queuer.choosePerformer()
</span><span class="cx">         result = (yield performer.performWork(None, None))
</span><span class="cx">         self.assertEquals(result, None)
</span><del>-
-
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextinternetsendfdportpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/internet/sendfdport.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/internet/sendfdport.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/internet/sendfdport.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -94,8 +94,8 @@
</span><span class="cx">     A socket in the master process pointing at a file descriptor that can be
</span><span class="cx">     used to transmit sockets to a subprocess.
</span><span class="cx"> 
</span><del>-    @ivar skt: the UNIX socket used as the sendmsg() transport.
-    @type skt: L{socket.socket}
</del><ins>+    @ivar outSocket: the UNIX socket used as the sendmsg() transport.
+    @type outSocket: L{socket.socket}
</ins><span class="cx"> 
</span><span class="cx">     @ivar outgoingSocketQueue: an outgoing queue of sockets to send to the
</span><span class="cx">         subprocess, along with their descriptions (strings describing their
</span><span class="lines">@@ -115,12 +115,13 @@
</span><span class="cx">     @type dispatcher: L{InheritedSocketDispatcher}
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def __init__(self, dispatcher, skt, status):
</del><ins>+    def __init__(self, dispatcher, inSocket, outSocket, status):
</ins><span class="cx">         FileDescriptor.__init__(self, dispatcher.reactor)
</span><span class="cx">         self.status = status
</span><span class="cx">         self.dispatcher = dispatcher
</span><del>-        self.skt = skt          # XXX needs to be set non-blocking by somebody
-        self.fileno = skt.fileno
</del><ins>+        self.inSocket = inSocket
+        self.outSocket = outSocket   # XXX needs to be set non-blocking by somebody
+        self.fileno = outSocket.fileno
</ins><span class="cx">         self.outgoingSocketQueue = []
</span><span class="cx">         self.pendingCloseSocketQueue = []
</span><span class="cx"> 
</span><span class="lines">@@ -138,7 +139,7 @@
</span><span class="cx">         Receive a status / health message and record it.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         try:
</span><del>-            data, _ignore_flags, _ignore_ancillary = recvmsg(self.skt.fileno())
</del><ins>+            data, _ignore_flags, _ignore_ancillary = recvmsg(self.outSocket.fileno())
</ins><span class="cx">         except SocketError, se:
</span><span class="cx">             if se.errno not in (EAGAIN, ENOBUFS):
</span><span class="cx">                 raise
</span><span class="lines">@@ -155,7 +156,7 @@
</span><span class="cx">         while self.outgoingSocketQueue:
</span><span class="cx">             skt, desc = self.outgoingSocketQueue.pop(0)
</span><span class="cx">             try:
</span><del>-                sendfd(self.skt.fileno(), skt.fileno(), desc)
</del><ins>+                sendfd(self.outSocket.fileno(), skt.fileno(), desc)
</ins><span class="cx">             except SocketError, se:
</span><span class="cx">                 if se.errno in (EAGAIN, ENOBUFS):
</span><span class="cx">                     self.outgoingSocketQueue.insert(0, (skt, desc))
</span><span class="lines">@@ -341,14 +342,27 @@
</span><span class="cx">         i, o = socketpair()
</span><span class="cx">         i.setblocking(False)
</span><span class="cx">         o.setblocking(False)
</span><del>-        a = _SubprocessSocket(self, o, self.statusWatcher.initialStatus())
</del><ins>+        a = _SubprocessSocket(self, i, o, self.statusWatcher.initialStatus())
</ins><span class="cx">         self._subprocessSockets.append(a)
</span><span class="cx">         if self._isDispatching:
</span><span class="cx">             a.startReading()
</span><span class="cx">         return i
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def removeSocket(self, skt):
+        &quot;&quot;&quot;
+        Removes a previously added socket from the pool of sockets being used
+        for transmitting file descriptors to child processes.
+        &quot;&quot;&quot;
+        for a in self._subprocessSockets:
+            if a.inSocket == skt:
+                self._subprocessSockets.remove(a)
+                break
+        else:
+            raise ValueError(&quot;Unknown socket: {0}&quot;.format(skt))
</ins><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class InheritedPort(FileDescriptor, object):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     An L{InheritedPort} is an L{IReadDescriptor}/L{IWriteDescriptor} created in
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextprotocolsechopyfromrev12016CalendarServertrunktwextprotocolsechopy"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/protocols/echo.py (from rev 12016, CalendarServer/trunk/twext/protocols/echo.py) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/protocols/echo.py                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/protocols/echo.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+##
+# Copyright (c) 2013 Apple Inc. 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;
+Echo protocol.
+&quot;&quot;&quot;
+
+__all__ = [&quot;EchoProtocol&quot;]
+
+from twisted.internet.protocol import Protocol
+
+
+class EchoProtocol(Protocol):
+    &quot;&quot;&quot;
+    Say what you hear.
+    &quot;&quot;&quot;
+
+    def dataReceived(self, data):
+        &quot;&quot;&quot;
+        As soon as any data is received, write it back.
+        &quot;&quot;&quot;
+        self.transport.write(data)
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextprotocolstesttest_memcachepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/protocols/test/test_memcache.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/protocols/test/test_memcache.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/protocols/test/test_memcache.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -14,7 +14,17 @@
</span><span class="cx"> from twisted.internet.defer import Deferred, gatherResults, TimeoutError
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+def onConnectionLossFire(protocol, deferred):
+    &quot;&quot;&quot;
+    When the given L{MemCacheProtocol} is disconnected, fire the given
+    L{Deferred} with L{None}.
+    &quot;&quot;&quot;
+    def cl(reason):
+        deferred.callback(None)
+    protocol.connectionLost = cl
</ins><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class MemCacheTestCase(TestCase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Test client protocol class L{MemCacheProtocol}.
</span><span class="lines">@@ -244,7 +254,7 @@
</span><span class="cx">         d1 = self.proto.get(&quot;foo&quot;)
</span><span class="cx">         d2 = self.proto.get(&quot;bar&quot;)
</span><span class="cx">         d3 = Deferred()
</span><del>-        self.proto.connectionLost = d3.callback
</del><ins>+        onConnectionLossFire(self.proto, d3)
</ins><span class="cx"> 
</span><span class="cx">         self.clock.advance(self.proto.persistentTimeOut)
</span><span class="cx">         self.assertFailure(d1, TimeoutError)
</span><span class="lines">@@ -280,7 +290,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         d1 = self.proto.get(&quot;foo&quot;)
</span><span class="cx">         d2 = Deferred()
</span><del>-        self.proto.connectionLost = d2.callback
</del><ins>+        onConnectionLossFire(self.proto, d2)
</ins><span class="cx"> 
</span><span class="cx">         self.proto.dataReceived(&quot;VALUE foo 0 10\r\n12345&quot;)
</span><span class="cx">         self.clock.advance(self.proto.persistentTimeOut)
</span><span class="lines">@@ -295,7 +305,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         d1 = self.proto.stats()
</span><span class="cx">         d2 = Deferred()
</span><del>-        self.proto.connectionLost = d2.callback
</del><ins>+        onConnectionLossFire(self.proto, d2)
</ins><span class="cx"> 
</span><span class="cx">         self.proto.dataReceived(&quot;STAT foo bar\r\n&quot;)
</span><span class="cx">         self.clock.advance(self.proto.persistentTimeOut)
</span><span class="lines">@@ -311,7 +321,7 @@
</span><span class="cx">         d1 = self.proto.get(&quot;foo&quot;)
</span><span class="cx">         d2 = self.proto.get(&quot;bar&quot;)
</span><span class="cx">         d3 = Deferred()
</span><del>-        self.proto.connectionLost = d3.callback
</del><ins>+        onConnectionLossFire(self.proto, d3)
</ins><span class="cx"> 
</span><span class="cx">         self.clock.advance(self.proto.persistentTimeOut - 1)
</span><span class="cx">         self.proto.dataReceived(&quot;VALUE foo 0 3\r\nbar\r\nEND\r\n&quot;)
</span><span class="lines">@@ -319,7 +329,7 @@
</span><span class="cx">         def check(result):
</span><span class="cx">             self.assertEquals(result, (0, &quot;bar&quot;))
</span><span class="cx">             self.assertEquals(len(self.clock.calls), 1)
</span><del>-            for i in range(self.proto.persistentTimeOut):
</del><ins>+            for _ignore_i in range(self.proto.persistentTimeOut):
</ins><span class="cx">                 self.clock.advance(1)
</span><span class="cx">             return self.assertFailure(d2, TimeoutError).addCallback(checkTime)
</span><span class="cx">         def checkTime(ignored):
</span><span class="lines">@@ -338,7 +348,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         d1 = self.proto.get(&quot;foo&quot;)
</span><span class="cx">         d3 = Deferred()
</span><del>-        self.proto.connectionLost = d3.callback
</del><ins>+        onConnectionLossFire(self.proto, d3)
</ins><span class="cx"> 
</span><span class="cx">         self.clock.advance(self.proto.persistentTimeOut - 1)
</span><span class="cx">         d2 = self.proto.get(&quot;bar&quot;)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhoaggregatepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/aggregate.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/aggregate.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/aggregate.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -30,8 +30,8 @@
</span><span class="cx"> 
</span><span class="cx"> from twext.who.idirectory import DirectoryConfigurationError
</span><span class="cx"> from twext.who.idirectory import IDirectoryService
</span><del>-from twext.who.index import DirectoryService as BaseDirectoryService
-from twext.who.index import DirectoryRecord
</del><ins>+from twext.who.directory import DirectoryService as BaseDirectoryService
+from twext.who.directory import DirectoryRecord
</ins><span class="cx"> from twext.who.util import ConstantsContainer
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -78,10 +78,10 @@
</span><span class="cx">         return self._recordType
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def recordsFromExpression(self, expression, records=None):
</del><ins>+    def recordsFromExpression(self, expression):
</ins><span class="cx">         ds = []
</span><span class="cx">         for service in self.services:
</span><del>-            d = service.recordsFromExpression(expression, records)
</del><ins>+            d = service.recordsFromExpression(expression)
</ins><span class="cx">             ds.append(d)
</span><span class="cx"> 
</span><span class="cx">         def unwrapFirstError(f):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhodirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/directory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/directory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/directory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -24,35 +24,81 @@
</span><span class="cx">     &quot;DirectoryRecord&quot;,
</span><span class="cx"> ]
</span><span class="cx"> 
</span><del>-from uuid import UUID
</del><ins>+from zope.interface import implementer
</ins><span class="cx"> 
</span><del>-from zope.interface import implements
-
</del><span class="cx"> from twisted.internet.defer import inlineCallbacks, returnValue
</span><span class="cx"> from twisted.internet.defer import succeed, fail
</span><span class="cx"> 
</span><span class="cx"> from twext.who.idirectory import QueryNotSupportedError, NotAllowedError
</span><span class="cx"> from twext.who.idirectory import FieldName, RecordType
</span><del>-from twext.who.idirectory import Operand
</del><span class="cx"> from twext.who.idirectory import IDirectoryService, IDirectoryRecord
</span><ins>+from twext.who.expression import CompoundExpression, Operand
</ins><span class="cx"> from twext.who.expression import MatchExpression
</span><span class="cx"> from twext.who.util import uniqueResult, describe
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+@implementer(IDirectoryService)
</ins><span class="cx"> class DirectoryService(object):
</span><del>-    implements(IDirectoryService)
</del><ins>+    &quot;&quot;&quot;
+    Generic (and abstract) implementation of L{IDirectoryService}.
</ins><span class="cx"> 
</span><ins>+    Most of the C{recordsWith*} methods call L{recordsWithFieldValue}, which in
+    turn calls L{recordsFromExpression} with a corresponding
+    L{MatchExpression}.
+
+    L{recordsFromExpression} relies on L{recordsFromNonCompoundExpression} for
+    all expression types other than L{CompoundExpression}, which it handles
+    directly.
+
+    L{recordsFromNonCompoundExpression} (and therefore most uses of the other
+    methods) will always fail with a L{QueryNotSupportedError}.
+
+    A subclass should therefore override L{recordsFromNonCompoundExpression}
+    with an implementation that handles any queries that it can support (which
+    should include L{MatchExpression}) and calls its superclass' implementation
+    with any query it cannot support.
+
+    A subclass may override L{recordsFromExpression} if it is to support
+    L{CompoundExpression}s with operands other than L{Operand.AND} and
+    L{Operand.OR}.
+
+    A subclass may override L{recordsFromExpression} if it is built on top
+    of a directory service that supports compound expressions, as that may be
+    more effient than relying on L{DirectoryService}'s implementation.
+
+    L{updateRecords} and L{removeRecords} will fail with L{NotAllowedError}
+    when asked to modify data.
+    A subclass should override these methods if is to allow editing of
+    directory information.
+
+    @cvar recordType: a L{Names} class or compatible object (eg.
+        L{ConstantsContainer}) which contains the L{NamedConstant}s denoting
+        the record types that are supported by this directory service.
+
+    @cvar fieldName: a L{Names} class or compatible object (eg.
+        L{ConstantsContainer}) which contains the L{NamedConstant}s denoting
+        the record field names that are supported by this directory service.
+
+    @cvar normalizedFields: a L{dict} mapping of (ie. L{NamedConstant}s
+        contained in the C{fieldName} class variable) to callables that take
+        a field value (a L{unicode}) and return a normalized field value (also
+        a L{unicode}).
+    &quot;&quot;&quot;
+
</ins><span class="cx">     recordType = RecordType
</span><span class="cx">     fieldName  = FieldName
</span><span class="cx"> 
</span><span class="cx">     normalizedFields = {
</span><del>-        FieldName.guid: lambda g: UUID(g).hex,
-        FieldName.emailAddresses: lambda e: e.lower(),
</del><ins>+        FieldName.emailAddresses: lambda e: bytes(e).lower(),
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, realmName):
</span><ins>+        &quot;&quot;&quot;
+        @param realmName: a realm name
+        @type realmName: L{unicode}
+        &quot;&quot;&quot;
</ins><span class="cx">         self.realmName = realmName
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -67,59 +113,98 @@
</span><span class="cx">         return self.recordType.iterconstants()
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def recordsFromExpression(self, expression, records=None):
</del><ins>+    def recordsFromNonCompoundExpression(self, expression, records=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><del>-        Finds records matching a single expression.
-        @param expression: an expression
</del><ins>+        Finds records matching a expression.
+
+        @note: This method is called by L{recordsFromExpression} to handle
+            all expressions other than L{CompoundExpression}.
+            This implementation always fails with L{QueryNotSupportedError}.
+            Subclasses should override this in order to handle additional
+            expression types, and call on the superclass' implementation
+            for other expression types.
+
+        @note: This interface is the same as L{recordsFromExpression}, except
+            for the additional C{records} argument.
+
+        @param expression: an expression to apply
</ins><span class="cx">         @type expression: L{object}
</span><del>-        @param records: a set of records to search within. C{None} if
</del><ins>+
+        @param records: a set of records to limit the search to. C{None} if
</ins><span class="cx">             the whole directory should be searched.
</span><ins>+            This is provided by L{recordsFromExpression} when it has already
+            narrowed down results to a set of records.
+            That is, it's a performance optimization; ignoring this and
+            searching the entire directory will also work.
</ins><span class="cx">         @type records: L{set} or L{frozenset}
</span><ins>+
+        @return: The matching records.
+        @rtype: deferred iterable of L{IDirectoryRecord}s
+
+        @raises: L{QueryNotSupportedError} if the expression is not
+            supported by this directory service.
</ins><span class="cx">         &quot;&quot;&quot;
</span><ins>+        if records is not None:
+            for record in records:
+                break
+            else:
+                return succeed(())
+
</ins><span class="cx">         return fail(QueryNotSupportedError(
</span><span class="cx">             &quot;Unknown expression: {0}&quot;.format(expression)
</span><span class="cx">         ))
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def recordsFromQuery(self, expressions, operand=Operand.AND):
-        expressionIterator = iter(expressions)
</del><ins>+    def recordsFromExpression(self, expression):
+        if isinstance(expression, CompoundExpression):
+            operand = expression.operand
+            subExpressions = iter(expression.expressions)
</ins><span class="cx"> 
</span><del>-        try:
-            expression = expressionIterator.next()
-        except StopIteration:
-            returnValue(())
</del><ins>+            try:
+                subExpression = subExpressions.next()
+            except StopIteration:
+                returnValue(())
</ins><span class="cx"> 
</span><del>-        results = set((yield self.recordsFromExpression(expression)))
</del><ins>+            results = set((
+                yield self.recordsFromNonCompoundExpression(subExpression)
+            ))
</ins><span class="cx"> 
</span><del>-        for expression in expressions:
-            if operand == Operand.AND:
-                if not results:
-                    # No need to bother continuing here
-                    returnValue(())
</del><ins>+            for subExpression in subExpressions:
+                if operand == Operand.AND:
+                    if not results:
+                        # No need to bother continuing here
+                        returnValue(())
</ins><span class="cx"> 
</span><del>-                records = results
-            else:
-                records = None
</del><ins>+                    records = results
+                else:
+                    records = None
</ins><span class="cx"> 
</span><del>-            recordsMatchingExpression = frozenset((
-                yield self.recordsFromExpression(expression, records=records)
-            ))
</del><ins>+                recordsMatchingExpression = frozenset((
+                    yield self.recordsFromNonCompoundExpression(
+                        subExpression,
+                        records=records
+                    )
+                ))
</ins><span class="cx"> 
</span><del>-            if operand == Operand.AND:
-                results &amp;= recordsMatchingExpression
-            elif operand == Operand.OR:
-                results |= recordsMatchingExpression
-            else:
-                raise QueryNotSupportedError(
-                    &quot;Unknown operand: {0}&quot;.format(operand)
-                )
</del><ins>+                if operand == Operand.AND:
+                    results &amp;= recordsMatchingExpression
+                elif operand == Operand.OR:
+                    results |= recordsMatchingExpression
+                else:
+                    raise QueryNotSupportedError(
+                        &quot;Unknown operand: {0}&quot;.format(operand)
+                    )
+        else:
+            results = yield self.recordsFromNonCompoundExpression(expression)
</ins><span class="cx"> 
</span><span class="cx">         returnValue(results)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def recordsWithFieldValue(self, fieldName, value):
</span><del>-        return self.recordsFromExpression(MatchExpression(fieldName, value))
</del><ins>+        return self.recordsFromExpression(
+            MatchExpression(fieldName, value)
+        )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -142,10 +227,17 @@
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def recordWithShortName(self, recordType, shortName):
</span><del>-        returnValue(uniqueResult((yield self.recordsFromQuery((
-            MatchExpression(FieldName.recordType, recordType),
-            MatchExpression(FieldName.shortNames, shortName),
-        )))))
</del><ins>+        returnValue(uniqueResult((
+            yield self.recordsFromExpression(
+                CompoundExpression(
+                    (
+                        MatchExpression(FieldName.recordType, recordType),
+                        MatchExpression(FieldName.shortNames, shortName),
+                    ),
+                    operand=Operand.AND
+                )
+            )
+        )))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def recordsWithEmailAddress(self, emailAddress):
</span><span class="lines">@@ -158,17 +250,32 @@
</span><span class="cx">     def updateRecords(self, records, create=False):
</span><span class="cx">         for record in records:
</span><span class="cx">             return fail(NotAllowedError(&quot;Record updates not allowed.&quot;))
</span><ins>+        return succeed(None)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def removeRecords(self, uids):
</span><span class="cx">         for uid in uids:
</span><span class="cx">             return fail(NotAllowedError(&quot;Record removal not allowed.&quot;))
</span><ins>+        return succeed(None)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+@implementer(IDirectoryRecord)
</ins><span class="cx"> class DirectoryRecord(object):
</span><del>-    implements(IDirectoryRecord)
</del><ins>+    &quot;&quot;&quot;
+    Generic implementation of L{IDirectoryService}.
</ins><span class="cx"> 
</span><ins>+    This is an incomplete implementation of L{IDirectoryRecord}.
+
+    L{groups} will always fail with L{NotImplementedError} and L{members} will
+    do so if this is a group record.
+    A subclass should override these methods to support group membership and
+    complete this implementation.
+
+    @cvar requiredFields: an iterable of field names that must be present in
+        all directory records.
+    &quot;&quot;&quot;
+
</ins><span class="cx">     requiredFields = (
</span><span class="cx">         FieldName.uid,
</span><span class="cx">         FieldName.recordType,
</span><span class="lines">@@ -183,11 +290,6 @@
</span><span class="cx"> 
</span><span class="cx">             if FieldName.isMultiValue(fieldName):
</span><span class="cx">                 values = fields[fieldName]
</span><del>-                if len(values) == 0:
-                    raise ValueError(
-                        &quot;{0} field must have at least one value.&quot;
-                        .format(fieldName)
-                    )
</del><span class="cx">                 for value in values:
</span><span class="cx">                     if not value:
</span><span class="cx">                         raise ValueError(
</span><span class="lines">@@ -262,32 +364,47 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def description(self):
</span><del>-        description = [self.__class__.__name__, &quot;:&quot;]
</del><ins>+        &quot;&quot;&quot;
+        Generate a string description of this directory record.
</ins><span class="cx"> 
</span><del>-        for name, value in self.fields.items():
</del><ins>+        @return: A description.
+        @rtype: L{unicode}
+        &quot;&quot;&quot;
+        description = [self.__class__.__name__, u&quot;:&quot;]
+
+        for name in sorted(self.service.fieldName.iterconstants()):
+            if name not in self.fields:
+                continue
+
+            value = self.fields[name]
+
</ins><span class="cx">             if hasattr(name, &quot;description&quot;):
</span><span class="cx">                 name = name.description
</span><span class="cx">             else:
</span><del>-                name = str(name)
</del><ins>+                name = unicode(name)
</ins><span class="cx"> 
</span><span class="cx">             if hasattr(value, &quot;description&quot;):
</span><span class="cx">                 value = value.description
</span><span class="cx">             else:
</span><del>-                value = str(value)
</del><ins>+                value = unicode(value)
</ins><span class="cx"> 
</span><del>-            description.append(&quot;\n  &quot;)
</del><ins>+            description.append(u&quot;\n  &quot;)
</ins><span class="cx">             description.append(name)
</span><del>-            description.append(&quot; = &quot;)
</del><ins>+            description.append(u&quot; = &quot;)
</ins><span class="cx">             description.append(value)
</span><span class="cx"> 
</span><del>-        return &quot;&quot;.join(description)
</del><ins>+        description.append(u&quot;\n&quot;)
</ins><span class="cx"> 
</span><ins>+        return u&quot;&quot;.join(description)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def members(self):
</span><span class="cx">         if self.recordType == RecordType.group:
</span><del>-            raise NotImplementedError(&quot;Subclasses must implement members()&quot;)
</del><ins>+            return fail(
+                NotImplementedError(&quot;Subclasses must implement members()&quot;)
+            )
</ins><span class="cx">         return succeed(())
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def groups(self):
</span><del>-        raise NotImplementedError(&quot;Subclasses must implement groups()&quot;)
</del><ins>+        return fail(NotImplementedError(&quot;Subclasses must implement groups()&quot;))
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhoexpressionpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/expression.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/expression.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/expression.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -20,6 +20,9 @@
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> __all__ = [
</span><ins>+    &quot;Operand&quot;,
+    &quot;CompoundExpression&quot;,
+
</ins><span class="cx">     &quot;MatchType&quot;,
</span><span class="cx">     &quot;MatchFlags&quot;,
</span><span class="cx">     &quot;MatchExpression&quot;,
</span><span class="lines">@@ -28,25 +31,55 @@
</span><span class="cx"> from twisted.python.constants import Names, NamedConstant
</span><span class="cx"> from twisted.python.constants import Flags, FlagConstant
</span><span class="cx"> 
</span><ins>+from twext.who.util import iterFlags, describe
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-##
-# Match expression
-##
</del><ins>+#
+# Compound expression
+#
</ins><span class="cx"> 
</span><ins>+class Operand(Names):
+    &quot;&quot;&quot;
+    Contants for common operands.
+    &quot;&quot;&quot;
+    OR  = NamedConstant()
+    AND = NamedConstant()
</ins><span class="cx"> 
</span><ins>+    OR.description  = u&quot;or&quot;
+    AND.description = u&quot;and&quot;
</ins><span class="cx"> 
</span><ins>+
+
+class CompoundExpression(object):
+    &quot;&quot;&quot;
+    An expression that groups multiple expressions with an operand.
+
+    @ivar expressions: An iterable of expressions.
+
+    @ivar operand: A L{NamedConstant} specifying an operand.
+    &quot;&quot;&quot;
+
+    def __init__(self, expressions, operand):
+        self.expressions = expressions
+        self.operand = operand
+
+
+#
+# Match expression
+#
+
</ins><span class="cx"> class MatchType(Names):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Query match types.
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    equals     = NamedConstant()
</del><ins>+    equals = NamedConstant()
+    equals.description = u&quot;equals&quot;
+
</ins><span class="cx">     startsWith = NamedConstant()
</span><del>-    contains   = NamedConstant()
</del><ins>+    startsWith.description = u&quot;starts with&quot;
</ins><span class="cx"> 
</span><del>-    equals.description     = &quot;equals&quot;
-    startsWith.description = &quot;starts with&quot;
-    contains.description   = &quot;contains&quot;
</del><ins>+    contains = NamedConstant()
+    contains.description = u&quot;contains&quot;
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -55,21 +88,95 @@
</span><span class="cx">     Match expression flags.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     NOT = FlagConstant()
</span><del>-    NOT.description = &quot;not&quot;
</del><ins>+    NOT.description = u&quot;not&quot;
</ins><span class="cx"> 
</span><span class="cx">     caseInsensitive = FlagConstant()
</span><del>-    caseInsensitive.description = &quot;case insensitive&quot;
</del><ins>+    caseInsensitive.description = u&quot;case insensitive&quot;
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    @staticmethod
+    def _setMatchFunctions(flags):
+        &quot;&quot;&quot;
+        Compute a predicate and normalize functions for the given match
+        expression flags.
</ins><span class="cx"> 
</span><ins>+        @param flags: Match expression flags.
+        @type flags: L{MatchFlags}
+
+        @return: Predicate and normalize functions.
+        @rtype: L{tuple} of callables.
+        &quot;&quot;&quot;
+        predicate = lambda x: x
+        normalize = lambda x: x
+
+        if flags is None:
+            flags = FlagConstant()
+        else:
+            for flag in iterFlags(flags):
+                if flag == MatchFlags.NOT:
+                    predicate = lambda x: not x
+                elif flag == MatchFlags.caseInsensitive:
+                    normalize = lambda x: x.lower()
+                else:
+                    raise NotImplementedError(
+                        &quot;Unknown query flag: {0}&quot;.format(describe(flag))
+                    )
+
+        flags._predicate = predicate
+        flags._normalize = normalize
+
+        return flags
+
+
+    @staticmethod
+    def predicator(flags):
+        &quot;&quot;&quot;
+        Determine a predicate function for the given flags.
+
+        @param flags: Match expression flags.
+        @type flags: L{MatchFlags}
+
+        @return: a L{callable} that accepts an L{object} argument and returns a
+        L{object} that has the opposite or same truth value as the argument,
+        depending on whether L{MatchFlags.NOT} is or is not in C{flags}.
+        @rtype: callable
+        &quot;&quot;&quot;
+        if not hasattr(flags, &quot;_predicate&quot;):
+            flags = MatchFlags._setMatchFunctions(flags)
+        return flags._predicate
+
+
+    @staticmethod
+    def normalizer(flags):
+        &quot;&quot;&quot;
+        Determine a predicate function for the given flags.
+
+        @param flags: Match expression flags.
+        @type flags: L{MatchFlags}
+
+        @return: a L{callable} that accepts a L{unicode} and returns the same
+        L{unicode} or a normalized L{unicode} that can be compared with other
+        normalized L{unicode}s in a case-insensitive fashion, depending on
+        whether L{MatchFlags.caseInsensitive} is not or is in C{flags}.
+        @rtype: callable
+        &quot;&quot;&quot;
+        if not hasattr(flags, &quot;_normalize&quot;):
+            flags = MatchFlags._setMatchFunctions(flags)
+        return flags._normalize
+
+
+
</ins><span class="cx"> class MatchExpression(object):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Query for a matching value in a given field.
</span><span class="cx"> 
</span><del>-    @ivar fieldName: a L{NamedConstant} specifying the field
-    @ivar fieldValue: a text value to match
-    @ivar matchType: a L{NamedConstant} specifying the match algorythm
-    @ivar flags: L{NamedConstant} specifying additional options
</del><ins>+    @ivar fieldName: A L{NamedConstant} specifying the field.
+
+    @ivar fieldValue: A value to match.
+
+    @ivar matchType: A L{NamedConstant} specifying the match algorithm.
+
+    @ivar flags: A L{NamedConstant} specifying additional options.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     def __init__(
</span><span class="lines">@@ -77,14 +184,15 @@
</span><span class="cx">         fieldName, fieldValue,
</span><span class="cx">         matchType=MatchType.equals, flags=None
</span><span class="cx">     ):
</span><del>-        self.fieldName  = fieldName
</del><ins>+        self.fieldName = fieldName
</ins><span class="cx">         self.fieldValue = fieldValue
</span><del>-        self.matchType  = matchType
-        self.flags      = flags
</del><ins>+        self.matchType = matchType
+        self.flags = flags
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def __repr__(self):
</span><span class="cx">         def describe(constant):
</span><del>-            return getattr(constant, &quot;description&quot;, str(constant))
</del><ins>+            return getattr(constant, &quot;description&quot;, unicode(constant))
</ins><span class="cx"> 
</span><span class="cx">         if self.flags is None:
</span><span class="cx">             flags = &quot;&quot;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhoidirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/idirectory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/idirectory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/idirectory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> &quot;&quot;&quot;
</span><del>-Directory service interface.
</del><ins>+Directory service interfaces.
</ins><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> __all__ = [
</span><span class="lines">@@ -30,21 +30,22 @@
</span><span class="cx"> 
</span><span class="cx">     &quot;RecordType&quot;,
</span><span class="cx">     &quot;FieldName&quot;,
</span><del>-    &quot;Operand&quot;,
</del><span class="cx"> 
</span><span class="cx">     &quot;IDirectoryService&quot;,
</span><span class="cx">     &quot;IDirectoryRecord&quot;,
</span><span class="cx"> ]
</span><span class="cx"> 
</span><ins>+from uuid import UUID
+
</ins><span class="cx"> from zope.interface import Attribute, Interface
</span><span class="cx"> 
</span><span class="cx"> from twisted.python.constants import Names, NamedConstant
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-##
</del><ins>+#
</ins><span class="cx"> # Exceptions
</span><del>-##
</del><ins>+#
</ins><span class="cx"> 
</span><span class="cx"> class DirectoryServiceError(Exception):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -55,7 +56,7 @@
</span><span class="cx"> 
</span><span class="cx"> class DirectoryConfigurationError(DirectoryServiceError):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Directory configurtion error.
</del><ins>+    Directory configuration error.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -93,27 +94,54 @@
</span><span class="cx"> 
</span><span class="cx"> class NotAllowedError(DirectoryServiceError):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Apparently, you can't do that.
</del><ins>+    It seems you aren't permitted to do that.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-##
</del><ins>+#
</ins><span class="cx"> # Data Types
</span><del>-##
</del><ins>+#
</ins><span class="cx"> 
</span><span class="cx"> class RecordType(Names):
</span><ins>+    &quot;&quot;&quot;
+    Constants for common directory record types.
+    &quot;&quot;&quot;
</ins><span class="cx">     user  = NamedConstant()
</span><span class="cx">     group = NamedConstant()
</span><span class="cx"> 
</span><del>-    user.description  = &quot;user&quot;
-    group.description = &quot;group&quot;
</del><ins>+    user.description  = u&quot;user&quot;
+    group.description = u&quot;group&quot;
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class FieldName(Names):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Constants for common field names.
</del><ins>+    Constants for common directory record field names.
+
+    Fields as assciated with either a single value or an iterable of values.
+
+    @cvar uid: The primary unique identifier for a directory record.
+        The associated value must be a L{unicode}.
+
+    @cvar guid: The globally unique identifier for a directory record.
+        The associated value must be a L{UUID} or C{None}.
+
+    @cvar recordType: The type of a directory record.
+        The associated value must be a L{NamedConstant}.
+
+    @cvar shortNames: The short names for a directory record.
+        The associated values must L{unicode}s and there must be at least
+        one associated value.
+
+    @cvar fullNames: The full names for a directory record.
+        The associated values must be L{unicode}s.
+
+    @cvar emailAddresses: The email addresses for a directory record.
+        The associated values must be L{unicodes}.
+
+    @cvar password: The clear text password for a directory record.
+        The associated value must be a L{unicode} or C{None}.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     uid            = NamedConstant()
</span><span class="cx">     guid           = NamedConstant()
</span><span class="lines">@@ -123,14 +151,16 @@
</span><span class="cx">     emailAddresses = NamedConstant()
</span><span class="cx">     password       = NamedConstant()
</span><span class="cx"> 
</span><del>-    uid.description            = &quot;UID&quot;
-    guid.description           = &quot;GUID&quot;
-    recordType.description     = &quot;record type&quot;
-    shortNames.description     = &quot;short names&quot;
-    fullNames.description      = &quot;full names&quot;
-    emailAddresses.description = &quot;email addresses&quot;
-    password.description       = &quot;password&quot;
</del><ins>+    uid.description            = u&quot;UID&quot;
+    guid.description           = u&quot;GUID&quot;
+    recordType.description     = u&quot;record type&quot;
+    shortNames.description     = u&quot;short names&quot;
+    fullNames.description      = u&quot;full names&quot;
+    emailAddresses.description = u&quot;email addresses&quot;
+    password.description       = u&quot;password&quot;
</ins><span class="cx"> 
</span><ins>+    guid.valueType = UUID
+
</ins><span class="cx">     shortNames.multiValue     = True
</span><span class="cx">     fullNames.multiValue      = True
</span><span class="cx">     emailAddresses.multiValue = True
</span><span class="lines">@@ -138,22 +168,36 @@
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="cx">     def isMultiValue(name):
</span><ins>+        &quot;&quot;&quot;
+        Check for whether a field is multi-value (as opposed to single-value).
+
+        @param name: The name of the field.
+        @type name: L{NamedConstant}
+
+        @return: C{True} if the field is multi-value, C{False} otherwise.
+        @rtype: L{BOOL}
+        &quot;&quot;&quot;
</ins><span class="cx">         return getattr(name, &quot;multiValue&quot;, False)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    @staticmethod
+    def valueType(name):
+        &quot;&quot;&quot;
+        Check for the expected type of values for a field.
</ins><span class="cx"> 
</span><del>-class Operand(Names):
-    OR  = NamedConstant()
-    AND = NamedConstant()
</del><ins>+        @param name: The name of the field.
+        @type name: L{NamedConstant}
</ins><span class="cx"> 
</span><del>-    OR.description  = &quot;or&quot;
-    AND.description = &quot;and&quot;
</del><ins>+        @return: The expected type.
+        @rtype: L{type}
+        &quot;&quot;&quot;
+        return getattr(name, &quot;valueType&quot;, unicode)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-##
</del><ins>+#
</ins><span class="cx"> # Interfaces
</span><del>-##
</del><ins>+#
</ins><span class="cx"> 
</span><span class="cx"> class IDirectoryService(Interface):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -169,7 +213,15 @@
</span><span class="cx"> 
</span><span class="cx">     A directory service may allow support the editing, removal and
</span><span class="cx">     addition of records.
</span><ins>+    Services are read-only should fail with L{NotAllowedError} in editing
+    methods.
+
+    The L{FieldName.uid} field, the L{FieldName.guid} field (if not C{None}),
+    and the combination of the L{FieldName.recordType} and
+    L{FieldName.shortName} fields must be unique to each directory record
+    vended by a directory service.
</ins><span class="cx">     &quot;&quot;&quot;
</span><ins>+
</ins><span class="cx">     realmName = Attribute(
</span><span class="cx">         &quot;The name of the authentication realm this service represents.&quot;
</span><span class="cx">     )
</span><span class="lines">@@ -177,32 +229,24 @@
</span><span class="cx"> 
</span><span class="cx">     def recordTypes():
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        @return: an iterable of L{NamedConstant}s denoting the record
-            types that are kept in this directory.
</del><ins>+        Get the record types supported by this directory service.
+
+        @return: The record types that are supported by this directory service.
+        @rtype: iterable of L{NamedConstant}s
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def recordsFromExpression(self, expression):
</del><ins>+    def recordsFromExpression(expression):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Find records matching an expression.
</span><ins>+
</ins><span class="cx">         @param expression: an expression to apply
</span><span class="cx">         @type expression: L{object}
</span><del>-        @return: a deferred iterable of matching L{IDirectoryRecord}s.
-        @raises: L{QueryNotSupportedError} if the expression is not
-            supported by this directory service.
-        &quot;&quot;&quot;
</del><span class="cx"> 
</span><ins>+        @return: The matching records.
+        @rtype: deferred iterable of L{IDirectoryRecord}s
</ins><span class="cx"> 
</span><del>-    def recordsFromQuery(expressions, operand=Operand.AND):
-        &quot;&quot;&quot;
-        Find records by composing a query consisting of an iterable of
-        expressions and an operand.
-        @param expressions: expressions to query against
-        @type expressions: iterable of L{object}s
-        @param operand: an operand
-        @type operand: a L{NamedConstant}
-        @return: a deferred iterable of matching L{IDirectoryRecord}s.
-        @raises: L{QueryNotSupportedError} if the query is not
</del><ins>+        @raises: L{QueryNotSupportedError} if the expression is not
</ins><span class="cx">             supported by this directory service.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -211,80 +255,111 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Find records that have the given field name with the given
</span><span class="cx">         value.
</span><ins>+
</ins><span class="cx">         @param fieldName: a field name
</span><span class="cx">         @type fieldName: L{NamedConstant}
</span><ins>+
</ins><span class="cx">         @param value: a value to match
</span><span class="cx">         @type value: L{bytes}
</span><del>-        @return: a deferred iterable of L{IDirectoryRecord}s.
</del><ins>+
+        @return: The matching records.
+        @rtype: deferred iterable of L{IDirectoryRecord}s
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def recordWithUID(uid):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Find the record that has the given UID.
</span><ins>+
</ins><span class="cx">         @param uid: a UID
</span><span class="cx">         @type uid: L{bytes}
</span><del>-        @return: a deferred iterable of L{IDirectoryRecord}s, or
-            C{None} if there is no such record.
</del><ins>+
+        @return: The matching record or C{None} if there is no match.
+        @rtype: deferred L{IDirectoryRecord}s or C{None}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def recordWithGUID(guid):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Find the record that has the given GUID.
</span><ins>+
</ins><span class="cx">         @param guid: a GUID
</span><del>-        @type guid: L{bytes}
-        @return: a deferred iterable of L{IDirectoryRecord}s, or
-            C{None} if there is no such record.
</del><ins>+        @type guid: L{UUID}
+
+        @return: The matching record or C{None} if there is no match.
+        @rtype: deferred L{IDirectoryRecord}s or C{None}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def recordsWithRecordType(recordType):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Find the records that have the given record type.
</span><ins>+
</ins><span class="cx">         @param recordType: a record type
</span><span class="cx">         @type recordType: L{NamedConstant}
</span><del>-        @return: a deferred iterable of L{IDirectoryRecord}s.
</del><ins>+
+        @return: The matching records.
+        @rtype: deferred iterable of L{IDirectoryRecord}s
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def recordWithShortName(recordType, shortName):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Find the record that has the given record type and short name.
</span><ins>+
</ins><span class="cx">         @param recordType: a record type
</span><span class="cx">         @type recordType: L{NamedConstant}
</span><ins>+
</ins><span class="cx">         @param shortName: a short name
</span><span class="cx">         @type shortName: L{bytes}
</span><del>-        @return: a deferred iterable of L{IDirectoryRecord}s, or
-            C{None} if there is no such record.
</del><ins>+
+        @return: The matching record or C{None} if there is no match.
+        @rtype: deferred L{IDirectoryRecord}s or C{None}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def recordsWithEmailAddress(emailAddress):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Find the records that have the given email address.
</span><ins>+
</ins><span class="cx">         @param emailAddress: an email address
</span><span class="cx">         @type emailAddress: L{bytes}
</span><del>-        @return: a deferred iterable of L{IDirectoryRecord}s, or
-            C{None} if there is no such record.
</del><ins>+
+        @return: The matching records.
+        @rtype: deferred iterable of L{IDirectoryRecord}s
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def updateRecords(records, create=False):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Updates existing directory records.
</span><ins>+
</ins><span class="cx">         @param records: the records to update
</span><span class="cx">         @type records: iterable of L{IDirectoryRecord}s
</span><ins>+
</ins><span class="cx">         @param create: if true, create records if necessary
</span><span class="cx">         @type create: boolean
</span><ins>+
+        @return: unspecifiied
+        @rtype: deferred object
+
+        @raises L{NotAllowedError}: if the update is not allowed by the
+            directory service.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def removeRecords(uids):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Removes the records with the given UIDs.
</span><ins>+
</ins><span class="cx">         @param uids: the UIDs of the records to remove
</span><span class="cx">         @type uids: iterable of L{bytes}
</span><ins>+
+        @return: unspecifiied
+        @rtype: deferred object
+
+        @raises L{NotAllowedError}: if the removal is not allowed by the
+            directory service.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -325,6 +400,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Find the records that are members of this group.  Only direct
</span><span class="cx">         members are included; members of members are not expanded.
</span><ins>+
</ins><span class="cx">         @return: a deferred iterable of L{IDirectoryRecord}s which are
</span><span class="cx">             direct members of this group.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -335,6 +411,7 @@
</span><span class="cx">         Find the group records that this record is a member of.  Only
</span><span class="cx">         groups for which this record is a direct member is are
</span><span class="cx">         included; membership is not expanded.
</span><ins>+
</ins><span class="cx">         @return: a deferred iterable of L{IDirectoryRecord}s which are
</span><span class="cx">             groups that this record is a member of.
</span><span class="cx">         &quot;&quot;&quot;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhoindexpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/index.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/index.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/index.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -30,7 +30,7 @@
</span><span class="cx"> from twisted.internet.defer import succeed, inlineCallbacks, returnValue
</span><span class="cx"> 
</span><span class="cx"> from twext.who.util import ConstantsContainer
</span><del>-from twext.who.util import describe, uniqueResult, iterFlags
</del><ins>+from twext.who.util import uniqueResult
</ins><span class="cx"> from twext.who.idirectory import FieldName as BaseFieldName
</span><span class="cx"> from twext.who.expression import MatchExpression, MatchType, MatchFlags
</span><span class="cx"> from twext.who.directory import DirectoryService as BaseDirectoryService
</span><span class="lines">@@ -44,7 +44,7 @@
</span><span class="cx"> 
</span><span class="cx"> class FieldName(Names):
</span><span class="cx">     memberUIDs = NamedConstant()
</span><del>-    memberUIDs.description = &quot;member UIDs&quot;
</del><ins>+    memberUIDs.description = u&quot;member UIDs&quot;
</ins><span class="cx">     memberUIDs.multiValue = True
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -55,7 +55,91 @@
</span><span class="cx"> 
</span><span class="cx"> class DirectoryService(BaseDirectoryService):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    XML directory service.
</del><ins>+    Generic (and abstract) in-memory-indexed directory service.
+
+    This class implements the record access API in L{BaseDirectoryService} by
+    caching all records in an in-memory dictionary.
+
+    Each indexed field has a top-level key in the index and in turn contains
+    a dictionary in which keys are field values, and values are directory
+    records which have a matching field value for the cooresponding key::
+
+        {
+            &lt;FieldName1&gt;: {
+                &lt;value1a&gt;: set([&lt;record1a1&gt;, ...]),
+                ...
+            },
+            ...
+        }
+
+    Here is an example index for a service with a three user records and one
+    group record::
+
+        {
+            &lt;FieldName=uid&gt;: {
+                u'__calendar-dev__': set([
+                    &lt;DirectoryRecord (group)calendar-dev&gt;
+                ]),
+                u'__dre__': set([
+                    &lt;DirectoryRecord (user)dre&gt;
+                ]),
+                u'__sagen__': set([
+                    &lt;DirectoryRecord (user)sagen&gt;
+                ]),
+                u'__wsanchez__': set([
+                    &lt;DirectoryRecord (user)wsanchez&gt;
+                ])
+            },
+            &lt;FieldName=recordType&gt;: {
+                &lt;RecordType=group&gt;: set([
+                    &lt;DirectoryRecord (group)calendar-dev&gt;,
+                ]),
+                &lt;RecordType=user&gt;: set([
+                    &lt;DirectoryRecord (user)sagen&gt;,
+                    &lt;DirectoryRecord (user)wsanchez&gt;
+                ])
+            },
+            &lt;FieldName=shortNames&gt;: {
+                u'calendar-dev': set([&lt;DirectoryRecord (group)calendar-dev&gt;]),
+                u'dre': set([&lt;DirectoryRecord (user)dre&gt;]),
+                u'sagen': set([&lt;DirectoryRecord (user)sagen&gt;]),
+                u'wilfredo_sanchez': set([&lt;DirectoryRecord (user)wsanchez&gt;]),
+                u'wsanchez': set([&lt;DirectoryRecord (user)wsanchez&gt;])
+            },
+            &lt;FieldName=emailAddresses&gt;: {
+                'dev@bitbucket.calendarserver.org': set([
+                    &lt;DirectoryRecord (group)calendar-dev&gt;
+                ]),
+                'dre@bitbucket.calendarserver.org': set([
+                    &lt;DirectoryRecord (user)dre&gt;
+                ]),
+                'sagen@bitbucket.calendarserver.org': set([
+                    &lt;DirectoryRecord (user)sagen&gt;
+                ]),
+                'shared@example.com': set([
+                    &lt;DirectoryRecord (user)sagen&gt;,
+                    &lt;DirectoryRecord (user)dre&gt;
+                ]),
+                'wsanchez@bitbucket.calendarserver.org': set([
+                    &lt;DirectoryRecord (user)wsanchez&gt;
+                ]),
+                'wsanchez@devnull.twistedmatrix.com': set([
+                    &lt;DirectoryRecord (user)wsanchez&gt;
+                ])
+            },
+            &lt;FieldName=memberUIDs&gt;: {
+                u'__sagen__': set([&lt;DirectoryRecord (group)calendar-dev&gt;]),
+                u'__wsanchez__': set([&lt;DirectoryRecord (group)calendar-dev&gt;])
+            }
+        }
+
+    The field names that are indexed are defined by the C{indexedFields}
+    attribute of the service.
+
+    A subclass must override L{loadRecords}, which populates the index.
+
+    @cvar indexedFields: an iterable of field names (C{NamedConstant})
+        which are indexed.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     fieldName = ConstantsContainer(chain(
</span><span class="lines">@@ -81,58 +165,95 @@
</span><span class="cx"> 
</span><span class="cx">     @property
</span><span class="cx">     def index(self):
</span><ins>+        &quot;&quot;&quot;
+        Call L{loadRecords} and return the index.
+        &quot;&quot;&quot;
</ins><span class="cx">         self.loadRecords()
</span><span class="cx">         return self._index
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    @index.setter
-    def index(self, value):
-        self._index = value
</del><ins>+    def loadRecords(self):
+        &quot;&quot;&quot;
+        Load records.  This method is called by the L{index} property and
+        provides a hook into which the index can be updated.
</ins><span class="cx"> 
</span><ins>+        This method must be implemented by subclasses.
</ins><span class="cx"> 
</span><del>-    def loadRecords(self):
</del><ins>+        An example implementation::
+
+            def loadRecords(self):
+                self.flush()
+                while True:
+                    records = readSomeRecordsFromMyBackEnd()
+                    if not records:
+                        break
+                    self.indexRecords(records)
</ins><span class="cx">         &quot;&quot;&quot;
</span><del>-        Load records.
-        &quot;&quot;&quot;
</del><span class="cx">         raise NotImplementedError(&quot;Subclasses must implement loadRecords().&quot;)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def indexRecords(self, records):
+        &quot;&quot;&quot;
+        Add some records to the index.
+
+        @param records: The records to index.
+        @type records: iterable of L{DirectoryRecord}
+        &quot;&quot;&quot;
+        index = self._index
+
+        for fieldName in self.indexedFields:
+            index.setdefault(fieldName, {})
+
+        for record in records:
+            for fieldName in self.indexedFields:
+                values = record.fields.get(fieldName, None)
+
+                if values is not None:
+                    if not BaseFieldName.isMultiValue(fieldName):
+                        values = (values,)
+
+                    for value in values:
+                        index[fieldName].setdefault(value, set()).add(record)
+
+
</ins><span class="cx">     def flush(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Flush the index.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        self._index = None
</del><ins>+        index = {}
</ins><span class="cx"> 
</span><ins>+        for fieldName in self.indexedFields:
+            index.setdefault(fieldName, {})
</ins><span class="cx"> 
</span><del>-    @staticmethod
-    def _queryFlags(flags):
-        predicate = lambda x: x
-        normalize = lambda x: x
</del><ins>+        self._index = index
</ins><span class="cx"> 
</span><del>-        if flags is not None:
-            for flag in iterFlags(flags):
-                if flag == MatchFlags.NOT:
-                    predicate = lambda x: not x
-                elif flag == MatchFlags.caseInsensitive:
-                    normalize = lambda x: x.lower()
-                else:
-                    raise NotImplementedError(
-                        &quot;Unknown query flag: {0}&quot;.format(describe(flag))
-                    )
</del><span class="cx"> 
</span><del>-        return predicate, normalize
</del><ins>+    def indexedRecordsFromMatchExpression(self, expression, records=None):
+        &quot;&quot;&quot;
+        Finds records in the internal indexes matching a single expression.
</ins><span class="cx"> 
</span><ins>+        @param expression: An expression.
+        @type expression: L{MatchExpression}
</ins><span class="cx"> 
</span><del>-    def indexedRecordsFromMatchExpression(self, expression, records=None):
</del><ins>+        @param records: a set of records to limit the search to. C{None} if
+            the whole directory should be searched.
+        @type records: L{set} or L{frozenset}
+
+        @return: The matching records.
+        @rtype: deferred iterable of L{DirectoryRecord}s
</ins><span class="cx">         &quot;&quot;&quot;
</span><del>-        Finds records in the internal indexes matching a single
-        expression.
-        @param expression: an expression
-        @type expression: L{object}
-        &quot;&quot;&quot;
-        predicate, normalize = self._queryFlags(expression.flags)
</del><ins>+        predicate = MatchFlags.predicator(expression.flags)
+        normalize = MatchFlags.normalizer(expression.flags)
</ins><span class="cx"> 
</span><del>-        fieldIndex = self.index[expression.fieldName]
</del><ins>+        try:
+            fieldIndex = self.index[expression.fieldName]
+        except KeyError:
+            raise TypeError(
+                &quot;indexedRecordsFromMatchExpression() was passed an &quot;
+                &quot;expression with an unindexed field: {0!r}&quot;
+                .format(expression.fieldName)
+            )
+
</ins><span class="cx">         matchValue = normalize(expression.fieldValue)
</span><span class="cx">         matchType  = expression.matchType
</span><span class="cx"> 
</span><span class="lines">@@ -156,27 +277,36 @@
</span><span class="cx">                 )
</span><span class="cx">         else:
</span><span class="cx">             raise NotImplementedError(
</span><del>-                &quot;Unknown match type: {0}&quot;.format(describe(matchType))
</del><ins>+                &quot;Unknown match type: {0!r}&quot;.format(matchType)
</ins><span class="cx">             )
</span><span class="cx"> 
</span><span class="cx">         matchingRecords = set()
</span><span class="cx">         for key in indexKeys:
</span><span class="cx">             matchingRecords |= fieldIndex.get(key, frozenset())
</span><span class="cx"> 
</span><del>-        if records is not None:
-            matchingRecords &amp;= records
</del><ins>+        # Not necessary, so don't unless we know it's a performance win:
+        # if records is not None:
+        #     matchingRecords &amp;= records
</ins><span class="cx"> 
</span><span class="cx">         return succeed(matchingRecords)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def unIndexedRecordsFromMatchExpression(self, expression, records=None):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        Finds records not in the internal indexes matching a single
-        expression.
-        @param expression: an expression
-        @type expression: L{object}
</del><ins>+        Finds records not in the internal indexes matching a single expression.
+
+        @param expression: An expression.
+        @type expression: L{MatchExpression}
+
+        @param records: a set of records to limit the search to. C{None} if
+            the whole directory should be searched.
+        @type records: L{set} or L{frozenset}
+
+        @return: The matching records.
+        @rtype: deferred iterable of L{DirectoryRecord}s
</ins><span class="cx">         &quot;&quot;&quot;
</span><del>-        predicate, normalize = self._queryFlags(expression.flags)
</del><ins>+        predicate = MatchFlags.predicator(expression.flags)
+        normalize = MatchFlags.normalizer(expression.flags)
</ins><span class="cx"> 
</span><span class="cx">         matchValue = normalize(expression.fieldValue)
</span><span class="cx">         matchType  = expression.matchType
</span><span class="lines">@@ -191,7 +321,7 @@
</span><span class="cx">             match = lambda fieldValue: predicate(fieldValue == matchValue)
</span><span class="cx">         else:
</span><span class="cx">             raise NotImplementedError(
</span><del>-                &quot;Unknown match type: {0}&quot;.format(describe(matchType))
</del><ins>+                &quot;Unknown match type: {0!r}&quot;.format(matchType)
</ins><span class="cx">             )
</span><span class="cx"> 
</span><span class="cx">         result = set()
</span><span class="lines">@@ -215,7 +345,11 @@
</span><span class="cx">         return succeed(result)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def recordsFromExpression(self, expression, records=None):
</del><ins>+    def recordsFromNonCompoundExpression(self, expression, records=None):
+        &quot;&quot;&quot;
+        This implementation can handle L{MatchExpression} expressions; other
+        expressions are passed up to the superclass.
+        &quot;&quot;&quot;
</ins><span class="cx">         if isinstance(expression, MatchExpression):
</span><span class="cx">             if expression.fieldName in self.indexedFields:
</span><span class="cx">                 return self.indexedRecordsFromMatchExpression(
</span><span class="lines">@@ -226,7 +360,7 @@
</span><span class="cx">                     expression, records=records
</span><span class="cx">                 )
</span><span class="cx">         else:
</span><del>-            return BaseDirectoryService.recordsFromExpression(
</del><ins>+            return BaseDirectoryService.recordsFromNonCompoundExpression(
</ins><span class="cx">                 self, expression, records=records
</span><span class="cx">             )
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_aggregatepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_aggregate.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_aggregate.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_aggregate.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -22,14 +22,16 @@
</span><span class="cx"> from twisted.trial import unittest
</span><span class="cx"> 
</span><span class="cx"> from twext.who.idirectory import IDirectoryService, DirectoryConfigurationError
</span><del>-from twext.who.aggregate import DirectoryService
</del><ins>+from twext.who.aggregate import DirectoryService, DirectoryRecord
</ins><span class="cx"> from twext.who.util import ConstantsContainer
</span><del>-
</del><span class="cx"> from twext.who.test import test_directory, test_xml
</span><del>-from twext.who.test.test_xml import QueryMixIn, xmlService, TestService as XMLTestService
</del><ins>+from twext.who.test.test_xml import (
+    QueryMixIn, xmlService,
+    TestService as XMLTestService,
+    DirectoryServiceConvenienceTestMixIn
+)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> class BaseTest(object):
</span><span class="cx">     def service(self, services=None):
</span><span class="cx">         if services is None:
</span><span class="lines">@@ -48,18 +50,30 @@
</span><span class="cx">         class TestService(DirectoryService, QueryMixIn):
</span><span class="cx">             pass
</span><span class="cx"> 
</span><del>-        return TestService(&quot;xyzzy&quot;, services)
</del><ins>+        return TestService(u&quot;xyzzy&quot;, services)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def xmlService(self, xmlData=None, serviceClass=None):
</span><del>-        return xmlService(self.mktemp(), xmlData, serviceClass)
</del><ins>+        return xmlService(
+            self.mktemp(),
+            xmlData=xmlData,
+            serviceClass=serviceClass
+        )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceBaseTest(BaseTest, test_xml.DirectoryServiceBaseTest):
</del><ins>+class DirectoryServiceTest(
+    unittest.TestCase,
+    BaseTest,
+    DirectoryServiceConvenienceTestMixIn,
+    test_directory.BaseDirectoryServiceTest
+):
+    serviceClass = DirectoryService
+    directoryRecordClass = DirectoryRecord
+
</ins><span class="cx">     def test_repr(self):
</span><span class="cx">         service = self.service()
</span><del>-        self.assertEquals(repr(service), &quot;&lt;TestService 'xyzzy'&gt;&quot;)
</del><ins>+        self.assertEquals(repr(service), &quot;&lt;TestService u'xyzzy'&gt;&quot;)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -68,8 +82,12 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceImmutableTest(BaseTest, test_directory.DirectoryServiceImmutableTest):
-    pass
</del><ins>+class DirectoryServiceImmutableTest(
+    BaseTest,
+    test_directory.BaseDirectoryServiceImmutableTest,
+):
+    serviceClass = DirectoryService
+    directoryRecordClass = DirectoryRecord
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -81,24 +99,42 @@
</span><span class="cx">         class GroupsDirectoryService(XMLTestService):
</span><span class="cx">             recordType = ConstantsContainer((XMLTestService.recordType.group,))
</span><span class="cx"> 
</span><del>-        usersService  = self.xmlService(testXMLConfigUsers, UsersDirectoryService)
-        groupsService = self.xmlService(testXMLConfigGroups, GroupsDirectoryService)
</del><ins>+        usersService = self.xmlService(
+            xmlData=testXMLConfigUsers,
+            serviceClass=UsersDirectoryService
+        )
+        groupsService = self.xmlService(
+            xmlData=testXMLConfigGroups,
+            serviceClass=GroupsDirectoryService
+        )
</ins><span class="cx"> 
</span><del>-        return BaseTest.service(self, (usersService, groupsService))
</del><ins>+        return BaseTest.service(
+            self,
+            services=(usersService, groupsService)
+        )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceAggregatedBaseTest(AggregatedBaseTest, DirectoryServiceBaseTest):
</del><ins>+class DirectoryServiceAggregatedBaseTest(
+    AggregatedBaseTest,
+    DirectoryServiceTest,
+):
</ins><span class="cx">     pass
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceAggregatedQueryTest(AggregatedBaseTest, test_xml.DirectoryServiceQueryTest):
</del><ins>+class DirectoryServiceAggregatedQueryTest(
+    AggregatedBaseTest,
+    test_xml.DirectoryServiceQueryTest,
+):
</ins><span class="cx">     pass
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceAggregatedImmutableTest(AggregatedBaseTest, test_directory.DirectoryServiceImmutableTest):
</del><ins>+class DirectoryServiceAggregatedImmutableTest(
+    AggregatedBaseTest,
+    test_directory.BaseDirectoryServiceImmutableTest,
+):
</ins><span class="cx">     pass
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -107,8 +143,8 @@
</span><span class="cx">     def test_conflictingRecordTypes(self):
</span><span class="cx">         self.assertRaises(
</span><span class="cx">             DirectoryConfigurationError,
</span><del>-            BaseTest.service, self,
-            (self.xmlService(), self.xmlService(testXMLConfigUsers)),
</del><ins>+            self.service,
+            services=(self.xmlService(), self.xmlService(testXMLConfigUsers)),
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_directorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_directory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_directory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_directory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,32 +18,96 @@
</span><span class="cx"> Generic directory service base implementation tests.
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><ins>+from uuid import UUID
+from textwrap import dedent
+
</ins><span class="cx"> from zope.interface.verify import verifyObject, BrokenMethodImplementation
</span><span class="cx"> 
</span><ins>+from twisted.python.constants import Names, NamedConstant
</ins><span class="cx"> from twisted.trial import unittest
</span><del>-from twisted.trial.unittest import SkipTest
</del><span class="cx"> from twisted.internet.defer import inlineCallbacks
</span><ins>+from twisted.internet.defer import succeed
</ins><span class="cx"> 
</span><span class="cx"> from twext.who.idirectory import QueryNotSupportedError, NotAllowedError
</span><span class="cx"> from twext.who.idirectory import RecordType, FieldName
</span><span class="cx"> from twext.who.idirectory import IDirectoryService, IDirectoryRecord
</span><ins>+from twext.who.expression import CompoundExpression, Operand
</ins><span class="cx"> from twext.who.directory import DirectoryService, DirectoryRecord
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class BaseTest(unittest.TestCase):
-    realmName = &quot;xyzzy&quot;
</del><ins>+class StubDirectoryService(DirectoryService):
+    &quot;&quot;&quot;
+    Stub directory service with some built-in records and an implementation
+    of C{recordsFromNonCompoundExpression}.
+    &quot;&quot;&quot;
</ins><span class="cx"> 
</span><ins>+    def __init__(self, realmName):
+        DirectoryService.__init__(self, realmName)
</ins><span class="cx"> 
</span><del>-    def service(self):
-        if not hasattr(self, &quot;_service&quot;):
-            self._service = DirectoryService(self.realmName)
-        return self._service
</del><ins>+        self.records = RecordStorage(self, DirectoryRecord)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def recordsFromExpression(self, expression):
+        self.seenExpressions = []
</ins><span class="cx"> 
</span><del>-class DirectoryServiceTest(BaseTest):
</del><ins>+        return DirectoryService.recordsFromExpression(self, expression)
+
+
+    def recordsFromNonCompoundExpression(self, expression, records=None):
+        &quot;&quot;&quot;
+        This implementation handles three expressions:
+
+        The expression C{u&quot;None&quot;} will match no records.
+
+        The expressions C{u&quot;twistedmatrix.com&quot;} and C{u&quot;calendarserver.org&quot;}
+        will match records that have an email address ending with the
+        given expression.
+        &quot;&quot;&quot;
+        self.seenExpressions.append(expression)
+
+        if expression == u&quot;None&quot;:
+            return succeed([])
+
+        if expression in (u&quot;twistedmatrix.com&quot;, u&quot;calendarserver.org&quot;):
+            result = []
+            for record in self.records:
+                for email in record.emailAddresses:
+                    if email.endswith(expression):
+                        result.append(record)
+                        break
+            return succeed(result)
+
+        return DirectoryService.recordsFromNonCompoundExpression(
+            self, expression, records=records
+        )
+
+
+
+class ServiceMixIn(object):
+    &quot;&quot;&quot;
+    MixIn that sets up a service appropriate for testing.
+    &quot;&quot;&quot;
+
+    realmName = u&quot;xyzzy&quot;
+
+
+    def service(self, subClass=None):
+        if subClass is None:
+            subClass = self.serviceClass
+        return subClass(self.realmName)
+
+
+
+class BaseDirectoryServiceTest(ServiceMixIn):
+    &quot;&quot;&quot;
+    Tests for directory services.
+    &quot;&quot;&quot;
+
</ins><span class="cx">     def test_interface(self):
</span><ins>+        &quot;&quot;&quot;
+        Service instance conforms to L{IDirectoryService}.
+        &quot;&quot;&quot;
</ins><span class="cx">         service = self.service()
</span><span class="cx">         try:
</span><span class="cx">             verifyObject(IDirectoryService, service)
</span><span class="lines">@@ -52,16 +116,30 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_init(self):
</span><ins>+        &quot;&quot;&quot;
+        Test initialization.
+        &quot;&quot;&quot;
</ins><span class="cx">         service = self.service()
</span><span class="cx">         self.assertEquals(service.realmName, self.realmName)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_repr(self):
</span><ins>+        &quot;&quot;&quot;
+        L{DirectoryService.repr} returns the expected string.
+        &quot;&quot;&quot;
</ins><span class="cx">         service = self.service()
</span><del>-        self.assertEquals(repr(service), &quot;&lt;DirectoryService 'xyzzy'&gt;&quot;)
</del><ins>+        self.assertEquals(
+            repr(service),
+            &quot;&lt;{0} u'xyzzy'&gt;&quot;.format(self.serviceClass.__name__)
+        )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_recordTypes(self):
</span><ins>+        &quot;&quot;&quot;
+        L{DirectoryService.recordTypes} returns the supported set of record
+        types. For L{DirectoryService}, that's the set of constants in the
+        L{DirectoryService.recordType} attribute.
+        &quot;&quot;&quot;
</ins><span class="cx">         service = self.service()
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(service.recordTypes()),
</span><span class="lines">@@ -69,102 +147,451 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def test_recordsFromNonCompoundExpression_unknownExpression(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromNonCompoundExpression} with an unknown
+        expression type fails with L{QueryNotSupportedError}.
+        &quot;&quot;&quot;
+        service = self.service()
+        self.assertFailure(
+            service.recordsFromNonCompoundExpression(object()),
+            QueryNotSupportedError
+        )
+
+
</ins><span class="cx">     @inlineCallbacks
</span><del>-    def test_recordsFromQueryNone(self):
</del><ins>+    def test_recordsFromNonCompoundExpression_emptyRecords(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromNonCompoundExpression} with an unknown
+        expression type and an empty C{records} set returns an empty result.
+        &quot;&quot;&quot;
</ins><span class="cx">         service = self.service()
</span><del>-        records = (yield service.recordsFromQuery(()))
-        for record in records:
-            self.failTest(&quot;No records expected&quot;)
</del><ins>+        result = (
+            yield service.recordsFromNonCompoundExpression(
+                object(), records=()
+            )
+        )
+        self.assertEquals(set(result), set(()))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def test_recordsFromQueryBogus(self):
</del><ins>+    def test_recordsFromNonCompoundExpression_nonEmptyRecords(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromNonCompoundExpression} with an unknown
+        expression type and a non-empty C{records} fails with
+        L{QueryNotSupportedError}.
+        &quot;&quot;&quot;
</ins><span class="cx">         service = self.service()
</span><del>-        self.assertFailure(service.recordsFromQuery((object(),)), QueryNotSupportedError)
</del><span class="cx"> 
</span><ins>+        wsanchez = self.directoryRecordClass(
+            service,
+            {
+                service.fieldName.recordType: service.recordType.user,
+                service.fieldName.uid: u&quot;__wsanchez__&quot;,
+                service.fieldName.shortNames: [u&quot;wsanchez&quot;],
+            }
+        )
</ins><span class="cx"> 
</span><ins>+        self.assertFailure(
+            service.recordsFromNonCompoundExpression(
+                object(), records=((wsanchez,))
+            ),
+            QueryNotSupportedError
+        )
+
+
+    def test_recordsFromExpression_unknownExpression(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromExpression} with an unknown expression
+        type fails with L{QueryNotSupportedError}.
+        &quot;&quot;&quot;
+        service = self.service()
+        result = yield(service.recordsFromExpression(object()))
+        self.assertFailure(result, QueryNotSupportedError)
+
+
+    @inlineCallbacks
+    def test_recordsFromExpression_emptyExpression(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromExpression} with an unknown expression
+        type and an empty L{CompoundExpression} returns an empty result.
+        &quot;&quot;&quot;
+        service = self.service()
+
+        for operand in Operand.iterconstants():
+            result = yield(service.recordsFromExpression(
+                CompoundExpression((), operand)
+            ))
+            self.assertEquals(set(result), set(()))
+
+
+    def _unimplemented(self):
+        &quot;&quot;&quot;
+        Unimplemented test.
+        &quot;&quot;&quot;
+        raise NotImplementedError(&quot;Subclasses should implement this test.&quot;)
+
+
+    test_recordWithUID = _unimplemented
+    test_recordWithGUID = _unimplemented
+    test_recordsWithRecordType = _unimplemented
+    test_recordWithShortName = _unimplemented
+    test_recordsWithEmailAddress = _unimplemented
+
+
+    def test_updateRecordsEmpty(self):
+        &quot;&quot;&quot;
+        Updating no records is not an error.
+        &quot;&quot;&quot;
+        service = self.service()
+        for create in (True, False):
+            service.updateRecords((), create=create),
+
+
+    def test_removeRecordsEmpty(self):
+        &quot;&quot;&quot;
+        Removing no records is allowed.
+        &quot;&quot;&quot;
+        service = self.service()
+
+        service.removeRecords(())
+
+
+
+class DirectoryServiceRecordsFromExpressionTest(
+    unittest.TestCase,
+    ServiceMixIn
+):
+    &quot;&quot;&quot;
+    Tests for L{DirectoryService.recordsFromExpression}.
+    &quot;&quot;&quot;
+    serviceClass = StubDirectoryService
+    directoryRecordClass = DirectoryRecord
+
+    @inlineCallbacks
+    def test_recordsFromExpression_single(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromExpression} handles a single expression.
+        &quot;&quot;&quot;
+        service = self.service()
+
+        result = yield service.recordsFromExpression(&quot;twistedmatrix.com&quot;)
+
+        self.assertEquals(
+            set((
+                u&quot;__wsanchez__&quot;,
+                u&quot;__glyph__&quot;,
+                u&quot;__exarkun__&quot;,
+                u&quot;__dreid__&quot;,
+            )),
+            set((record.uid for record in result))
+        )
+
+
+    @inlineCallbacks
+    def test_recordsFromExpression_OR(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromExpression} handles a
+        L{CompoundExpression} with L{Operand.OR}.
+        &quot;&quot;&quot;
+        service = self.service()
+
+        result = yield service.recordsFromExpression(
+            CompoundExpression(
+                (
+                    u&quot;twistedmatrix.com&quot;,
+                    u&quot;calendarserver.org&quot;,
+                ),
+                Operand.OR
+            )
+        )
+
+        self.assertEquals(
+            set((
+                u&quot;__wsanchez__&quot;,
+                u&quot;__glyph__&quot;,
+                u&quot;__sagen__&quot;,
+                u&quot;__cdaboo__&quot;,
+                u&quot;__dre__&quot;,
+                u&quot;__exarkun__&quot;,
+                u&quot;__dreid__&quot;,
+            )),
+            set((record.uid for record in result))
+        )
+
+
+    @inlineCallbacks
+    def test_recordsFromExpression_AND(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromExpression} handles a
+        L{CompoundExpression} with L{Operand.AND}.
+        &quot;&quot;&quot;
+        service = self.service()
+
+        result = yield service.recordsFromExpression(
+            CompoundExpression(
+                (
+                    u&quot;twistedmatrix.com&quot;,
+                    u&quot;calendarserver.org&quot;,
+                ),
+                Operand.AND
+            )
+        )
+
+        self.assertEquals(
+            set((
+                u&quot;__wsanchez__&quot;,
+                u&quot;__glyph__&quot;,
+            )),
+            set((record.uid for record in result))
+        )
+
+
+    @inlineCallbacks
+    def test_recordsFromExpression_AND_optimized(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromExpression} handles a
+        L{CompoundExpression} with L{Operand.AND}, and when one of the
+        expression matches no records, the subsequent expressions are skipped.
+        &quot;&quot;&quot;
+        service = self.service()
+
+        result = yield service.recordsFromExpression(
+            CompoundExpression(
+                (
+                    u&quot;twistedmatrix.com&quot;,
+                    u&quot;None&quot;,
+                    u&quot;calendarserver.org&quot;,
+                ),
+                Operand.AND
+            )
+        )
+
+        self.assertEquals(
+            set(()),
+            set((record.uid for record in result))
+        )
+
+        self.assertEquals(
+            [u&quot;twistedmatrix.com&quot;, u&quot;None&quot;],
+            service.seenExpressions
+        )
+
+
+    def test_recordsFromExpression_unknownOperand(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromExpression} fails with
+        L{QueryNotSupportedError} when given a L{CompoundExpression} with an
+        unknown operand.
+        &quot;&quot;&quot;
+        service = self.service()
+
+        results = service.recordsFromExpression(
+            CompoundExpression(
+                (
+                    u&quot;twistedmatrix.com&quot;,
+                    u&quot;calendarserver.org&quot;,
+                ),
+                WackyOperand.WHUH
+            )
+        )
+
+        self.assertFailure(results, QueryNotSupportedError)
+
+
+
+class DirectoryServiceConvenienceTest(
+    unittest.TestCase,
+    BaseDirectoryServiceTest
+):
+    &quot;&quot;&quot;
+    Tests for L{DirectoryService} convenience methods.
+    &quot;&quot;&quot;
+    serviceClass = DirectoryService
+    directoryRecordClass = DirectoryRecord
+
+
</ins><span class="cx">     def test_recordWithUID(self):
</span><del>-        raise SkipTest(&quot;Subclasses should implement this test.&quot;)
</del><ins>+        &quot;&quot;&quot;
+        L{DirectoryService.recordWithUID} fails with L{QueryNotSupportedError}.
+        &quot;&quot;&quot;
+        service = self.service()
</ins><span class="cx"> 
</span><ins>+        self.assertFailure(
+            service.recordWithUID(u&quot;&quot;),
+            QueryNotSupportedError
+        )
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordWithGUID(self):
</span><del>-        raise SkipTest(&quot;Subclasses should implement this test.&quot;)
</del><ins>+        &quot;&quot;&quot;
+        L{DirectoryService.recordWithGUID} fails with
+        L{QueryNotSupportedError}.
+        &quot;&quot;&quot;
+        service = self.service()
</ins><span class="cx"> 
</span><ins>+        self.assertFailure(
+            service.recordWithGUID(UUID(int=0)),
+            QueryNotSupportedError
+        )
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordsWithRecordType(self):
</span><del>-        raise SkipTest(&quot;Subclasses should implement this test.&quot;)
</del><ins>+        &quot;&quot;&quot;
+        L{DirectoryService.recordsWithRecordType} fails with
+        L{QueryNotSupportedError}.
+        &quot;&quot;&quot;
+        service = self.service()
</ins><span class="cx"> 
</span><ins>+        for recordType in RecordType.iterconstants():
+            self.assertFailure(
+                service.recordsWithRecordType(recordType),
+                QueryNotSupportedError
+            )
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordWithShortName(self):
</span><del>-        raise SkipTest(&quot;Subclasses should implement this test.&quot;)
</del><ins>+        &quot;&quot;&quot;
+        L{DirectoryService.recordWithShortName} fails with
+        L{QueryNotSupportedError}.
+        &quot;&quot;&quot;
+        service = self.service()
</ins><span class="cx"> 
</span><ins>+        for recordType in RecordType.iterconstants():
+            self.assertFailure(
+                service.recordWithShortName(recordType, u&quot;&quot;),
+                QueryNotSupportedError
+            )
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordsWithEmailAddress(self):
</span><del>-        raise SkipTest(&quot;Subclasses should implement this test.&quot;)
</del><ins>+        &quot;&quot;&quot;
+        L{DirectoryService.recordsWithEmailAddress} fails with
+        L{QueryNotSupportedError}.
+        &quot;&quot;&quot;
+        service = self.service()
</ins><span class="cx"> 
</span><ins>+        self.assertFailure(
+            service.recordsWithEmailAddress(&quot;a@b&quot;),
+            QueryNotSupportedError
+        )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceImmutableTest(BaseTest):
</del><ins>+
+class BaseDirectoryServiceImmutableTest(ServiceMixIn):
+    &quot;&quot;&quot;
+    Tests for immutable directory services.
+    &quot;&quot;&quot;
+
</ins><span class="cx">     def test_updateRecordsNotAllowed(self):
</span><ins>+        &quot;&quot;&quot;
+        Updating records is not allowed.
+        &quot;&quot;&quot;
</ins><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><del>-        newRecord = DirectoryRecord(
</del><ins>+        newRecord = self.directoryRecordClass(
</ins><span class="cx">             service,
</span><del>-            fields = {
-                service.fieldName.uid:        &quot;__plugh__&quot;,
</del><ins>+            fields={
+                service.fieldName.uid: u&quot;__plugh__&quot;,
</ins><span class="cx">                 service.fieldName.recordType: service.recordType.user,
</span><del>-                service.fieldName.shortNames: (&quot;plugh&quot;,),
</del><ins>+                service.fieldName.shortNames: (u&quot;plugh&quot;,),
</ins><span class="cx">             }
</span><span class="cx">         )
</span><span class="cx"> 
</span><del>-        self.assertFailure(
-            service.updateRecords((newRecord,), create=True),
-            NotAllowedError,
-        )
</del><ins>+        for create in (True, False):
+            self.assertFailure(
+                service.updateRecords((newRecord,), create=create),
+                NotAllowedError,
+            )
</ins><span class="cx"> 
</span><del>-        self.assertFailure(
-            service.updateRecords((newRecord,), create=False),
-            NotAllowedError,
-        )
</del><span class="cx"> 
</span><del>-
</del><span class="cx">     def test_removeRecordsNotAllowed(self):
</span><ins>+        &quot;&quot;&quot;
+        Removing records is not allowed.
+        &quot;&quot;&quot;
</ins><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><del>-        service.removeRecords(())
</del><span class="cx">         self.assertFailure(
</span><del>-            service.removeRecords((&quot;foo&quot;,)),
</del><ins>+            service.removeRecords((u&quot;foo&quot;,)),
</ins><span class="cx">             NotAllowedError,
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryRecordTest(BaseTest):
</del><ins>+class DirectoryServiceImmutableTest(
+    unittest.TestCase,
+    BaseDirectoryServiceImmutableTest,
+):
+    &quot;&quot;&quot;
+    Tests for immutable L{DirectoryService}.
+    &quot;&quot;&quot;
+    serviceClass = DirectoryService
+    directoryRecordClass = DirectoryRecord
+
+
+
+class BaseDirectoryRecordTest(ServiceMixIn):
+    &quot;&quot;&quot;
+    Tests for directory records.
+    &quot;&quot;&quot;
+
</ins><span class="cx">     fields_wsanchez = {
</span><del>-        FieldName.uid:            &quot;UID:wsanchez&quot;,
-        FieldName.recordType:     RecordType.user,
-        FieldName.shortNames:     (&quot;wsanchez&quot;, &quot;wilfredo_sanchez&quot;),
-        FieldName.fullNames:      (&quot;Wilfredo Sanchez&quot;, &quot;Wilfredo Sanchez Vega&quot;),
-        FieldName.emailAddresses: (&quot;wsanchez@calendarserver.org&quot;, &quot;wsanchez@example.com&quot;)
</del><ins>+        FieldName.uid: u&quot;UID:wsanchez&quot;,
+        FieldName.recordType: RecordType.user,
+        FieldName.shortNames: (u&quot;wsanchez&quot;, u&quot;wilfredo_sanchez&quot;),
+        FieldName.fullNames: (
+            u&quot;Wilfredo Sanchez&quot;,
+            u&quot;Wilfredo Sanchez Vega&quot;,
+        ),
+        FieldName.emailAddresses: (
+            u&quot;wsanchez@calendarserver.org&quot;,
+            u&quot;wsanchez@example.com&quot;,
+        )
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     fields_glyph = {
</span><del>-        FieldName.uid:            &quot;UID:glyph&quot;,
-        FieldName.recordType:     RecordType.user,
-        FieldName.shortNames:     (&quot;glyph&quot;,),
-        FieldName.fullNames:      (&quot;Glyph Lefkowitz&quot;,),
-        FieldName.emailAddresses: (&quot;glyph@calendarserver.org&quot;,)
</del><ins>+        FieldName.uid: u&quot;UID:glyph&quot;,
+        FieldName.recordType: RecordType.user,
+        FieldName.shortNames: (u&quot;glyph&quot;,),
+        FieldName.fullNames: (u&quot;Glyph Lefkowitz&quot;,),
+        FieldName.emailAddresses: (u&quot;glyph@calendarserver.org&quot;,)
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     fields_sagen = {
</span><del>-        FieldName.uid:            &quot;UID:sagen&quot;,
-        FieldName.recordType:     RecordType.user,
-        FieldName.shortNames:     (&quot;sagen&quot;,),
-        FieldName.fullNames:      (&quot;Morgen Sagen&quot;,),
-        FieldName.emailAddresses: (&quot;sagen@CalendarServer.org&quot;,)
</del><ins>+        FieldName.uid: u&quot;UID:sagen&quot;,
+        FieldName.recordType: RecordType.user,
+        FieldName.shortNames: (u&quot;sagen&quot;,),
+        FieldName.fullNames: (u&quot;Morgen Sagen&quot;,),
+        FieldName.emailAddresses: (u&quot;sagen@CalendarServer.org&quot;,)
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    fields_nobody = {
+        FieldName.uid: u&quot;UID:nobody&quot;,
+        FieldName.recordType: RecordType.user,
+        FieldName.shortNames: (u&quot;nobody&quot;,),
+    }
</ins><span class="cx"> 
</span><del>-    def _testRecord(self, fields=None, service=None):
</del><ins>+    fields_staff = {
+        FieldName.uid: u&quot;UID:staff&quot;,
+        FieldName.recordType: RecordType.group,
+        FieldName.shortNames: (u&quot;staff&quot;,),
+        FieldName.fullNames: (u&quot;Staff&quot;,),
+        FieldName.emailAddresses: (u&quot;staff@CalendarServer.org&quot;,)
+    }
+
+
+    def makeRecord(self, fields=None, service=None):
+        &quot;&quot;&quot;
+        Create a directory record from fields and a service.
+
+        @param fields: Record fields.
+        @type fields: L{dict} with L{FieldName} keys
+
+        @param service: Directory service.
+        @type service: L{DirectoryService}
+
+        @return: A directory record.
+        @rtype: L{DirectoryRecord}
+        &quot;&quot;&quot;
</ins><span class="cx">         if fields is None:
</span><span class="cx">             fields = self.fields_wsanchez
</span><span class="cx">         if service is None:
</span><span class="lines">@@ -173,7 +600,10 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_interface(self):
</span><del>-        record = self._testRecord()
</del><ins>+        &quot;&quot;&quot;
+        L{DirectoryRecord} complies with L{IDirectoryRecord}.
+        &quot;&quot;&quot;
+        record = self.makeRecord()
</ins><span class="cx">         try:
</span><span class="cx">             verifyObject(IDirectoryRecord, record)
</span><span class="cx">         except BrokenMethodImplementation as e:
</span><span class="lines">@@ -181,100 +611,348 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_init(self):
</span><ins>+        &quot;&quot;&quot;
+        L{DirectoryRecord} initialization sets service and fields.
+        &quot;&quot;&quot;
</ins><span class="cx">         service  = self.service()
</span><del>-        wsanchez = self._testRecord(self.fields_wsanchez, service=service)
</del><ins>+        wsanchez = self.makeRecord(self.fields_wsanchez, service=service)
</ins><span class="cx"> 
</span><span class="cx">         self.assertEquals(wsanchez.service, service)
</span><del>-        self.assertEquals(wsanchez.fields , self.fields_wsanchez)
</del><ins>+        self.assertEquals(wsanchez.fields, self.fields_wsanchez)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_initWithNoUID(self):
</span><ins>+        &quot;&quot;&quot;
+        Directory records must have a UID.
+        &quot;&quot;&quot;
</ins><span class="cx">         fields = self.fields_wsanchez.copy()
</span><span class="cx">         del fields[FieldName.uid]
</span><del>-        self.assertRaises(ValueError, self._testRecord, fields)
</del><ins>+        self.assertRaises(ValueError, self.makeRecord, fields)
</ins><span class="cx"> 
</span><span class="cx">         fields = self.fields_wsanchez.copy()
</span><del>-        fields[FieldName.uid] = &quot;&quot;
-        self.assertRaises(ValueError, self._testRecord, fields)
</del><ins>+        fields[FieldName.uid] = u&quot;&quot;
+        self.assertRaises(ValueError, self.makeRecord, fields)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_initWithNoRecordType(self):
</span><ins>+        &quot;&quot;&quot;
+        Directory records must have a record type.
+        &quot;&quot;&quot;
</ins><span class="cx">         fields = self.fields_wsanchez.copy()
</span><span class="cx">         del fields[FieldName.recordType]
</span><del>-        self.assertRaises(ValueError, self._testRecord, fields)
</del><ins>+        self.assertRaises(ValueError, self.makeRecord, fields)
</ins><span class="cx"> 
</span><span class="cx">         fields = self.fields_wsanchez.copy()
</span><del>-        fields[FieldName.recordType] = &quot;&quot;
-        self.assertRaises(ValueError, self._testRecord, fields)
</del><ins>+        fields[FieldName.recordType] = None
+        self.assertRaises(ValueError, self.makeRecord, fields)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def test_initWithBogusRecordType(self):
+        &quot;&quot;&quot;
+        Directory records must have a known record type.
+        &quot;&quot;&quot;
+        fields = self.fields_wsanchez.copy()
+        fields[FieldName.recordType] = object()
+        self.assertRaises(ValueError, self.makeRecord, fields)
+
+
</ins><span class="cx">     def test_initWithNoShortNames(self):
</span><ins>+        &quot;&quot;&quot;
+        Directory records must have a short name.
+        &quot;&quot;&quot;
</ins><span class="cx">         fields = self.fields_wsanchez.copy()
</span><span class="cx">         del fields[FieldName.shortNames]
</span><del>-        self.assertRaises(ValueError, self._testRecord, fields)
</del><ins>+        self.assertRaises(ValueError, self.makeRecord, fields)
</ins><span class="cx"> 
</span><span class="cx">         fields = self.fields_wsanchez.copy()
</span><span class="cx">         fields[FieldName.shortNames] = ()
</span><del>-        self.assertRaises(ValueError, self._testRecord, fields)
</del><ins>+        self.assertRaises(ValueError, self.makeRecord, fields)
</ins><span class="cx"> 
</span><span class="cx">         fields = self.fields_wsanchez.copy()
</span><del>-        fields[FieldName.shortNames] = (&quot;&quot;,)
-        self.assertRaises(ValueError, self._testRecord, fields)
</del><ins>+        fields[FieldName.shortNames] = (u&quot;&quot;,)
+        self.assertRaises(ValueError, self.makeRecord, fields)
</ins><span class="cx"> 
</span><span class="cx">         fields = self.fields_wsanchez.copy()
</span><del>-        fields[FieldName.shortNames] = (&quot;wsanchez&quot;, &quot;&quot;)
-        self.assertRaises(ValueError, self._testRecord, fields)
</del><ins>+        fields[FieldName.shortNames] = (u&quot;wsanchez&quot;, u&quot;&quot;)
+        self.assertRaises(ValueError, self.makeRecord, fields)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def test_initWithBogusRecordType(self):
-        fields = self.fields_wsanchez.copy()
-        fields[FieldName.recordType] = object()
-        self.assertRaises(ValueError, self._testRecord, fields)
</del><ins>+    def test_initNormalizeEmailLowercase(self):
+        &quot;&quot;&quot;
+        Email addresses are normalized to lowercase.
+        &quot;&quot;&quot;
+        sagen = self.makeRecord(self.fields_sagen)
</ins><span class="cx"> 
</span><ins>+        self.assertEquals(
+            sagen.fields[FieldName.emailAddresses],
+            (u&quot;sagen@calendarserver.org&quot;,)
+        )
</ins><span class="cx"> 
</span><del>-    def test_initNormalize(self):
-        sagen = self._testRecord(self.fields_sagen)
</del><span class="cx"> 
</span><ins>+    def test_repr(self):
+        &quot;&quot;&quot;
+        L{DirectoryRecord.repr} returns the expected string.
+        &quot;&quot;&quot;
+        wsanchez = self.makeRecord(self.fields_wsanchez)
+
</ins><span class="cx">         self.assertEquals(
</span><del>-            sagen.fields[FieldName.emailAddresses],
-            (&quot;sagen@calendarserver.org&quot;,)
</del><ins>+            &quot;&lt;DirectoryRecord (user)wsanchez&gt;&quot;,
+            repr(wsanchez)
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_compare(self):
</span><ins>+        &quot;&quot;&quot;
+        Comparison of records.
+        &quot;&quot;&quot;
</ins><span class="cx">         fields_glyphmod = self.fields_glyph.copy()
</span><span class="cx">         del fields_glyphmod[FieldName.emailAddresses]
</span><span class="cx"> 
</span><del>-        wsanchez    = self._testRecord(self.fields_wsanchez)
-        wsanchezmod = self._testRecord(self.fields_wsanchez, DirectoryService(&quot;plugh&quot;))
-        glyph       = self._testRecord(self.fields_glyph)
-        glyphmod    = self._testRecord(fields_glyphmod)
</del><ins>+        plugh = DirectoryService(u&quot;plugh&quot;)
</ins><span class="cx"> 
</span><ins>+        wsanchez    = self.makeRecord(self.fields_wsanchez)
+        wsanchezmod = self.makeRecord(self.fields_wsanchez, plugh)
+        glyph       = self.makeRecord(self.fields_glyph)
+        glyphmod    = self.makeRecord(fields_glyphmod)
+
</ins><span class="cx">         self.assertEquals(wsanchez, wsanchez)
</span><span class="cx">         self.assertNotEqual(wsanchez, glyph)
</span><del>-        self.assertNotEqual(glyph, glyphmod) # UID matches, other fields do not
</del><ins>+        self.assertNotEqual(glyph, glyphmod)  # UID matches, other fields don't
</ins><span class="cx">         self.assertNotEqual(glyphmod, wsanchez)
</span><del>-        self.assertNotEqual(wsanchez, wsanchezmod) # Different service
</del><ins>+        self.assertNotEqual(wsanchez, wsanchezmod)  # Different service
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_attributeAccess(self):
</span><del>-        wsanchez = self._testRecord(self.fields_wsanchez)
</del><ins>+        &quot;&quot;&quot;
+        Fields can be accessed as attributes.
+        &quot;&quot;&quot;
+        wsanchez = self.makeRecord(self.fields_wsanchez)
</ins><span class="cx"> 
</span><del>-        self.assertEquals(wsanchez.recordType    , wsanchez.fields[FieldName.recordType    ])
-        self.assertEquals(wsanchez.uid           , wsanchez.fields[FieldName.uid           ])
-        self.assertEquals(wsanchez.shortNames    , wsanchez.fields[FieldName.shortNames    ])
-        self.assertEquals(wsanchez.emailAddresses, wsanchez.fields[FieldName.emailAddresses])
</del><ins>+        self.assertEquals(
+            wsanchez.recordType,
+            wsanchez.fields[FieldName.recordType]
+        )
+        self.assertEquals(
+            wsanchez.uid,
+            wsanchez.fields[FieldName.uid]
+        )
+        self.assertEquals(
+            wsanchez.shortNames,
+            wsanchez.fields[FieldName.shortNames]
+        )
+        self.assertEquals(
+            wsanchez.emailAddresses,
+            wsanchez.fields[FieldName.emailAddresses]
+        )
</ins><span class="cx"> 
</span><ins>+        self.assertRaises(AttributeError, lambda: wsanchez.fooBarBaz)
+
+        nobody = self.makeRecord(self.fields_nobody)
+
+        self.assertRaises(AttributeError, lambda: nobody.emailAddresses)
+
+
+    def test_description(self):
+        &quot;&quot;&quot;
+        L{DirectoryRecord.description} returns the expected string.
+        &quot;&quot;&quot;
+        sagen = self.makeRecord(self.fields_sagen)
+
+        self.assertEquals(
+            dedent(
+                u&quot;&quot;&quot;
+                DirectoryRecord:
+                  UID = UID:sagen
+                  record type = user
+                  short names = (u'sagen',)
+                  full names = (u'Morgen Sagen',)
+                  email addresses = ('sagen@calendarserver.org',)
+                &quot;&quot;&quot;[1:]
+            ),
+            sagen.description()
+        )
+
+    test_description.todo = &quot;Intermittent order issues&quot;
+
+
+    def test_members_group(self):
+        &quot;&quot;&quot;
+        Group members for group records.
+        &quot;&quot;&quot;
+        raise NotImplementedError(&quot;Subclasses should implement this test.&quot;)
+
+
</ins><span class="cx">     @inlineCallbacks
</span><del>-    def test_members(self):
-        wsanchez = self._testRecord(self.fields_wsanchez)
</del><ins>+    def test_members_nonGroup(self):
+        &quot;&quot;&quot;
+        Group members for non-group records.  Non-groups have no members.
+        &quot;&quot;&quot;
+        wsanchez = self.makeRecord(self.fields_wsanchez)
</ins><span class="cx"> 
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set((yield wsanchez.members())),
</span><span class="cx">             set()
</span><span class="cx">         )
</span><span class="cx"> 
</span><del>-        raise SkipTest(&quot;Subclasses should implement this test.&quot;)
</del><span class="cx"> 
</span><del>-    def test_groups(self):
-        raise SkipTest(&quot;Subclasses should implement this test.&quot;)
</del><ins>+    def test_memberships(self):
+        &quot;&quot;&quot;
+        Group memberships.
+        &quot;&quot;&quot;
+        raise NotImplementedError(&quot;Subclasses should implement this test.&quot;)
+
+
+
+class DirectoryRecordTest(unittest.TestCase, BaseDirectoryRecordTest):
+    &quot;&quot;&quot;
+    Tests for L{DirectoryRecord}.
+    &quot;&quot;&quot;
+    serviceClass = DirectoryService
+    directoryRecordClass = DirectoryRecord
+
+    def test_members_group(self):
+        staff = self.makeRecord(self.fields_staff)
+
+        self.assertFailure(staff.members(), NotImplementedError)
+
+
+    def test_memberships(self):
+        wsanchez = self.makeRecord(self.fields_wsanchez)
+
+        self.assertFailure(wsanchez.groups(), NotImplementedError)
+
+
+
+class RecordStorage(object):
+    &quot;&quot;&quot;
+    Container for directory records.
+    &quot;&quot;&quot;
+    def __init__(self, service, recordClass):
+        self.service = service
+        self.recordClass = recordClass
+        self.records = []
+
+        self.addDefaultRecords()
+
+
+    def addDefaultRecords(self):
+        &quot;&quot;&quot;
+        Add a known set of records to this service.
+        &quot;&quot;&quot;
+        self.addUser(
+            shortNames=[u&quot;wsanchez&quot;, u&quot;wilfredo_sanchez&quot;],
+            fullNames=[
+                u&quot;Wilfredo S\xe1nchez Vega&quot;,
+                u&quot;Wilfredo Sanchez Vega&quot;,
+                u&quot;Wilfredo Sanchez&quot;,
+            ],
+            emailAddresses=[
+                u&quot;wsanchez@bitbucket.calendarserver.org&quot;,
+                u&quot;wsanchez@devnull.twistedmatrix.com&quot;,
+            ],
+        )
+
+        self.addUser(
+            shortNames=[u&quot;glyph&quot;],
+            fullNames=[u&quot;Glyph Lefkowitz&quot;],
+            emailAddresses=[
+                u&quot;glyph@bitbucket.calendarserver.org&quot;,
+                u&quot;glyph@devnull.twistedmatrix.com&quot;,
+            ],
+        )
+
+        self.addUser(
+            shortNames=[u&quot;sagen&quot;],
+            fullNames=[u&quot;Morgen Sagen&quot;],
+            emailAddresses=[
+                u&quot;sagen@bitbucket.calendarserver.org&quot;,
+                u&quot;shared@example.com&quot;,
+            ],
+        )
+
+        self.addUser(
+            shortNames=[u&quot;cdaboo&quot;],
+            fullNames=[u&quot;Cyrus Daboo&quot;],
+            emailAddresses=[
+                u&quot;cdaboo@bitbucket.calendarserver.org&quot;,
+            ],
+        )
+
+        self.addUser(
+            shortNames=[u&quot;dre&quot;],
+            fullNames=[u&quot;Andre LaBranche&quot;],
+            emailAddresses=[
+                u&quot;dre@bitbucket.calendarserver.org&quot;,
+                u&quot;shared@example.com&quot;,
+            ],
+        )
+
+        self.addUser(
+            shortNames=[u&quot;exarkun&quot;],
+            fullNames=[u&quot;Jean-Paul Calderone&quot;],
+            emailAddresses=[
+                u&quot;exarkun@devnull.twistedmatrix.com&quot;,
+            ],
+        )
+
+        self.addUser(
+            shortNames=[u&quot;dreid&quot;],
+            fullNames=[u&quot;David Reid&quot;],
+            emailAddresses=[
+                u&quot;dreid@devnull.twistedmatrix.com&quot;,
+            ],
+        )
+
+        self.addUser(
+            shortNames=[u&quot;joe&quot;],
+            fullNames=[u&quot;Joe Schmoe&quot;],
+            emailAddresses=[
+                u&quot;joe@example.com&quot;,
+            ],
+        )
+
+        self.addUser(
+            shortNames=[u&quot;alyssa&quot;],
+            fullNames=[u&quot;Alyssa P. Hacker&quot;],
+            emailAddresses=[
+                u&quot;alyssa@example.com&quot;,
+            ],
+        )
+
+
+    def addUser(self, shortNames, fullNames, emailAddresses=[]):
+        &quot;&quot;&quot;
+        Add a user record with the given field information.
+
+        @param shortNames: Record short names.
+        @type shortNames: L{list} of L{unicode}s
+
+        @param fullNames: Record full names.
+        @type fullNames: L{list} of L{unicode}s
+
+        @param emailAddresses: Record email addresses.
+        @type emailAddresses: L{list} of L{unicode}s
+        &quot;&quot;&quot;
+        service = self.service
+        fieldName = service.fieldName
+        recordType = service.recordType
+        self.records.append(self.recordClass(self.service, {
+            fieldName.recordType: recordType.user,
+            fieldName.uid: u&quot;__{0}__&quot;.format(shortNames[0]),
+            fieldName.shortNames: shortNames,
+            fieldName.fullNames: fullNames,
+            fieldName.password: u&quot;&quot;.join(reversed(shortNames[0])),
+            fieldName.emailAddresses: emailAddresses,
+        }))
+
+
+    def __iter__(self):
+        return iter(self.records)
+
+
+
+class WackyOperand(Names):
+    &quot;&quot;&quot;
+    Wacky operands.
+    &quot;&quot;&quot;
+    WHUH = NamedConstant()
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_expressionpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_expression.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_expression.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_expression.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -26,29 +26,31 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class MatchExpressionTest(unittest.TestCase):
</span><del>-    def test_repr(self):
</del><ins>+    def test_repr_name(self):
</ins><span class="cx">         self.assertEquals(
</span><del>-            &quot;&lt;MatchExpression: 'full names' equals 'Wilfredo Sanchez'&gt;&quot;,
</del><ins>+            &quot;&lt;MatchExpression: u'full names' equals u'Wilfredo Sanchez'&gt;&quot;,
</ins><span class="cx">             repr(MatchExpression(
</span><span class="cx">                 FieldName.fullNames,
</span><del>-                &quot;Wilfredo Sanchez&quot;,
</del><ins>+                u&quot;Wilfredo Sanchez&quot;,
</ins><span class="cx">             )),
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+    def test_repr_type(self):
</ins><span class="cx">         self.assertEquals(
</span><del>-            &quot;&lt;MatchExpression: 'full names' contains 'Sanchez'&gt;&quot;,
</del><ins>+            &quot;&lt;MatchExpression: u'full names' contains u'Sanchez'&gt;&quot;,
</ins><span class="cx">             repr(MatchExpression(
</span><span class="cx">                 FieldName.fullNames,
</span><del>-                &quot;Sanchez&quot;,
</del><ins>+                u&quot;Sanchez&quot;,
</ins><span class="cx">                 matchType=MatchType.contains,
</span><span class="cx">             )),
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+    def test_repr_flags(self):
</ins><span class="cx">         self.assertEquals(
</span><del>-            &quot;&lt;MatchExpression: 'full names' starts with 'Wilfredo' (not)&gt;&quot;,
</del><ins>+            &quot;&lt;MatchExpression: u'full names' starts with u'Wilfredo' (not)&gt;&quot;,
</ins><span class="cx">             repr(MatchExpression(
</span><span class="cx">                 FieldName.fullNames,
</span><del>-                &quot;Wilfredo&quot;,
</del><ins>+                u&quot;Wilfredo&quot;,
</ins><span class="cx">                 matchType=MatchType.startsWith,
</span><span class="cx">                 flags=MatchFlags.NOT,
</span><span class="cx">             )),
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_indexpyfromrev12016CalendarServertrunktwextwhotesttest_indexpy"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_index.py (from rev 12016, CalendarServer/trunk/twext/who/test/test_index.py) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_index.py                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_index.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,486 @@
</span><ins>+##
+# Copyright (c) 2013 Apple Inc. 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;
+Indexed directory service base implementation tests.
+&quot;&quot;&quot;
+
+from twisted.trial import unittest
+from twisted.internet.defer import inlineCallbacks, returnValue
+
+from twext.who.idirectory import FieldName as BaseFieldName
+from twext.who.idirectory import QueryNotSupportedError
+from twext.who.expression import MatchExpression, MatchType
+from twext.who.index import DirectoryService, DirectoryRecord
+from twext.who.test import test_directory
+from twext.who.test.test_directory import RecordStorage
+
+
+
+def noLoadDirectoryService(superClass):
+    &quot;&quot;&quot;
+    Creates an indexed directory service that has a no-op implementation of
+    L{DirectoryService.loadRecords}.
+
+    @param superClass: The superclass of the new service.
+    @type superClass: subclass of L{DirectoryService}
+
+    @return: A new directory service class.
+    @rtype: subclass of C{superClass}
+    &quot;&quot;&quot;
+    assert issubclass(superClass, DirectoryService)
+
+    class NoLoadDirectoryService(superClass):
+        def loadRecords(self):
+            pass
+
+        def indexedRecordsFromMatchExpression(self, *args, **kwargs):
+            self._calledIndexed = True
+            return superClass.indexedRecordsFromMatchExpression(
+                self, *args, **kwargs
+            )
+
+        def unIndexedRecordsFromMatchExpression(self, *args, **kwargs):
+            self._calledUnindexed = True
+            return superClass.unIndexedRecordsFromMatchExpression(
+                self, *args, **kwargs
+            )
+
+    return NoLoadDirectoryService
+
+
+class BaseDirectoryServiceTest(test_directory.BaseDirectoryServiceTest):
+    &quot;&quot;&quot;
+    Tests for indexed directory services.
+    &quot;&quot;&quot;
+
+    def noLoadServicePopulated(self):
+        service = self.service(
+            subClass=noLoadDirectoryService(self.serviceClass)
+        )
+
+        records = RecordStorage(service, DirectoryRecord)
+        service.indexRecords(records)
+        service.records = records
+
+        return service
+
+    def test_indexRecords_positive(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.indexRecords} ensures all record data is in the
+        index.
+        &quot;&quot;&quot;
+        service = self.noLoadServicePopulated()
+        index = service.index
+
+        # Verify that the fields that should be indexed are, in fact, indexed
+        # for each record.
+        for record in service.records:
+            for fieldName in service.indexedFields:
+                values = record.fields.get(fieldName, None)
+
+                if values is None:
+                    continue
+
+                if not BaseFieldName.isMultiValue(fieldName):
+                    values = (values,)
+
+                for value in values:
+                    self.assertIn(fieldName, index)
+                    self.assertIn(value, index[fieldName])
+
+                    indexedRecords = index[fieldName][value]
+                    self.assertIn(record, indexedRecords)
+
+
+    def test_indexRecords_negative(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.indexRecords} does not have extra data in the index.
+        &quot;&quot;&quot;
+        service = self.noLoadServicePopulated()
+        index = service.index
+
+        # Verify that all data in the index cooresponds to the records passed
+        # in.
+        for fieldName, fieldIndex in index.iteritems():
+            for fieldValue, records in fieldIndex.iteritems():
+                for record in records:
+                    self.assertIn(fieldName, record.fields)
+                    values = record.fields[fieldName]
+
+                    if not BaseFieldName.isMultiValue(fieldName):
+                        values = (values,)
+
+                    self.assertIn(fieldValue, values)
+
+
+    def test_flush(self):
+        &quot;&quot;&quot;
+        C{flush} empties the index.
+        &quot;&quot;&quot;
+        service = self.noLoadServicePopulated()
+
+        self.assertFalse(emptyIndex(service.index))  # Test the test
+        service.flush()
+        self.assertTrue(emptyIndex(service.index))
+
+
+    @inlineCallbacks
+    def _test_indexedRecordsFromMatchExpression(
+        self, inOut, matchType, fieldName=BaseFieldName.shortNames,
+    ):
+        service = self.noLoadServicePopulated()
+
+        for subString, uids in (inOut):
+            records = yield service.indexedRecordsFromMatchExpression(
+                MatchExpression(
+                    fieldName, subString,
+                    matchType
+                )
+            )
+            self.assertEquals(
+                set((record.uid for record in records)),
+                set(uids)
+            )
+
+
+    def test_indexedRecordsFromMatchExpression_startsWith(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.indexedRecordsFromMatchExpression} with a startsWith
+        expression.
+        &quot;&quot;&quot;
+        return self._test_indexedRecordsFromMatchExpression(
+            (
+                (u&quot;w&quot;, (u&quot;__wsanchez__&quot;,)),           # Duplicates
+                (u&quot;dr&quot;, (u&quot;__dre__&quot;, u&quot;__dreid__&quot;)),  # Multiple
+                (u&quot;sage&quot;, (u&quot;__sagen__&quot;,)),           # Single
+            ),
+            MatchType.startsWith
+        )
+
+
+    def test_indexedRecordsFromMatchExpression_contains(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.indexedRecordsFromMatchExpression} with a contains
+        expression.
+        &quot;&quot;&quot;
+        return self._test_indexedRecordsFromMatchExpression(
+            (
+                (u&quot;sanch&quot;, (u&quot;__wsanchez__&quot;,)),       # Duplicates
+                (u&quot;dr&quot;, (u&quot;__dre__&quot;, u&quot;__dreid__&quot;)),  # Multiple
+                (u&quot;agen&quot;, (u&quot;__sagen__&quot;,)),           # Single
+            ),
+            MatchType.contains
+        )
+
+
+    def test_indexedRecordsFromMatchExpression_equals(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.indexedRecordsFromMatchExpression} with an equals
+        expression.
+        &quot;&quot;&quot;
+        return self._test_indexedRecordsFromMatchExpression(
+            (
+                (u&quot;wsanchez&quot;, (u&quot;__wsanchez__&quot;,)),  # MultiValue
+                (u&quot;dre&quot;, (u&quot;__dre__&quot;,)),            # Single value
+            ),
+            MatchType.equals
+        )
+
+
+    def test_indexedRecordsFromMatchExpression_notIndexed(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.indexedRecordsFromMatchExpression} with an
+        unindexed field name.
+        &quot;&quot;&quot;
+        result = self._test_indexedRecordsFromMatchExpression(
+            (
+                (u&quot;zehcnasw&quot;, (u&quot;__wsanchez__&quot;,)),
+            ),
+            MatchType.equals,
+            fieldName=BaseFieldName.password
+        )
+        self.assertFailure(result, TypeError)
+
+
+    def test_indexedRecordsFromMatchExpression_notMatchExpression(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.indexedRecordsFromMatchExpression} with a
+        non-match expression.
+        &quot;&quot;&quot;
+        result = self._test_indexedRecordsFromMatchExpression(
+            (
+                (u&quot;zehcnasw&quot;, (u&quot;__wsanchez__&quot;,)),
+            ),
+            &quot;Not a match type we know about&quot;
+        )
+        self.assertFailure(result, NotImplementedError)
+
+
+    @inlineCallbacks
+    def _test_unIndexedRecordsFromMatchExpression(
+        self, inOut, matchType, fieldName=BaseFieldName.fullNames,
+    ):
+        service = self.noLoadServicePopulated()
+
+        for subString, uids in (inOut):
+            records = yield service.unIndexedRecordsFromMatchExpression(
+                MatchExpression(
+                    fieldName, subString,
+                    matchType
+                )
+            )
+            self.assertEquals(
+                set((record.uid for record in records)),
+                set(uids)
+            )
+
+
+    def test_unIndexedRecordsFromMatchExpression_startsWith(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.unIndexedRecordsFromMatchExpression} with a
+        startsWith expression.
+        &quot;&quot;&quot;
+        return self._test_unIndexedRecordsFromMatchExpression(
+            (
+                (u&quot;Wilfredo&quot;, (u&quot;__wsanchez__&quot;,)),    # Duplicates
+                (u&quot;A&quot;, (u&quot;__alyssa__&quot;, u&quot;__dre__&quot;)),  # Multiple
+                (u&quot;Andre&quot;, (u&quot;__dre__&quot;,)),            # Single
+            ),
+            MatchType.startsWith
+        )
+
+
+    def test_unIndexedRecordsFromMatchExpression_contains(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.unIndexedRecordsFromMatchExpression} with a contains
+        expression.
+        &quot;&quot;&quot;
+        return self._test_unIndexedRecordsFromMatchExpression(
+            (
+                (u&quot;Sanchez&quot;, (u&quot;__wsanchez__&quot;,)),     # Duplicates
+                (u&quot;A&quot;, (u&quot;__alyssa__&quot;, u&quot;__dre__&quot;)),  # Multiple
+                (u&quot;LaBra&quot;, (u&quot;__dre__&quot;,)),            # Single
+            ),
+            MatchType.contains
+        )
+
+
+    def test_unIndexedRecordsFromMatchExpression_equals(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.unIndexedRecordsFromMatchExpression} with an equals
+        expression.
+        &quot;&quot;&quot;
+        return self._test_unIndexedRecordsFromMatchExpression(
+            (
+                (u&quot;Wilfredo Sanchez&quot;, (u&quot;__wsanchez__&quot;,)),  # MultiValue
+                (u&quot;Andre LaBranche&quot;, (u&quot;__dre__&quot;,)),        # Single value
+            ),
+            MatchType.equals
+        )
+
+
+    def test_unIndexedRecordsFromMatchExpression_indexed(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.unIndexedRecordsFromMatchExpression} with an
+        indexed field name.
+        &quot;&quot;&quot;
+        self._test_unIndexedRecordsFromMatchExpression(
+            (
+                (u&quot;wsanchez&quot;, (u&quot;__wsanchez__&quot;,)),
+            ),
+            MatchType.equals,
+            fieldName=BaseFieldName.shortNames
+        )
+
+
+    def test_unIndexedRecordsFromMatchExpression_notMatchExpression(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.unIndexedRecordsFromMatchExpression} with a
+        non-match expression.
+        &quot;&quot;&quot;
+        result = self._test_unIndexedRecordsFromMatchExpression(
+            (
+                (u&quot;zehcnasw&quot;, (u&quot;__wsanchez__&quot;,)),
+            ),
+            &quot;Not a match type we know about&quot;
+        )
+        self.assertFailure(result, NotImplementedError)
+
+
+    @inlineCallbacks
+    def _test_recordsFromNonCompoundExpression(self, expression):
+        service = self.noLoadServicePopulated()
+        yield service.recordsFromNonCompoundExpression(expression)
+        returnValue(service)
+
+
+    @inlineCallbacks
+    def test_recordsFromNonCompoundExpression_match_indexed(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromNonCompoundExpression} with a
+        L{MatchExpression} for an indexed field calls
+        L{DirectoryRecord.indexedRecordsFromMatchExpression}.
+        &quot;&quot;&quot;
+        service = yield self._test_recordsFromNonCompoundExpression(
+            MatchExpression(BaseFieldName.shortNames, u&quot;...&quot;)
+        )
+        self.assertTrue(getattr(service, &quot;_calledIndexed&quot;, False))
+        self.assertFalse(getattr(service, &quot;_calledUnindexed&quot;, False))
+
+
+    @inlineCallbacks
+    def test_recordsFromNonCompoundExpression_match_unindexed(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromNonCompoundExpression} with a
+        L{MatchExpression} for an unindexed field calls
+        L{DirectoryRecord.unIndexedRecordsFromMatchExpression}.
+        &quot;&quot;&quot;
+        service = yield self._test_recordsFromNonCompoundExpression(
+            MatchExpression(BaseFieldName.password, u&quot;...&quot;)
+        )
+        self.assertFalse(getattr(service, &quot;_calledIndexed&quot;, False))
+        self.assertTrue(getattr(service, &quot;_calledUnindexed&quot;, False))
+
+
+    def test_recordsFromNonCompoundExpression_unknown(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.recordsFromNonCompoundExpression} with a
+        an unknown expression calls superclass, which will result in a
+        L{QueryNotSupportedError}.
+        &quot;&quot;&quot;
+        result = self._test_recordsFromNonCompoundExpression(object())
+        self.assertFailure(result, QueryNotSupportedError)
+
+
+
+class DirectoryServiceTest(unittest.TestCase, BaseDirectoryServiceTest):
+    &quot;&quot;&quot;
+    Tests for L{DirectoryService}.
+    &quot;&quot;&quot;
+    serviceClass = DirectoryService
+    directoryRecordClass = DirectoryRecord
+
+
+    def test_init_noIndex(self):
+        &quot;&quot;&quot;
+        Index starts as C{None}.
+        &quot;&quot;&quot;
+        service = self.service()
+        self.assertTrue(emptyIndex(service._index))
+
+
+    def test_index_get(self):
+        &quot;&quot;&quot;
+        Getting the C{index} property calls C{loadRecords}.
+        &quot;&quot;&quot;
+        class TestService(DirectoryService):
+            loaded = False
+
+            def loadRecords(self):
+                self.loaded = True
+
+        service = TestService(u&quot;&quot;)
+        service.index
+        self.assertTrue(service.loaded)
+
+
+    def test_loadRecords(self):
+        &quot;&quot;&quot;
+        L{DirectoryService.loadRecords} raises C{NotImplementedError}.
+        &quot;&quot;&quot;
+        service = self.service()
+        self.assertRaises(NotImplementedError, service.loadRecords)
+
+
+    def _noop(self):
+        &quot;&quot;&quot;
+        Does nothing.
+        &quot;&quot;&quot;
+
+
+    test_recordWithUID = _noop
+    test_recordWithGUID = _noop
+    test_recordsWithRecordType = _noop
+    test_recordWithShortName = _noop
+    test_recordsWithEmailAddress = _noop
+
+
+
+class BaseDirectoryServiceImmutableTest(
+    test_directory.BaseDirectoryServiceImmutableTest
+):
+    &quot;&quot;&quot;
+    Tests for immutable indexed directory services.
+    &quot;&quot;&quot;
+
+
+
+class DirectoryServiceImmutableTest(
+    unittest.TestCase, BaseDirectoryServiceImmutableTest
+):
+    &quot;&quot;&quot;
+    Tests for immutable L{DirectoryService}.
+    &quot;&quot;&quot;
+    serviceClass = DirectoryService
+    directoryRecordClass = DirectoryRecord
+
+
+
+class BaseDirectoryRecordTest(test_directory.BaseDirectoryRecordTest):
+    &quot;&quot;&quot;
+    Tests for indexed directory records.
+    &quot;&quot;&quot;
+
+
+
+class DirectoryRecordTest(unittest.TestCase, BaseDirectoryRecordTest):
+    &quot;&quot;&quot;
+    Tests for L{DirectoryRecord}.
+    &quot;&quot;&quot;
+    serviceClass = DirectoryService
+    directoryRecordClass = DirectoryRecord
+
+
+    def _noop(self):
+        &quot;&quot;&quot;
+        Does nothing.
+        &quot;&quot;&quot;
+
+
+    test_members_group = _noop
+    test_memberships = _noop
+
+
+
+def emptyIndex(index):
+    &quot;&quot;&quot;
+    Determine whether an index is empty.
+
+    @param index: An index.
+    @type index: L{dict}
+
+    @return: true if C{index} is empty, otherwise false.
+    &quot;&quot;&quot;
+    if not index:
+        return True
+
+    for fieldName, fieldIndex in index.iteritems():
+        for fieldValue, records in fieldIndex.iteritems():
+            for record in records:
+                return False
+
+    return True
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_utilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_util.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_util.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -29,11 +29,11 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class Tools(Names):
</span><del>-    hammer      = NamedConstant()
</del><ins>+    hammer = NamedConstant()
</ins><span class="cx">     screwdriver = NamedConstant()
</span><span class="cx"> 
</span><del>-    hammer.description      = &quot;nail pounder&quot;
-    screwdriver.description = &quot;screw twister&quot;
</del><ins>+    hammer.description = u&quot;nail pounder&quot;
+    screwdriver.description = u&quot;screw twister&quot;
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -48,9 +48,9 @@
</span><span class="cx">     g = FlagConstant()
</span><span class="cx">     b = FlagConstant()
</span><span class="cx"> 
</span><del>-    r.description = &quot;red&quot;
-    g.description = &quot;green&quot;
-    b.description = &quot;blue&quot;
</del><ins>+    r.description = u&quot;red&quot;
+    g.description = u&quot;green&quot;
+    b.description = u&quot;blue&quot;
</ins><span class="cx"> 
</span><span class="cx">     black = FlagConstant()
</span><span class="cx"> 
</span><span class="lines">@@ -82,7 +82,11 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">     def test_lookupByName(self):
</span><del>-        constants = set((Instruments.hammer, Tools.screwdriver, Instruments.chisel))
</del><ins>+        constants = set((
+            Instruments.hammer,
+            Tools.screwdriver,
+            Instruments.chisel,
+        ))
</ins><span class="cx">         container = ConstantsContainer(constants)
</span><span class="cx"> 
</span><span class="cx">         self.assertEquals(
</span><span class="lines">@@ -108,13 +112,13 @@
</span><span class="cx"> class UtilTest(unittest.TestCase):
</span><span class="cx">     def test_uniqueResult(self):
</span><span class="cx">         self.assertEquals(1, uniqueResult((1,)))
</span><del>-        self.assertRaises(DirectoryServiceError, uniqueResult, (1,2,3))
</del><ins>+        self.assertRaises(DirectoryServiceError, uniqueResult, (1, 2, 3))
</ins><span class="cx"> 
</span><span class="cx">     def test_describe(self):
</span><del>-        self.assertEquals(&quot;nail pounder&quot;, describe(Tools.hammer))
-        self.assertEquals(&quot;hammer&quot;, describe(Instruments.hammer))
</del><ins>+        self.assertEquals(u&quot;nail pounder&quot;, describe(Tools.hammer))
+        self.assertEquals(u&quot;hammer&quot;, describe(Instruments.hammer))
</ins><span class="cx"> 
</span><span class="cx">     def test_describeFlags(self):
</span><del>-        self.assertEquals(&quot;blue&quot;, describe(Switches.b))
-        self.assertEquals(&quot;red|green&quot;, describe(Switches.r|Switches.g))
-        self.assertEquals(&quot;blue|black&quot;, describe(Switches.b|Switches.black))
</del><ins>+        self.assertEquals(u&quot;blue&quot;, describe(Switches.b))
+        self.assertEquals(u&quot;red|green&quot;, describe(Switches.r | Switches.g))
+        self.assertEquals(u&quot;blue|black&quot;, describe(Switches.b | Switches.black))
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhotesttest_xmlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_xml.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_xml.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/test/test_xml.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -19,26 +19,31 @@
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> from time import sleep
</span><ins>+from uuid import UUID
+from textwrap import dedent
</ins><span class="cx"> 
</span><span class="cx"> from twisted.trial import unittest
</span><span class="cx"> from twisted.python.filepath import FilePath
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks
</span><span class="cx"> 
</span><span class="cx"> from twext.who.idirectory import NoSuchRecordError
</span><del>-from twext.who.idirectory import Operand
</del><ins>+from twext.who.expression import CompoundExpression, Operand
</ins><span class="cx"> from twext.who.expression import MatchExpression, MatchType, MatchFlags
</span><span class="cx"> from twext.who.xml import ParseError
</span><span class="cx"> from twext.who.xml import DirectoryService, DirectoryRecord
</span><ins>+from twext.who.test import test_index
</ins><span class="cx"> 
</span><del>-from twext.who.test import test_directory
</del><span class="cx"> 
</span><span class="cx"> 
</span><ins>+class BaseTest(object):
+    def service(self, subClass=None, xmlData=None):
+        return xmlService(
+            self.mktemp(),
+            xmlData=xmlData,
+            serviceClass=subClass
+        )
</ins><span class="cx"> 
</span><del>-class BaseTest(unittest.TestCase):
-    def service(self, xmlData=None):
-        return xmlService(self.mktemp(), xmlData)
</del><span class="cx"> 
</span><del>-
</del><span class="cx">     def assertRecords(self, records, uids):
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             frozenset((record.uid for record in records)),
</span><span class="lines">@@ -47,30 +52,26 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceBaseTest(BaseTest, test_directory.DirectoryServiceTest):
-    def test_repr(self):
-        service = self.service()
-
-        self.assertEquals(repr(service), &quot;&lt;TestService (not loaded)&gt;&quot;)
-        service.loadRecords()
-        self.assertEquals(repr(service), &quot;&lt;TestService 'xyzzy'&gt;&quot;)
-
-
</del><ins>+class DirectoryServiceConvenienceTestMixIn(BaseTest):
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_recordWithUID(self):
</span><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><del>-        record = (yield service.recordWithUID(&quot;__null__&quot;))
</del><ins>+        record = (yield service.recordWithUID(u&quot;__null__&quot;))
</ins><span class="cx">         self.assertEquals(record, None)
</span><span class="cx"> 
</span><del>-        record = (yield service.recordWithUID(&quot;__wsanchez__&quot;))
-        self.assertEquals(record.uid, &quot;__wsanchez__&quot;)
</del><ins>+        record = (yield service.recordWithUID(u&quot;__wsanchez__&quot;))
+        self.assertEquals(record.uid, u&quot;__wsanchez__&quot;)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_recordWithGUID(self):
</span><span class="cx">         service = self.service()
</span><del>-        record = (yield service.recordWithGUID(&quot;6C495FCD-7E78-4D5C-AA66-BC890AD04C9D&quot;))
</del><ins>+        record = (
+            yield service.recordWithGUID(
+                UUID(&quot;6C495FCD-7E78-4D5C-AA66-BC890AD04C9D&quot;)
+            )
+        )
</ins><span class="cx">         self.assertEquals(record, None)
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -80,27 +81,33 @@
</span><span class="cx">         records = (yield service.recordsWithRecordType(object()))
</span><span class="cx">         self.assertEquals(set(records), set())
</span><span class="cx"> 
</span><del>-        records = (yield service.recordsWithRecordType(service.recordType.user))
-        self.assertRecords(records,
</del><ins>+        records = (
+            yield service.recordsWithRecordType(service.recordType.user)
+        )
+        self.assertRecords(
+            records,
</ins><span class="cx">             (
</span><del>-                &quot;__wsanchez__&quot;,
-                &quot;__glyph__&quot;,
-                &quot;__sagen__&quot;,
-                &quot;__cdaboo__&quot;,
-                &quot;__dre__&quot;,
-                &quot;__exarkun__&quot;,
-                &quot;__dreid__&quot;,
-                &quot;__alyssa__&quot;,
-                &quot;__joe__&quot;,
</del><ins>+                u&quot;__wsanchez__&quot;,
+                u&quot;__glyph__&quot;,
+                u&quot;__sagen__&quot;,
+                u&quot;__cdaboo__&quot;,
+                u&quot;__dre__&quot;,
+                u&quot;__exarkun__&quot;,
+                u&quot;__dreid__&quot;,
+                u&quot;__alyssa__&quot;,
+                u&quot;__joe__&quot;,
</ins><span class="cx">             ),
</span><span class="cx">         )
</span><span class="cx"> 
</span><del>-        records = (yield service.recordsWithRecordType(service.recordType.group))
-        self.assertRecords(records,
</del><ins>+        records = (
+            yield service.recordsWithRecordType(service.recordType.group)
+        )
+        self.assertRecords(
+            records,
</ins><span class="cx">             (
</span><del>-                &quot;__calendar-dev__&quot;,
-                &quot;__twisted__&quot;,
-                &quot;__developers__&quot;,
</del><ins>+                u&quot;__calendar-dev__&quot;,
+                u&quot;__twisted__&quot;,
+                u&quot;__developers__&quot;,
</ins><span class="cx">             ),
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -109,42 +116,86 @@
</span><span class="cx">     def test_recordWithShortName(self):
</span><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><del>-        record = (yield service.recordWithShortName(service.recordType.user, &quot;null&quot;))
</del><ins>+        record = (
+            yield service.recordWithShortName(
+                service.recordType.user,
+                u&quot;null&quot;,
+            )
+        )
</ins><span class="cx">         self.assertEquals(record, None)
</span><span class="cx"> 
</span><del>-        record = (yield service.recordWithShortName(service.recordType.user, &quot;wsanchez&quot;))
-        self.assertEquals(record.uid, &quot;__wsanchez__&quot;)
</del><ins>+        record = (
+            yield service.recordWithShortName(
+                service.recordType.user,
+                u&quot;wsanchez&quot;,
+            )
+        )
+        self.assertEquals(record.uid, u&quot;__wsanchez__&quot;)
</ins><span class="cx"> 
</span><del>-        record = (yield service.recordWithShortName(service.recordType.user, &quot;wilfredo_sanchez&quot;))
-        self.assertEquals(record.uid, &quot;__wsanchez__&quot;)
</del><ins>+        record = (
+            yield service.recordWithShortName(
+                service.recordType.user,
+                u&quot;wilfredo_sanchez&quot;,
+            )
+        )
+        self.assertEquals(record.uid, u&quot;__wsanchez__&quot;)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_recordsWithEmailAddress(self):
</span><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><del>-        records = (yield service.recordsWithEmailAddress(&quot;wsanchez@bitbucket.calendarserver.org&quot;))
-        self.assertRecords(records, (&quot;__wsanchez__&quot;,))
</del><ins>+        records = (
+            yield service.recordsWithEmailAddress(
+                u&quot;wsanchez@bitbucket.calendarserver.org&quot;
+            )
+        )
+        self.assertRecords(records, (u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><del>-        records = (yield service.recordsWithEmailAddress(&quot;wsanchez@devnull.twistedmatrix.com&quot;))
-        self.assertRecords(records, (&quot;__wsanchez__&quot;,))
</del><ins>+        records = (
+            yield service.recordsWithEmailAddress(
+                u&quot;wsanchez@devnull.twistedmatrix.com&quot;
+            )
+        )
+        self.assertRecords(records, (u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><del>-        records = (yield service.recordsWithEmailAddress(&quot;shared@example.com&quot;))
-        self.assertRecords(records, (&quot;__sagen__&quot;, &quot;__dre__&quot;))
</del><ins>+        records = (
+            yield service.recordsWithEmailAddress(
+                u&quot;shared@example.com&quot;
+            )
+        )
+        self.assertRecords(records, (u&quot;__sagen__&quot;, u&quot;__dre__&quot;))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceRealmTest(BaseTest):
</del><ins>+class DirectoryServiceTest(
+    unittest.TestCase,
+    DirectoryServiceConvenienceTestMixIn,
+    test_index.BaseDirectoryServiceTest,
+):
+    serviceClass = DirectoryService
+    directoryRecordClass = DirectoryRecord
+
+    def test_repr(self):
+        service = self.service()
+
+        self.assertEquals(repr(service), &quot;&lt;TestService (not loaded)&gt;&quot;)
+        service.loadRecords()
+        self.assertEquals(repr(service), &quot;&lt;TestService u'xyzzy'&gt;&quot;)
+
+
+
+class DirectoryServiceRealmTest(unittest.TestCase, BaseTest):
</ins><span class="cx">     def test_realmNameImmutable(self):
</span><span class="cx">         def setRealmName():
</span><span class="cx">             service = self.service()
</span><del>-            service.realmName = &quot;foo&quot;
</del><ins>+            service.realmName = u&quot;foo&quot;
</ins><span class="cx"> 
</span><span class="cx">         self.assertRaises(AssertionError, setRealmName)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceParsingTest(BaseTest):
</del><ins>+class DirectoryServiceParsingTest(unittest.TestCase, BaseTest):
</ins><span class="cx">     def test_reloadInterval(self):
</span><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><span class="lines">@@ -176,12 +227,13 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_badRootElement(self):
</span><del>-        service = self.service(xmlData=
-&quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</del><ins>+        service = self.service(xmlData=(dedent(
+            b&quot;&quot;&quot;
+            &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</ins><span class="cx"> 
</span><del>-&lt;frobnitz /&gt;
-&quot;&quot;&quot;
-        )
</del><ins>+            &lt;frobnitz /&gt;
+            &quot;&quot;&quot;[1:]
+        )))
</ins><span class="cx"> 
</span><span class="cx">         self.assertRaises(ParseError, service.loadRecords)
</span><span class="cx">         try:
</span><span class="lines">@@ -189,16 +241,17 @@
</span><span class="cx">         except ParseError as e:
</span><span class="cx">             self.assertTrue(str(e).startswith(&quot;Incorrect root element&quot;), e)
</span><span class="cx">         else:
</span><del>-            raise AssertionError
</del><ins>+            raise AssertionError(&quot;Expected ParseError&quot;)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_noRealmName(self):
</span><del>-        service = self.service(xmlData=
-&quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</del><ins>+        service = self.service(xmlData=(dedent(
+            b&quot;&quot;&quot;
+            &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</ins><span class="cx"> 
</span><del>-&lt;directory /&gt;
-&quot;&quot;&quot;
-        )
</del><ins>+            &lt;directory /&gt;
+            &quot;&quot;&quot;[1:]
+        )))
</ins><span class="cx"> 
</span><span class="cx">         self.assertRaises(ParseError, service.loadRecords)
</span><span class="cx">         try:
</span><span class="lines">@@ -206,7 +259,7 @@
</span><span class="cx">         except ParseError as e:
</span><span class="cx">             self.assertTrue(str(e).startswith(&quot;No realm name&quot;), e)
</span><span class="cx">         else:
</span><del>-            raise AssertionError
</del><ins>+            raise AssertionError(&quot;Expected ParseError&quot;)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_unknownFieldElementsClean(self):
</span><span class="lines">@@ -215,19 +268,23 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_unknownFieldElementsDirty(self):
</span><del>-        service = self.service(xmlData=
-&quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</del><ins>+        service = self.service(xmlData=(dedent(
+            b&quot;&quot;&quot;
+            &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</ins><span class="cx"> 
</span><del>-&lt;directory realm=&quot;Unknown Record Types&quot;&gt;
-  &lt;record type=&quot;user&quot;&gt;
-    &lt;uid&gt;__wsanchez__&lt;/uid&gt;
-    &lt;short-name&gt;wsanchez&lt;/short-name&gt;
-    &lt;political-affiliation&gt;Community and Freedom Party&lt;/political-affiliation&gt;
-  &lt;/record&gt;
-&lt;/directory&gt;
-&quot;&quot;&quot;
</del><ins>+            &lt;directory realm=&quot;Unknown Record Types&quot;&gt;
+              &lt;record type=&quot;user&quot;&gt;
+                &lt;uid&gt;__wsanchez__&lt;/uid&gt;
+                &lt;short-name&gt;wsanchez&lt;/short-name&gt;
+                &lt;political-affiliation&gt;Community and Freedom Party&lt;/political-affiliation&gt;
+              &lt;/record&gt;
+            &lt;/directory&gt;
+            &quot;&quot;&quot;[1:]
+        )))
+        self.assertEquals(
+            set(service.unknownFieldElements),
+            set((u&quot;political-affiliation&quot;,))
</ins><span class="cx">         )
</span><del>-        self.assertEquals(set(service.unknownFieldElements), set((&quot;political-affiliation&quot;,)))
</del><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_unknownRecordTypesClean(self):
</span><span class="lines">@@ -236,34 +293,37 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_unknownRecordTypesDirty(self):
</span><del>-        service = self.service(xmlData=
-&quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</del><ins>+        service = self.service(xmlData=(dedent(
+            b&quot;&quot;&quot;
+            &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</ins><span class="cx"> 
</span><del>-&lt;directory realm=&quot;Unknown Record Types&quot;&gt;
-  &lt;record type=&quot;camera&quot;&gt;
-    &lt;uid&gt;__d600__&lt;/uid&gt;
-    &lt;short-name&gt;d600&lt;/short-name&gt;
-    &lt;full-name&gt;Nikon D600&lt;/full-name&gt;
-  &lt;/record&gt;
-&lt;/directory&gt;
-&quot;&quot;&quot;
-        )
-        self.assertEquals(set(service.unknownRecordTypes), set((&quot;camera&quot;,)))
</del><ins>+            &lt;directory realm=&quot;Unknown Record Types&quot;&gt;
+              &lt;record type=&quot;camera&quot;&gt;
+                &lt;uid&gt;__d600__&lt;/uid&gt;
+                &lt;short-name&gt;d600&lt;/short-name&gt;
+                &lt;full-name&gt;Nikon D600&lt;/full-name&gt;
+              &lt;/record&gt;
+            &lt;/directory&gt;
+            &quot;&quot;&quot;[1:]
+        )))
+        self.assertEquals(set(service.unknownRecordTypes), set((u&quot;camera&quot;,)))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceQueryTest(BaseTest):
</del><ins>+class DirectoryServiceQueryTest(unittest.TestCase, BaseTest):
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryAnd(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery(
-            (
-                service.query(&quot;emailAddresses&quot;, &quot;shared@example.com&quot;),
-                service.query(&quot;shortNames&quot;, &quot;sagen&quot;),
-            ),
-            operand=Operand.AND
</del><ins>+        records = yield service.recordsFromExpression(
+            CompoundExpression(
+                (
+                    service.query(u&quot;emailAddresses&quot;, u&quot;shared@example.com&quot;),
+                    service.query(u&quot;shortNames&quot;, u&quot;sagen&quot;),
+                ),
+                operand=Operand.AND
+            )
</ins><span class="cx">         )
</span><del>-        self.assertRecords(records, (&quot;__sagen__&quot;,))
</del><ins>+        self.assertRecords(records, (u&quot;__sagen__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -272,12 +332,14 @@
</span><span class="cx">         Test optimized case, where first expression yields no results.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery(
-            (
-                service.query(&quot;emailAddresses&quot;, &quot;nobody@example.com&quot;),
-                service.query(&quot;shortNames&quot;, &quot;sagen&quot;),
-            ),
-            operand=Operand.AND
</del><ins>+        records = yield service.recordsFromExpression(
+            CompoundExpression(
+                (
+                    service.query(u&quot;emailAddresses&quot;, u&quot;nobody@example.com&quot;),
+                    service.query(u&quot;shortNames&quot;, u&quot;sagen&quot;),
+                ),
+                operand=Operand.AND
+            )
</ins><span class="cx">         )
</span><span class="cx">         self.assertRecords(records, ())
</span><span class="cx"> 
</span><span class="lines">@@ -285,102 +347,131 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryOr(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery(
-            (
-                service.query(&quot;emailAddresses&quot;, &quot;shared@example.com&quot;),
-                service.query(&quot;shortNames&quot;, &quot;wsanchez&quot;),
-            ),
-            operand=Operand.OR
</del><ins>+        records = yield service.recordsFromExpression(
+            CompoundExpression(
+                (
+                    service.query(u&quot;emailAddresses&quot;, u&quot;shared@example.com&quot;),
+                    service.query(u&quot;shortNames&quot;, u&quot;wsanchez&quot;),
+                ),
+                operand=Operand.OR
+            )
</ins><span class="cx">         )
</span><del>-        self.assertRecords(records, (&quot;__sagen__&quot;, &quot;__dre__&quot;, &quot;__wsanchez__&quot;))
</del><ins>+        self.assertRecords(
+            records,
+            (u&quot;__sagen__&quot;, u&quot;__dre__&quot;, u&quot;__wsanchez__&quot;)
+        )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryNot(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery(
-            (
-                service.query(&quot;emailAddresses&quot;, &quot;shared@example.com&quot;),
-                service.query(&quot;shortNames&quot;, &quot;sagen&quot;, flags=MatchFlags.NOT),
-            ),
-            operand=Operand.AND
</del><ins>+        records = yield service.recordsFromExpression(
+            CompoundExpression(
+                (
+                    service.query(
+                        u&quot;emailAddresses&quot;, u&quot;shared@example.com&quot;
+                    ),
+                    service.query(
+                        u&quot;shortNames&quot;, u&quot;sagen&quot;,
+                        flags=MatchFlags.NOT
+                    ),
+                ),
+                operand=Operand.AND
+            )
</ins><span class="cx">         )
</span><del>-        self.assertRecords(records, (&quot;__dre__&quot;,))
</del><ins>+        self.assertRecords(records, (u&quot;__dre__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryNotNoIndex(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery(
-            (
-                service.query(&quot;emailAddresses&quot;, &quot;shared@example.com&quot;),
-                service.query(&quot;fullNames&quot;, &quot;Andre LaBranche&quot;, flags=MatchFlags.NOT),
-            ),
-            operand=Operand.AND
</del><ins>+        records = yield service.recordsFromExpression(
+            CompoundExpression(
+                (
+                    service.query(u&quot;emailAddresses&quot;, u&quot;shared@example.com&quot;),
+                    service.query(
+                        u&quot;fullNames&quot;, u&quot;Andre LaBranche&quot;,
+                        flags=MatchFlags.NOT
+                    ),
+                ),
+                operand=Operand.AND
+            )
</ins><span class="cx">         )
</span><del>-        self.assertRecords(records, (&quot;__sagen__&quot;,))
</del><ins>+        self.assertRecords(records, (u&quot;__sagen__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryCaseInsensitive(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
-            service.query(&quot;shortNames&quot;, &quot;SagEn&quot;, flags=MatchFlags.caseInsensitive),
-        ))
-        self.assertRecords(records, (&quot;__sagen__&quot;,))
</del><ins>+        records = yield service.recordsFromExpression(
+            service.query(
+                u&quot;shortNames&quot;, u&quot;SagEn&quot;,
+                flags=MatchFlags.caseInsensitive
+            )
+        )
+        self.assertRecords(records, (u&quot;__sagen__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryCaseInsensitiveNoIndex(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
-            service.query(&quot;fullNames&quot;, &quot;moRGen SAGen&quot;, flags=MatchFlags.caseInsensitive),
-        ))
-        self.assertRecords(records, (&quot;__sagen__&quot;,))
</del><ins>+        records = yield service.recordsFromExpression(
+            service.query(
+                u&quot;fullNames&quot;, u&quot;moRGen SAGen&quot;,
+                flags=MatchFlags.caseInsensitive
+            )
+        )
+        self.assertRecords(records, (u&quot;__sagen__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryStartsWith(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
-            service.query(&quot;shortNames&quot;, &quot;wil&quot;, matchType=MatchType.startsWith),
-        ))
-        self.assertRecords(records, (&quot;__wsanchez__&quot;,))
</del><ins>+        records = yield service.recordsFromExpression(
+            service.query(
+                u&quot;shortNames&quot;, u&quot;wil&quot;,
+                matchType=MatchType.startsWith
+            )
+        )
+        self.assertRecords(records, (u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryStartsWithNoIndex(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
-            service.query(&quot;fullNames&quot;, &quot;Wilfredo&quot;, matchType=MatchType.startsWith),
-        ))
-        self.assertRecords(records, (&quot;__wsanchez__&quot;,))
</del><ins>+        records = yield service.recordsFromExpression(
+            service.query(
+                u&quot;fullNames&quot;, u&quot;Wilfredo&quot;,
+                matchType=MatchType.startsWith
+            )
+        )
+        self.assertRecords(records, (u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryStartsWithNot(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
</del><ins>+        records = yield service.recordsFromExpression(
</ins><span class="cx">             service.query(
</span><del>-                &quot;shortNames&quot;, &quot;w&quot;,
-                matchType = MatchType.startsWith,
-                flags = MatchFlags.NOT,
-            ),
-        ))
</del><ins>+                u&quot;shortNames&quot;, u&quot;w&quot;,
+                matchType=MatchType.startsWith,
+                flags=MatchFlags.NOT,
+            )
+        )
</ins><span class="cx">         self.assertRecords(
</span><span class="cx">             records,
</span><span class="cx">             (
</span><del>-                '__alyssa__',
-                '__calendar-dev__',
-                '__cdaboo__',
-                '__developers__',
-                '__dre__',
-                '__dreid__',
-                '__exarkun__',
-                '__glyph__',
-                '__joe__',
-                '__sagen__',
-                '__twisted__',
</del><ins>+                u&quot;__alyssa__&quot;,
+                u&quot;__calendar-dev__&quot;,
+                u&quot;__cdaboo__&quot;,
+                u&quot;__developers__&quot;,
+                u&quot;__dre__&quot;,
+                u&quot;__dreid__&quot;,
+                u&quot;__exarkun__&quot;,
+                u&quot;__glyph__&quot;,
+                u&quot;__joe__&quot;,
+                u&quot;__sagen__&quot;,
+                u&quot;__twisted__&quot;,
</ins><span class="cx">             ),
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -394,28 +485,28 @@
</span><span class="cx">         should NOT require that all match?
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
</del><ins>+        records = yield service.recordsFromExpression(
</ins><span class="cx">             service.query(
</span><del>-                &quot;shortNames&quot;, &quot;wil&quot;,
-                matchType = MatchType.startsWith,
-                flags = MatchFlags.NOT,
-            ),
-        ))
</del><ins>+                u&quot;shortNames&quot;, u&quot;wil&quot;,
+                matchType=MatchType.startsWith,
+                flags=MatchFlags.NOT,
+            )
+        )
</ins><span class="cx">         self.assertRecords(
</span><span class="cx">             records,
</span><span class="cx">             (
</span><del>-                '__alyssa__',
-                '__calendar-dev__',
-                '__cdaboo__',
-                '__developers__',
-                '__dre__',
-                '__dreid__',
-                '__exarkun__',
-                '__glyph__',
-                '__joe__',
-                '__sagen__',
-                '__twisted__',
-                '__wsanchez__',
</del><ins>+                u&quot;__alyssa__&quot;,
+                u&quot;__calendar-dev__&quot;,
+                u&quot;__cdaboo__&quot;,
+                u&quot;__developers__&quot;,
+                u&quot;__dre__&quot;,
+                u&quot;__dreid__&quot;,
+                u&quot;__exarkun__&quot;,
+                u&quot;__glyph__&quot;,
+                u&quot;__joe__&quot;,
+                u&quot;__sagen__&quot;,
+                u&quot;__twisted__&quot;,
+                u&quot;__wsanchez__&quot;,
</ins><span class="cx">             ),
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -423,27 +514,27 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryStartsWithNotNoIndex(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
</del><ins>+        records = yield service.recordsFromExpression(
</ins><span class="cx">             service.query(
</span><del>-                &quot;fullNames&quot;, &quot;Wilfredo&quot;,
-                matchType = MatchType.startsWith,
-                flags = MatchFlags.NOT,
-            ),
-        ))
</del><ins>+                u&quot;fullNames&quot;, u&quot;Wilfredo&quot;,
+                matchType=MatchType.startsWith,
+                flags=MatchFlags.NOT,
+            )
+        )
</ins><span class="cx">         self.assertRecords(
</span><span class="cx">             records,
</span><span class="cx">             (
</span><del>-                '__alyssa__',
-                '__calendar-dev__',
-                '__cdaboo__',
-                '__developers__',
-                '__dre__',
-                '__dreid__',
-                '__exarkun__',
-                '__glyph__',
-                '__joe__',
-                '__sagen__',
-                '__twisted__',
</del><ins>+                u&quot;__alyssa__&quot;,
+                u&quot;__calendar-dev__&quot;,
+                u&quot;__cdaboo__&quot;,
+                u&quot;__developers__&quot;,
+                u&quot;__dre__&quot;,
+                u&quot;__dreid__&quot;,
+                u&quot;__exarkun__&quot;,
+                u&quot;__glyph__&quot;,
+                u&quot;__joe__&quot;,
+                u&quot;__sagen__&quot;,
+                u&quot;__twisted__&quot;,
</ins><span class="cx">             ),
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -451,71 +542,77 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryStartsWithCaseInsensitive(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
</del><ins>+        records = yield service.recordsFromExpression(
</ins><span class="cx">             service.query(
</span><del>-                &quot;shortNames&quot;, &quot;WIL&quot;,
-                matchType = MatchType.startsWith,
-                flags = MatchFlags.caseInsensitive,
-            ),
-        ))
-        self.assertRecords(records, (&quot;__wsanchez__&quot;,))
</del><ins>+                u&quot;shortNames&quot;, u&quot;WIL&quot;,
+                matchType=MatchType.startsWith,
+                flags=MatchFlags.caseInsensitive,
+            )
+        )
+        self.assertRecords(records, (u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryStartsWithCaseInsensitiveNoIndex(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
</del><ins>+        records = yield service.recordsFromExpression(
</ins><span class="cx">             service.query(
</span><del>-                &quot;fullNames&quot;, &quot;wilfrEdo&quot;,
-                matchType = MatchType.startsWith,
-                flags = MatchFlags.caseInsensitive,
-            ),
-        ))
-        self.assertRecords(records, (&quot;__wsanchez__&quot;,))
</del><ins>+                u&quot;fullNames&quot;, u&quot;wilfrEdo&quot;,
+                matchType=MatchType.startsWith,
+                flags=MatchFlags.caseInsensitive,
+            )
+        )
+        self.assertRecords(records, (u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryContains(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
-            service.query(&quot;shortNames&quot;, &quot;sanchez&quot;, matchType=MatchType.contains),
-        ))
-        self.assertRecords(records, (&quot;__wsanchez__&quot;,))
</del><ins>+        records = yield service.recordsFromExpression(
+            service.query(
+                u&quot;shortNames&quot;, u&quot;sanchez&quot;,
+                matchType=MatchType.contains,
+            )
+        )
+        self.assertRecords(records, (u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryContainsNoIndex(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
-            service.query(&quot;fullNames&quot;, &quot;fred&quot;, matchType=MatchType.contains),
-        ))
-        self.assertRecords(records, (&quot;__wsanchez__&quot;,))
</del><ins>+        records = yield service.recordsFromExpression(
+            service.query(
+                u&quot;fullNames&quot;, u&quot;fred&quot;,
+                matchType=MatchType.contains,
+            )
+        )
+        self.assertRecords(records, (u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryContainsNot(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
</del><ins>+        records = yield service.recordsFromExpression(
</ins><span class="cx">             service.query(
</span><del>-                &quot;shortNames&quot;, &quot;sanchez&quot;,
-                matchType = MatchType.contains,
-                flags = MatchFlags.NOT,
-            ),
-        ))
</del><ins>+                u&quot;shortNames&quot;, u&quot;sanchez&quot;,
+                matchType=MatchType.contains,
+                flags=MatchFlags.NOT,
+            )
+        )
</ins><span class="cx">         self.assertRecords(
</span><span class="cx">             records,
</span><span class="cx">             (
</span><del>-                '__alyssa__',
-                '__calendar-dev__',
-                '__cdaboo__',
-                '__developers__',
-                '__dre__',
-                '__dreid__',
-                '__exarkun__',
-                '__glyph__',
-                '__joe__',
-                '__sagen__',
-                '__twisted__',
</del><ins>+                u&quot;__alyssa__&quot;,
+                u&quot;__calendar-dev__&quot;,
+                u&quot;__cdaboo__&quot;,
+                u&quot;__developers__&quot;,
+                u&quot;__dre__&quot;,
+                u&quot;__dreid__&quot;,
+                u&quot;__exarkun__&quot;,
+                u&quot;__glyph__&quot;,
+                u&quot;__joe__&quot;,
+                u&quot;__sagen__&quot;,
+                u&quot;__twisted__&quot;,
</ins><span class="cx">             ),
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -523,27 +620,27 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryContainsNotNoIndex(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
</del><ins>+        records = yield service.recordsFromExpression(
</ins><span class="cx">             service.query(
</span><del>-                &quot;fullNames&quot;, &quot;fred&quot;,
-                matchType = MatchType.contains,
-                flags = MatchFlags.NOT,
-            ),
-        ))
</del><ins>+                u&quot;fullNames&quot;, u&quot;fred&quot;,
+                matchType=MatchType.contains,
+                flags=MatchFlags.NOT,
+            )
+        )
</ins><span class="cx">         self.assertRecords(
</span><span class="cx">             records,
</span><span class="cx">             (
</span><del>-                '__alyssa__',
-                '__calendar-dev__',
-                '__cdaboo__',
-                '__developers__',
-                '__dre__',
-                '__dreid__',
-                '__exarkun__',
-                '__glyph__',
-                '__joe__',
-                '__sagen__',
-                '__twisted__',
</del><ins>+                u&quot;__alyssa__&quot;,
+                u&quot;__calendar-dev__&quot;,
+                u&quot;__cdaboo__&quot;,
+                u&quot;__developers__&quot;,
+                u&quot;__dre__&quot;,
+                u&quot;__dreid__&quot;,
+                u&quot;__exarkun__&quot;,
+                u&quot;__glyph__&quot;,
+                u&quot;__joe__&quot;,
+                u&quot;__sagen__&quot;,
+                u&quot;__twisted__&quot;,
</ins><span class="cx">             ),
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -551,51 +648,57 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryContainsCaseInsensitive(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
</del><ins>+        records = yield service.recordsFromExpression(
</ins><span class="cx">             service.query(
</span><del>-                &quot;shortNames&quot;, &quot;Sanchez&quot;,
</del><ins>+                u&quot;shortNames&quot;, u&quot;Sanchez&quot;,
</ins><span class="cx">                 matchType=MatchType.contains,
</span><span class="cx">                 flags=MatchFlags.caseInsensitive,
</span><del>-            ),
-        ))
-        self.assertRecords(records, (&quot;__wsanchez__&quot;,))
</del><ins>+            )
+        )
+        self.assertRecords(records, (u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_queryContainsCaseInsensitiveNoIndex(self):
</span><span class="cx">         service = self.service()
</span><del>-        records = yield service.recordsFromQuery((
</del><ins>+        records = yield service.recordsFromExpression(
</ins><span class="cx">             service.query(
</span><del>-                &quot;fullNames&quot;, &quot;frEdo&quot;,
</del><ins>+                u&quot;fullNames&quot;, u&quot;frEdo&quot;,
</ins><span class="cx">                 matchType=MatchType.contains,
</span><span class="cx">                 flags=MatchFlags.caseInsensitive,
</span><del>-            ),
-        ))
-        self.assertRecords(records, (&quot;__wsanchez__&quot;,))
</del><ins>+            )
+        )
+        self.assertRecords(records, (u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryServiceMutableTest(BaseTest):
</del><ins>+class DirectoryServiceMutableTest(unittest.TestCase, BaseTest):
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_updateRecord(self):
</span><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><del>-        record = (yield service.recordWithUID(&quot;__wsanchez__&quot;))
</del><ins>+        record = (yield service.recordWithUID(u&quot;__wsanchez__&quot;))
</ins><span class="cx"> 
</span><span class="cx">         fields = record.fields.copy()
</span><del>-        fields[service.fieldName.fullNames] = [&quot;Wilfredo Sanchez Vega&quot;]
</del><ins>+        fields[service.fieldName.fullNames] = [u&quot;Wilfredo Sanchez Vega&quot;]
</ins><span class="cx"> 
</span><span class="cx">         updatedRecord = DirectoryRecord(service, fields)
</span><span class="cx">         yield service.updateRecords((updatedRecord,))
</span><span class="cx"> 
</span><span class="cx">         # Verify change is present immediately
</span><del>-        record = (yield service.recordWithUID(&quot;__wsanchez__&quot;))
-        self.assertEquals(set(record.fullNames), set((&quot;Wilfredo Sanchez Vega&quot;,)))
</del><ins>+        record = (yield service.recordWithUID(u&quot;__wsanchez__&quot;))
+        self.assertEquals(
+            set(record.fullNames),
+            set((u&quot;Wilfredo Sanchez Vega&quot;,))
+        )
</ins><span class="cx"> 
</span><span class="cx">         # Verify change is persisted
</span><span class="cx">         service.flush()
</span><del>-        record = (yield service.recordWithUID(&quot;__wsanchez__&quot;))
-        self.assertEquals(set(record.fullNames), set((&quot;Wilfredo Sanchez Vega&quot;,)))
</del><ins>+        record = (yield service.recordWithUID(u&quot;__wsanchez__&quot;))
+        self.assertEquals(
+            set(record.fullNames),
+            set((u&quot;Wilfredo Sanchez Vega&quot;,))
+        )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -604,23 +707,23 @@
</span><span class="cx"> 
</span><span class="cx">         newRecord = DirectoryRecord(
</span><span class="cx">             service,
</span><del>-            fields = {
-                service.fieldName.uid:        &quot;__plugh__&quot;,
</del><ins>+            fields={
+                service.fieldName.uid: u&quot;__plugh__&quot;,
</ins><span class="cx">                 service.fieldName.recordType: service.recordType.user,
</span><del>-                service.fieldName.shortNames: (&quot;plugh&quot;,),
</del><ins>+                service.fieldName.shortNames: (u&quot;plugh&quot;,),
</ins><span class="cx">             }
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         yield service.updateRecords((newRecord,), create=True)
</span><span class="cx"> 
</span><span class="cx">         # Verify change is present immediately
</span><del>-        record = (yield service.recordWithUID(&quot;__plugh__&quot;))
-        self.assertEquals(set(record.shortNames), set((&quot;plugh&quot;,)))
</del><ins>+        record = (yield service.recordWithUID(u&quot;__plugh__&quot;))
+        self.assertEquals(set(record.shortNames), set((u&quot;plugh&quot;,)))
</ins><span class="cx"> 
</span><span class="cx">         # Verify change is persisted
</span><span class="cx">         service.flush()
</span><del>-        record = (yield service.recordWithUID(&quot;__plugh__&quot;))
-        self.assertEquals(set(record.shortNames), set((&quot;plugh&quot;,)))
</del><ins>+        record = (yield service.recordWithUID(u&quot;__plugh__&quot;))
+        self.assertEquals(set(record.shortNames), set((u&quot;plugh&quot;,)))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_addRecordNoCreate(self):
</span><span class="lines">@@ -628,81 +731,91 @@
</span><span class="cx"> 
</span><span class="cx">         newRecord = DirectoryRecord(
</span><span class="cx">             service,
</span><del>-            fields = {
-                service.fieldName.uid:        &quot;__plugh__&quot;,
</del><ins>+            fields={
+                service.fieldName.uid: u&quot;__plugh__&quot;,
</ins><span class="cx">                 service.fieldName.recordType: service.recordType.user,
</span><del>-                service.fieldName.shortNames: (&quot;plugh&quot;,),
</del><ins>+                service.fieldName.shortNames: (u&quot;plugh&quot;,),
</ins><span class="cx">             }
</span><span class="cx">         )
</span><span class="cx"> 
</span><del>-        self.assertFailure(service.updateRecords((newRecord,)), NoSuchRecordError)
</del><ins>+        self.assertFailure(
+            service.updateRecords((newRecord,)),
+            NoSuchRecordError
+        )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_removeRecord(self):
</span><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><del>-        yield service.removeRecords((&quot;__wsanchez__&quot;,))
</del><ins>+        yield service.removeRecords((u&quot;__wsanchez__&quot;,))
</ins><span class="cx"> 
</span><span class="cx">         # Verify change is present immediately
</span><del>-        self.assertEquals((yield service.recordWithUID(&quot;__wsanchez__&quot;)), None)
</del><ins>+        self.assertEquals((yield service.recordWithUID(u&quot;__wsanchez__&quot;)), None)
</ins><span class="cx"> 
</span><span class="cx">         # Verify change is persisted
</span><span class="cx">         service.flush()
</span><del>-        self.assertEquals((yield service.recordWithUID(&quot;__wsanchez__&quot;)), None)
</del><ins>+        self.assertEquals((yield service.recordWithUID(u&quot;__wsanchez__&quot;)), None)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_removeRecordNoExist(self):
</span><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><del>-        return service.removeRecords((&quot;__plugh__&quot;,))
</del><ins>+        return service.removeRecords((u&quot;__plugh__&quot;,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DirectoryRecordTest(BaseTest, test_directory.DirectoryRecordTest):
</del><ins>+class DirectoryRecordTest(
+    unittest.TestCase,
+    BaseTest,
+    test_index.BaseDirectoryRecordTest
+):
+    serviceClass = DirectoryService
+    directoryRecordClass = DirectoryRecord
+
</ins><span class="cx">     @inlineCallbacks
</span><del>-    def test_members(self):
</del><ins>+    def test_members_group(self):
</ins><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><del>-        record = (yield service.recordWithUID(&quot;__wsanchez__&quot;))
</del><ins>+        record = (yield service.recordWithUID(u&quot;__wsanchez__&quot;))
</ins><span class="cx">         members = (yield record.members())
</span><span class="cx">         self.assertEquals(set(members), set())
</span><span class="cx"> 
</span><del>-        record = (yield service.recordWithUID(&quot;__twisted__&quot;))
</del><ins>+        record = (yield service.recordWithUID(u&quot;__twisted__&quot;))
</ins><span class="cx">         members = (yield record.members())
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set((member.uid for member in members)),
</span><span class="cx">             set((
</span><del>-                &quot;__wsanchez__&quot;,
-                &quot;__glyph__&quot;,
-                &quot;__exarkun__&quot;,
-                &quot;__dreid__&quot;,
-                &quot;__dre__&quot;,
</del><ins>+                u&quot;__wsanchez__&quot;,
+                u&quot;__glyph__&quot;,
+                u&quot;__exarkun__&quot;,
+                u&quot;__dreid__&quot;,
+                u&quot;__dre__&quot;,
</ins><span class="cx">             ))
</span><span class="cx">         )
</span><span class="cx"> 
</span><del>-        record = (yield service.recordWithUID(&quot;__developers__&quot;))
</del><ins>+        record = (yield service.recordWithUID(u&quot;__developers__&quot;))
</ins><span class="cx">         members = (yield record.members())
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set((member.uid for member in members)),
</span><span class="cx">             set((
</span><del>-                &quot;__calendar-dev__&quot;,
-                &quot;__twisted__&quot;,
-                &quot;__alyssa__&quot;,
</del><ins>+                u&quot;__calendar-dev__&quot;,
+                u&quot;__twisted__&quot;,
+                u&quot;__alyssa__&quot;,
</ins><span class="cx">             ))
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def test_groups(self):
</del><ins>+    def test_memberships(self):
</ins><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><del>-        record = (yield service.recordWithUID(&quot;__wsanchez__&quot;))
</del><ins>+        record = (yield service.recordWithUID(u&quot;__wsanchez__&quot;))
</ins><span class="cx">         groups = (yield record.groups())
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(group.uid for group in groups),
</span><span class="cx">             set((
</span><del>-                &quot;__calendar-dev__&quot;,
-                &quot;__twisted__&quot;,
</del><ins>+                u&quot;__calendar-dev__&quot;,
+                u&quot;__twisted__&quot;,
</ins><span class="cx">             ))
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -714,8 +827,8 @@
</span><span class="cx">         assert name is not None
</span><span class="cx">         return MatchExpression(
</span><span class="cx">             name, value,
</span><del>-            matchType = matchType,
-            flags = flags,
</del><ins>+            matchType=matchType,
+            flags=flags,
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -735,11 +848,17 @@
</span><span class="cx">     filePath = FilePath(tmp)
</span><span class="cx">     filePath.setContent(xmlData)
</span><span class="cx"> 
</span><del>-    return serviceClass(filePath)
</del><ins>+    try:
+        return serviceClass(filePath)
+    except Exception as e:
+        raise AssertionError(
+            &quot;Unable to instantiate XML service {0}: {1}&quot;
+            .format(serviceClass, e)
+        )
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-testXMLConfig = &quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</del><ins>+testXMLConfig = b&quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;directory realm=&quot;xyzzy&quot;&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhoutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/util.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/util.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -45,15 +45,18 @@
</span><span class="cx"> 
</span><span class="cx">         self._constants = myConstants
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def __getattr__(self, name):
</span><span class="cx">         try:
</span><span class="cx">             return self._constants[name]
</span><span class="cx">         except KeyError:
</span><span class="cx">             raise AttributeError(name)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def iterconstants(self):
</span><span class="cx">         return self._constants.itervalues()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def lookupByName(self, name):
</span><span class="cx">         try:
</span><span class="cx">             return self._constants[name]
</span><span class="lines">@@ -61,6 +64,7 @@
</span><span class="cx">             raise ValueError(name)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def uniqueResult(values):
</span><span class="cx">     result = None
</span><span class="cx">     for value in values:
</span><span class="lines">@@ -73,6 +77,7 @@
</span><span class="cx">     return result
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def describe(constant):
</span><span class="cx">     if isinstance(constant, FlagConstant):
</span><span class="cx">         parts = []
</span><span class="lines">@@ -83,6 +88,7 @@
</span><span class="cx">         return getattr(constant, &quot;description&quot;, constant.name)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def iterFlags(flags):
</span><span class="cx">     if hasattr(flags, &quot;__iter__&quot;):
</span><span class="cx">         return flags
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwextwhoxmlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/xml.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/xml.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twext/who/xml.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> ]
</span><span class="cx"> 
</span><span class="cx"> from time import time
</span><ins>+from uuid import UUID
</ins><span class="cx"> 
</span><span class="cx"> from xml.etree.ElementTree import parse as parseXML
</span><span class="cx"> from xml.etree.ElementTree import ParseError as XMLParseError
</span><span class="lines">@@ -62,38 +63,38 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> class Element(Values):
</span><del>-    directory = ValueConstant(&quot;directory&quot;)
-    record    = ValueConstant(&quot;record&quot;)
</del><ins>+    directory = ValueConstant(u&quot;directory&quot;)
+    record    = ValueConstant(u&quot;record&quot;)
</ins><span class="cx"> 
</span><span class="cx">     #
</span><span class="cx">     # Field names
</span><span class="cx">     #
</span><del>-    uid = ValueConstant(&quot;uid&quot;)
</del><ins>+    uid = ValueConstant(u&quot;uid&quot;)
</ins><span class="cx">     uid.fieldName = BaseFieldName.uid
</span><span class="cx"> 
</span><del>-    guid = ValueConstant(&quot;guid&quot;)
</del><ins>+    guid = ValueConstant(u&quot;guid&quot;)
</ins><span class="cx">     guid.fieldName = BaseFieldName.guid
</span><span class="cx"> 
</span><del>-    shortName = ValueConstant(&quot;short-name&quot;)
</del><ins>+    shortName = ValueConstant(u&quot;short-name&quot;)
</ins><span class="cx">     shortName.fieldName = BaseFieldName.shortNames
</span><span class="cx"> 
</span><del>-    fullName = ValueConstant(&quot;full-name&quot;)
</del><ins>+    fullName = ValueConstant(u&quot;full-name&quot;)
</ins><span class="cx">     fullName.fieldName = BaseFieldName.fullNames
</span><span class="cx"> 
</span><del>-    emailAddress = ValueConstant(&quot;email&quot;)
</del><ins>+    emailAddress = ValueConstant(u&quot;email&quot;)
</ins><span class="cx">     emailAddress.fieldName = BaseFieldName.emailAddresses
</span><span class="cx"> 
</span><del>-    password = ValueConstant(&quot;password&quot;)
</del><ins>+    password = ValueConstant(u&quot;password&quot;)
</ins><span class="cx">     password.fieldName = BaseFieldName.password
</span><span class="cx"> 
</span><del>-    memberUID = ValueConstant(&quot;member-uid&quot;)
</del><ins>+    memberUID = ValueConstant(u&quot;member-uid&quot;)
</ins><span class="cx">     memberUID.fieldName = IndexFieldName.memberUIDs
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class Attribute(Values):
</span><del>-    realm      = ValueConstant(&quot;realm&quot;)
-    recordType = ValueConstant(&quot;type&quot;)
</del><ins>+    realm      = ValueConstant(u&quot;realm&quot;)
+    recordType = ValueConstant(u&quot;type&quot;)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -101,16 +102,16 @@
</span><span class="cx">     #
</span><span class="cx">     # Booleans
</span><span class="cx">     #
</span><del>-    true  = ValueConstant(&quot;true&quot;)
-    false = ValueConstant(&quot;false&quot;)
</del><ins>+    true  = ValueConstant(u&quot;true&quot;)
+    false = ValueConstant(u&quot;false&quot;)
</ins><span class="cx"> 
</span><span class="cx">     #
</span><span class="cx">     # Record types
</span><span class="cx">     #
</span><del>-    user = ValueConstant(&quot;user&quot;)
</del><ins>+    user = ValueConstant(u&quot;user&quot;)
</ins><span class="cx">     user.recordType = RecordType.user
</span><span class="cx"> 
</span><del>-    group = ValueConstant(&quot;group&quot;)
</del><ins>+    group = ValueConstant(u&quot;group&quot;)
</ins><span class="cx">     group.recordType = RecordType.group
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -234,14 +235,14 @@
</span><span class="cx">                 &quot;Incorrect root element: {0}&quot;.format(directoryNode.tag)
</span><span class="cx">             )
</span><span class="cx"> 
</span><del>-        realmName = directoryNode.get(
-            self.attribute.realm.value, &quot;&quot;
-        ).encode(&quot;utf-8&quot;)
</del><ins>+        realmName = unicode(directoryNode.get(
+            self.attribute.realm.value, u&quot;&quot;
+        ))
</ins><span class="cx"> 
</span><span class="cx">         if not realmName:
</span><span class="cx">             raise ParseError(&quot;No realm name.&quot;)
</span><span class="cx"> 
</span><del>-        unknownRecordTypes   = set()
</del><ins>+        unknownRecordTypes = set()
</ins><span class="cx">         unknownFieldElements = set()
</span><span class="cx"> 
</span><span class="cx">         records = set()
</span><span class="lines">@@ -258,39 +259,24 @@
</span><span class="cx">         # Store results
</span><span class="cx">         #
</span><span class="cx"> 
</span><del>-        index = {}
</del><ins>+        self.flush()
+        self.indexRecords(records)
</ins><span class="cx"> 
</span><del>-        for fieldName in self.indexedFields:
-            index[fieldName] = {}
-
-        for record in records:
-            for fieldName in self.indexedFields:
-                values = record.fields.get(fieldName, None)
-
-                if values is not None:
-                    if not BaseFieldName.isMultiValue(fieldName):
-                        values = (values,)
-
-                    for value in values:
-                        index[fieldName].setdefault(value, set()).add(record)
-
</del><span class="cx">         self._realmName = realmName
</span><span class="cx"> 
</span><del>-        self._unknownRecordTypes   = unknownRecordTypes
</del><ins>+        self._unknownRecordTypes = unknownRecordTypes
</ins><span class="cx">         self._unknownFieldElements = unknownFieldElements
</span><span class="cx"> 
</span><span class="cx">         self._cacheTag = cacheTag
</span><span class="cx">         self._lastRefresh = now
</span><span class="cx"> 
</span><del>-        self.index = index
-
</del><span class="cx">         return etree
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def parseRecordNode(self, recordNode, unknownFieldElements=None):
</span><span class="cx">         recordTypeAttribute = recordNode.get(
</span><del>-            self.attribute.recordType.value, &quot;&quot;
-        ).encode(&quot;utf-8&quot;)
</del><ins>+            self.attribute.recordType.value, u&quot;&quot;
+        )
</ins><span class="cx">         if recordTypeAttribute:
</span><span class="cx">             try:
</span><span class="cx">                 recordType = (
</span><span class="lines">@@ -317,8 +303,16 @@
</span><span class="cx">                 if unknownFieldElements is not None:
</span><span class="cx">                     unknownFieldElements.add(fieldNode.tag)
</span><span class="cx"> 
</span><del>-            value = fieldNode.text.encode(&quot;utf-8&quot;)
</del><ins>+            vType = BaseFieldName.valueType(fieldName)
</ins><span class="cx"> 
</span><ins>+            if vType in (unicode, UUID):
+                value = vType(fieldNode.text)
+            else:
+                raise AssertionError(
+                    &quot;Unknown value type {0} for field {1}&quot;,
+                    vType, fieldName
+                )
+
</ins><span class="cx">             if BaseFieldName.isMultiValue(fieldName):
</span><span class="cx">                 values = fields.setdefault(fieldName, [])
</span><span class="cx">                 values.append(value)
</span><span class="lines">@@ -339,11 +333,11 @@
</span><span class="cx">     def flush(self):
</span><span class="cx">         BaseDirectoryService.flush(self)
</span><span class="cx"> 
</span><del>-        self._realmName            = None
-        self._unknownRecordTypes   = None
</del><ins>+        self._realmName = None
+        self._unknownRecordTypes = None
</ins><span class="cx">         self._unknownFieldElements = None
</span><del>-        self._cacheTag             = None
-        self._lastRefresh          = 0
</del><ins>+        self._cacheTag = None
+        self._lastRefresh = 0
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def updateRecords(self, records, create=False):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedpluginsmasterchildpyfromrev12016CalendarServertrunktwistedpluginsmasterchildpy"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/twisted/plugins/masterchild.py (from rev 12016, CalendarServer/trunk/twisted/plugins/masterchild.py) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twisted/plugins/masterchild.py                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twisted/plugins/masterchild.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,58 @@
</span><ins>+##
+# Copyright (c) 2010-2013 Apple Inc. 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 zope.interface import implementer
+
+from twisted.python.reflect import namedClass
+from twisted.plugin import IPlugin
+from twisted.application.service import IServiceMaker
+
+from twext.application.masterchild import MasterOptions, ChildOptions
+
+
+@implementer(IPlugin, IServiceMaker)
+class ServiceMaker(object):
+    def __init__(self, name, description, options, serviceMakerClass):
+        self.tapname = name
+        self.description = description
+        self.options = options
+        self.serviceMakerClass = serviceMakerClass
+        self._serviceMaker = None
+
+
+    def makeService(self, options):
+        if self._serviceMaker is None:
+            self._serviceMaker = namedClass(self.serviceMakerClass)()
+
+        return self._serviceMaker.makeService(options)
+
+
+
+masterServiceMaker = ServiceMaker(
+    &quot;master&quot;,
+    &quot;Master process application container&quot;,
+    MasterOptions,
+    &quot;twext.application.masterchild.MasterServiceMaker&quot;
+)
+
+
+
+childServiceMaker = ServiceMaker(
+    &quot;child&quot;,
+    &quot;Child process application container&quot;,
+    ChildOptions,
+    &quot;twext.application.masterchild.ChildServiceMaker&quot;
+)
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldav__init__py"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/__init__.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/__init__.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/__init__.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -59,12 +59,14 @@
</span><span class="cx"> })
</span><span class="cx"> 
</span><span class="cx"> # Do some PyCalendar init
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.property import PyCalendarProperty
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.icalendar.property import Property
+from pycalendar.vcard.card import Card
+from pycalendar.value import Value
</ins><span class="cx"> 
</span><del>-PyCalendar.setPRODID(&quot;-//CALENDARSERVER.ORG//NONSGML Version 1//EN&quot;)
</del><ins>+Calendar.setPRODID(&quot;-//CALENDARSERVER.ORG//NONSGML Version 1//EN&quot;)
+Card.setPRODID(&quot;-//CALENDARSERVER.ORG//NONSGML Version 1//EN&quot;)
</ins><span class="cx"> 
</span><span class="cx"> # These are properties we use directly and we want the default value type set for TEXT
</span><del>-PyCalendarProperty.registerDefaultValue(&quot;X-CALENDARSERVER-PRIVATE-COMMENT&quot;, PyCalendarValue.VALUETYPE_TEXT)
-PyCalendarProperty.registerDefaultValue(&quot;X-CALENDARSERVER-ATTENDEE-COMMENT&quot;, PyCalendarValue.VALUETYPE_TEXT)
</del><ins>+Property.registerDefaultValue(&quot;X-CALENDARSERVER-PRIVATE-COMMENT&quot;, Value.VALUETYPE_TEXT)
+Property.registerDefaultValue(&quot;X-CALENDARSERVER-ATTENDEE-COMMENT&quot;, Value.VALUETYPE_TEXT)
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavaccountingpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/accounting.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/accounting.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/accounting.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -42,6 +42,8 @@
</span><span class="cx">         accountingEnabledForPrincipal(principal)
</span><span class="cx">     )
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def accountingEnabledForCategory(category):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Determine if accounting is enabled for the given category.
</span><span class="lines">@@ -51,6 +53,8 @@
</span><span class="cx">         return False
</span><span class="cx">     return AccountingCategories.get(category, False)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def accountingEnabledForPrincipal(principal):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Determine if accounting is enabled for the given principal.
</span><span class="lines">@@ -69,6 +73,8 @@
</span><span class="cx"> 
</span><span class="cx">     return False
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def emitAccounting(category, principal, data, tag=None):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Write the supplied data to the appropriate location for the given
</span><span class="lines">@@ -80,7 +86,7 @@
</span><span class="cx">     @type category: C{tuple}
</span><span class="cx">     @param data: data to write.
</span><span class="cx">     @type data: C{str}
</span><del>-    &quot;&quot;&quot;    
</del><ins>+    &quot;&quot;&quot;
</ins><span class="cx">     if isinstance(principal, str):
</span><span class="cx">         principalLogPath = principal
</span><span class="cx">     elif accountingEnabled(category, principal):
</span><span class="lines">@@ -107,7 +113,7 @@
</span><span class="cx">             logDirectory,
</span><span class="cx">             datetime.datetime.now().isoformat()
</span><span class="cx">         )
</span><del>-    
</del><ins>+
</ins><span class="cx">         if not os.path.isdir(os.path.join(logRoot, logDirectory)):
</span><span class="cx">             os.makedirs(os.path.join(logRoot, logDirectory))
</span><span class="cx">             logFilename = &quot;%s-01&quot; % (logFilename,)
</span><span class="lines">@@ -128,7 +134,7 @@
</span><span class="cx">                     log.error(&quot;Too many %s accounting files for %s&quot; % (category, principal))
</span><span class="cx">                     return None
</span><span class="cx">                 index += 1
</span><del>-    
</del><ins>+
</ins><span class="cx">         #
</span><span class="cx">         # Now write out the data to the log file
</span><span class="cx">         #
</span><span class="lines">@@ -137,7 +143,7 @@
</span><span class="cx">             logFile.write(data)
</span><span class="cx">         finally:
</span><span class="cx">             logFile.close()
</span><del>-            
</del><ins>+
</ins><span class="cx">         return logFilename
</span><span class="cx"> 
</span><span class="cx">     except OSError, e:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavauthkerbpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/authkerb.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/authkerb.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/authkerb.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -22,7 +22,7 @@
</span><span class="cx"> 
</span><span class="cx">     1. An alternative to password based BASIC authentication in which the BASIC credentials are
</span><span class="cx">         verified against Kerberos.
</span><del>-   
</del><ins>+
</ins><span class="cx">     2. The NEGOTIATE mechanism (as defined in http://www.ietf.org/rfc/rfc4559.txt)
</span><span class="cx">         that implements full GSSAPI authentication.
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="lines">@@ -58,7 +58,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, principal=None, type=None, hostname=None):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         @param principal:  full Kerberos principal (e.g., 'HTTP/server.example.com@EXAMPLE.COM'). If C{None}
</span><span class="cx">             then the type and hostname arguments are used instead.
</span><span class="cx">         @type service:     str
</span><span class="lines">@@ -82,6 +82,7 @@
</span><span class="cx"> 
</span><span class="cx">         self.service, self.realm = self._splitPrincipal(principal)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _splitPrincipal(self, principal):
</span><span class="cx"> 
</span><span class="cx">         try:
</span><span class="lines">@@ -93,12 +94,14 @@
</span><span class="cx">         except IndexError:
</span><span class="cx">             self.log.error(&quot;Invalid Kerberos principal: %s&quot; % (principal,))
</span><span class="cx">             raise ValueError('Authentication System Failure: Invalid Kerberos principal: %s' % (principal,))
</span><del>-                
</del><ins>+
</ins><span class="cx">         service = &quot;%s@%s&quot; % (servicetype, service,)
</span><span class="cx">         realm = realm
</span><del>-        
</del><ins>+
</ins><span class="cx">         return (service, realm,)
</span><del>-        
</del><ins>+
+
+
</ins><span class="cx"> class BasicKerberosCredentials(credentials.UsernamePassword):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     A set of user/password credentials that checks itself against Kerberos.
</span><span class="lines">@@ -106,7 +109,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, username, password, service, realm):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         @param username:   user name of user to authenticate
</span><span class="cx">         @type username:    str
</span><span class="cx">         @param password:   password for user being authenticated
</span><span class="lines">@@ -117,11 +120,13 @@
</span><span class="cx">         @type hostname:    str
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         credentials.UsernamePassword.__init__(self, username, password)
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Convert Kerberos principal spec into service and realm
</span><span class="cx">         self.service = service
</span><span class="cx">         self.default_realm = realm
</span><del>-        
</del><ins>+
+
+
</ins><span class="cx"> class BasicKerberosCredentialFactory(KerberosCredentialFactoryBase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Authorizer for insecure Basic (base64-encoded plaintext) authentication.
</span><span class="lines">@@ -134,7 +139,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, principal=None, type=None, hostname=None):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         @param principal:  full Kerberos principal (e.g., 'HTTP/server.example.com@EXAMPLE.COM'). If C{None}
</span><span class="cx">             then the type and hostname arguments are used instead.
</span><span class="cx">         @type service:     str
</span><span class="lines">@@ -146,9 +151,11 @@
</span><span class="cx"> 
</span><span class="cx">         super(BasicKerberosCredentialFactory, self).__init__(principal, type, hostname)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def getChallenge(self, _ignore_peer):
</span><span class="cx">         return succeed({'realm': self.realm})
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def decode(self, response, request): #@UnusedVariable
</span><span class="cx">         try:
</span><span class="cx">             creds = (response + '===').decode('base64')
</span><span class="lines">@@ -161,6 +168,8 @@
</span><span class="cx">             return succeed(c)
</span><span class="cx">         raise error.LoginFailed('Invalid credentials')
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class BasicKerberosCredentialsChecker(object):
</span><span class="cx">     log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -187,9 +196,11 @@
</span><span class="cx">                     pcreds.authnPrincipal,
</span><span class="cx">                     pcreds.authzPrincipal,
</span><span class="cx">                 ))
</span><del>-        
</del><ins>+
</ins><span class="cx">         raise error.UnauthorizedLogin(&quot;Bad credentials for: %s&quot; % (pcreds.authnURI,))
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class NegotiateCredentials(object):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     A set of user/password credentials that checks itself against Kerberos.
</span><span class="lines">@@ -198,10 +209,12 @@
</span><span class="cx">     implements(credentials.ICredentials)
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, principal, username):
</span><del>-        
</del><ins>+
</ins><span class="cx">         self.principal = principal
</span><span class="cx">         self.username = username
</span><del>-        
</del><ins>+
+
+
</ins><span class="cx"> class NegotiateCredentialFactory(KerberosCredentialFactoryBase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Authorizer for Negotiate authentication (http://www.ietf.org/rfc/rfc4559.txt).
</span><span class="lines">@@ -211,7 +224,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, principal=None, type=None, hostname=None):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         @param principal:  full Kerberos principal (e.g., 'HTTP/server.example.com@EXAMPLE.COM'). If C{None}
</span><span class="cx">             then the type and hostname arguments are used instead.
</span><span class="cx">         @type service:     str
</span><span class="lines">@@ -223,22 +236,24 @@
</span><span class="cx"> 
</span><span class="cx">         super(NegotiateCredentialFactory, self).__init__(principal, type, hostname)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def getChallenge(self, _ignore_peer):
</span><span class="cx">         return succeed({})
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def decode(self, base64data, request):
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Init GSSAPI first - we won't specify the service now as we need to accept a target
</span><span class="cx">         # name that is case-insenstive as some clients will use &quot;http&quot; instead of &quot;HTTP&quot;
</span><span class="cx">         try:
</span><del>-            _ignore_result, context = kerberos.authGSSServerInit(&quot;&quot;);
</del><ins>+            _ignore_result, context = kerberos.authGSSServerInit(&quot;&quot;)
</ins><span class="cx">         except kerberos.GSSError, ex:
</span><span class="cx">             self.log.error(&quot;authGSSServerInit: %s(%s)&quot; % (ex[0][0], ex[1][0],))
</span><span class="cx">             raise error.LoginFailed('Authentication System Failure: %s(%s)' % (ex[0][0], ex[1][0],))
</span><span class="cx"> 
</span><span class="cx">         # Do the GSSAPI step and get response and username
</span><span class="cx">         try:
</span><del>-            kerberos.authGSSServerStep(context, base64data);
</del><ins>+            kerberos.authGSSServerStep(context, base64data)
</ins><span class="cx">         except kerberos.GSSError, ex:
</span><span class="cx">             self.log.error(&quot;authGSSServerStep: %s(%s)&quot; % (ex[0][0], ex[1][0],))
</span><span class="cx">             kerberos.authGSSServerClean(context)
</span><span class="lines">@@ -264,13 +279,13 @@
</span><span class="cx">         principal = kerberos.authGSSServerUserName(context)
</span><span class="cx">         username = principal
</span><span class="cx">         realmname = &quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Username may include realm suffix which we want to strip
</span><span class="cx">         if username.find(&quot;@&quot;) != -1:
</span><span class="cx">             splits = username.split(&quot;@&quot;, 1)
</span><span class="cx">             username = splits[0]
</span><span class="cx">             realmname = splits[1]
</span><del>-        
</del><ins>+
</ins><span class="cx">         # We currently do not support cross-realm authentication, so we
</span><span class="cx">         # must verify that the realm we got exactly matches the one we expect.
</span><span class="cx">         if realmname != self.realm:
</span><span class="lines">@@ -278,11 +293,11 @@
</span><span class="cx"> 
</span><span class="cx">         # Close the context
</span><span class="cx">         try:
</span><del>-            kerberos.authGSSServerClean(context);
</del><ins>+            kerberos.authGSSServerClean(context)
</ins><span class="cx">         except kerberos.GSSError, ex:
</span><span class="cx">             self.log.error(&quot;authGSSServerClean: %s&quot; % (ex[0][0], ex[1][0],))
</span><span class="cx">             raise error.LoginFailed('Authentication System Failure %s(%s)' % (ex[0][0], ex[1][0],))
</span><del>-        
</del><ins>+
</ins><span class="cx">         # If we successfully decoded and verified the Kerberos credentials we need to add the Kerberos
</span><span class="cx">         # response data to the outgoing request
</span><span class="cx"> 
</span><span class="lines">@@ -299,6 +314,8 @@
</span><span class="cx"> 
</span><span class="cx">         return succeed(NegotiateCredentials(principal, username))
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class NegotiateCredentialsChecker(object):
</span><span class="cx"> 
</span><span class="cx">     implements(checkers.ICredentialsChecker)
</span><span class="lines">@@ -320,6 +337,5 @@
</span><span class="cx">                 pcreds.authnPrincipal,
</span><span class="cx">                 pcreds.authzPrincipal,
</span><span class="cx">             ))
</span><del>-        
</del><ins>+
</ins><span class="cx">         raise error.UnauthorizedLogin(&quot;Bad credentials for: %s&quot; % (pcreds.authnURI,))
</span><del>-
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavbackuppy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/backup.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/backup.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/backup.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -38,19 +38,22 @@
</span><span class="cx">         for x in xrange(0, len(argv)):
</span><span class="cx">             opt = argv[x]
</span><span class="cx">             if opt.startswith('-'):
</span><del>-                self[opt.strip('-')] = argv[x+1]
</del><ins>+                self[opt.strip('-')] = argv[x + 1]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def debug(string):
</span><span class="cx">     if VERBOSE:
</span><span class="cx">         print(&quot;DEBUG:&quot;, string)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def funclog(string):
</span><span class="cx">     if FUNCLOG:
</span><span class="cx">         print(&quot;FUNCLOG:&quot;, string)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def logFuncCall(func):
</span><span class="cx">     def printArgs(args):
</span><span class="cx">         a = []
</span><span class="lines">@@ -60,6 +63,7 @@
</span><span class="cx"> 
</span><span class="cx">         return ''.join(a).strip(', ')
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def printKwargs(kwargs):
</span><span class="cx">         a = []
</span><span class="cx">         for kwarg, value in kwargs:
</span><span class="lines">@@ -67,8 +71,9 @@
</span><span class="cx"> 
</span><span class="cx">         return ''.join(a).strip(', ')
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _(*args, **kwargs):
</span><del>-        funclog(&quot;%s(%s)&quot; % (func.func_name, 
</del><ins>+        funclog(&quot;%s(%s)&quot; % (func.func_name,
</ins><span class="cx">                             ', '.join((printArgs(args),
</span><span class="cx">                                        printKwargs(kwargs))).strip(', ')))
</span><span class="cx"> 
</span><span class="lines">@@ -77,10 +82,11 @@
</span><span class="cx">         funclog(&quot;%s - &gt; %s&quot; % (func.func_name, retval))
</span><span class="cx"> 
</span><span class="cx">         return retval
</span><del>-    
</del><ins>+
</ins><span class="cx">     return _
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @logFuncCall
</span><span class="cx"> def readConfig(configFile):
</span><span class="cx">     config = readPlist(configFile + '.default')
</span><span class="lines">@@ -89,14 +95,16 @@
</span><span class="cx">         config.update(readPlist(configFile))
</span><span class="cx"> 
</span><span class="cx">     return config
</span><del>-        
</del><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> @logFuncCall
</span><span class="cx"> def mkroot(path):
</span><span class="cx">     root = '/'.join(path.rstrip('/').split('/')[:-1])
</span><span class="cx">     os.makedirs(root)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @logFuncCall
</span><span class="cx"> def serveradmin(action, service):
</span><span class="cx">     cmd = ' '.join((
</span><span class="lines">@@ -112,6 +120,7 @@
</span><span class="cx">     return status
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @logFuncCall
</span><span class="cx"> def isRunning(service):
</span><span class="cx">     cmd = ' '.join((
</span><span class="lines">@@ -134,21 +143,25 @@
</span><span class="cx">         return False
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @logFuncCall
</span><span class="cx"> def copy(src, dst):
</span><span class="cx">     shutil.copytree(src, dst)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @logFuncCall
</span><span class="cx"> def move(src, dst):
</span><span class="cx">     os.rename(src, dst)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @logFuncCall
</span><span class="cx"> def remove(dst):
</span><span class="cx">     shutil.rmtree(dst)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @logFuncCall
</span><span class="cx"> def purge(root, patterns):
</span><span class="cx">     removed = []
</span><span class="lines">@@ -175,5 +188,5 @@
</span><span class="cx">                     os.remove(full)
</span><span class="cx"> 
</span><span class="cx">                     removed.append(full)
</span><del>-                    
</del><ins>+
</ins><span class="cx">     return removed
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavcaldavxmlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/caldavxml.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/caldavxml.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/caldavxml.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -25,8 +25,8 @@
</span><span class="cx"> See draft spec: http://ietf.webdav.org/caldav/draft-dusseault-caldav.txt
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from txdav.xml.element import registerElement, dav_namespace
</span><span class="cx"> from txdav.xml.element import WebDAVElement, PCDATAElement
</span><span class="lines">@@ -110,8 +110,8 @@
</span><span class="cx">         if &quot;start&quot; not in attributes and &quot;end&quot; not in attributes:
</span><span class="cx">             raise ValueError(&quot;One of 'start' or 'end' must be present in CALDAV:time-range&quot;)
</span><span class="cx"> 
</span><del>-        self.start = PyCalendarDateTime.parseText(attributes[&quot;start&quot;]) if &quot;start&quot; in attributes else None
-        self.end = PyCalendarDateTime.parseText(attributes[&quot;end&quot;]) if &quot;end&quot; in attributes else None
</del><ins>+        self.start = DateTime.parseText(attributes[&quot;start&quot;]) if &quot;start&quot; in attributes else None
+        self.end = DateTime.parseText(attributes[&quot;end&quot;]) if &quot;end&quot; in attributes else None
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def valid(self, level=0):
</span><span class="lines">@@ -139,23 +139,102 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class CalDAVTimeZoneElement (CalDAVTextElement):
</del><ins>+class CalDAVDataMixin(object):
</ins><span class="cx">     &quot;&quot;&quot;
</span><del>-    CalDAV element containing iCalendar data with a single VTIMEZONE component.
</del><ins>+    A mixin to support accept/returning data in various formats.
</ins><span class="cx">     &quot;&quot;&quot;
</span><ins>+
+    def __init__(self, *children, **attributes):
+
+        if &quot;content-type&quot; in attributes:
+            self.content_type = attributes[&quot;content-type&quot;]
+        else:
+            self.content_type = &quot;text/calendar&quot;
+
+        if &quot;version&quot; in attributes:
+            self.version = attributes[&quot;version&quot;]
+        else:
+            self.version = &quot;2.0&quot;
+
+        super(CalDAVDataMixin, self).__init__(*children, **attributes)
+
+
+    def verifyTypeVersion(self):
+        &quot;&quot;&quot;
+        Make sure any content-type and version matches at least one supported set.
+
+        @return: C{True} if there is at least one match, C{False} otherwise.
+        &quot;&quot;&quot;
+        allowedTypes = set()
+        allowedTypes.add((&quot;text/calendar&quot;, &quot;2.0&quot;,))
+        if config.EnableJSONData:
+            allowedTypes.add((&quot;application/calendar+json&quot;, &quot;2.0&quot;,))
+        for format, version in allowedTypes:
+            if (format == self.content_type) and (version == self.version):
+                return True
+
+        return False
+
+
+    @classmethod
+    def fromCalendar(clazz, calendar, format=None):
+        attrs = {}
+        if format is not None and format != &quot;text/calendar&quot;:
+            attrs[&quot;content-type&quot;] = format
+
+        if isinstance(calendar, str):
+            if not calendar:
+                raise ValueError(&quot;Missing calendar data&quot;)
+            return clazz(PCDATAElement(calendar), **attrs)
+        elif isinstance(calendar, iComponent):
+            assert calendar.name() == &quot;VCALENDAR&quot;, &quot;Not a calendar: %r&quot; % (calendar,)
+            return clazz(PCDATAElement(calendar.getTextWithTimezones(includeTimezones=not config.EnableTimezonesByReference, format=format)), **attrs)
+        else:
+            raise ValueError(&quot;Not a calendar: %s&quot; % (calendar,))
+
+    fromTextData = fromCalendar
+    fromComponent = fromCalendar
+
</ins><span class="cx">     def calendar(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        Returns a calendar component derived from this element, which contains
-        exactly one VTIMEZONE component.
</del><ins>+        Returns a calendar component derived from this element.
</ins><span class="cx">         &quot;&quot;&quot;
</span><del>-        return iComponent.fromString(str(self))
</del><ins>+        data = self.calendarData()
+        if data:
+            return iComponent.fromString(data, format=self.content_type)
+        else:
+            return None
</ins><span class="cx"> 
</span><ins>+    generateComponent = calendar
</ins><span class="cx"> 
</span><ins>+
+    def calendarData(self):
+        &quot;&quot;&quot;
+        Returns the calendar data derived from this element.
+        &quot;&quot;&quot;
+        for data in self.children:
+            if not isinstance(data, PCDATAElement):
+                return None
+            else:
+                # We guaranteed in __init__() that there is only one child...
+                break
+
+        return str(data)
+
+    textData = calendarData
+
+
+
+class CalDAVTimeZoneElement (CalDAVDataMixin, CalDAVTextElement):
+    &quot;&quot;&quot;
+    CalDAV element containing iCalendar data with a single VTIMEZONE component.
+    &quot;&quot;&quot;
+
</ins><span class="cx">     def gettimezone(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Get the timezone to use. If none, return UTC timezone.
</span><span class="cx"> 
</span><del>-        @return: the L{PyCalendarTimezone} derived from the VTIMEZONE or utc.
</del><ins>+        @return: the L{Timezone} derived from the VTIMEZONE or utc.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         calendar = self.calendar()
</span><span class="cx">         if calendar is not None:
</span><span class="lines">@@ -164,7 +243,7 @@
</span><span class="cx">                 return tz
</span><span class="cx"> 
</span><span class="cx">         # Default to using utc tzinfo
</span><del>-        return PyCalendarTimezone(utc=True)
</del><ins>+        return Timezone(utc=True)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def valid(self):
</span><span class="lines">@@ -231,8 +310,13 @@
</span><span class="cx">     name = &quot;calendar-timezone&quot;
</span><span class="cx">     hidden = True
</span><span class="cx"> 
</span><ins>+    allowed_attributes = {
+        &quot;content-type&quot;: False,
+        &quot;version&quot;     : False,
+    }
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class SupportedCalendarComponentSets (CalDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -428,7 +512,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> @registerElement
</span><del>-class CalendarData (CalDAVElement):
</del><ins>+class CalendarData (CalDAVDataMixin, CalDAVElement):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Defines which parts of a calendar component object should be returned by a
</span><span class="cx">     report.
</span><span class="lines">@@ -448,21 +532,6 @@
</span><span class="cx">         &quot;version&quot;     : False,
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    @classmethod
-    def fromCalendar(clazz, calendar):
-        if isinstance(calendar, str):
-            if not calendar:
-                raise ValueError(&quot;Missing calendar data&quot;)
-            return clazz(PCDATAElement(calendar))
-        elif isinstance(calendar, iComponent):
-            assert calendar.name() == &quot;VCALENDAR&quot;, &quot;Not a calendar: %r&quot; % (calendar,)
-            return clazz(PCDATAElement(calendar.getTextWithTimezones(includeTimezones=not config.EnableTimezonesByReference)))
-        else:
-            raise ValueError(&quot;Not a calendar: %s&quot; % (calendar,))
-
-    fromTextData = fromCalendar
-
-
</del><span class="cx">     def __init__(self, *children, **attributes):
</span><span class="cx">         super(CalendarData, self).__init__(*children, **attributes)
</span><span class="cx"> 
</span><span class="lines">@@ -515,61 +584,8 @@
</span><span class="cx">                 # optimize them originals away
</span><span class="cx">                 self.children = (data,)
</span><span class="cx"> 
</span><del>-        if &quot;content-type&quot; in attributes:
-            self.content_type = attributes[&quot;content-type&quot;]
-        else:
-            self.content_type = &quot;text/calendar&quot;
</del><span class="cx"> 
</span><del>-        if &quot;version&quot; in attributes:
-            self.version = attributes[&quot;version&quot;]
-        else:
-            self.version = &quot;2.0&quot;
</del><span class="cx"> 
</span><del>-
-    def verifyTypeVersion(self, types_and_versions):
-        &quot;&quot;&quot;
-        Make sure any content-type and version matches at least one of the supplied set.
-
-        @param types_and_versions: a list of (content-type, version) tuples to test against.
-        @return:                   True if there is at least one match, False otherwise.
-        &quot;&quot;&quot;
-        for item in types_and_versions:
-            if (item[0] == self.content_type) and (item[1] == self.version):
-                return True
-
-        return False
-
-
-    def calendar(self):
-        &quot;&quot;&quot;
-        Returns a calendar component derived from this element.
-        &quot;&quot;&quot;
-        data = self.calendarData()
-        if data:
-            return iComponent.fromString(data)
-        else:
-            return None
-
-    generateComponent = calendar
-
-
-    def calendarData(self):
-        &quot;&quot;&quot;
-        Returns the calendar data derived from this element.
-        &quot;&quot;&quot;
-        for data in self.children:
-            if not isinstance(data, PCDATAElement):
-                return None
-            else:
-                # We guaranteed in __init__() that there is only one child...
-                break
-
-        return str(data)
-
-    textData = calendarData
-
-
-
</del><span class="cx"> @registerElement
</span><span class="cx"> class CalendarComponent (CalDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -882,8 +898,13 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     name = &quot;timezone&quot;
</span><span class="cx"> 
</span><ins>+    allowed_attributes = {
+        &quot;content-type&quot;: False,
+        &quot;version&quot;     : False,
+    }
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class TimeRange (CalDAVTimeRangeElement):
</span><span class="cx">     &quot;&quot;&quot;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavcarddavxmlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/carddavxml.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/carddavxml.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/carddavxml.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -22,7 +22,7 @@
</span><span class="cx"> This API is considered private to static.py and is therefore subject to
</span><span class="cx"> change.
</span><span class="cx"> 
</span><del>-See draft spec: 
</del><ins>+See draft spec:
</ins><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> from txdav.xml.element import registerElement, dav_namespace
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> from txdav.xml.element import WebDAVEmptyElement, WebDAVTextElement
</span><span class="cx"> from txdav.xml.element import ResourceType, Collection
</span><span class="cx"> 
</span><ins>+from twistedcaldav.config import config
</ins><span class="cx"> from twistedcaldav.vcard import Component
</span><span class="cx"> 
</span><span class="cx"> ##
</span><span class="lines">@@ -50,6 +51,7 @@
</span><span class="cx">     namespace = carddav_namespace
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class CardDAVEmptyElement (WebDAVEmptyElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     CardDAV element with no contents.
</span><span class="lines">@@ -57,6 +59,7 @@
</span><span class="cx">     namespace = carddav_namespace
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class CardDAVTextElement (WebDAVTextElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     CardDAV element containing PCDATA.
</span><span class="lines">@@ -64,6 +67,93 @@
</span><span class="cx">     namespace = carddav_namespace
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
+class CardDAVDataMixin(object):
+    &quot;&quot;&quot;
+    A mixin to support accept/returning data in various formats.
+    &quot;&quot;&quot;
+
+    def __init__(self, *children, **attributes):
+
+        if &quot;content-type&quot; in attributes:
+            self.content_type = attributes[&quot;content-type&quot;]
+        else:
+            self.content_type = &quot;text/vcard&quot;
+
+        if &quot;version&quot; in attributes:
+            self.version = attributes[&quot;version&quot;]
+        else:
+            self.version = &quot;3.0&quot;
+
+        super(CardDAVDataMixin, self).__init__(*children, **attributes)
+
+
+    def verifyTypeVersion(self):
+        &quot;&quot;&quot;
+        Make sure any content-type and version matches at least one supported set.
+
+        @return: C{True} if there is at least one match, C{False} otherwise.
+        &quot;&quot;&quot;
+        allowedTypes = set()
+        allowedTypes.add((&quot;text/vcard&quot;, &quot;3.0&quot;,))
+        if config.EnableJSONData:
+            allowedTypes.add((&quot;application/vcard+json&quot;, &quot;3.0&quot;,))
+        for format, version in allowedTypes:
+            if (format == self.content_type) and (version == self.version):
+                return True
+
+        return False
+
+
+    @classmethod
+    def fromAddress(clazz, address, format=None):
+        attrs = {}
+        if format is not None and format != &quot;text/vcard&quot;:
+            attrs[&quot;content-type&quot;] = format
+
+        if isinstance(address, str):
+            if not address:
+                raise ValueError(&quot;Missing address data&quot;)
+            return clazz(PCDATAElement(address), **attrs)
+        elif isinstance(address, Component):
+            assert address.name() == &quot;VCARD&quot;, &quot;Not a vCard: %r&quot; % (address,)
+            return clazz(PCDATAElement(address.getText(format)), **attrs)
+        else:
+            raise ValueError(&quot;Not an address: %s&quot; % (address,))
+
+    fromTextData = fromAddress
+    fromComponent = fromAddress
+
+    def address(self):
+        &quot;&quot;&quot;
+        Returns an address component derived from this element.
+        &quot;&quot;&quot;
+        data = self.addressData()
+        if data:
+            return Component.fromString(data, format=self.content_type)
+        else:
+            return None
+
+    generateComponent = address
+
+
+    def addressData(self):
+        &quot;&quot;&quot;
+        Returns the address data derived from this element.
+        &quot;&quot;&quot;
+        for data in self.children:
+            if not isinstance(data, PCDATAElement):
+                return None
+            else:
+                # We guaranteed in __init__() that there is only one child...
+                break
+
+        return str(data)
+
+    textData = addressData
+
+
+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class AddressBookHomeSet (CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -73,9 +163,10 @@
</span><span class="cx">     name = &quot;addressbook-home-set&quot;
</span><span class="cx">     hidden = True
</span><span class="cx"> 
</span><del>-    allowed_children = { (dav_namespace, &quot;href&quot;): (0, None) }
</del><ins>+    allowed_children = {(dav_namespace, &quot;href&quot;): (0, None)}
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class AddressBookDescription (CardDAVTextElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -88,6 +179,7 @@
</span><span class="cx">     # May be protected; but we'll let the client set this if they like.
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class SupportedAddressData (CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -98,9 +190,10 @@
</span><span class="cx">     hidden = True
</span><span class="cx">     protected = True
</span><span class="cx"> 
</span><del>-    allowed_children = { (carddav_namespace, &quot;address-data-type&quot;): (0, None) }
</del><ins>+    allowed_children = {(carddav_namespace, &quot;address-data-type&quot;): (0, None)}
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class MaxResourceSize (CardDAVTextElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -112,6 +205,7 @@
</span><span class="cx">     protected = True
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class AddressBook (CardDAVEmptyElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -121,6 +215,7 @@
</span><span class="cx">     name = &quot;addressbook&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class AddressBookQuery (CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -130,11 +225,11 @@
</span><span class="cx">     name = &quot;addressbook-query&quot;
</span><span class="cx"> 
</span><span class="cx">     allowed_children = {
</span><del>-        (dav_namespace,     &quot;allprop&quot; ): (0, None),
-        (dav_namespace,     &quot;propname&quot;): (0, None),
-        (dav_namespace,     &quot;prop&quot;    ): (0, None),
-        (carddav_namespace, &quot;filter&quot;  ): (0, 1), # Actually (1, 1) unless element is empty
-        (carddav_namespace, &quot;limit&quot;    ): (0, None),
</del><ins>+        (dav_namespace, &quot;allprop&quot;): (0, None),
+        (dav_namespace, &quot;propname&quot;): (0, None),
+        (dav_namespace, &quot;prop&quot;): (0, None),
+        (carddav_namespace, &quot;filter&quot;): (0, 1), # Actually (1, 1) unless element is empty
+        (carddav_namespace, &quot;limit&quot;): (0, None),
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, *children, **attributes):
</span><span class="lines">@@ -148,9 +243,9 @@
</span><span class="cx">             qname = child.qname()
</span><span class="cx"> 
</span><span class="cx">             if qname in (
</span><del>-                (dav_namespace, &quot;allprop&quot; ),
</del><ins>+                (dav_namespace, &quot;allprop&quot;),
</ins><span class="cx">                 (dav_namespace, &quot;propname&quot;),
</span><del>-                (dav_namespace, &quot;prop&quot;    ),
</del><ins>+                (dav_namespace, &quot;prop&quot;),
</ins><span class="cx">             ):
</span><span class="cx">                 if props is not None:
</span><span class="cx">                     raise ValueError(&quot;Only one of CardDAV:allprop, CardDAV:propname, CardDAV:prop allowed&quot;)
</span><span class="lines">@@ -159,7 +254,7 @@
</span><span class="cx">             elif qname == (carddav_namespace, &quot;filter&quot;):
</span><span class="cx">                 filter = child
</span><span class="cx">             elif qname == (carddav_namespace, &quot;limit&quot;):
</span><del>-                # type check 
</del><ins>+                # type check
</ins><span class="cx">                 child.childOfType(NResults)
</span><span class="cx">                 limit = child
</span><span class="cx"> 
</span><span class="lines">@@ -170,11 +265,12 @@
</span><span class="cx">             if filter is None:
</span><span class="cx">                 raise ValueError(&quot;CARDDAV:filter required&quot;)
</span><span class="cx"> 
</span><del>-        self.props  = props
</del><ins>+        self.props = props
</ins><span class="cx">         self.filter = filter
</span><span class="cx">         self.limit = limit
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class AddressDataType (CardDAVEmptyElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -190,8 +286,9 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><del>-class AddressData (CardDAVElement):
</del><ins>+class AddressData (CardDAVDataMixin, CardDAVElement):
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Defines which parts of a address component object should be returned by a
</span><span class="cx">     report.
</span><span class="lines">@@ -201,7 +298,7 @@
</span><span class="cx"> 
</span><span class="cx">     allowed_children = {
</span><span class="cx">         (carddav_namespace, &quot;allprop&quot;): (0, 1),
</span><del>-        (carddav_namespace, &quot;prop&quot;   ): (0, None),
</del><ins>+        (carddav_namespace, &quot;prop&quot;): (0, None),
</ins><span class="cx">         PCDATAElement                 : (0, None),
</span><span class="cx">     }
</span><span class="cx">     allowed_attributes = {
</span><span class="lines">@@ -209,27 +306,11 @@
</span><span class="cx">         &quot;version&quot;     : False,
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    @classmethod
-    def fromAddress(clazz, address):
-        assert address.name() == &quot;VCARD&quot;, &quot;Not a vCard: %r&quot; % (address,)
-        return clazz(PCDATAElement(str(address)))
-
-    @classmethod
-    def fromAddressData(clazz, addressdata):
-        &quot;&quot;&quot;
-        Return a AddressData element comprised of the supplied address data.
-        @param addressdata: a string of valid address data.
-        @return: a L{Addressata} element.
-        &quot;&quot;&quot;
-        return clazz(PCDATAElement(addressdata))
-
-    fromTextData = fromAddressData
-
</del><span class="cx">     def __init__(self, *children, **attributes):
</span><span class="cx">         super(AddressData, self).__init__(*children, **attributes)
</span><span class="cx"> 
</span><span class="cx">         properties = None
</span><del>-        data       = None
</del><ins>+        data = None
</ins><span class="cx"> 
</span><span class="cx">         for child in self.children:
</span><span class="cx">             qname = child.qname()
</span><span class="lines">@@ -256,73 +337,25 @@
</span><span class="cx">                 else:
</span><span class="cx">                     data += child
</span><span class="cx"> 
</span><del>-            else: raise AssertionError(&quot;We shouldn't be here&quot;)
</del><ins>+            else:
+                raise AssertionError(&quot;We shouldn't be here&quot;)
</ins><span class="cx"> 
</span><del>-
</del><span class="cx">         self.properties = properties
</span><span class="cx"> 
</span><span class="cx">         if data is not None:
</span><span class="cx">             try:
</span><span class="cx">                 if properties is not None:
</span><del>-                    raise ValueError(&quot;Only one of allprop, prop (%r) or PCDATA (%r) allowed&quot;% (properties, str(data)))
</del><ins>+                    raise ValueError(&quot;Only one of allprop, prop (%r) or PCDATA (%r) allowed&quot; % (properties, str(data)))
</ins><span class="cx">             except ValueError:
</span><del>-                if not data.isWhitespace(): raise
</del><ins>+                if not data.isWhitespace():
+                    raise
</ins><span class="cx">             else:
</span><span class="cx">                 # Since we've already combined PCDATA elements, we'd may as well
</span><span class="cx">                 # optimize them originals away
</span><span class="cx">                 self.children = (data,)
</span><span class="cx"> 
</span><del>-        if &quot;content-type&quot; in attributes:
-            self.content_type = attributes[&quot;content-type&quot;]
-        else:
-            self.content_type = &quot;text/vcard&quot;
</del><span class="cx"> 
</span><del>-        if &quot;version&quot; in attributes:
-            self.version = attributes[&quot;version&quot;]
-        else:
-            self.version = &quot;3.0&quot;
</del><span class="cx"> 
</span><del>-    def verifyTypeVersion(self, types_and_versions):
-        &quot;&quot;&quot;
-        Make sure any content-type and version matches at least one of the supplied set.
-        
-        @param types_and_versions: a list of (content-type, version) tuples to test against.
-        @return:                   True if there is at least one match, False otherwise.
-        &quot;&quot;&quot;
-        for item in types_and_versions:
-            if (item[0] == self.content_type) and (item[1] == self.version):
-                return True
-        
-        return False
-
-    def address(self):
-        &quot;&quot;&quot;
-        Returns an address component derived from this element.
-        &quot;&quot;&quot;
-        data = self.addressData()
-        if data:
-            return Component.fromString(data)
-        else:
-            return None
-
-    generateComponent = address
-
-    def addressData(self):
-        &quot;&quot;&quot;
-        Returns an address component derived from this element.
-        &quot;&quot;&quot;
-        for data in self.children:
-            if not isinstance(data, PCDATAElement):
-                return None
-            else:
-                # We guaranteed in __init__() that there is only one child...
-                break
-
-        return str(data)
-
-    textData = addressData
-
-
</del><span class="cx"> @registerElement
</span><span class="cx"> class AllProperties (CardDAVEmptyElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -332,6 +365,7 @@
</span><span class="cx">     name = &quot;allprop&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class Property (CardDAVEmptyElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -362,6 +396,7 @@
</span><span class="cx">             self.novalue = False
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class Filter (CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -370,10 +405,11 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     name = &quot;filter&quot;
</span><span class="cx"> 
</span><del>-    allowed_children = { (carddav_namespace, &quot;prop-filter&quot;): (0, None) }
-    allowed_attributes = { &quot;test&quot;: False }
-        
</del><ins>+    allowed_children = {(carddav_namespace, &quot;prop-filter&quot;): (0, None)}
+    allowed_attributes = {&quot;test&quot;: False}
</ins><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class PropertyFilter (CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -383,9 +419,9 @@
</span><span class="cx">     name = &quot;prop-filter&quot;
</span><span class="cx"> 
</span><span class="cx">     allowed_children = {
</span><del>-        (carddav_namespace, &quot;is-not-defined&quot; ): (0, 1),
-        (carddav_namespace, &quot;text-match&quot;     ): (0, None),
-        (carddav_namespace, &quot;param-filter&quot;   ): (0, None),
</del><ins>+        (carddav_namespace, &quot;is-not-defined&quot;): (0, 1),
+        (carddav_namespace, &quot;text-match&quot;): (0, None),
+        (carddav_namespace, &quot;param-filter&quot;): (0, None),
</ins><span class="cx">     }
</span><span class="cx">     allowed_attributes = {
</span><span class="cx">         &quot;name&quot;: True,
</span><span class="lines">@@ -393,6 +429,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class ParameterFilter (CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -402,12 +439,13 @@
</span><span class="cx">     name = &quot;param-filter&quot;
</span><span class="cx"> 
</span><span class="cx">     allowed_children = {
</span><del>-        (carddav_namespace, &quot;is-not-defined&quot; ): (0, 1),
-        (carddav_namespace, &quot;text-match&quot;     ): (0, 1),
</del><ins>+        (carddav_namespace, &quot;is-not-defined&quot;): (0, 1),
+        (carddav_namespace, &quot;text-match&quot;): (0, 1),
</ins><span class="cx">     }
</span><del>-    allowed_attributes = { &quot;name&quot;: True }
</del><ins>+    allowed_attributes = {&quot;name&quot;: True}
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class Limit (WebDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -416,10 +454,11 @@
</span><span class="cx">     namespace = carddav_namespace
</span><span class="cx">     name = &quot;limit&quot;
</span><span class="cx">     allowed_children = {
</span><del>-        (carddav_namespace, &quot;nresults&quot; )  : (1, 1),
</del><ins>+        (carddav_namespace, &quot;nresults&quot;)  : (1, 1),
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class NResults (WebDAVTextElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -439,6 +478,7 @@
</span><span class="cx">     name = &quot;is-not-defined&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class TextMatch (CardDAVTextElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -464,6 +504,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class AddressBookMultiGet (CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -475,10 +516,10 @@
</span><span class="cx">     # To allow for an empty element in a supported-report-set property we need
</span><span class="cx">     # to relax the child restrictions
</span><span class="cx">     allowed_children = {
</span><del>-        (dav_namespace, &quot;allprop&quot; ): (0, 1),
</del><ins>+        (dav_namespace, &quot;allprop&quot;): (0, 1),
</ins><span class="cx">         (dav_namespace, &quot;propname&quot;): (0, 1),
</span><del>-        (dav_namespace, &quot;prop&quot;    ): (0, 1),
-        (dav_namespace, &quot;href&quot;    ): (0, None),    # Actually ought to be (1, None)
</del><ins>+        (dav_namespace, &quot;prop&quot;): (0, 1),
+        (dav_namespace, &quot;href&quot;): (0, None),    # Actually ought to be (1, None)
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, *children, **attributes):
</span><span class="lines">@@ -491,9 +532,9 @@
</span><span class="cx">             qname = child.qname()
</span><span class="cx"> 
</span><span class="cx">             if qname in (
</span><del>-                (dav_namespace, &quot;allprop&quot; ),
</del><ins>+                (dav_namespace, &quot;allprop&quot;),
</ins><span class="cx">                 (dav_namespace, &quot;propname&quot;),
</span><del>-                (dav_namespace, &quot;prop&quot;    ),
</del><ins>+                (dav_namespace, &quot;prop&quot;),
</ins><span class="cx">             ):
</span><span class="cx">                 if property is not None:
</span><span class="cx">                     raise ValueError(&quot;Only one of DAV:allprop, DAV:propname, DAV:prop allowed&quot;)
</span><span class="lines">@@ -502,10 +543,11 @@
</span><span class="cx">             elif qname == (dav_namespace, &quot;href&quot;):
</span><span class="cx">                 resources.append(child)
</span><span class="cx"> 
</span><del>-        self.property  = property
</del><ins>+        self.property = property
</ins><span class="cx">         self.resources = resources
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class NoUIDConflict(CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -514,9 +556,10 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     name = &quot;no-uid-conflict&quot;
</span><span class="cx"> 
</span><del>-    allowed_children = { (dav_namespace, &quot;href&quot;): (1, 1) }
-    
</del><ins>+    allowed_children = {(dav_namespace, &quot;href&quot;): (1, 1)}
</ins><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class SupportedFilter(CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -527,11 +570,12 @@
</span><span class="cx">     name = &quot;supported-filter&quot;
</span><span class="cx"> 
</span><span class="cx">     allowed_children = {
</span><del>-        (carddav_namespace, &quot;prop-filter&quot; ): (0, None),
</del><ins>+        (carddav_namespace, &quot;prop-filter&quot;): (0, None),
</ins><span class="cx">         (carddav_namespace, &quot;param-filter&quot;): (0, None)
</span><span class="cx">     }
</span><del>-    
</del><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class DirectoryGateway(CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -541,17 +585,19 @@
</span><span class="cx">     hidden = True
</span><span class="cx">     protected = True
</span><span class="cx"> 
</span><del>-    allowed_children = { (dav_namespace, &quot;href&quot;): (0, None) }
-    
</del><ins>+    allowed_children = {(dav_namespace, &quot;href&quot;): (0, None)}
</ins><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class Directory(CardDAVEmptyElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     CardDAV property on a principal to indicate where the directory resource is.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     name = &quot;directory&quot;
</span><del>-    
</del><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class DefaultAddressBookURL (CardDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -559,14 +605,17 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     name = &quot;default-addressbook-URL&quot;
</span><span class="cx"> 
</span><del>-    allowed_children = { (dav_namespace, &quot;href&quot;): (0, 1) }
</del><ins>+    allowed_children = {(dav_namespace, &quot;href&quot;): (0, 1)}
</ins><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> ##
</span><span class="cx"> # Extensions to ResourceType
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-def _isAddressBook(self): return bool(self.childrenOfType(AddressBook))
</del><ins>+def _isAddressBook(self):
+    return bool(self.childrenOfType(AddressBook))
</ins><span class="cx"> ResourceType.isAddressBook = _isAddressBook
</span><span class="cx"> 
</span><span class="cx"> ResourceType.addressbook = ResourceType(Collection(), AddressBook())
</span><del>-ResourceType.directory   = ResourceType(Collection(), AddressBook(), Directory())
</del><ins>+ResourceType.directory = ResourceType(Collection(), AddressBook(), Directory())
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavconfigpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/config.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/config.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/config.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -97,6 +97,9 @@
</span><span class="cx">             self._defaults = ConfigDict()
</span><span class="cx">         else:
</span><span class="cx">             self._defaults = ConfigDict(copy.deepcopy(defaults))
</span><ins>+        self.importedFiles = []
+        self.includedFiles = []
+        self.missingFiles = []
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getDefaults(self):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavcustomxmlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/customxml.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/customxml.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/customxml.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -34,7 +34,7 @@
</span><span class="cx"> from twistedcaldav.caldavxml import caldav_namespace
</span><span class="cx"> from twistedcaldav.ical import Component as iComponent
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> calendarserver_namespace = &quot;http://calendarserver.org/ns/&quot;
</span><span class="lines">@@ -640,7 +640,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, *children):
</span><span class="cx">         super(DTStamp, self).__init__(children)
</span><del>-        self.children = (PCDATAElement(PyCalendarDateTime.getNowUTC().getText()),)
</del><ins>+        self.children = (PCDATAElement(DateTime.getNowUTC().getText()),)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdatabasepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/database.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/database.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/database.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -44,14 +44,15 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     A ThreadPool that closes connections for each worker thread
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">     def _worker(self):
</span><span class="cx">         log.debug(&quot;Starting ADBAPI thread: %s&quot; % (thread.get_ident(),))
</span><span class="cx">         ThreadPool._worker(self)
</span><span class="cx">         self._closeConnection()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _closeConnection(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         tid = thread.get_ident()
</span><span class="cx">         log.debug(&quot;Closing ADBAPI thread: %s&quot; % (tid,))
</span><span class="cx"> 
</span><span class="lines">@@ -59,6 +60,8 @@
</span><span class="cx">         self.pool._close(conn)
</span><span class="cx">         del self.pool.connections[tid]
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class AbstractADBAPIDatabase(object):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     A generic SQL database.
</span><span class="lines">@@ -66,7 +69,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, dbID, dbapiName, dbapiArgs, persistent, **kwargs):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         @param persistent: C{True} if the data in the DB must be perserved during upgrades,
</span><span class="cx">             C{False} if the DB data can be re-created from an external source.
</span><span class="cx">         @type persistent: bool
</span><span class="lines">@@ -77,12 +80,14 @@
</span><span class="cx">         self.dbapikwargs = kwargs
</span><span class="cx"> 
</span><span class="cx">         self.persistent = persistent
</span><del>-        
</del><ins>+
</ins><span class="cx">         self.initialized = False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def __repr__(self):
</span><span class="cx">         return &quot;&lt;%s %r&gt;&quot; % (self.__class__.__name__, self.pool)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def open(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -92,7 +97,7 @@
</span><span class="cx">         if not self.initialized:
</span><span class="cx"> 
</span><span class="cx">             self.pool = ConnectionPool(self.dbapiName, *self.dbapiArgs, **self.dbapikwargs)
</span><del>-            
</del><ins>+
</ins><span class="cx">             # sqlite3 is not thread safe which means we have to close the sqlite3 connections in the same thread that
</span><span class="cx">             # opened them. We need a special thread pool class that has a thread worker function that does a close
</span><span class="cx">             # when a thread is closed.
</span><span class="lines">@@ -126,7 +131,7 @@
</span><span class="cx">                         elif version != self._db_version():
</span><span class="cx">                             log.error(&quot;Database %s has different schema (v.%s vs. v.%s)&quot;
</span><span class="cx">                                       % (self.dbID, version, self._db_version()))
</span><del>-                            
</del><ins>+
</ins><span class="cx">                             # Upgrade the DB
</span><span class="cx">                             yield self._db_upgrade(version)
</span><span class="cx"> 
</span><span class="lines">@@ -139,8 +144,9 @@
</span><span class="cx">                 self.pool = None
</span><span class="cx">                 raise
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def close(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         if self.initialized:
</span><span class="cx">             try:
</span><span class="cx">                 self.pool.close()
</span><span class="lines">@@ -149,9 +155,10 @@
</span><span class="cx">             self.pool = None
</span><span class="cx">             self.initialized = False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def clean(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Re-try at least once
</span><span class="cx">         for _ignore in (0, 1):
</span><span class="cx">             if not self.initialized:
</span><span class="lines">@@ -165,14 +172,15 @@
</span><span class="cx">             else:
</span><span class="cx">                 break
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def execute(self, sql, *query_params):
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Re-try at least once
</span><span class="cx">         for _ignore in (0, 1):
</span><span class="cx">             if not self.initialized:
</span><span class="cx">                 yield self.open()
</span><del>-    
</del><ins>+
</ins><span class="cx">             try:
</span><span class="cx">                 yield self._db_execute(sql, *query_params)
</span><span class="cx">             except Exception, e:
</span><span class="lines">@@ -181,14 +189,15 @@
</span><span class="cx">             else:
</span><span class="cx">                 break
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def executescript(self, script):
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Re-try at least once
</span><span class="cx">         for _ignore in (0, 1):
</span><span class="cx">             if not self.initialized:
</span><span class="cx">                 yield self.open()
</span><del>-    
</del><ins>+
</ins><span class="cx">             try:
</span><span class="cx">                 yield self._db_execute_script(script)
</span><span class="cx">             except Exception, e:
</span><span class="lines">@@ -197,14 +206,15 @@
</span><span class="cx">             else:
</span><span class="cx">                 break
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def query(self, sql, *query_params):
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Re-try at least once
</span><span class="cx">         for _ignore in (0, 1):
</span><span class="cx">             if not self.initialized:
</span><span class="cx">                 yield self.open()
</span><del>-    
</del><ins>+
</ins><span class="cx">             try:
</span><span class="cx">                 result = (yield self._db_all_values_for_sql(sql, *query_params))
</span><span class="cx">             except Exception, e:
</span><span class="lines">@@ -215,14 +225,15 @@
</span><span class="cx"> 
</span><span class="cx">         returnValue(result)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def queryList(self, sql, *query_params):
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Re-try at least once
</span><span class="cx">         for _ignore in (0, 1):
</span><span class="cx">             if not self.initialized:
</span><span class="cx">                 yield self.open()
</span><del>-            
</del><ins>+
</ins><span class="cx">             try:
</span><span class="cx">                 result = (yield self._db_values_for_sql(sql, *query_params))
</span><span class="cx">             except Exception, e:
</span><span class="lines">@@ -233,14 +244,15 @@
</span><span class="cx"> 
</span><span class="cx">         returnValue(result)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def queryOne(self, sql, *query_params):
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Re-try at least once
</span><span class="cx">         for _ignore in (0, 1):
</span><span class="cx">             if not self.initialized:
</span><span class="cx">                 yield self.open()
</span><del>-    
</del><ins>+
</ins><span class="cx">             try:
</span><span class="cx">                 result = (yield self._db_value_for_sql(sql, *query_params))
</span><span class="cx">             except Exception, e:
</span><span class="lines">@@ -251,21 +263,25 @@
</span><span class="cx"> 
</span><span class="cx">         returnValue(result)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_version(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the schema version assigned to this DB.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         raise NotImplementedError
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def _db_type(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the collection type assigned to this DB.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         raise NotImplementedError
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def _test_schema_table(self):
</span><span class="cx">         return self._test_table(&quot;CALDAV&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _db_init(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -275,12 +291,12 @@
</span><span class="cx"> 
</span><span class="cx">         # TODO we need an exclusive lock of some kind here to prevent a race condition
</span><span class="cx">         # in which multiple processes try to create the tables.
</span><del>-        
</del><span class="cx"> 
</span><span class="cx">         yield self._db_init_schema_table()
</span><span class="cx">         yield self._db_init_data_tables()
</span><span class="cx">         yield self._db_recreate()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _db_init_schema_table(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -310,12 +326,14 @@
</span><span class="cx">             &quot;&quot;&quot;, (self._db_type(),)
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_init_data_tables(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Initialise the underlying database tables.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         raise NotImplementedError
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_empty_data_tables(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Delete the database tables.
</span><span class="lines">@@ -323,7 +341,8 @@
</span><span class="cx"> 
</span><span class="cx">         # Implementations can override this to re-create data
</span><span class="cx">         pass
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def _db_recreate(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Recreate the database tables.
</span><span class="lines">@@ -332,12 +351,13 @@
</span><span class="cx">         # Implementations can override this to re-create data
</span><span class="cx">         pass
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _db_upgrade(self, old_version):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Upgrade the database tables.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         if self.persistent:
</span><span class="cx">             yield self._db_upgrade_data_tables(old_version)
</span><span class="cx">             yield self._db_upgrade_schema()
</span><span class="lines">@@ -346,7 +366,8 @@
</span><span class="cx">             # DB upgrades they SHOULD override this method and handle those for better performance.
</span><span class="cx">             yield self._db_remove()
</span><span class="cx">             yield self._db_init()
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def _db_upgrade_data_tables(self, old_version):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Upgrade the data from an older version of the DB.
</span><span class="lines">@@ -372,12 +393,14 @@
</span><span class="cx">         yield self._db_remove_data_tables()
</span><span class="cx">         yield self._db_remove_schema()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_remove_data_tables(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Remove all the data from an older version of the DB.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         raise NotImplementedError(&quot;Each database must remove its own tables.&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _db_remove_schema(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -385,6 +408,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         yield self._db_execute(&quot;drop table if exists CALDAV&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _db_all_values_for_sql(self, sql, *query_params):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -395,11 +419,12 @@
</span><span class="cx">             resulting from executing C{sql} with C{query_params}.
</span><span class="cx">         @raise AssertionError: if the query yields multiple columns.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         sql = self._prepare_statement(sql)
</span><span class="cx">         results = (yield self.pool.runQuery(sql, *query_params))
</span><span class="cx">         returnValue(tuple(results))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _db_values_for_sql(self, sql, *query_params):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -411,11 +436,12 @@
</span><span class="cx">             resulting from executing C{sql} with C{query_params}.
</span><span class="cx">         @raise AssertionError: if the query yields multiple columns.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         sql = self._prepare_statement(sql)
</span><span class="cx">         results = (yield self.pool.runQuery(sql, *query_params))
</span><span class="cx">         returnValue(tuple([row[0] for row in results]))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _db_value_for_sql(self, sql, *query_params):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -433,6 +459,7 @@
</span><span class="cx">             value = row
</span><span class="cx">         returnValue(value)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_execute(self, sql, *query_params):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Execute an SQL operation that returns None.
</span><span class="lines">@@ -442,7 +469,7 @@
</span><span class="cx">         @return: an iterable of tuples for each row resulting from executing
</span><span class="cx">             C{sql} with C{query_params}.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         sql = self._prepare_statement(sql)
</span><span class="cx">         return self.pool.runOperation(sql, *query_params)
</span><span class="cx"> 
</span><span class="lines">@@ -450,37 +477,43 @@
</span><span class="cx">     Since different databases support different types of columns and modifiers on those we need to
</span><span class="cx">     have an &quot;abstract&quot; way of specifying columns in our code and then map the abstract specifiers to
</span><span class="cx">     the underlying DB's allowed types.
</span><del>-    
</del><ins>+
</ins><span class="cx">     Types we can use are:
</span><del>-    
</del><ins>+
</ins><span class="cx">     integer
</span><span class="cx">     text
</span><span class="cx">     text(n)
</span><span class="cx">     date
</span><span class="cx">     serial
</span><del>-    
</del><ins>+
</ins><span class="cx">     The &quot; unique&quot; modifier can be appended to any of those.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     def _map_column_types(self, type):
</span><span class="cx">         raise NotImplementedError
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def _create_table(self, name, columns, ifnotexists=False):
</span><span class="cx">         raise NotImplementedError
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _test_table(self, name):
</span><span class="cx">         raise NotImplementedError
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _create_index(self, name, ontable, columns, ifnotexists=False):
</span><span class="cx">         raise NotImplementedError
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _prepare_statement(self, sql):
</span><span class="cx">         raise NotImplementedError
</span><del>-        
</del><ins>+
+
+
</ins><span class="cx"> class ADBAPISqliteMixin(object):
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><span class="cx">     def _map_column_types(self, coltype):
</span><del>-        
</del><ins>+
</ins><span class="cx">         result = &quot;&quot;
</span><span class="cx">         splits = coltype.split()
</span><span class="cx">         if splits[0] == &quot;integer&quot;:
</span><span class="lines">@@ -493,15 +526,16 @@
</span><span class="cx">             result = &quot;date&quot;
</span><span class="cx">         elif splits[0] == &quot;serial&quot;:
</span><span class="cx">             result = &quot;integer primary key autoincrement&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         if len(splits) &gt; 1 and splits[1] == &quot;unique&quot;:
</span><span class="cx">             result += &quot; unique&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         return result
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _create_table(self, name, columns, ifnotexists=False):
</span><del>-        
</del><ins>+
</ins><span class="cx">         colDefs = [&quot;%s %s&quot; % (colname, self._map_column_types(coltype)) for colname, coltype in columns]
</span><span class="cx">         statement = &quot;create table %s%s (%s)&quot; % (
</span><span class="cx">             &quot;if not exists &quot; if ifnotexists else &quot;&quot;,
</span><span class="lines">@@ -510,6 +544,7 @@
</span><span class="cx">         )
</span><span class="cx">         yield self._db_execute(statement)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _test_table(self, name):
</span><span class="cx">         result = (yield self._db_value_for_sql(&quot;&quot;&quot;
</span><span class="lines">@@ -518,9 +553,10 @@
</span><span class="cx">         &quot;&quot;&quot; % (name,)))
</span><span class="cx">         returnValue(result)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _create_index(self, name, ontable, columns, ifnotexists=False):
</span><del>-        
</del><ins>+
</ins><span class="cx">         statement = &quot;create index %s%s on %s (%s)&quot; % (
</span><span class="cx">             &quot;if not exists &quot; if ifnotexists else &quot;&quot;,
</span><span class="cx">             name,
</span><span class="lines">@@ -529,6 +565,7 @@
</span><span class="cx">         )
</span><span class="cx">         yield self._db_execute(statement)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _prepare_statement(self, sql):
</span><span class="cx">         # We are going to use the sqlite syntax of :1, :2 etc for our
</span><span class="cx">         # internal statements so we do not need to remap those
</span><span class="lines">@@ -537,10 +574,10 @@
</span><span class="cx"> if pgdb:
</span><span class="cx"> 
</span><span class="cx">     class ADBAPIPostgreSQLMixin(object):
</span><del>-        
</del><ins>+
</ins><span class="cx">         @classmethod
</span><span class="cx">         def _map_column_types(self, coltype):
</span><del>-            
</del><ins>+
</ins><span class="cx">             result = &quot;&quot;
</span><span class="cx">             splits = coltype.split()
</span><span class="cx">             if splits[0] == &quot;integer&quot;:
</span><span class="lines">@@ -553,32 +590,34 @@
</span><span class="cx">                 result = &quot;date&quot;
</span><span class="cx">             elif splits[0] == &quot;serial&quot;:
</span><span class="cx">                 result = &quot;serial&quot;
</span><del>-            
</del><ins>+
</ins><span class="cx">             if len(splits) &gt; 1 and splits[1] == &quot;unique&quot;:
</span><span class="cx">                 result += &quot; unique&quot;
</span><del>-            
</del><ins>+
</ins><span class="cx">             return result
</span><del>-    
</del><ins>+
+
</ins><span class="cx">         @inlineCallbacks
</span><span class="cx">         def _create_table(self, name, columns, ifnotexists=False):
</span><del>-            
</del><ins>+
</ins><span class="cx">             colDefs = [&quot;%s %s&quot; % (colname, self._map_column_types(coltype)) for colname, coltype in columns]
</span><span class="cx">             statement = &quot;create table %s (%s)&quot; % (
</span><span class="cx">                 name,
</span><span class="cx">                 &quot;, &quot;.join(colDefs),
</span><span class="cx">             )
</span><del>-            
</del><ins>+
</ins><span class="cx">             try:
</span><span class="cx">                 yield self._db_execute(statement)
</span><span class="cx">             except pgdb.DatabaseError:
</span><del>-                
</del><ins>+
</ins><span class="cx">                 if not ifnotexists:
</span><span class="cx">                     raise
</span><del>-                
</del><ins>+
</ins><span class="cx">                 result = (yield self._test_table(name))
</span><span class="cx">                 if not result:
</span><del>-                    raise 
-    
</del><ins>+                    raise
+
+
</ins><span class="cx">         @inlineCallbacks
</span><span class="cx">         def _test_table(self, name):
</span><span class="cx">             result = (yield self._db_value_for_sql(&quot;&quot;&quot;
</span><span class="lines">@@ -586,27 +625,29 @@
</span><span class="cx">              where tablename = '%s'
</span><span class="cx">             &quot;&quot;&quot; % (name.lower(),)))
</span><span class="cx">             returnValue(result)
</span><del>-    
</del><ins>+
+
</ins><span class="cx">         @inlineCallbacks
</span><span class="cx">         def _create_index(self, name, ontable, columns, ifnotexists=False):
</span><del>-            
</del><ins>+
</ins><span class="cx">             statement = &quot;create index %s on %s (%s)&quot; % (
</span><span class="cx">                 name,
</span><span class="cx">                 ontable,
</span><span class="cx">                 &quot;, &quot;.join(columns),
</span><span class="cx">             )
</span><del>-            
</del><ins>+
</ins><span class="cx">             try:
</span><span class="cx">                 yield self._db_execute(statement)
</span><span class="cx">             except pgdb.DatabaseError:
</span><del>-                
</del><ins>+
</ins><span class="cx">                 if not ifnotexists:
</span><span class="cx">                     raise
</span><del>-                
</del><ins>+
</ins><span class="cx">                 result = (yield self._test_table(name))
</span><span class="cx">                 if not result:
</span><del>-                    raise 
-    
</del><ins>+                    raise
+
+
</ins><span class="cx">         @inlineCallbacks
</span><span class="cx">         def _db_init_schema_table(self):
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="lines">@@ -614,7 +655,7 @@
</span><span class="cx">             @param db_filename: the file name of the index database.
</span><span class="cx">             @param q:           a database cursor to use.
</span><span class="cx">             &quot;&quot;&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">             #
</span><span class="cx">             # CALDAV table keeps track of our schema version and type
</span><span class="cx">             #
</span><span class="lines">@@ -623,7 +664,7 @@
</span><span class="cx">                     (&quot;KEY&quot;, &quot;text unique&quot;),
</span><span class="cx">                     (&quot;VALUE&quot;, &quot;text unique&quot;),
</span><span class="cx">                 ), True)
</span><del>-    
</del><ins>+
</ins><span class="cx">                 yield self._db_execute(
</span><span class="cx">                     &quot;&quot;&quot;
</span><span class="cx">                     insert into CALDAV (KEY, VALUE)
</span><span class="lines">@@ -638,7 +679,8 @@
</span><span class="cx">                 )
</span><span class="cx">             except pgdb.DatabaseError:
</span><span class="cx">                 pass
</span><del>-    
</del><ins>+
+
</ins><span class="cx">         def _prepare_statement(self, sql):
</span><span class="cx">             # Convert :1, :2 etc format into %s
</span><span class="cx">             ctr = 1
</span><span class="lines">@@ -649,6 +691,6 @@
</span><span class="cx"> 
</span><span class="cx"> else:
</span><span class="cx">     class ADBAPIPostgreSQLMixin(object):
</span><del>-        
</del><ins>+
</ins><span class="cx">         def __init__(self):
</span><span class="cx">             raise ConfigurationError(&quot;PostgreSQL module not available.&quot;)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdatafilterscalendardatapy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/datafilters/calendardata.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/datafilters/calendardata.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/datafilters/calendardata.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -19,7 +19,7 @@
</span><span class="cx"> from twistedcaldav.datafilters.filter import CalendarFilter
</span><span class="cx"> from twistedcaldav.dateops import clipPeriod
</span><span class="cx"> from twistedcaldav.ical import Component
</span><del>-from pycalendar.period import PyCalendarPeriod
</del><ins>+from pycalendar.period import Period
</ins><span class="cx"> 
</span><span class="cx"> __all__ = [
</span><span class="cx">     &quot;CalendarDataFilter&quot;,
</span><span class="lines">@@ -161,7 +161,7 @@
</span><span class="cx">             for property in component.properties(&quot;FREEBUSY&quot;):
</span><span class="cx">                 newvalue = []
</span><span class="cx">                 for period in property.value():
</span><del>-                    clipped = clipPeriod(period.getValue(), PyCalendarPeriod(self.calendardata.freebusy_set.start, self.calendardata.freebusy_set.end))
</del><ins>+                    clipped = clipPeriod(period.getValue(), Period(self.calendardata.freebusy_set.start, self.calendardata.freebusy_set.end))
</ins><span class="cx">                     if clipped:
</span><span class="cx">                         newvalue.append(clipped)
</span><span class="cx">                 if len(newvalue):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdateopspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/dateops.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/dateops.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/dateops.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -28,9 +28,9 @@
</span><span class="cx">     &quot;clipPeriod&quot;
</span><span class="cx"> ]
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
-from pycalendar.period import PyCalendarPeriod
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
+from pycalendar.period import Period
</ins><span class="cx"> 
</span><span class="cx"> import datetime
</span><span class="cx"> import dateutil.tz
</span><span class="lines">@@ -39,14 +39,14 @@
</span><span class="cx"> 
</span><span class="cx"> def normalizeForIndex(dt):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Normalize a L{PyCalendarDateTime} object for use in the Index.
</del><ins>+    Normalize a L{DateTime} object for use in the Index.
</ins><span class="cx">     Convert to date-time in UTC.
</span><del>-    @param dt: a L{PyCalendarDateTime} object to normalize
-    @return: the normalized PyCalendarDateTime
</del><ins>+    @param dt: a L{DateTime} object to normalize
+    @return: the normalized DateTime
</ins><span class="cx">     &quot;&quot;&quot;
</span><del>-    if not isinstance(dt, PyCalendarDateTime):
-        raise TypeError(&quot;%r is not a PyCalendarDateTime instance&quot; % (dt,))
-    
</del><ins>+    if not isinstance(dt, DateTime):
+        raise TypeError(&quot;%r is not a DateTime instance&quot; % (dt,))
+
</ins><span class="cx">     dt = dt.duplicate()
</span><span class="cx">     if dt.isDateOnly():
</span><span class="cx">         dt.setDateOnly(False)
</span><span class="lines">@@ -59,13 +59,15 @@
</span><span class="cx">         dt.adjustToUTC()
</span><span class="cx">         return dt
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def normalizeToUTC(dt):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Normalize a L{PyCalendarDateTime} object to UTC.
</del><ins>+    Normalize a L{DateTime} object to UTC.
</ins><span class="cx">     &quot;&quot;&quot;
</span><del>-    if not isinstance(dt, PyCalendarDateTime):
-        raise TypeError(&quot;%r is not a PyCalendarDateTime instance&quot; % (dt,))
-    
</del><ins>+    if not isinstance(dt, DateTime):
+        raise TypeError(&quot;%r is not a DateTime instance&quot; % (dt,))
+
</ins><span class="cx">     dt = dt.duplicate()
</span><span class="cx">     if dt.isDateOnly():
</span><span class="cx">         dt.setDateOnly(False)
</span><span class="lines">@@ -79,16 +81,18 @@
</span><span class="cx">         dt.adjustToUTC()
</span><span class="cx">         return dt
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def normalizeForExpand(dt):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Normalize a L{PyCalendarDateTime} object for use with the CalDAV expand option.
</del><ins>+    Normalize a L{DateTime} object for use with the CalDAV expand option.
</ins><span class="cx">     Convert to date-time in UTC, leave date only and floating alone.
</span><del>-    @param dt: a L{PyCalendarDateTime} object to normalize
-    @return: the normalized PyCalendarDateTime
</del><ins>+    @param dt: a L{DateTime} object to normalize
+    @return: the normalized DateTime
</ins><span class="cx">     &quot;&quot;&quot;
</span><del>-    if not isinstance(dt, PyCalendarDateTime):
-        raise TypeError(&quot;%r is not a PyCalendarDateTime instance&quot; % (dt,))
-    
</del><ins>+    if not isinstance(dt, DateTime):
+        raise TypeError(&quot;%r is not a DateTime instance&quot; % (dt,))
+
</ins><span class="cx">     dt = dt.duplicate()
</span><span class="cx">     if dt.isDateOnly() or dt.floating():
</span><span class="cx">         return dt
</span><span class="lines">@@ -96,41 +100,49 @@
</span><span class="cx">         dt.adjustToUTC()
</span><span class="cx">         return dt
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def floatoffset(dt, pytz):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Apply the timezone offset to the supplied time, then force tz to utc. This gives the local
</span><span class="cx">     date-time as if the local tz were UTC. It can be used in floating time comparisons with UTC date-times.
</span><del>-    
-    @param dt: a L{PyCalendarDateTime} object to normalize
-    @param pytz: a L{PyCalendarTimezone} object to apply offset from
-    @return: the normalized PyCalendarDateTime
</del><ins>+
+    @param dt: a L{DateTime} object to normalize
+    @param pytz: a L{Timezone} object to apply offset from
+    @return: the normalized DateTime
</ins><span class="cx">     &quot;&quot;&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">     if pytz is None:
</span><del>-        pytz = PyCalendarTimezone(utc=True)
-    
</del><ins>+        pytz = Timezone(utc=True)
+
</ins><span class="cx">     dt = dt.duplicate()
</span><span class="cx">     dt.adjustTimezone(pytz)
</span><span class="cx">     dt.setTimezoneUTC(True)
</span><span class="cx">     return dt
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def adjustFloatingToTimezone(dtadjust, dtcopyfrom, pytz=None):
</span><del>-    
</del><ins>+
</ins><span class="cx">     dtadjust = dtadjust.duplicate()
</span><span class="cx">     dtadjust.setTimezone(pytz if pytz else dtcopyfrom.getTimezone())
</span><span class="cx">     return dtadjust
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def compareDateTime(dt1, dt2, defaulttz=None):
</span><del>-    
</del><ins>+
</ins><span class="cx">     if dt1.floating() and not dt2.floating():
</span><span class="cx">         dt1 = adjustFloatingToTimezone(dt1, dt2, defaulttz)
</span><span class="cx">     elif dt2.floating() and not dt1.floating():
</span><span class="cx">         dt2 = adjustFloatingToTimezone(dt2, dt1, defaulttz)
</span><del>-    
</del><ins>+
</ins><span class="cx">     return dt1.compareDateTime(dt2)
</span><span class="cx"> 
</span><del>-def differenceDateTime(start, end, defaulttz = None):
</del><span class="cx"> 
</span><ins>+
+def differenceDateTime(start, end, defaulttz=None):
+
</ins><span class="cx">     if start.floating() and not end.floating():
</span><span class="cx">         start = adjustFloatingToTimezone(start, end, defaulttz)
</span><span class="cx">     elif end.floating() and not start.floating():
</span><span class="lines">@@ -138,13 +150,19 @@
</span><span class="cx"> 
</span><span class="cx">     return end - start
</span><span class="cx"> 
</span><del>-def timeRangesOverlap(start1, end1, start2, end2, defaulttz = None):
</del><ins>+
+
+def timeRangesOverlap(start1, end1, start2, end2, defaulttz=None):
</ins><span class="cx">     # Can't compare date-time and date only, so normalize
</span><span class="cx">     # to date only if they are mixed.
</span><del>-    if (start1 is not None) and not start1.isDateOnly() and (start2 is not None) and start2.isDateOnly(): start1.setDateOnly(True)
-    if (start2 is not None) and not start2.isDateOnly() and (start1 is not None) and start1.isDateOnly(): start2.setDateOnly(True)
-    if (end1 is not None) and not end1.isDateOnly() and (end2 is not None) and end2.isDateOnly(): end1.setDateOnly(True)
-    if (end2 is not None) and not end2.isDateOnly() and (end1 is not None) and end1.isDateOnly(): end2.setDateOnly(True)
</del><ins>+    if (start1 is not None) and not start1.isDateOnly() and (start2 is not None) and start2.isDateOnly():
+        start1.setDateOnly(True)
+    if (start2 is not None) and not start2.isDateOnly() and (start1 is not None) and start1.isDateOnly():
+        start2.setDateOnly(True)
+    if (end1 is not None) and not end1.isDateOnly() and (end2 is not None) and end2.isDateOnly():
+        end1.setDateOnly(True)
+    if (end2 is not None) and not end2.isDateOnly() and (end1 is not None) and end1.isDateOnly():
+        end2.setDateOnly(True)
</ins><span class="cx"> 
</span><span class="cx">     # Note that start times are inclusive and end times are not.
</span><span class="cx">     if start1 is not None and start2 is not None:
</span><span class="lines">@@ -163,40 +181,41 @@
</span><span class="cx">     else:
</span><span class="cx">         return False
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def normalizePeriodList(periods):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Normalize the list of periods by merging overlapping or consecutive ranges
</span><span class="cx">     and sorting the list by each periods start.
</span><del>-    @param list: a list of tuples of L{PyCalendarPeriod}. The list is changed in place.
</del><ins>+    @param list: a list of tuples of L{Period}. The list is changed in place.
</ins><span class="cx">     &quot;&quot;&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">     # First sort the list
</span><span class="cx">     def sortPeriods(p1, p2):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Compare two periods. Sort by their start and then end times.
</span><del>-        A period is a L{PyCalendarPeriod}.
</del><ins>+        A period is a L{Period}.
</ins><span class="cx">         @param p1: first period
</span><span class="cx">         @param p2: second period
</span><span class="cx">         @return: 1 if p1&gt;p2, 0 if p1==p2, -1 if p1&lt;p2
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        assert isinstance(p1, PyCalendarPeriod), &quot;Period is not a PyCalendarPeriod: %r&quot; % (p1,)
-        assert isinstance(p2, PyCalendarPeriod), &quot;Period is not a PyCalendarPeriod: %r&quot; % (p2,)
-        
-        
</del><ins>+        assert isinstance(p1, Period), &quot;Period is not a Period: %r&quot; % (p1,)
+        assert isinstance(p2, Period), &quot;Period is not a Period: %r&quot; % (p2,)
+
</ins><span class="cx">         if p1.getStart() == p2.getStart():
</span><span class="cx">             cmp1 = p1.getEnd()
</span><span class="cx">             cmp2 = p2.getEnd()
</span><span class="cx">         else:
</span><span class="cx">             cmp1 = p1.getStart()
</span><span class="cx">             cmp2 = p2.getStart()
</span><del>-        
</del><ins>+
</ins><span class="cx">         return compareDateTime(cmp1, cmp2)
</span><span class="cx"> 
</span><span class="cx">     for period in periods:
</span><span class="cx">         period.adjustToUTC()
</span><span class="cx">     periods.sort(cmp=sortPeriods)
</span><del>-    
</del><ins>+
</ins><span class="cx">     # Now merge overlaps and consecutive periods
</span><span class="cx">     index = None
</span><span class="cx">     p = None
</span><span class="lines">@@ -210,15 +229,17 @@
</span><span class="cx">         ie = periods[i].getEnd()
</span><span class="cx">         if (pe &gt;= periods[i].getStart()):
</span><span class="cx">             if ie &gt; pe:
</span><del>-                periods[index] = PyCalendarPeriod(periods[index].getStart(), ie)
</del><ins>+                periods[index] = Period(periods[index].getStart(), ie)
</ins><span class="cx">                 pe = ie
</span><span class="cx">             periods[i] = None
</span><span class="cx">         else:
</span><span class="cx">             index = i
</span><span class="cx">             p = periods[i]
</span><del>-            pe =p.getEnd()
</del><ins>+            pe = p.getEnd()
</ins><span class="cx">     periods[:] = [x for x in periods if x]
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def clipPeriod(period, clipPeriod):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Clip the start/end period so that it lies entirely within the clip period.
</span><span class="lines">@@ -234,20 +255,22 @@
</span><span class="cx"> 
</span><span class="cx">     if start &lt; clipStart:
</span><span class="cx">         start = clipStart
</span><del>-    
</del><ins>+
</ins><span class="cx">     if end &gt; clipEnd:
</span><span class="cx">         end = clipEnd
</span><del>-    
</del><ins>+
</ins><span class="cx">     if start &gt;= end:
</span><span class="cx">         return None
</span><span class="cx">     else:
</span><span class="cx">         # Try to preserve use of duration in period
</span><del>-        result = PyCalendarPeriod(start, end)
</del><ins>+        result = Period(start, end)
</ins><span class="cx">         result.setUseDuration(period.getUseDuration())
</span><span class="cx">         return result
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def pyCalendarTodatetime(pydt):
</span><del>-    
</del><ins>+
</ins><span class="cx">     if pydt.isDateOnly():
</span><span class="cx">         return datetime.date(year=pydt.getYear(), month=pydt.getMonth(), day=pydt.getDay())
</span><span class="cx">     else:
</span><span class="lines">@@ -261,17 +284,19 @@
</span><span class="cx">             tzinfo=dateutil.tz.tzutc()
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def parseSQLTimestampToPyCalendar(ts):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Parse an SQL formated timestamp into a PyCalendarDateTime
</del><ins>+    Parse an SQL formated timestamp into a DateTime
</ins><span class="cx">     @param ts: the SQL timestamp
</span><span class="cx">     @type ts: C{str}
</span><del>-    
-    @return: L{PyCalendarDateTime} result
</del><ins>+
+    @return: L{DateTime} result
</ins><span class="cx">     &quot;&quot;&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">     # Format is &quot;%Y-%m-%d %H:%M:%S&quot;
</span><del>-    return PyCalendarDateTime(
</del><ins>+    return DateTime(
</ins><span class="cx">         year=int(ts[0:4]),
</span><span class="cx">         month=int(ts[5:7]),
</span><span class="cx">         day=int(ts[8:10]),
</span><span class="lines">@@ -280,22 +305,26 @@
</span><span class="cx">         seconds=int(ts[17:19])
</span><span class="cx">     )
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def parseSQLDateToPyCalendar(ts):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Parse an SQL formated date into a PyCalendarDateTime
</del><ins>+    Parse an SQL formated date into a DateTime
</ins><span class="cx">     @param ts: the SQL date
</span><span class="cx">     @type ts: C{str}
</span><del>-    
-    @return: L{PyCalendarDateTime} result
</del><ins>+
+    @return: L{DateTime} result
</ins><span class="cx">     &quot;&quot;&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">     # Format is &quot;%Y-%m-%d&quot;, though Oracle may add zero time which we ignore
</span><del>-    return PyCalendarDateTime(
</del><ins>+    return DateTime(
</ins><span class="cx">         year=int(ts[0:4]),
</span><span class="cx">         month=int(ts[5:7]),
</span><span class="cx">         day=int(ts[8:10])
</span><span class="cx">     )
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def datetimeMktime(dt):
</span><span class="cx"> 
</span><span class="cx">     assert isinstance(dt, datetime.date)
</span><span class="lines">@@ -303,4 +332,3 @@
</span><span class="cx">     if dt.tzinfo is None:
</span><span class="cx">         dt.replace(tzinfo=dateutil.tz.tzutc())
</span><span class="cx">     return calendar.timegm(dt.utctimetuple())
</span><del>-
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryaddressbookpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/addressbook.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/addressbook.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/addressbook.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -56,6 +56,8 @@
</span><span class="cx">             + config.CalDAVComplianceClasses
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class DirectoryAddressBookProvisioningResource (
</span><span class="cx">     ReadOnlyResourceMixIn,
</span><span class="cx">     CalDAVComplianceMixIn,
</span><span class="lines">@@ -65,18 +67,21 @@
</span><span class="cx">     def defaultAccessControlList(self):
</span><span class="cx">         return config.ProvisioningResourceACL
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def etag(self):
</span><span class="cx">         return succeed(ETag(str(uuid4())))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def contentType(self):
</span><span class="cx">         return MimeType(&quot;httpd&quot;, &quot;unix-directory&quot;)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class DirectoryAddressBookHomeProvisioningResource (
</span><span class="cx">         DirectoryAddressBookProvisioningResource
</span><span class="cx">     ):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Resource which provisions address book home collections as needed.    
</del><ins>+    Resource which provisions address book home collections as needed.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     def __init__(self, directory, url, store):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -103,22 +108,27 @@
</span><span class="cx"> 
</span><span class="cx">         self.putChild(uidsResourceName, DirectoryAddressBookHomeUIDProvisioningResource(self))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def url(self):
</span><span class="cx">         return self._url
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def listChildren(self):
</span><span class="cx">         return self.directory.recordTypes()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def principalCollections(self):
</span><span class="cx">         # FIXME: directory.principalCollection smells like a hack
</span><span class="cx">         # See DirectoryPrincipalProvisioningResource.__init__()
</span><span class="cx">         return self.directory.principalCollection.principalCollections()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def principalForRecord(self, record):
</span><span class="cx">         # FIXME: directory.principalCollection smells like a hack
</span><span class="cx">         # See DirectoryPrincipalProvisioningResource.__init__()
</span><span class="cx">         return self.directory.principalCollection.principalForRecord(record)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def homeForDirectoryRecord(self, record, request):
</span><span class="cx">         uidResource = self.getChild(uidsResourceName)
</span><span class="cx">         if uidResource is None:
</span><span class="lines">@@ -126,17 +136,20 @@
</span><span class="cx">         else:
</span><span class="cx">             return uidResource.homeResourceForRecord(record, request)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     ##
</span><span class="cx">     # DAV
</span><span class="cx">     ##
</span><del>-    
</del><ins>+
</ins><span class="cx">     def isCollection(self):
</span><span class="cx">         return True
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def displayName(self):
</span><span class="cx">         return &quot;addressbooks&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class DirectoryAddressBookHomeTypeProvisioningResource (
</span><span class="cx">         CommonHomeTypeProvisioningResource,
</span><span class="cx">         DirectoryAddressBookProvisioningResource
</span><span class="lines">@@ -159,6 +172,7 @@
</span><span class="cx">         self.recordType = recordType
</span><span class="cx">         self._parent = parent
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def url(self):
</span><span class="cx">         return joinURL(self._parent.url(), self.recordType)
</span><span class="cx"> 
</span><span class="lines">@@ -177,16 +191,19 @@
</span><span class="cx">             # Not a listable collection
</span><span class="cx">             raise HTTPError(responsecode.FORBIDDEN)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def makeChild(self, name):
</span><span class="cx">         return None
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     ##
</span><span class="cx">     # DAV
</span><span class="cx">     ##
</span><del>-    
</del><ins>+
</ins><span class="cx">     def isCollection(self):
</span><span class="cx">         return True
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def displayName(self):
</span><span class="cx">         return self.recordType
</span><span class="cx"> 
</span><span class="lines">@@ -194,13 +211,16 @@
</span><span class="cx">     # ACL
</span><span class="cx">     ##
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def principalCollections(self):
</span><span class="cx">         return self._parent.principalCollections()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def principalForRecord(self, record):
</span><span class="cx">         return self._parent.principalForRecord(record)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class DirectoryAddressBookHomeUIDProvisioningResource (
</span><span class="cx">         CommonUIDProvisioningResource,
</span><span class="cx">         DirectoryAddressBookProvisioningResource
</span><span class="lines">@@ -210,11 +230,13 @@
</span><span class="cx"> 
</span><span class="cx">     enabledAttribute = 'enabledForAddressBooks'
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def homeResourceCreator(self, record, transaction):
</span><span class="cx">         return DirectoryAddressBookHomeResource.createHomeResource(
</span><span class="cx">             self, record, transaction)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class DirectoryAddressBookHomeResource (AddressBookHomeResource):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Address book home collection resource.
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryaugmentpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/augment.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/augment.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/augment.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -25,11 +25,11 @@
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav.config import fullServerPath, config
</span><del>-from twistedcaldav.database import AbstractADBAPIDatabase, ADBAPISqliteMixin,\
</del><ins>+from twistedcaldav.database import AbstractADBAPIDatabase, ADBAPISqliteMixin, \
</ins><span class="cx">     ADBAPIPostgreSQLMixin
</span><span class="cx"> from twistedcaldav.directory import xmlaugmentsparser
</span><span class="cx"> from twistedcaldav.directory.xmlaugmentsparser import XMLAugmentsParser
</span><del>-from twistedcaldav.xmlutil import newElementTreeWithRoot, addSubElement,\
</del><ins>+from twistedcaldav.xmlutil import newElementTreeWithRoot, addSubElement, \
</ins><span class="cx">     writeXML, readXML
</span><span class="cx"> from twistedcaldav.directory.util import normalizeUUID
</span><span class="cx"> 
</span><span class="lines">@@ -56,7 +56,6 @@
</span><span class="cx">         uid,
</span><span class="cx">         enabled=False,
</span><span class="cx">         serverID=&quot;&quot;,
</span><del>-        partitionID=&quot;&quot;,
</del><span class="cx">         enabledForCalendaring=False,
</span><span class="cx">         autoSchedule=False,
</span><span class="cx">         autoScheduleMode=&quot;default&quot;,
</span><span class="lines">@@ -67,7 +66,6 @@
</span><span class="cx">         self.uid = uid
</span><span class="cx">         self.enabled = enabled
</span><span class="cx">         self.serverID = serverID
</span><del>-        self.partitionID = partitionID
</del><span class="cx">         self.enabledForCalendaring = enabledForCalendaring
</span><span class="cx">         self.enabledForAddressBooks = enabledForAddressBooks
</span><span class="cx">         self.enabledForLogin = enabledForLogin
</span><span class="lines">@@ -87,9 +85,9 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Abstract base class for an augment record database.
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">     def __init__(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         self.cachedRecords = {}
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -126,10 +124,10 @@
</span><span class="cx"> 
</span><span class="cx">         @param uid: directory UID to lookup
</span><span class="cx">         @type uid: C{str}
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         recordType = recordTypesMap[recordType]
</span><span class="cx"> 
</span><span class="cx">         result = (yield self._lookupAugmentRecord(uid))
</span><span class="lines">@@ -166,6 +164,7 @@
</span><span class="cx">         result.clonedFromDefault = True
</span><span class="cx">         returnValue(result)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def getAllUIDs(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -173,21 +172,23 @@
</span><span class="cx"> 
</span><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         raise NotImplementedError(&quot;Child class must define this.&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _lookupAugmentRecord(self, uid):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Get an AugmentRecord for the specified UID.
</span><span class="cx"> 
</span><span class="cx">         @param uid: directory UID to lookup
</span><span class="cx">         @type uid: C{str}
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         raise NotImplementedError(&quot;Child class must define this.&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _cachedAugmentRecord(self, uid):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -195,59 +196,64 @@
</span><span class="cx"> 
</span><span class="cx">         @param uid: directory UID to lookup
</span><span class="cx">         @type uid: C{str}
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         if not uid in self.cachedRecords:
</span><span class="cx">             result = (yield self._lookupAugmentRecord(uid))
</span><span class="cx">             self.cachedRecords[uid] = result
</span><span class="cx">         returnValue(self.cachedRecords[uid])
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def addAugmentRecords(self, records):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Add an AugmentRecord to the DB.
</span><span class="cx"> 
</span><span class="cx">         @param record: augment records to add
</span><span class="cx">         @type record: C{list} of L{AugmentRecord}
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         raise NotImplementedError(&quot;Child class must define this.&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def removeAugmentRecords(self, uids):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Remove AugmentRecords with the specified UIDs.
</span><span class="cx"> 
</span><span class="cx">         @param uid: directory UIDs to remove
</span><span class="cx">         @type uid: C{list} of C{str}
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         raise NotImplementedError(&quot;Child class must define this.&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def refresh(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Refresh any cached data.
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         self.cachedRecords.clear()
</span><span class="cx">         return succeed(None)
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def clean(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Remove all records.
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         raise NotImplementedError(&quot;Child class must define this.&quot;)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class AugmentXMLDB(AugmentDB):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     XMLFile based augment database implementation.
</span><span class="lines">@@ -257,7 +263,7 @@
</span><span class="cx"> 
</span><span class="cx">         super(AugmentXMLDB, self).__init__()
</span><span class="cx">         self.xmlFiles = [fullServerPath(config.DataRoot, path) for path in xmlFiles]
</span><del>-        self.xmlFileStats = { }
</del><ins>+        self.xmlFileStats = {}
</ins><span class="cx">         for path in self.xmlFiles:
</span><span class="cx">             self.xmlFileStats[path] = (0, 0) # mtime, size
</span><span class="cx"> 
</span><span class="lines">@@ -290,16 +296,17 @@
</span><span class="cx"> 
</span><span class="cx">         @param uid: directory UID to lookup
</span><span class="cx">         @type uid: C{str}
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         # May need to re-cache
</span><span class="cx">         if time.time() - self.lastCached &gt; self.statSeconds:
</span><span class="cx">             self.refresh()
</span><del>-            
</del><ins>+
</ins><span class="cx">         return succeed(self.db.get(uid))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def addAugmentRecords(self, records):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Add an AugmentRecord to the DB.
</span><span class="lines">@@ -308,13 +315,13 @@
</span><span class="cx">         @type records: C{list} of L{AugmentRecord}
</span><span class="cx">         @param update: C{True} if changing an existing record
</span><span class="cx">         @type update: C{bool}
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Look at each record and determine whether it is new or a modify
</span><span class="cx">         new_records = list()
</span><del>-        existing_records = list() 
</del><ins>+        existing_records = list()
</ins><span class="cx">         for record in records:
</span><span class="cx">             (existing_records if record.uid in self.db else new_records).append(record)
</span><span class="cx"> 
</span><span class="lines">@@ -332,6 +339,7 @@
</span><span class="cx"> 
</span><span class="cx">         return succeed(None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _doAddToFile(self, xmlfile, records):
</span><span class="cx"> 
</span><span class="cx">         if not os.path.exists(xmlfile):
</span><span class="lines">@@ -343,7 +351,6 @@
</span><span class="cx">             for record in self.db.itervalues():
</span><span class="cx">                 self._addRecordToXMLDB(record, augments_node)
</span><span class="cx"> 
</span><del>-
</del><span class="cx">             writeXML(xmlfile, augments_node)
</span><span class="cx"> 
</span><span class="cx">             # Set permissions
</span><span class="lines">@@ -362,33 +369,33 @@
</span><span class="cx">             if uid != -1 and gid != -1:
</span><span class="cx">                 os.chown(xmlfile, uid, gid)
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         _ignore_etree, augments_node = readXML(xmlfile)
</span><span class="cx"> 
</span><span class="cx">         # Create new record
</span><span class="cx">         for record in records:
</span><span class="cx">             self._addRecordToXMLDB(record, augments_node)
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Modify xmlfile
</span><span class="cx">         writeXML(xmlfile, augments_node)
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def _doModifyInFile(self, xmlfile, records):
</span><del>-    
</del><ins>+
</ins><span class="cx">         if not os.path.exists(xmlfile):
</span><span class="cx">             return
</span><span class="cx"> 
</span><span class="cx">         _ignore_etree, augments_node = readXML(xmlfile)
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Map uid-&gt;record for fast lookup
</span><span class="cx">         recordMap = dict([(record.uid, record) for record in records])
</span><span class="cx"> 
</span><span class="cx">         # Make sure UID is present
</span><span class="cx">         changed = False
</span><span class="cx">         for record_node in augments_node:
</span><del>-            
</del><ins>+
</ins><span class="cx">             if record_node.tag != xmlaugmentsparser.ELEMENT_RECORD:
</span><span class="cx">                 continue
</span><del>-    
</del><ins>+
</ins><span class="cx">             uid = record_node.find(xmlaugmentsparser.ELEMENT_UID).text
</span><span class="cx">             if uid in recordMap:
</span><span class="cx">                 # Modify record
</span><span class="lines">@@ -400,13 +407,14 @@
</span><span class="cx">         if changed:
</span><span class="cx">             writeXML(xmlfile, augments_node)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def removeAugmentRecords(self, uids):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Remove AugmentRecords with the specified UIDs.
</span><span class="cx"> 
</span><span class="cx">         @param uids: list of uids to remove
</span><span class="cx">         @type uids: C{list} of C{str}
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -423,10 +431,11 @@
</span><span class="cx"> 
</span><span class="cx">         return succeed(None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _doRemoveFromFile(self, xmlfile, uids):
</span><del>-    
</del><ins>+
</ins><span class="cx">         _ignore_etree, augments_node = readXML(xmlfile)
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Remove all UIDs present
</span><span class="cx">         changed = False
</span><span class="cx">         for child in augments_node:
</span><span class="lines">@@ -440,20 +449,19 @@
</span><span class="cx">         # Modify xmlfile
</span><span class="cx">         if changed:
</span><span class="cx">             writeXML(xmlfile, augments_node)
</span><del>-        
-        
</del><ins>+
+
</ins><span class="cx">     def _addRecordToXMLDB(self, record, parentNode):
</span><span class="cx">         record_node = addSubElement(parentNode, xmlaugmentsparser.ELEMENT_RECORD)
</span><span class="cx">         self._updateRecordInXMLDB(record, record_node)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _updateRecordInXMLDB(self, record, recordNode):
</span><span class="cx">         del recordNode[:]
</span><span class="cx">         addSubElement(recordNode, xmlaugmentsparser.ELEMENT_UID, record.uid)
</span><span class="cx">         addSubElement(recordNode, xmlaugmentsparser.ELEMENT_ENABLE, &quot;true&quot; if record.enabled else &quot;false&quot;)
</span><span class="cx">         if record.serverID:
</span><span class="cx">             addSubElement(recordNode, xmlaugmentsparser.ELEMENT_SERVERID, record.serverID)
</span><del>-        if record.partitionID:
-            addSubElement(recordNode, xmlaugmentsparser.ELEMENT_PARTITIONID, record.partitionID)
</del><span class="cx">         addSubElement(recordNode, xmlaugmentsparser.ELEMENT_ENABLECALENDAR, &quot;true&quot; if record.enabledForCalendaring else &quot;false&quot;)
</span><span class="cx">         addSubElement(recordNode, xmlaugmentsparser.ELEMENT_ENABLEADDRESSBOOK, &quot;true&quot; if record.enabledForAddressBooks else &quot;false&quot;)
</span><span class="cx">         addSubElement(recordNode, xmlaugmentsparser.ELEMENT_ENABLELOGIN, &quot;true&quot; if record.enabledForLogin else &quot;false&quot;)
</span><span class="lines">@@ -463,6 +471,7 @@
</span><span class="cx">         if record.autoAcceptGroup:
</span><span class="cx">             addSubElement(recordNode, xmlaugmentsparser.ELEMENT_AUTOACCEPTGROUP, record.autoAcceptGroup)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def refresh(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Refresh any cached data.
</span><span class="lines">@@ -479,6 +488,7 @@
</span><span class="cx"> 
</span><span class="cx">         return succeed(None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def clean(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Remove all records.
</span><span class="lines">@@ -487,6 +497,7 @@
</span><span class="cx">         self.removeAugmentRecords(self.db.keys())
</span><span class="cx">         return succeed(None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _shouldReparse(self, xmlFiles):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Check to see whether any of the given files have been modified since
</span><span class="lines">@@ -501,6 +512,7 @@
</span><span class="cx">                     return True
</span><span class="cx">         return False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _parseXML(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Parse self.xmlFiles into AugmentRecords.
</span><span class="lines">@@ -536,19 +548,22 @@
</span><span class="cx"> 
</span><span class="cx">         return results
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class AugmentADAPI(AugmentDB, AbstractADBAPIDatabase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     DBAPI based augment database implementation.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    schema_version = &quot;2&quot;
-    schema_type    = &quot;AugmentDB&quot;
-    
</del><ins>+    schema_version = &quot;3&quot;
+    schema_type = &quot;AugmentDB&quot;
+
</ins><span class="cx">     def __init__(self, dbID, dbapiName, dbapiArgs, **kwargs):
</span><del>-        
</del><ins>+
</ins><span class="cx">         AugmentDB.__init__(self)
</span><span class="cx">         AbstractADBAPIDatabase.__init__(self, dbID, dbapiName, dbapiArgs, True, **kwargs)
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def getAllUIDs(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -556,11 +571,12 @@
</span><span class="cx"> 
</span><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Query for the record information
</span><span class="cx">         results = (yield self.queryList(&quot;select UID from AUGMENTS&quot;, ()))
</span><span class="cx">         returnValue(results)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _lookupAugmentRecord(self, uid):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -571,34 +587,34 @@
</span><span class="cx"> 
</span><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Query for the record information
</span><del>-        results = (yield self.query(&quot;select UID, ENABLED, SERVERID, PARTITIONID, CALENDARING, ADDRESSBOOKS, AUTOSCHEDULE, AUTOSCHEDULEMODE, AUTOACCEPTGROUP, LOGINENABLED from AUGMENTS where UID = :1&quot;, (uid,)))
</del><ins>+        results = (yield self.query(&quot;select UID, ENABLED, SERVERID, CALENDARING, ADDRESSBOOKS, AUTOSCHEDULE, AUTOSCHEDULEMODE, AUTOACCEPTGROUP, LOGINENABLED from AUGMENTS where UID = :1&quot;, (uid,)))
</ins><span class="cx">         if not results:
</span><span class="cx">             returnValue(None)
</span><span class="cx">         else:
</span><del>-            uid, enabled, serverid, partitionid, enabledForCalendaring, enabledForAddressBooks, autoSchedule, autoScheduleMode, autoAcceptGroup, enabledForLogin = results[0]
-            
</del><ins>+            uid, enabled, serverid, enabledForCalendaring, enabledForAddressBooks, autoSchedule, autoScheduleMode, autoAcceptGroup, enabledForLogin = results[0]
+
</ins><span class="cx">             record = AugmentRecord(
</span><del>-                uid = uid,
-                enabled = enabled == &quot;T&quot;,
-                serverID = serverid,
-                partitionID = partitionid,
-                enabledForCalendaring = enabledForCalendaring == &quot;T&quot;,
-                enabledForAddressBooks = enabledForAddressBooks == &quot;T&quot;,
-                enabledForLogin = enabledForLogin == &quot;T&quot;,
-                autoSchedule = autoSchedule == &quot;T&quot;,
-                autoScheduleMode = autoScheduleMode,
-                autoAcceptGroup = autoAcceptGroup,
</del><ins>+                uid=uid,
+                enabled=enabled == &quot;T&quot;,
+                serverID=serverid,
+                enabledForCalendaring=enabledForCalendaring == &quot;T&quot;,
+                enabledForAddressBooks=enabledForAddressBooks == &quot;T&quot;,
+                enabledForLogin=enabledForLogin == &quot;T&quot;,
+                autoSchedule=autoSchedule == &quot;T&quot;,
+                autoScheduleMode=autoScheduleMode,
+                autoAcceptGroup=autoAcceptGroup,
</ins><span class="cx">             )
</span><del>-            
</del><ins>+
</ins><span class="cx">             returnValue(record)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def addAugmentRecords(self, records):
</span><span class="cx"> 
</span><span class="cx">         for record in records:
</span><del>-            
</del><ins>+
</ins><span class="cx">             results = (yield self.query(&quot;select UID from AUGMENTS where UID = :1&quot;, (record.uid,)))
</span><span class="cx">             update = len(results) &gt; 0
</span><span class="cx"> 
</span><span class="lines">@@ -607,6 +623,7 @@
</span><span class="cx">             else:
</span><span class="cx">                 yield self._addRecord(record)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def removeAugmentRecords(self, uids):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -614,32 +631,36 @@
</span><span class="cx"> 
</span><span class="cx">         @param uids: list of uids to remove
</span><span class="cx">         @type uids: C{list} of C{str}
</span><del>-        
</del><ins>+
</ins><span class="cx">         @return: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         for uid in uids:
</span><span class="cx">             yield self.execute(&quot;delete from AUGMENTS where UID = :1&quot;, (uid,))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def clean(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Remove all records.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         return self.execute(&quot;delete from AUGMENTS&quot;, ())
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def _db_version(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the schema version assigned to this index.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return AugmentADAPI.schema_version
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def _db_type(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the collection type assigned to this index.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return AugmentADAPI.schema_type
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _db_init_data_tables(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -652,45 +673,47 @@
</span><span class="cx">         yield self._create_table(
</span><span class="cx">             &quot;AUGMENTS&quot;,
</span><span class="cx">             (
</span><del>-                (&quot;UID&quot;,              &quot;text unique&quot;),
-                (&quot;ENABLED&quot;,          &quot;text(1)&quot;),
-                (&quot;SERVERID&quot;,         &quot;text&quot;),
-                (&quot;PARTITIONID&quot;,      &quot;text&quot;),
-                (&quot;CALENDARING&quot;,      &quot;text(1)&quot;),
-                (&quot;ADDRESSBOOKS&quot;,     &quot;text(1)&quot;),
-                (&quot;AUTOSCHEDULE&quot;,     &quot;text(1)&quot;),
</del><ins>+                (&quot;UID&quot;, &quot;text unique&quot;),
+                (&quot;ENABLED&quot;, &quot;text(1)&quot;),
+                (&quot;SERVERID&quot;, &quot;text&quot;),
+                (&quot;CALENDARING&quot;, &quot;text(1)&quot;),
+                (&quot;ADDRESSBOOKS&quot;, &quot;text(1)&quot;),
+                (&quot;AUTOSCHEDULE&quot;, &quot;text(1)&quot;),
</ins><span class="cx">                 (&quot;AUTOSCHEDULEMODE&quot;, &quot;text&quot;),
</span><del>-                (&quot;AUTOACCEPTGROUP&quot;,  &quot;text&quot;),
-                (&quot;LOGINENABLED&quot;,     &quot;text(1)&quot;),
</del><ins>+                (&quot;AUTOACCEPTGROUP&quot;, &quot;text&quot;),
+                (&quot;LOGINENABLED&quot;, &quot;text(1)&quot;),
</ins><span class="cx">             ),
</span><span class="cx">             ifnotexists=True,
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _db_empty_data_tables(self):
</span><span class="cx">         yield self._db_execute(&quot;delete from AUGMENTS&quot;)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class AugmentSqliteDB(ADBAPISqliteMixin, AugmentADAPI):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Sqlite based augment database implementation.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, dbpath):
</span><del>-        
</del><ins>+
</ins><span class="cx">         ADBAPISqliteMixin.__init__(self)
</span><span class="cx">         AugmentADAPI.__init__(self, &quot;Augments&quot;, &quot;sqlite3&quot;, (fullServerPath(config.DataRoot, dbpath),))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _addRecord(self, record):
</span><span class="cx">         yield self.execute(
</span><span class="cx">             &quot;&quot;&quot;insert or replace into AUGMENTS
</span><del>-            (UID, ENABLED, SERVERID, PARTITIONID, CALENDARING, ADDRESSBOOKS, AUTOSCHEDULE, AUTOSCHEDULEMODE, AUTOACCEPTGROUP, LOGINENABLED)
-            values (:1, :2, :3, :4, :5, :6, :7, :8, :9, :10)&quot;&quot;&quot;,
</del><ins>+            (UID, ENABLED, SERVERID, CALENDARING, ADDRESSBOOKS, AUTOSCHEDULE, AUTOSCHEDULEMODE, AUTOACCEPTGROUP, LOGINENABLED)
+            values (:1, :2, :3, :4, :5, :6, :7, :8, :9)&quot;&quot;&quot;,
</ins><span class="cx">             (
</span><span class="cx">                 record.uid,
</span><span class="cx">                 &quot;T&quot; if record.enabled else &quot;F&quot;,
</span><span class="cx">                 record.serverID,
</span><del>-                record.partitionID,
</del><span class="cx">                 &quot;T&quot; if record.enabledForCalendaring else &quot;F&quot;,
</span><span class="cx">                 &quot;T&quot; if record.enabledForAddressBooks else &quot;F&quot;,
</span><span class="cx">                 &quot;T&quot; if record.autoSchedule else &quot;F&quot;,
</span><span class="lines">@@ -700,30 +723,33 @@
</span><span class="cx">             )
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _modifyRecord(self, record):
</span><span class="cx">         return self._addRecord(record)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class AugmentPostgreSQLDB(ADBAPIPostgreSQLMixin, AugmentADAPI):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     PostgreSQL based augment database implementation.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, host, database, user=None, password=None):
</span><del>-        
</del><ins>+
</ins><span class="cx">         ADBAPIPostgreSQLMixin.__init__(self)
</span><span class="cx">         AugmentADAPI.__init__(self, &quot;Augments&quot;, &quot;pgdb&quot;, (), host=host, database=database, user=user, password=password,)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _addRecord(self, record):
</span><span class="cx">         yield self.execute(
</span><span class="cx">             &quot;&quot;&quot;insert into AUGMENTS
</span><del>-            (UID, ENABLED, SERVERID, PARTITIONID, CALENDARING, ADDRESSBOOKS, AUTOSCHEDULE, AUTOSCHEDULEMODE, AUTOACCEPTGROUP, LOGINENABLED)
-            values (:1, :2, :3, :4, :5, :6, :7, :8, :9, :10)&quot;&quot;&quot;,
</del><ins>+            (UID, ENABLED, SERVERID, CALENDARING, ADDRESSBOOKS, AUTOSCHEDULE, AUTOSCHEDULEMODE, AUTOACCEPTGROUP, LOGINENABLED)
+            values (:1, :2, :3, :4, :5, :6, :7, :8, :9)&quot;&quot;&quot;,
</ins><span class="cx">             (
</span><span class="cx">                 record.uid,
</span><span class="cx">                 &quot;T&quot; if record.enabled else &quot;F&quot;,
</span><span class="cx">                 record.serverID,
</span><del>-                record.partitionID,
</del><span class="cx">                 &quot;T&quot; if record.enabledForCalendaring else &quot;F&quot;,
</span><span class="cx">                 &quot;T&quot; if record.enabledForAddressBooks else &quot;F&quot;,
</span><span class="cx">                 &quot;T&quot; if record.autoSchedule else &quot;F&quot;,
</span><span class="lines">@@ -733,17 +759,17 @@
</span><span class="cx">             )
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _modifyRecord(self, record):
</span><span class="cx">         yield self.execute(
</span><span class="cx">             &quot;&quot;&quot;update AUGMENTS set
</span><del>-            (UID, ENABLED, SERVERID, PARTITIONID, CALENDARING, ADDRESSBOOKS, AUTOSCHEDULE, AUTOSCHEDULEMODE, AUTOACCEPTGROUP, LOGINENABLED) =
-            (:1, :2, :3, :4, :5, :6, :7, :8, :9, :10) where UID = :11&quot;&quot;&quot;,
</del><ins>+            (UID, ENABLED, SERVERID, CALENDARING, ADDRESSBOOKS, AUTOSCHEDULE, AUTOSCHEDULEMODE, AUTOACCEPTGROUP, LOGINENABLED) =
+            (:1, :2, :3, :4, :5, :6, :7, :8, :9) where UID = :10&quot;&quot;&quot;,
</ins><span class="cx">             (
</span><span class="cx">                 record.uid,
</span><span class="cx">                 &quot;T&quot; if record.enabled else &quot;F&quot;,
</span><span class="cx">                 record.serverID,
</span><del>-                record.partitionID,
</del><span class="cx">                 &quot;T&quot; if record.enabledForCalendaring else &quot;F&quot;,
</span><span class="cx">                 &quot;T&quot; if record.enabledForAddressBooks else &quot;F&quot;,
</span><span class="cx">                 &quot;T&quot; if record.autoSchedule else &quot;F&quot;,
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorycommonpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/common.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/common.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/common.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -42,7 +42,7 @@
</span><span class="cx">     Common ancestor for addressbook/calendar UID provisioning resources.
</span><span class="cx"> 
</span><span class="cx">     Must be mixed in to the hierarchy I{before} the appropriate resource type.
</span><del>-    
</del><ins>+
</ins><span class="cx">     @ivar homeResourceTypeName: The name of the home resource type ('calendars'
</span><span class="cx">         or 'addressbooks').
</span><span class="cx"> 
</span><span class="lines">@@ -78,13 +78,11 @@
</span><span class="cx"> 
</span><span class="cx">         assert len(name) &gt; 4, &quot;Directory record has an invalid GUID: %r&quot; % (
</span><span class="cx">             name,)
</span><del>-        
-        if record.locallyHosted():
</del><ins>+
+        if record.thisServer():
</ins><span class="cx">             child = yield self.homeResourceCreator(record, transaction)
</span><del>-        elif record.thisServer():
</del><ins>+        else:
</ins><span class="cx">             child = DirectoryReverseProxyResource(self, record)
</span><del>-        else:
-            child = None # Use a redirect?
</del><span class="cx"> 
</span><span class="cx">         returnValue(child)
</span><span class="cx"> 
</span><span class="lines">@@ -108,6 +106,7 @@
</span><span class="cx">         # Not a listable collection
</span><span class="cx">         raise HTTPError(responsecode.FORBIDDEN)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     ##
</span><span class="cx">     # ACL
</span><span class="cx">     ##
</span><span class="lines">@@ -115,12 +114,15 @@
</span><span class="cx">     def principalCollections(self):
</span><span class="cx">         return self.parent.principalCollections()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def principalForRecord(self, record):
</span><span class="cx">         return self.parent.principalForRecord(record)
</span><ins>+
+
</ins><span class="cx">     ##
</span><span class="cx">     # DAV
</span><span class="cx">     ##
</span><del>-    
</del><ins>+
</ins><span class="cx">     def isCollection(self):
</span><span class="cx">         return True
</span><span class="cx"> 
</span><span class="lines">@@ -129,9 +131,11 @@
</span><span class="cx">         raise NotImplementedError(self.__class__.__name__ +
</span><span class="cx">                                   &quot;.getChild no longer exists.&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def displayName(self):
</span><span class="cx">         return uidsResourceName
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def url(self):
</span><span class="cx">         return joinURL(self.parent.url(), uidsResourceName)
</span><span class="cx"> 
</span><span class="lines">@@ -153,4 +157,3 @@
</span><span class="cx"> 
</span><span class="cx">         child = yield self._parent.homeForDirectoryRecord(record, request)
</span><span class="cx">         returnValue((child, segments[1:]))
</span><del>-
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorydirectoryprincipalresourcehtml"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/directory-principal-resource.html (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/directory-principal-resource.html        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/directory-principal-resource.html        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -5,8 +5,7 @@
</span><span class="cx"> ---------------------
</span><span class="cx"> Directory GUID: &lt;t:slot name=&quot;directoryGUID&quot;/&gt;
</span><span class="cx"> Realm: &lt;t:slot name=&quot;realm&quot;/&gt;
</span><del>-&lt;t:transparent t:render=&quot;serversEnabled&quot;&gt;Hosted-At: &lt;t:slot name=&quot;hostedAt&quot;/&gt;
-Partition: &lt;t:slot name=&quot;partition&quot;/&gt;&lt;/t:transparent&gt;
</del><ins>+&lt;t:transparent t:render=&quot;serversEnabled&quot;&gt;Hosted-At: &lt;t:slot name=&quot;hostedAt&quot;/&gt;&lt;/t:transparent&gt;
</ins><span class="cx"> Principal Information
</span><span class="cx"> ---------------------
</span><span class="cx"> GUID: &lt;t:slot name=&quot;principalGUID&quot;/&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorydirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/directory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/directory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/directory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -89,8 +89,8 @@
</span><span class="cx"> 
</span><span class="cx">     searchContext_location = &quot;location&quot;
</span><span class="cx">     searchContext_resource = &quot;resource&quot;
</span><del>-    searchContext_user     = &quot;user&quot;
-    searchContext_group    = &quot;group&quot;
</del><ins>+    searchContext_user = &quot;user&quot;
+    searchContext_group = &quot;group&quot;
</ins><span class="cx">     searchContext_attendee = &quot;attendee&quot;
</span><span class="cx"> 
</span><span class="cx">     aggregateService = None
</span><span class="lines">@@ -628,6 +628,7 @@
</span><span class="cx">         self.expireSeconds = expireSeconds
</span><span class="cx">         self.lockSeconds = lockSeconds
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def setGroupsFor(self, guid, memberships):
</span><span class="cx">         self.log.debug(&quot;set groups-for %s : %s&quot; % (guid, memberships))
</span><span class="cx">         return self.set(&quot;groups-for:%s&quot; %
</span><span class="lines">@@ -675,7 +676,6 @@
</span><span class="cx">         return self.add(&quot;group-cacher-lock&quot;, &quot;1&quot;, expireTime=self.lockSeconds)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     def extendLock(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Update the expiration time of the memcached lock
</span><span class="lines">@@ -694,6 +694,7 @@
</span><span class="cx">         return self.delete(&quot;group-cacher-lock&quot;)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class GroupMembershipCacheUpdater(object):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Responsible for updating memcached with group memberships.  This will run
</span><span class="lines">@@ -1130,7 +1131,7 @@
</span><span class="cx">     implements(IDirectoryRecord, ICalendarStoreDirectoryRecord)
</span><span class="cx"> 
</span><span class="cx">     def __repr__(self):
</span><del>-        return &quot;&lt;%s[%s@%s(%s)] %s(%s) %r @ %s/#%s&gt;&quot; % (
</del><ins>+        return &quot;&lt;%s[%s@%s(%s)] %s(%s) %r @ %s&gt;&quot; % (
</ins><span class="cx">             self.__class__.__name__,
</span><span class="cx">             self.recordType,
</span><span class="cx">             self.service.guid,
</span><span class="lines">@@ -1139,7 +1140,6 @@
</span><span class="cx">             &quot;,&quot;.join(self.shortNames),
</span><span class="cx">             self.fullName,
</span><span class="cx">             self.serverURI(),
</span><del>-            self.partitionID,
</del><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1175,7 +1175,6 @@
</span><span class="cx">         self.uid = uid
</span><span class="cx">         self.enabled = False
</span><span class="cx">         self.serverID = &quot;&quot;
</span><del>-        self.partitionID = &quot;&quot;
</del><span class="cx">         self.shortNames = shortNames
</span><span class="cx">         self.authIDs = authIDs
</span><span class="cx">         self.fullName = fullName
</span><span class="lines">@@ -1257,7 +1256,6 @@
</span><span class="cx">         if augment:
</span><span class="cx">             self.enabled = augment.enabled
</span><span class="cx">             self.serverID = augment.serverID
</span><del>-            self.partitionID = augment.partitionID
</del><span class="cx">             self.enabledForCalendaring = augment.enabledForCalendaring
</span><span class="cx">             self.enabledForAddressBooks = augment.enabledForAddressBooks
</span><span class="cx">             self.autoSchedule = augment.autoSchedule
</span><span class="lines">@@ -1278,7 +1276,6 @@
</span><span class="cx">             # Groups are by default always enabled
</span><span class="cx">             self.enabled = (self.recordType == self.service.recordType_groups)
</span><span class="cx">             self.serverID = &quot;&quot;
</span><del>-            self.partitionID = &quot;&quot;
</del><span class="cx">             self.enabledForCalendaring = False
</span><span class="cx">             self.enabledForAddressBooks = False
</span><span class="cx">             self.enabledForLogin = False
</span><span class="lines">@@ -1496,46 +1493,9 @@
</span><span class="cx">             return None
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def partitionURI(self):
-        &quot;&quot;&quot;
-        URL of the server hosting this record. Return None if hosted on this server.
-        &quot;&quot;&quot;
-        if config.Servers.Enabled and self.serverID:
-            s = Servers.getServerById(self.serverID)
-            if s:
-                return s.getPartitionURIForId(self.partitionID)
-        return None
-
-
-    def locallyHosted(self):
-        &quot;&quot;&quot;
-        Hosted on this server/partition instance.
-        &quot;&quot;&quot;
-
-        if config.Servers.Enabled and self.serverID:
-            s = Servers.getServerById(self.serverID)
-            if s:
-                return s.thisServer and (not s.isPartitioned() or not self.partitionID or self.partitionID == config.ServerPartitionID)
-        return True
-
-
-    def effectivePartitionID(self):
-        &quot;&quot;&quot;
-        Record partition ID taking into account whether the server is partitioned.
-        &quot;&quot;&quot;
-        if config.Servers.Enabled and self.serverID:
-            s = Servers.getServerById(self.serverID)
-            if s and s.isPartitioned():
-                return self.partitionID
-        return &quot;&quot;
-
-
</del><span class="cx">     def thisServer(self):
</span><del>-        if config.Servers.Enabled and self.serverID:
-            s = Servers.getServerById(self.serverID)
-            if s:
-                return s.thisServer
-        return True
</del><ins>+        s = self.server()
+        return s.thisServer if s is not None else True
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def autoAcceptMembers(self):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryidirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/idirectory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/idirectory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/idirectory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -32,20 +32,20 @@
</span><span class="cx">     realmName = Attribute(&quot;The name of the authentication realm this service represents.&quot;)
</span><span class="cx">     guid = Attribute(&quot;A GUID for this service.&quot;)
</span><span class="cx"> 
</span><del>-    def recordTypes():
</del><ins>+    def recordTypes(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: a sequence of strings denoting the record types that
</span><span class="cx">             are kept in the directory.  For example: C{[&quot;users&quot;,
</span><span class="cx">             &quot;groups&quot;, &quot;resources&quot;]}.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def listRecords(recordType):
</del><ins>+    def listRecords(recordType): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param type: the type of records to retrieve.
</span><span class="cx">         @return: an iterable of records of the given type.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def recordWithShortName(recordType, shortName):
</del><ins>+    def recordWithShortName(recordType, shortName): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param recordType: the type of the record to look up.
</span><span class="cx">         @param shortName: the short name of the record to look up.
</span><span class="lines">@@ -53,21 +53,21 @@
</span><span class="cx">             C{None} if no such record exists.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def recordWithUID(uid):
</del><ins>+    def recordWithUID(uid): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param uid: the UID of the record to look up.
</span><span class="cx">         @return: an L{IDirectoryRecord} with the given UID, or C{None}
</span><span class="cx">             if no such record exists.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def recordWithGUID(guid):
</del><ins>+    def recordWithGUID(guid): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param guid: the GUID of the record to look up.
</span><span class="cx">         @return: an L{IDirectoryRecord} with the given GUID, or
</span><span class="cx">             C{None} if no such record exists.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def recordWithCalendarUserAddress(address):
</del><ins>+    def recordWithCalendarUserAddress(address): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param address: the calendar user address of the record to look up.
</span><span class="cx">         @type address: C{str}
</span><span class="lines">@@ -81,7 +81,7 @@
</span><span class="cx">             directory service may not be aware of these addresses.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def recordWithCachedGroupsAlias(recordType, alias):
</del><ins>+    def recordWithCachedGroupsAlias(recordType, alias): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param recordType: the type of the record to look up.
</span><span class="cx">         @param alias: the cached-groups alias of the record to look up.
</span><span class="lines">@@ -91,14 +91,13 @@
</span><span class="cx">             alias, or C{None} if no such record is found.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-
-    def recordsMatchingFields(fields):
</del><ins>+    def recordsMatchingFields(fields): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: a deferred sequence of L{IDirectoryRecord}s which
</span><span class="cx">             match the given fields.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def recordsMatchingTokens(tokens, context=None):
</del><ins>+    def recordsMatchingTokens(tokens, context=None): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param tokens: The tokens to search on
</span><span class="cx">         @type tokens: C{list} of C{str} (utf-8 bytes)
</span><span class="lines">@@ -119,31 +118,31 @@
</span><span class="cx">             &quot;attendee&quot;, only users, groups, and resources are considered.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-
-    def setRealm(realmName):
</del><ins>+    def setRealm(realmName): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Set a new realm name for this (and nested services if any)
</span><span class="cx"> 
</span><span class="cx">         @param realmName: the realm name this service should use.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class IDirectoryRecord(Interface):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Directory Record
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    service               = Attribute(&quot;The L{IDirectoryService} this record exists in.&quot;)
-    recordType            = Attribute(&quot;The type of this record.&quot;)
-    guid                  = Attribute(&quot;The GUID of this record.&quot;)
-    uid                   = Attribute(&quot;The UID of this record.&quot;)
-    enabled               = Attribute(&quot;Determines whether this record should allow a principal to be created.&quot;)
-    serverID              = Attribute(&quot;Identifies the server that actually hosts data for the record.&quot;)
-    partitionID           = Attribute(&quot;Identifies the partition node that actually hosts data for the record.&quot;)
-    shortNames            = Attribute(&quot;The names for this record.&quot;)
-    authIDs               = Attribute(&quot;Alternative security identities for this record.&quot;)
-    fullName              = Attribute(&quot;The full name of this record.&quot;)
-    firstName             = Attribute(&quot;The first name of this record.&quot;)
-    lastName              = Attribute(&quot;The last name of this record.&quot;)
-    emailAddresses        = Attribute(&quot;The email addresses of this record.&quot;)
</del><ins>+    service = Attribute(&quot;The L{IDirectoryService} this record exists in.&quot;)
+    recordType = Attribute(&quot;The type of this record.&quot;)
+    guid = Attribute(&quot;The GUID of this record.&quot;)
+    uid = Attribute(&quot;The UID of this record.&quot;)
+    enabled = Attribute(&quot;Determines whether this record should allow a principal to be created.&quot;)
+    serverID = Attribute(&quot;Identifies the server that actually hosts data for the record.&quot;)
+    shortNames = Attribute(&quot;The names for this record.&quot;)
+    authIDs = Attribute(&quot;Alternative security identities for this record.&quot;)
+    fullName = Attribute(&quot;The full name of this record.&quot;)
+    firstName = Attribute(&quot;The first name of this record.&quot;)
+    lastName = Attribute(&quot;The last name of this record.&quot;)
+    emailAddresses = Attribute(&quot;The email addresses of this record.&quot;)
</ins><span class="cx">     enabledForCalendaring = Attribute(&quot;Determines whether this record creates a principal with a calendar home.&quot;)
</span><span class="cx">     enabledForAddressBooks = Attribute(&quot;Determines whether this record creates a principal with an address book home.&quot;)
</span><span class="cx">     calendarUserAddresses = Attribute(
</span><span class="lines">@@ -159,19 +158,19 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">     )
</span><span class="cx"> 
</span><del>-    def members():
</del><ins>+    def members(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: an iterable of L{IDirectoryRecord}s for the members of this
</span><span class="cx">             (group) record.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def groups():
</del><ins>+    def groups(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: an iterable of L{IDirectoryRecord}s for the groups this
</span><span class="cx">             record is a member of.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def verifyCredentials(credentials):
</del><ins>+    def verifyCredentials(credentials): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Verify that the given credentials can authenticate the principal
</span><span class="cx">         represented by this record.
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryldapdirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/ldapdirectory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/ldapdirectory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/ldapdirectory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -75,12 +75,13 @@
</span><span class="cx">         return &quot;&lt;%s %r: %r&gt;&quot; % (self.__class__.__name__, self.realmName,
</span><span class="cx">             self.uri)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def __init__(self, params):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param params: a dictionary containing the following keys:
</span><span class="cx">             cacheTimeout, realmName, uri, tls, tlsCACertFile, tlsCACertDir,
</span><span class="cx">             tlsRequireCert, credentials, rdnSchema, groupSchema, resourceSchema
</span><del>-            partitionSchema
</del><ins>+            poddingSchema
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         defaults = {
</span><span class="lines">@@ -188,9 +189,8 @@
</span><span class="cx">                 &quot;readOnlyProxyAttr&quot;: None, # list of GUIDs
</span><span class="cx">                 &quot;autoAcceptGroupAttr&quot;: None, # single group GUID
</span><span class="cx">             },
</span><del>-            &quot;partitionSchema&quot;: {
</del><ins>+            &quot;poddingSchema&quot;: {
</ins><span class="cx">                 &quot;serverIdAttr&quot;: None, # maps to augments server-id
</span><del>-                &quot;partitionIdAttr&quot;: None, # maps to augments partition-id
</del><span class="cx">             },
</span><span class="cx">         }
</span><span class="cx">         ignored = None
</span><span class="lines">@@ -222,7 +222,7 @@
</span><span class="cx">         self.rdnSchema = params[&quot;rdnSchema&quot;]
</span><span class="cx">         self.groupSchema = params[&quot;groupSchema&quot;]
</span><span class="cx">         self.resourceSchema = params[&quot;resourceSchema&quot;]
</span><del>-        self.partitionSchema = params[&quot;partitionSchema&quot;]
</del><ins>+        self.poddingSchema = params[&quot;poddingSchema&quot;]
</ins><span class="cx"> 
</span><span class="cx">         self.base = ldap.dn.str2dn(self.rdnSchema[&quot;base&quot;])
</span><span class="cx"> 
</span><span class="lines">@@ -272,10 +272,8 @@
</span><span class="cx">             attrSet.add(self.resourceSchema[&quot;proxyAttr&quot;])
</span><span class="cx">         if self.resourceSchema[&quot;readOnlyProxyAttr&quot;]:
</span><span class="cx">             attrSet.add(self.resourceSchema[&quot;readOnlyProxyAttr&quot;])
</span><del>-        if self.partitionSchema[&quot;serverIdAttr&quot;]:
-            attrSet.add(self.partitionSchema[&quot;serverIdAttr&quot;])
-        if self.partitionSchema[&quot;partitionIdAttr&quot;]:
-            attrSet.add(self.partitionSchema[&quot;partitionIdAttr&quot;])
</del><ins>+        if self.poddingSchema[&quot;serverIdAttr&quot;]:
+            attrSet.add(self.poddingSchema[&quot;serverIdAttr&quot;])
</ins><span class="cx">         self.attrlist = list(attrSet)
</span><span class="cx"> 
</span><span class="cx">         self.typeDNs = {}
</span><span class="lines">@@ -284,10 +282,8 @@
</span><span class="cx">                 self.rdnSchema[recordType][&quot;rdn&quot;].lower()
</span><span class="cx">             ) + self.base
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         self.ldap = None
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         # Separate LDAP connection used solely for authenticating clients
</span><span class="cx">         self.authLDAP = None
</span><span class="cx"> 
</span><span class="lines">@@ -314,7 +310,7 @@
</span><span class="cx"> 
</span><span class="cx">         # Query the LDAP server
</span><span class="cx">         self.log.debug(&quot;Querying ldap for records matching base {base} and &quot;
</span><del>-            &quot;filter {filter} for attributes {attrs}.&quot;, 
</del><ins>+            &quot;filter {filter} for attributes {attrs}.&quot;,
</ins><span class="cx">             base=ldap.dn.dn2str(base), filter=filterstr, attrs=self.attrlist)
</span><span class="cx"> 
</span><span class="cx">         # This takes a while, so if you don't want to have a &quot;long request&quot;
</span><span class="lines">@@ -353,6 +349,7 @@
</span><span class="cx"> 
</span><span class="cx">         return records
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def recordWithCachedGroupsAlias(self, recordType, alias):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -373,6 +370,7 @@
</span><span class="cx">         else:
</span><span class="cx">             returnValue(None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def getExternalProxyAssignments(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Retrieve proxy assignments for locations and resources from the
</span><span class="lines">@@ -425,6 +423,7 @@
</span><span class="cx"> 
</span><span class="cx">         return assignments
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def getLDAPConnection(self):
</span><span class="cx">         if self.ldap is None:
</span><span class="cx">             self.log.info(&quot;Connecting to LDAP {uri}&quot;, uri=repr(self.uri))
</span><span class="lines">@@ -443,6 +442,7 @@
</span><span class="cx">                     raise DirectoryConfigurationError()
</span><span class="cx">         return self.ldap
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def createLDAPConnection(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Create and configure LDAP connection
</span><span class="lines">@@ -478,7 +478,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         TRIES = 3
</span><span class="cx"> 
</span><del>-        for i in xrange(TRIES):
</del><ins>+        for _ignore_i in xrange(TRIES):
</ins><span class="cx">             self.log.debug(&quot;Authenticating %s&quot; % (dn,))
</span><span class="cx"> 
</span><span class="cx">             if self.authLDAP is None:
</span><span class="lines">@@ -555,11 +555,11 @@
</span><span class="cx">                 self.log.warn(&quot;LDAP timeout exceeded: %d seconds&quot; % (timeoutSeconds,))
</span><span class="cx">             except ldap.SERVER_DOWN:
</span><span class="cx">                 self.ldap = None
</span><del>-                self.log.error(&quot;LDAP server unavailable (tried %d times)&quot; % (i+1,))
</del><ins>+                self.log.error(&quot;LDAP server unavailable (tried %d times)&quot; % (i + 1,))
</ins><span class="cx">                 continue
</span><span class="cx"> 
</span><span class="cx">             # change format, ignoring resultsType
</span><del>-            result = [resultItem for resultType, resultItem in s.allResults]
</del><ins>+            result = [resultItem for _ignore_resultType, resultItem in s.allResults]
</ins><span class="cx"> 
</span><span class="cx">             totalTime = time.time() - startTime
</span><span class="cx">             if totalTime &gt; self.warningThresholdSeconds:
</span><span class="lines">@@ -769,7 +769,6 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         guid = None
</span><del>-        shortNames = ()
</del><span class="cx">         authIDs = set()
</span><span class="cx">         fullName = None
</span><span class="cx">         firstName = &quot;&quot;
</span><span class="lines">@@ -891,30 +890,27 @@
</span><span class="cx">                     autoAcceptGroup = self._getUniqueLdapAttribute(attrs,
</span><span class="cx">                         self.resourceSchema[&quot;autoAcceptGroupAttr&quot;])
</span><span class="cx"> 
</span><del>-        serverID = partitionID = None
-        if self.partitionSchema[&quot;serverIdAttr&quot;]:
</del><ins>+        serverID = None
+        if self.poddingSchema[&quot;serverIdAttr&quot;]:
</ins><span class="cx">             serverID = self._getUniqueLdapAttribute(attrs,
</span><del>-                self.partitionSchema[&quot;serverIdAttr&quot;])
-        if self.partitionSchema[&quot;partitionIdAttr&quot;]:
-            partitionID = self._getUniqueLdapAttribute(attrs,
-                self.partitionSchema[&quot;partitionIdAttr&quot;])
</del><ins>+                self.poddingSchema[&quot;serverIdAttr&quot;])
</ins><span class="cx"> 
</span><span class="cx">         record = LdapDirectoryRecord(
</span><del>-            service                 = self,
-            recordType              = recordType,
-            guid                    = guid,
-            shortNames              = shortNames,
-            authIDs                 = authIDs,
-            fullName                = fullName,
-            firstName               = firstName,
-            lastName                = lastName,
-            emailAddresses          = emailAddresses,
-            uid                     = uid,
-            dn                      = dn,
-            memberGUIDs             = memberGUIDs,
-            extProxies              = proxyGUIDs,
-            extReadOnlyProxies      = readOnlyProxyGUIDs,
-            attrs                   = attrs,
</del><ins>+            service=self,
+            recordType=recordType,
+            guid=guid,
+            shortNames=shortNames,
+            authIDs=authIDs,
+            fullName=fullName,
+            firstName=firstName,
+            lastName=lastName,
+            emailAddresses=emailAddresses,
+            uid=uid,
+            dn=dn,
+            memberGUIDs=memberGUIDs,
+            extProxies=proxyGUIDs,
+            extReadOnlyProxies=readOnlyProxyGUIDs,
+            attrs=attrs,
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         if self.augmentService is not None:
</span><span class="lines">@@ -924,7 +920,7 @@
</span><span class="cx">             # immediately.
</span><span class="cx">             d = self.augmentService.getAugmentRecord(record.guid,
</span><span class="cx">                 recordType)
</span><del>-            d.addCallback(lambda x:record.addAugmentInformation(x))
</del><ins>+            d.addCallback(lambda x: record.addAugmentInformation(x))
</ins><span class="cx"> 
</span><span class="cx">         else:
</span><span class="cx">             # Generate augment record based on information retrieved from LDAP
</span><span class="lines">@@ -932,7 +928,6 @@
</span><span class="cx">                 guid,
</span><span class="cx">                 enabled=True,
</span><span class="cx">                 serverID=serverID,
</span><del>-                partitionID=partitionID,
</del><span class="cx">                 enabledForCalendaring=enabledForCalendaring,
</span><span class="cx">                 autoSchedule=autoSchedule,
</span><span class="cx">                 autoAcceptGroup=autoAcceptGroup,
</span><span class="lines">@@ -965,7 +960,7 @@
</span><span class="cx">         matching the indexType and indexKey parameters.
</span><span class="cx"> 
</span><span class="cx">         recordTypes is a list of record types to limit the search to.
</span><del>-        indexType specifies one of the CachingDirectoryService contstants
</del><ins>+        indexType specifies one of the CachingDirectoryService constants
</ins><span class="cx">             identifying which attribute to search on.
</span><span class="cx">         indexKey is the value to search for.
</span><span class="cx"> 
</span><span class="lines">@@ -994,7 +989,8 @@
</span><span class="cx">                 # Query on guid only works if guid attribute has been defined.
</span><span class="cx">                 # Support for query on guid even if is auto-generated should
</span><span class="cx">                 # be added.
</span><del>-                if not guidAttr: return
</del><ins>+                if not guidAttr:
+                    return
</ins><span class="cx">                 filterstr = &quot;(&amp;%s(%s=%s))&quot; % (filterstr, guidAttr, indexKey)
</span><span class="cx"> 
</span><span class="cx">             elif indexType == self.INDEX_TYPE_SHORTNAME:
</span><span class="lines">@@ -1157,7 +1153,6 @@
</span><span class="cx"> 
</span><span class="cx">                 self.log.debug(&quot;LDAP search returned %d results, %d usable&quot; % (len(results), typeCounts[recordType]))
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         typeCountsStr = &quot;, &quot;.join([&quot;%s:%d&quot; % (rt, ct) for (rt, ct) in typeCounts.iteritems()])
</span><span class="cx">         totalTime = time.time() - startTime
</span><span class="cx">         self.log.info(&quot;Calendar user search for %s matched %d records (%s) in %.2f seconds&quot; % (tokens, len(records), typeCountsStr, totalTime))
</span><span class="lines">@@ -1172,7 +1167,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         records = []
</span><span class="cx"> 
</span><del>-        self.log.debug(&quot;Peforming principal property search for %s&quot; % (fields,))
</del><ins>+        self.log.debug(&quot;Performing principal property search for %s&quot; % (fields,))
</ins><span class="cx"> 
</span><span class="cx">         if recordType is None:
</span><span class="cx">             # Make a copy since we're modifying it
</span><span class="lines">@@ -1324,6 +1319,7 @@
</span><span class="cx"> 
</span><span class="cx">         returnValue(recordsByAlias.values())
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def recordTypeForDN(self, dnStr):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Examine a DN to determine which recordType it belongs to
</span><span class="lines">@@ -1339,6 +1335,7 @@
</span><span class="cx">         return None
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def dnContainedIn(child, parent):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Return True if child dn is contained within parent dn, otherwise False.
</span><span class="lines">@@ -1346,6 +1343,7 @@
</span><span class="cx">     return child[-len(parent):] == parent
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def normalizeDNstr(dnStr):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Convert to lowercase and remove extra whitespace
</span><span class="lines">@@ -1356,6 +1354,7 @@
</span><span class="cx">     return ' '.join(ldap.dn.dn2str(ldap.dn.str2dn(dnStr.lower())).split())
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def _convertValue(value, matchType):
</span><span class="cx">     if matchType == &quot;starts-with&quot;:
</span><span class="cx">         value = &quot;%s*&quot; % (ldapEsc(value),)
</span><span class="lines">@@ -1366,6 +1365,8 @@
</span><span class="cx">         value = ldapEsc(value)
</span><span class="cx">     return value
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def buildFilter(recordType, mapping, fields, operand=&quot;or&quot;, optimizeMultiName=False):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Create an LDAP filter string from a list of tuples representing directory
</span><span class="lines">@@ -1403,8 +1404,8 @@
</span><span class="cx">                 # try the various firstName/lastName permutations:
</span><span class="cx">                 if recordType == &quot;users&quot;:
</span><span class="cx">                     converted = []
</span><del>-                    for firstName, firstCaseless, firstMatchType in combined[&quot;firstName&quot;]:
-                        for lastName, lastCaseless, lastMatchType in combined[&quot;lastName&quot;]:
</del><ins>+                    for firstName, _ignore_firstCaseless, firstMatchType in combined[&quot;firstName&quot;]:
+                        for lastName, _ignore_lastCaseless, lastMatchType in combined[&quot;lastName&quot;]:
</ins><span class="cx">                             if firstName != lastName:
</span><span class="cx">                                 firstValue = _convertValue(firstName, firstMatchType)
</span><span class="cx">                                 lastValue = _convertValue(lastName, lastMatchType)
</span><span class="lines">@@ -1427,7 +1428,7 @@
</span><span class="cx">         # name, guid)
</span><span class="cx">         additional = []
</span><span class="cx">         for key in (&quot;recordName&quot;, &quot;guid&quot;):
</span><del>-            if mapping.has_key(key):
</del><ins>+            if key in mapping:
</ins><span class="cx">                 additional.append(&quot;(%s=*)&quot; % (mapping.get(key),))
</span><span class="cx">         if additional:
</span><span class="cx">             filterstr = &quot;(&amp;%s%s)&quot; % (&quot;&quot;.join(additional), filterstr)
</span><span class="lines">@@ -1435,6 +1436,7 @@
</span><span class="cx">     return filterstr
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def buildFilterFromTokens(recordType, mapping, tokens, extra=None):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Create an LDAP filter string from a list of query tokens.  Each token is
</span><span class="lines">@@ -1497,6 +1499,7 @@
</span><span class="cx">     return filterStr
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class LdapDirectoryRecord(CachingDirectoryRecord):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     LDAP implementation of L{IDirectoryRecord}.
</span><span class="lines">@@ -1509,18 +1512,18 @@
</span><span class="cx">         attrs
</span><span class="cx">     ):
</span><span class="cx">         super(LdapDirectoryRecord, self).__init__(
</span><del>-            service               = service,
-            recordType            = recordType,
-            guid                  = guid,
-            shortNames            = shortNames,
-            authIDs               = authIDs,
-            fullName              = fullName,
-            firstName             = firstName,
-            lastName              = lastName,
-            emailAddresses        = emailAddresses,
-            extProxies            = extProxies,
-            extReadOnlyProxies    = extReadOnlyProxies,
-            uid                   = uid,
</del><ins>+            service=service,
+            recordType=recordType,
+            guid=guid,
+            shortNames=shortNames,
+            authIDs=authIDs,
+            fullName=fullName,
+            firstName=firstName,
+            lastName=lastName,
+            emailAddresses=emailAddresses,
+            extProxies=extProxies,
+            extReadOnlyProxies=extReadOnlyProxies,
+            uid=uid,
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         # Save attributes of dn and attrs in case you might need them later
</span><span class="lines">@@ -1548,6 +1551,7 @@
</span><span class="cx">             self._members_storage = self._members()
</span><span class="cx">             return self._members_storage
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _members(self):
</span><span class="cx">         &quot;&quot;&quot; Fault in records for the members of this group &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -1578,7 +1582,7 @@
</span><span class="cx"> 
</span><span class="cx">                 dn, attrs = result.pop()
</span><span class="cx">                 dn = normalizeDNstr(dn)
</span><del>-                self.log.debug(&quot;Retrieved: %s %s&quot; % (dn,attrs))
</del><ins>+                self.log.debug(&quot;Retrieved: %s %s&quot; % (dn, attrs))
</ins><span class="cx">                 recordType = self.service.recordTypeForDN(dn)
</span><span class="cx">                 if recordType is None:
</span><span class="cx">                     self.log.error(&quot;Unable to map %s to a record type&quot; % (dn,))
</span><span class="lines">@@ -1595,6 +1599,7 @@
</span><span class="cx"> 
</span><span class="cx">         return results
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def groups(self):
</span><span class="cx">         &quot;&quot;&quot; Return the records representing groups this record is a member of &quot;&quot;&quot;
</span><span class="cx">         try:
</span><span class="lines">@@ -1603,6 +1608,7 @@
</span><span class="cx">             self._groups_storage = self._groups()
</span><span class="cx">             return self._groups_storage
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _groups(self):
</span><span class="cx">         &quot;&quot;&quot; Fault in the groups of which this record is a member &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -1618,7 +1624,7 @@
</span><span class="cx">         if len(membersAttrs) == 1:
</span><span class="cx">             filterstr = &quot;(%s=%s)&quot; % (membersAttrs[0], self._memberId)
</span><span class="cx">         else:
</span><del>-            filterstr = &quot;(|%s)&quot; % ( &quot;&quot;.join(
</del><ins>+            filterstr = &quot;(|%s)&quot; % (&quot;&quot;.join(
</ins><span class="cx">                     [&quot;(%s=%s)&quot; % (a, self._memberId) for a in membersAttrs]
</span><span class="cx">                 ),
</span><span class="cx">             )
</span><span class="lines">@@ -1641,6 +1647,7 @@
</span><span class="cx"> 
</span><span class="cx">         return groups
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def cachedGroupsAlias(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         See directory.py for full description
</span><span class="lines">@@ -1650,6 +1657,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return self._memberId
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def memberGUIDs(self):
</span><span class="cx">         return set(self._memberGUIDs)
</span><span class="cx"> 
</span><span class="lines">@@ -1717,10 +1725,13 @@
</span><span class="cx">         return super(LdapDirectoryRecord, self).verifyCredentials(credentials)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class MissingRecordNameException(Exception):
</span><span class="cx">     &quot;&quot;&quot; Raised when LDAP record is missing recordName &quot;&quot;&quot;
</span><span class="cx">     pass
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class MissingGuidException(Exception):
</span><span class="cx">     &quot;&quot;&quot; Raised when LDAP record is missing guidAttr and it's required &quot;&quot;&quot;
</span><span class="cx">     pass
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryopendirectorybackerpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/opendirectorybacker.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/opendirectorybacker.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/opendirectorybacker.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -35,9 +35,9 @@
</span><span class="cx"> from tempfile import mkstemp, gettempdir
</span><span class="cx"> from random import random
</span><span class="cx"> 
</span><del>-from pycalendar.n import N
-from pycalendar.adr import Adr
-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.vcard.n import N
+from pycalendar.vcard.adr import Adr
+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from socket import getfqdn
</span><span class="cx"> 
</span><span class="lines">@@ -1494,7 +1494,7 @@
</span><span class="cx"> 
</span><span class="cx">             birthdate = self.isoDateStringForDateAttribute(dsattributes.kDS1AttrBirthday)
</span><span class="cx">             if birthdate:
</span><del>-                vcard.addProperty(Property(&quot;BDAY&quot;, PyCalendarDateTime.parseText(birthdate, fullISO=True)))
</del><ins>+                vcard.addProperty(Property(&quot;BDAY&quot;, DateTime.parseText(birthdate, fullISO=True)))
</ins><span class="cx"> 
</span><span class="cx">             # 3.2 Delivery Addressing Types http://tools.ietf.org/html/rfc2426#section-3.2
</span><span class="cx">             #
</span><span class="lines">@@ -1685,7 +1685,7 @@
</span><span class="cx">             # 3.6.4 REV Type Definition
</span><span class="cx">             revDate = self.isoDateStringForDateAttribute(dsattributes.kDS1AttrModificationTimestamp)
</span><span class="cx">             if revDate:
</span><del>-                vcard.addProperty(Property(&quot;REV&quot;, PyCalendarDateTime.parseText(revDate, fullISO=True)))
</del><ins>+                vcard.addProperty(Property(&quot;REV&quot;, DateTime.parseText(revDate, fullISO=True)))
</ins><span class="cx"> 
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="cx">             # UNIMPLEMENTED:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryprincipalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/principal.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/principal.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/principal.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -601,7 +601,6 @@
</span><span class="cx">         record = self.resource.record
</span><span class="cx">         return tag.fillSlots(
</span><span class="cx">             hostedAt=str(record.serverURI()),
</span><del>-            partition=str(record.effectivePartitionID()),
</del><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1066,14 +1065,6 @@
</span><span class="cx">         return self.record.server()
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def partitionURI(self):
-        return self.record.partitionURI()
-
-
-    def locallyHosted(self):
-        return self.record.locallyHosted()
-
-
</del><span class="cx">     def thisServer(self):
</span><span class="cx">         return self.record.thisServer()
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryresourcepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/resource.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/resource.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/resource.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -25,14 +25,13 @@
</span><span class="cx"> __all__ = [&quot;DirectoryReverseProxyResource&quot;]
</span><span class="cx"> 
</span><span class="cx"> class DirectoryReverseProxyResource(ReverseProxyResource):
</span><del>-    
</del><ins>+
</ins><span class="cx">     def __init__(self, parent, record):
</span><span class="cx">         self.parent = parent
</span><span class="cx">         self.record = record
</span><del>-        
-        super(DirectoryReverseProxyResource, self).__init__(self.record.partitionID)
-    
-    def url(self):
-        return joinURL(self.parent.url(), self.record.uid)
</del><span class="cx"> 
</span><ins>+        super(DirectoryReverseProxyResource, self).__init__(self.record.serverID)
</ins><span class="cx"> 
</span><ins>+
+    def url(self):
+        return joinURL(self.parent.url(), self.record.uid)
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestaugmentstestdefaultxml"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/augments-test-default.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/augments-test-default.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/augments-test-default.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -24,40 +24,34 @@
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><span class="cx">     &lt;enable-calendar&gt;true&lt;/enable-calendar&gt;
</span><span class="cx">     &lt;enable-addressbook&gt;true&lt;/enable-addressbook&gt;
</span><del>-    &lt;partition-id&gt;00001&lt;/partition-id&gt;
</del><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;Location-Default&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><span class="cx">     &lt;enable-calendar&gt;true&lt;/enable-calendar&gt;
</span><del>-    &lt;partition-id&gt;00004&lt;/partition-id&gt;
</del><span class="cx">     &lt;auto-schedule&gt;true&lt;/auto-schedule&gt;
</span><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;Location-AA*&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><span class="cx">     &lt;enable-calendar&gt;true&lt;/enable-calendar&gt;
</span><del>-    &lt;partition-id&gt;00005&lt;/partition-id&gt;
</del><span class="cx">     &lt;auto-schedule&gt;true&lt;/auto-schedule&gt;
</span><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;Resource-Default&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><span class="cx">     &lt;enable-calendar&gt;true&lt;/enable-calendar&gt;
</span><del>-    &lt;partition-id&gt;00006&lt;/partition-id&gt;
</del><span class="cx">     &lt;auto-schedule&gt;true&lt;/auto-schedule&gt;
</span><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;Resource-AA*&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><span class="cx">     &lt;enable-calendar&gt;true&lt;/enable-calendar&gt;
</span><del>-    &lt;partition-id&gt;00007&lt;/partition-id&gt;
</del><span class="cx">     &lt;auto-schedule&gt;true&lt;/auto-schedule&gt;
</span><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;AA*&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><del>-    &lt;partition-id&gt;00001&lt;/partition-id&gt;
</del><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;AB*&lt;/uid&gt;
</span><span class="lines">@@ -66,14 +60,12 @@
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;B*&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><del>-    &lt;partition-id&gt;00002&lt;/partition-id&gt;
</del><span class="cx">     &lt;enable-calendar&gt;true&lt;/enable-calendar&gt;
</span><span class="cx">     &lt;enable-addressbook&gt;true&lt;/enable-addressbook&gt;
</span><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;C*&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><del>-    &lt;partition-id&gt;00003&lt;/partition-id&gt;
</del><span class="cx">     &lt;enable-calendar&gt;true&lt;/enable-calendar&gt;
</span><span class="cx">     &lt;enable-addressbook&gt;true&lt;/enable-addressbook&gt;
</span><span class="cx">     &lt;auto-schedule&gt;true&lt;/auto-schedule&gt;
</span><span class="lines">@@ -102,17 +94,14 @@
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><del>-    &lt;partition-id&gt;00001&lt;/partition-id&gt;
</del><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;543D28BA-F74F-4D5F-9243-B3E3A61171E5&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><del>-    &lt;partition-id&gt;00002&lt;/partition-id&gt;
</del><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;6A73326A-F781-47E7-A9F8-AF47364D4152&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><del>-    &lt;partition-id&gt;00002&lt;/partition-id&gt;
</del><span class="cx">     &lt;enable-calendar&gt;true&lt;/enable-calendar&gt;
</span><span class="cx">     &lt;enable-addressbook&gt;true&lt;/enable-addressbook&gt;
</span><span class="cx">     &lt;auto-schedule&gt;true&lt;/auto-schedule&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestaugmentstestxml"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/augments-test.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/augments-test.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/augments-test.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -42,12 +42,10 @@
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><del>-    &lt;partition-id&gt;00001&lt;/partition-id&gt;
</del><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;543D28BA-F74F-4D5F-9243-B3E3A61171E5&lt;/uid&gt;
</span><span class="cx">     &lt;enable&gt;true&lt;/enable&gt;
</span><del>-    &lt;partition-id&gt;00002&lt;/partition-id&gt;
</del><span class="cx">   &lt;/record&gt;
</span><span class="cx">   &lt;record&gt;
</span><span class="cx">     &lt;uid&gt;6A73326A-F781-47E7-A9F8-AF47364D4152&lt;/uid&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestresourcescaldavdplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/resources/caldavd.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/resources/caldavd.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/resources/caldavd.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -175,7 +175,6 @@
</span><span class="cx">         Augments for the directory service records to add calendar specific attributes.
</span><span class="cx"> 
</span><span class="cx">         A variety of augment services are available for use.
</span><del>-        When using a partitioned server, a service that can be accessed from each host will be needed.
</del><span class="cx">       --&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;!-- XML File Augment Service --&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestsudoersplist"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/sudoers.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/sudoers.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/sudoers.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,28 +0,0 @@
</span><del>-&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE plist PUBLIC &quot;-//Apple Computer//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
-&lt;plist version=&quot;1.0&quot;&gt;
-  &lt;dict&gt;
-    &lt;key&gt;users&lt;/key&gt;
-      &lt;array&gt;
-        &lt;dict&gt;
-          &lt;key&gt;authorize-as&lt;/key&gt;
-          &lt;dict&gt;
-            &lt;key&gt;allow&lt;/key&gt;
-            &lt;true /&gt;
-            &lt;key&gt;principals&lt;/key&gt;
-            &lt;array&gt;
-              &lt;string&gt;all&lt;/string&gt;
-            &lt;/array&gt;
-          &lt;/dict&gt;
-          &lt;key&gt;authorize-from&lt;/key&gt;
-          &lt;array&gt;
-            &lt;string&gt;127.0.0.1&lt;/string&gt;
-          &lt;/array&gt;
-          &lt;key&gt;password&lt;/key&gt;
-          &lt;string&gt;alice&lt;/string&gt;
-          &lt;key&gt;username&lt;/key&gt;
-          &lt;string&gt;alice&lt;/string&gt;
-        &lt;/dict&gt;
-      &lt;/array&gt;
-  &lt;/dict&gt;
-&lt;/plist&gt;
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestsudoers2plist"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/sudoers2.plist (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/sudoers2.plist        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/sudoers2.plist        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,47 +0,0 @@
</span><del>-&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE plist PUBLIC &quot;-//Apple Computer//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
-&lt;plist version=&quot;1.0&quot;&gt;
-  &lt;dict&gt;
-    &lt;key&gt;users&lt;/key&gt;
-      &lt;array&gt;
-        &lt;dict&gt;
-          &lt;key&gt;authorize-as&lt;/key&gt;
-          &lt;dict&gt;
-            &lt;key&gt;allow&lt;/key&gt;
-            &lt;true /&gt;
-            &lt;key&gt;principals&lt;/key&gt;
-            &lt;array&gt;
-              &lt;string&gt;all&lt;/string&gt;
-            &lt;/array&gt;
-          &lt;/dict&gt;
-          &lt;key&gt;authorize-from&lt;/key&gt;
-          &lt;array&gt;
-            &lt;string&gt;127.0.0.1&lt;/string&gt;
-          &lt;/array&gt;
-          &lt;key&gt;password&lt;/key&gt;
-          &lt;string&gt;alice&lt;/string&gt;
-          &lt;key&gt;username&lt;/key&gt;
-          &lt;string&gt;alice&lt;/string&gt;
-        &lt;/dict&gt;
-        &lt;dict&gt;
-          &lt;key&gt;authorize-as&lt;/key&gt;
-          &lt;dict&gt;
-            &lt;key&gt;allow&lt;/key&gt;
-            &lt;true /&gt;
-            &lt;key&gt;principals&lt;/key&gt;
-            &lt;array&gt;
-              &lt;string&gt;all&lt;/string&gt;
-            &lt;/array&gt;
-          &lt;/dict&gt;
-          &lt;key&gt;authorize-from&lt;/key&gt;
-          &lt;array&gt;
-            &lt;string&gt;127.0.0.1&lt;/string&gt;
-          &lt;/array&gt;
-          &lt;key&gt;password&lt;/key&gt;
-          &lt;string&gt;bob&lt;/string&gt;
-          &lt;key&gt;username&lt;/key&gt;
-          &lt;string&gt;bob&lt;/string&gt;
-        &lt;/dict&gt;
-      &lt;/array&gt;
-  &lt;/dict&gt;
-&lt;/plist&gt;
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_aggregatepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_aggregate.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_aggregate.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_aggregate.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -36,7 +36,8 @@
</span><span class="cx">                 recordTypes.add(prefix + recordType)
</span><span class="cx">         return recordTypes
</span><span class="cx"> 
</span><del>-    def _records(key):
</del><ins>+
+    def _records(key): #@NoSelf
</ins><span class="cx">         def get(self):
</span><span class="cx">             records = {}
</span><span class="cx">             for prefix, testClass in testServices:
</span><span class="lines">@@ -58,6 +59,7 @@
</span><span class="cx"> 
</span><span class="cx">     recordTypePrefixes = tuple(s[0] for s in testServices)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def service(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Returns an IDirectoryService.
</span><span class="lines">@@ -71,9 +73,9 @@
</span><span class="cx">         )
</span><span class="cx">         xmlService.recordTypePrefix = xml_prefix
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         return AggregateDirectoryService((xmlService,), None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_setRealm(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         setRealm gets propagated to nested services
</span><span class="lines">@@ -82,4 +84,3 @@
</span><span class="cx">         aggregatedService.setRealm(&quot;foo.example.com&quot;)
</span><span class="cx">         for service in aggregatedService._recordTypes.values():
</span><span class="cx">             self.assertEquals(&quot;foo.example.com&quot;, service.realmName)
</span><del>-
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_augmentpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_augment.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_augment.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_augment.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -15,7 +15,7 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav.test.util import TestCase
</span><del>-from twistedcaldav.directory.augment import AugmentXMLDB, AugmentSqliteDB,\
</del><ins>+from twistedcaldav.directory.augment import AugmentXMLDB, AugmentSqliteDB, \
</ins><span class="cx">     AugmentPostgreSQLDB, AugmentRecord
</span><span class="cx"> from twistedcaldav.directory.directory import DirectoryService
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks
</span><span class="lines">@@ -32,46 +32,46 @@
</span><span class="cx"> xmlFileNormalization = os.path.join(os.path.dirname(__file__), &quot;augments-normalization.xml&quot;)
</span><span class="cx"> 
</span><span class="cx"> testRecords = (
</span><del>-    {&quot;uid&quot;:&quot;D11F03A0-97EA-48AF-9A6C-FAC7F3975766&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;&quot;, &quot;enabledForCalendaring&quot;:False, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;6423F94A-6B76-4A3A-815B-D52CFD77935D&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;&quot;, &quot;enabledForCalendaring&quot;:True, &quot;enabledForAddressBooks&quot;:True, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;5A985493-EE2C-4665-94CF-4DFEA3A89500&quot;, &quot;enabled&quot;:False, &quot;partitionID&quot;:&quot;&quot;, &quot;enabledForCalendaring&quot;:False, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;8B4288F6-CC82-491D-8EF9-642EF4F3E7D0&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;&quot;, &quot;enabledForCalendaring&quot;:False, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00001&quot;, &quot;enabledForCalendaring&quot;:False, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;543D28BA-F74F-4D5F-9243-B3E3A61171E5&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00002&quot;, &quot;enabledForCalendaring&quot;:False, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;6A73326A-F781-47E7-A9F8-AF47364D4152&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00002&quot;, &quot;enabledForCalendaring&quot;:True, &quot;enabledForAddressBooks&quot;:True, &quot;autoSchedule&quot;:True, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;C5BAADEE-6B35-4FD5-A98A-5DF6BBAAC47A&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;&quot;, &quot;enabledForCalendaring&quot;:True, &quot;enabledForAddressBooks&quot;:True, &quot;autoSchedule&quot;:True, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;8AB34DF9-0297-4BA3-AADB-DB557DDD21E7&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;&quot;, &quot;enabledForCalendaring&quot;:True, &quot;enabledForAddressBooks&quot;:True, &quot;autoSchedule&quot;:True, &quot;autoScheduleMode&quot;:&quot;accept-always&quot;},
-    {&quot;uid&quot;:&quot;FC674703-8008-4A77-B80E-0DB55A9CE620&quot;, &quot;enabledForLogin&quot;:False,}, # Explicitly false
-    {&quot;uid&quot;:&quot;B473DC32-1B0D-45EE-9BAC-DA878AE9CE74&quot;, &quot;enabledForLogin&quot;:True,}, # Explicitly True
-    {&quot;uid&quot;:&quot;9F2B176D-B3F5-483A-AA63-0A1FC6E6D54B&quot;, &quot;enabledForLogin&quot;:True,}, # Default is True
</del><ins>+    {&quot;uid&quot;: &quot;D11F03A0-97EA-48AF-9A6C-FAC7F3975766&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: False, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;6423F94A-6B76-4A3A-815B-D52CFD77935D&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: True, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;5A985493-EE2C-4665-94CF-4DFEA3A89500&quot;, &quot;enabled&quot;: False, &quot;enabledForCalendaring&quot;: False, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;8B4288F6-CC82-491D-8EF9-642EF4F3E7D0&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: False, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: False, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;543D28BA-F74F-4D5F-9243-B3E3A61171E5&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: False, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;6A73326A-F781-47E7-A9F8-AF47364D4152&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: True, &quot;autoSchedule&quot;: True, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;C5BAADEE-6B35-4FD5-A98A-5DF6BBAAC47A&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: True, &quot;autoSchedule&quot;: True, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;8AB34DF9-0297-4BA3-AADB-DB557DDD21E7&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: True, &quot;autoSchedule&quot;: True, &quot;autoScheduleMode&quot;: &quot;accept-always&quot;},
+    {&quot;uid&quot;: &quot;FC674703-8008-4A77-B80E-0DB55A9CE620&quot;, &quot;enabledForLogin&quot;: False, }, # Explicitly false
+    {&quot;uid&quot;: &quot;B473DC32-1B0D-45EE-9BAC-DA878AE9CE74&quot;, &quot;enabledForLogin&quot;: True, }, # Explicitly True
+    {&quot;uid&quot;: &quot;9F2B176D-B3F5-483A-AA63-0A1FC6E6D54B&quot;, &quot;enabledForLogin&quot;: True, }, # Default is True
</ins><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> testRecordWildcardDefault = (
</span><del>-    {&quot;uid&quot;:&quot;A4318887-F2C7-4A70-9056-B88CC8DB26F1&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00001&quot;, &quot;enabledForCalendaring&quot;:True,  &quot;enabledForAddressBooks&quot;:True,  &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;AA5F935F-3358-4510-A649-B391D63279F2&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00001&quot;, &quot;enabledForCalendaring&quot;:False, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;ABF1A83B-1A29-4E04-BDC3-A6A66ECF27CA&quot;, &quot;enabled&quot;:False, &quot;partitionID&quot;:&quot;&quot;,      &quot;enabledForCalendaring&quot;:False, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;BC22A734-5E41-4FB7-B5C1-51DC0656DC2F&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00002&quot;, &quot;enabledForCalendaring&quot;:True,  &quot;enabledForAddressBooks&quot;:True,  &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;C6DEEBB1-E14A-47F2-98BA-7E3BB4353E3A&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00003&quot;, &quot;enabledForCalendaring&quot;:True,  &quot;enabledForAddressBooks&quot;:True,  &quot;autoSchedule&quot;:True,  &quot;autoScheduleMode&quot;:&quot;accept-always&quot;},
-    {&quot;uid&quot;:&quot;AA859321-2C72-4974-ADCF-0CBA0C76F95D&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00001&quot;, &quot;enabledForCalendaring&quot;:False, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;AB7C488B-9ED2-4265-881C-7E2E38A63584&quot;, &quot;enabled&quot;:False, &quot;partitionID&quot;:&quot;&quot;,      &quot;enabledForCalendaring&quot;:False, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;BB0C0DA1-0545-45F6-8D08-917C554D93A4&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00002&quot;, &quot;enabledForCalendaring&quot;:True,  &quot;enabledForAddressBooks&quot;:True,  &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
-    {&quot;uid&quot;:&quot;CCD30AD3-582F-4682-8B65-2EDE92C5656E&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00003&quot;, &quot;enabledForCalendaring&quot;:True,  &quot;enabledForAddressBooks&quot;:True,  &quot;autoSchedule&quot;:True,  &quot;autoScheduleMode&quot;:&quot;accept-always&quot;},
</del><ins>+    {&quot;uid&quot;: &quot;A4318887-F2C7-4A70-9056-B88CC8DB26F1&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: True, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;AA5F935F-3358-4510-A649-B391D63279F2&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: False, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;ABF1A83B-1A29-4E04-BDC3-A6A66ECF27CA&quot;, &quot;enabled&quot;: False, &quot;enabledForCalendaring&quot;: False, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;BC22A734-5E41-4FB7-B5C1-51DC0656DC2F&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: True, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;C6DEEBB1-E14A-47F2-98BA-7E3BB4353E3A&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: True, &quot;autoSchedule&quot;: True, &quot;autoScheduleMode&quot;: &quot;accept-always&quot;},
+    {&quot;uid&quot;: &quot;AA859321-2C72-4974-ADCF-0CBA0C76F95D&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: False, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;AB7C488B-9ED2-4265-881C-7E2E38A63584&quot;, &quot;enabled&quot;: False, &quot;enabledForCalendaring&quot;: False, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;BB0C0DA1-0545-45F6-8D08-917C554D93A4&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: True, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
+    {&quot;uid&quot;: &quot;CCD30AD3-582F-4682-8B65-2EDE92C5656E&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: True, &quot;autoSchedule&quot;: True, &quot;autoScheduleMode&quot;: &quot;accept-always&quot;},
</ins><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> testRecordTypeDefault = (
</span><del>-    (&quot;locations&quot;, {&quot;uid&quot;:&quot;A4318887-F2C7-4A70-9056-B88CC8DB26F1&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00004&quot;, &quot;enabledForCalendaring&quot;:True,  &quot;enabledForAddressBooks&quot;:False,  &quot;autoSchedule&quot;:True, &quot;autoScheduleMode&quot;:&quot;default&quot;}),
-    (&quot;locations&quot;, {&quot;uid&quot;:&quot;AA5F935F-3358-4510-A649-B391D63279F2&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00005&quot;, &quot;enabledForCalendaring&quot;:True, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:True, &quot;autoScheduleMode&quot;:&quot;default&quot;}),
-    (&quot;resources&quot;, {&quot;uid&quot;:&quot;A5318887-F2C7-4A70-9056-B88CC8DB26F1&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00006&quot;, &quot;enabledForCalendaring&quot;:True,  &quot;enabledForAddressBooks&quot;:False,  &quot;autoSchedule&quot;:True, &quot;autoScheduleMode&quot;:&quot;default&quot;}),
-    (&quot;resources&quot;, {&quot;uid&quot;:&quot;AA6F935F-3358-4510-A649-B391D63279F2&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;00007&quot;, &quot;enabledForCalendaring&quot;:True, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:True, &quot;autoScheduleMode&quot;:&quot;default&quot;}),
</del><ins>+    (&quot;locations&quot;, {&quot;uid&quot;: &quot;A4318887-F2C7-4A70-9056-B88CC8DB26F1&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: True, &quot;autoScheduleMode&quot;: &quot;default&quot;}),
+    (&quot;locations&quot;, {&quot;uid&quot;: &quot;AA5F935F-3358-4510-A649-B391D63279F2&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: True, &quot;autoScheduleMode&quot;: &quot;default&quot;}),
+    (&quot;resources&quot;, {&quot;uid&quot;: &quot;A5318887-F2C7-4A70-9056-B88CC8DB26F1&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: True, &quot;autoScheduleMode&quot;: &quot;default&quot;}),
+    (&quot;resources&quot;, {&quot;uid&quot;: &quot;AA6F935F-3358-4510-A649-B391D63279F2&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: True, &quot;autoScheduleMode&quot;: &quot;default&quot;}),
</ins><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> testAddRecords = (
</span><del>-    {&quot;uid&quot;:&quot;D11F03A0-97EA-48AF-9A6C-FAC7F3975767&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;&quot;, &quot;enabledForCalendaring&quot;:False, &quot;enabledForAddressBooks&quot;:False, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
</del><ins>+    {&quot;uid&quot;: &quot;D11F03A0-97EA-48AF-9A6C-FAC7F3975767&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: False, &quot;enabledForAddressBooks&quot;: False, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
</ins><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> testModifyRecords = (
</span><del>-    {&quot;uid&quot;:&quot;D11F03A0-97EA-48AF-9A6C-FAC7F3975767&quot;, &quot;enabled&quot;:True,  &quot;partitionID&quot;:&quot;&quot;, &quot;enabledForCalendaring&quot;:True, &quot;enabledForAddressBooks&quot;:True, &quot;autoSchedule&quot;:False, &quot;autoScheduleMode&quot;:&quot;default&quot;},
</del><ins>+    {&quot;uid&quot;: &quot;D11F03A0-97EA-48AF-9A6C-FAC7F3975767&quot;, &quot;enabled&quot;: True, &quot;enabledForCalendaring&quot;: True, &quot;enabledForAddressBooks&quot;: True, &quot;autoSchedule&quot;: False, &quot;autoScheduleMode&quot;: &quot;default&quot;},
</ins><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -79,27 +79,31 @@
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _checkRecord(self, db, items, recordType=DirectoryService.recordType_users):
</span><del>-        
</del><ins>+
</ins><span class="cx">         record = (yield db.getAugmentRecord(items[&quot;uid&quot;], recordType))
</span><span class="cx">         self.assertTrue(record is not None, &quot;Failed record uid: %s&quot; % (items[&quot;uid&quot;],))
</span><del>-        
-        for k,v in items.iteritems():
-            self.assertEqual(getattr(record, k), v, &quot;Failed record uid: %s, attribute: %s&quot; % (items[&quot;uid&quot;], k, ))
</del><span class="cx"> 
</span><ins>+        for k, v in items.iteritems():
+            self.assertEqual(getattr(record, k), v, &quot;Failed record uid: %s, attribute: %s&quot; % (items[&quot;uid&quot;], k,))
+
+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def _checkRecordExists(self, db, uid, recordType=DirectoryService.recordType_users):
</span><del>-        
</del><ins>+
</ins><span class="cx">         record = (yield db.getAugmentRecord(uid, recordType))
</span><span class="cx">         self.assertTrue(record is not None, &quot;Failed record uid: %s&quot; % (uid,))
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class AugmentTestsMixin(object):
</span><span class="cx"> 
</span><span class="cx">     def _db(self, dbpath=None):
</span><span class="cx">         raise NotImplementedError
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_read(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         dbpath = os.path.abspath(self.mktemp())
</span><span class="cx">         db = self._db(dbpath)
</span><span class="cx"> 
</span><span class="lines">@@ -113,9 +117,10 @@
</span><span class="cx">         # in the DB
</span><span class="cx">         yield self._checkRecordExists(db, &quot;D11F03A0-97EA-48AF-9A6C-FAC7F3975767&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_read_default(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         dbpath = os.path.abspath(self.mktemp())
</span><span class="cx">         db = self._db(dbpath)
</span><span class="cx"> 
</span><span class="lines">@@ -132,6 +137,7 @@
</span><span class="cx">         for item in testRecordWildcardDefault:
</span><span class="cx">             yield self._checkRecord(db, item)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_read_typed_default(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -159,7 +165,7 @@
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_add_modify(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         dbpath = os.path.abspath(self.mktemp())
</span><span class="cx">         db = self._db(dbpath)
</span><span class="cx"> 
</span><span class="lines">@@ -195,11 +201,13 @@
</span><span class="cx">             yield self._checkRecord(newdb, item)
</span><span class="cx">         yield self._checkRecord(newdb, testModifyRecords[0])
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class AugmentXMLTests(AugmentTests):
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_read(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         db = AugmentXMLDB((xmlFile,))
</span><span class="cx"> 
</span><span class="cx">         for item in testRecords:
</span><span class="lines">@@ -209,9 +217,10 @@
</span><span class="cx">         # in the DB
</span><span class="cx">         yield self._checkRecordExists(db, &quot;D11F03A0-97EA-48AF-9A6C-FAC7F3975767&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_read_default(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         db = AugmentXMLDB((xmlFileDefault,))
</span><span class="cx"> 
</span><span class="cx">         for item in testRecords:
</span><span class="lines">@@ -220,8 +229,9 @@
</span><span class="cx">         for item in testRecordWildcardDefault:
</span><span class="cx">             yield self._checkRecord(db, item)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_parseErrors(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         db = {}
</span><span class="cx">         self.assertRaises(RuntimeError, XMLAugmentsParser, cStringIO.StringIO(&quot;&quot;), db)
</span><span class="cx">         self.assertRaises(RuntimeError, XMLAugmentsParser, cStringIO.StringIO(&quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</span><span class="lines">@@ -249,13 +259,14 @@
</span><span class="cx">   &lt;/record&gt;
</span><span class="cx"> &quot;&quot;&quot;), db)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_add_modify(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Duplicate file as we will change it
</span><span class="cx">         newxmlfile = FilePath(self.mktemp())
</span><span class="cx">         FilePath(xmlFile).copyTo(newxmlfile)
</span><del>-        
</del><ins>+
</ins><span class="cx">         db = AugmentXMLDB((newxmlfile.path,))
</span><span class="cx"> 
</span><span class="cx">         for item in testRecords:
</span><span class="lines">@@ -283,6 +294,7 @@
</span><span class="cx">             yield self._checkRecord(newdb, item)
</span><span class="cx">         yield self._checkRecord(newdb, testModifyRecords[0])
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_shouldReparse(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Verify that a change to the file will get noticed
</span><span class="lines">@@ -294,6 +306,7 @@
</span><span class="cx">         newxmlfile.setContent(&quot;&quot;) # Change the file
</span><span class="cx">         self.assertTrue(db._shouldReparse([newxmlfile.path])) # Need to parse
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_refresh(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Ensure that a refresh without any file changes doesn't zero out the
</span><span class="lines">@@ -304,6 +317,7 @@
</span><span class="cx">         dbxml.refresh()
</span><span class="cx">         self.assertEquals(keys, dbxml.db.keys())
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def uidsFromFile(self, filename):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Return all uids from the augments xml file
</span><span class="lines">@@ -316,6 +330,7 @@
</span><span class="cx">             uid = record_node.find(xmlaugmentsparser.ELEMENT_UID).text
</span><span class="cx">             yield uid
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_normalize(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Ensure augment uids are normalized upon opening
</span><span class="lines">@@ -328,11 +343,15 @@
</span><span class="cx">         uids = list(self.uidsFromFile(newxmlfile.path))
</span><span class="cx">         self.assertEquals(uids, ['AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA'])
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class AugmentSqliteTests(AugmentTests, AugmentTestsMixin):
</span><span class="cx"> 
</span><span class="cx">     def _db(self, dbpath=None):
</span><span class="cx">         return AugmentSqliteDB(dbpath if dbpath else os.path.abspath(self.mktemp()))
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class AugmentPostgreSQLTests(AugmentTests, AugmentTestsMixin):
</span><span class="cx"> 
</span><span class="cx">     def _db(self, dbpath=None):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_cachedirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_cachedirectory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_cachedirectory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_cachedirectory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx">             DirectoryService.recordType_resources,
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def queryDirectory(self, recordTypes, indexType, indexKey):
</span><span class="cx"> 
</span><span class="cx">         self.queried = True
</span><span class="lines">@@ -58,42 +59,47 @@
</span><span class="cx"> 
</span><span class="cx">                 if cacheIt:
</span><span class="cx">                     cacheRecord = CachingDirectoryRecord(
</span><del>-                        service               = self,
-                        recordType            = recordType,
-                        guid                  = record.get(&quot;guid&quot;),
-                        shortNames            = record.get(&quot;shortname&quot;),
-                        authIDs               = record.get(&quot;authid&quot;),
-                        fullName              = record.get(&quot;fullName&quot;),
-                        firstName             = &quot;&quot;,
-                        lastName              = &quot;&quot;,
-                        emailAddresses        = record.get(&quot;email&quot;),
-                    ) 
-                    
</del><ins>+                        service=self,
+                        recordType=recordType,
+                        guid=record.get(&quot;guid&quot;),
+                        shortNames=record.get(&quot;shortname&quot;),
+                        authIDs=record.get(&quot;authid&quot;),
+                        fullName=record.get(&quot;fullName&quot;),
+                        firstName=&quot;&quot;,
+                        lastName=&quot;&quot;,
+                        emailAddresses=record.get(&quot;email&quot;),
+                    )
+
</ins><span class="cx">                     augmentRecord = AugmentRecord(
</span><del>-                        uid = cacheRecord.guid,
</del><ins>+                        uid=cacheRecord.guid,
</ins><span class="cx">                         enabled=True,
</span><del>-                        enabledForCalendaring = True,
</del><ins>+                        enabledForCalendaring=True,
</ins><span class="cx">                     )
</span><del>-                    
</del><ins>+
</ins><span class="cx">                     cacheRecord.addAugmentInformation(augmentRecord)
</span><span class="cx"> 
</span><span class="cx">                     self.recordCacheForType(recordType).addRecord(cacheRecord,
</span><span class="cx">                         indexType, indexKey)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class CachingDirectoryTest(TestCase):
</span><del>-    
</del><ins>+
</ins><span class="cx">     baseGUID = str(uuid4())
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def setUp(self):
</span><span class="cx">         super(CachingDirectoryTest, self).setUp()
</span><span class="cx">         self.service = TestDirectoryService()
</span><span class="cx">         self.service.queried = False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def loadRecords(self, records):
</span><span class="cx">         self.service._initCaches()
</span><span class="cx">         self.service.fakerecords = records
</span><span class="cx">         self.service.queried = False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def fakeRecord(
</span><span class="cx">         self,
</span><span class="cx">         fullName,
</span><span class="lines">@@ -109,15 +115,15 @@
</span><span class="cx">             shortNames = (self.shortNameForFullName(fullName),)
</span><span class="cx">             if multinames:
</span><span class="cx">                 shortNames += (fullName,)
</span><del>-    
</del><ins>+
</ins><span class="cx">         if guid is None:
</span><span class="cx">             guid = self.guidForShortName(shortNames[0], recordType=recordType)
</span><span class="cx">         else:
</span><span class="cx">             guid = guid.lower()
</span><del>-    
</del><ins>+
</ins><span class="cx">         if emails is None:
</span><span class="cx">             emails = (&quot;%s@example.com&quot; % (shortNames[0],),)
</span><del>-    
</del><ins>+
</ins><span class="cx">         attrs = {
</span><span class="cx">             &quot;fullName&quot;: fullName,
</span><span class="cx">             &quot;guid&quot;: guid,
</span><span class="lines">@@ -126,35 +132,38 @@
</span><span class="cx">             &quot;cua&quot;: tuple([&quot;mailto:%s&quot; % email for email in emails]),
</span><span class="cx">             &quot;authid&quot;: tuple([&quot;Kerberos:%s&quot; % email for email in emails])
</span><span class="cx">         }
</span><del>-        
</del><ins>+
</ins><span class="cx">         if members:
</span><span class="cx">             attrs[&quot;members&quot;] = members
</span><del>-    
</del><ins>+
</ins><span class="cx">         if resourceInfo:
</span><span class="cx">             attrs[&quot;resourceInfo&quot;] = resourceInfo
</span><del>-    
</del><ins>+
</ins><span class="cx">         return attrs
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def shortNameForFullName(self, fullName):
</span><span class="cx">         return fullName.lower().replace(&quot; &quot;, &quot;&quot;)
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def guidForShortName(self, shortName, recordType=&quot;&quot;):
</span><span class="cx">         return uuidFromName(self.baseGUID, &quot;%s%s&quot; % (recordType, shortName))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def dummyRecords(self):
</span><span class="cx">         SIZE = 10
</span><span class="cx">         records = {
</span><span class="cx">             DirectoryService.recordType_users: [
</span><del>-                self.fakeRecord(&quot;User %02d&quot; % x, DirectoryService.recordType_users, multinames=(x&gt;5)) for x in range(1,SIZE+1)
</del><ins>+                self.fakeRecord(&quot;User %02d&quot; % x, DirectoryService.recordType_users, multinames=(x &gt; 5)) for x in range(1, SIZE + 1)
</ins><span class="cx">             ],
</span><span class="cx">             DirectoryService.recordType_groups: [
</span><del>-                self.fakeRecord(&quot;Group %02d&quot; % x, DirectoryService.recordType_groups) for x in range(1,SIZE+1)
</del><ins>+                self.fakeRecord(&quot;Group %02d&quot; % x, DirectoryService.recordType_groups) for x in range(1, SIZE + 1)
</ins><span class="cx">             ],
</span><span class="cx">             DirectoryService.recordType_resources: [
</span><del>-                self.fakeRecord(&quot;Resource %02d&quot; % x, DirectoryService.recordType_resources) for x in range(1,SIZE+1)
</del><ins>+                self.fakeRecord(&quot;Resource %02d&quot; % x, DirectoryService.recordType_resources) for x in range(1, SIZE + 1)
</ins><span class="cx">             ],
</span><span class="cx">             DirectoryService.recordType_locations: [
</span><del>-                self.fakeRecord(&quot;Location %02d&quot; % x, DirectoryService.recordType_locations) for x in range(1,SIZE+1)
</del><ins>+                self.fakeRecord(&quot;Location %02d&quot; % x, DirectoryService.recordType_locations) for x in range(1, SIZE + 1)
</ins><span class="cx">             ],
</span><span class="cx">         }
</span><span class="cx">         # Add duplicate shortnames
</span><span class="lines">@@ -165,14 +174,17 @@
</span><span class="cx"> 
</span><span class="cx">         self.loadRecords(records)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def verifyRecords(self, recordType, expectedGUIDs):
</span><del>-        
</del><ins>+
</ins><span class="cx">         records = self.service.listRecords(recordType)
</span><span class="cx">         recordGUIDs = set([record.guid for record in records])
</span><span class="cx">         self.assertEqual(recordGUIDs, expectedGUIDs)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class GUIDLookups(CachingDirectoryTest):
</span><del>-    
</del><ins>+
</ins><span class="cx">     def test_emptylist(self):
</span><span class="cx">         self.dummyRecords()
</span><span class="cx"> 
</span><span class="lines">@@ -180,7 +192,8 @@
</span><span class="cx">         self.verifyRecords(DirectoryService.recordType_groups, set())
</span><span class="cx">         self.verifyRecords(DirectoryService.recordType_resources, set())
</span><span class="cx">         self.verifyRecords(DirectoryService.recordType_locations, set())
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def test_cacheoneguid(self):
</span><span class="cx">         self.dummyRecords()
</span><span class="cx"> 
</span><span class="lines">@@ -200,7 +213,8 @@
</span><span class="cx"> 
</span><span class="cx">         # Make sure guid is case-insensitive
</span><span class="cx">         self.assertTrue(self.service.recordWithGUID(self.guidForShortName(&quot;user01&quot;, recordType=DirectoryService.recordType_users).lower()) is not None)
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def test_cacheoneshortname(self):
</span><span class="cx">         self.dummyRecords()
</span><span class="cx"> 
</span><span class="lines">@@ -224,6 +238,7 @@
</span><span class="cx">         ) is not None)
</span><span class="cx">         self.assertFalse(self.service.queried)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_cacheoneemail(self):
</span><span class="cx">         self.dummyRecords()
</span><span class="cx"> 
</span><span class="lines">@@ -245,6 +260,7 @@
</span><span class="cx">         ) is not None)
</span><span class="cx">         self.assertFalse(self.service.queried)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_cacheonePrincipalsURLWithUIDS(self):
</span><span class="cx">         self.dummyRecords()
</span><span class="cx"> 
</span><span class="lines">@@ -267,6 +283,7 @@
</span><span class="cx">         ) is not None)
</span><span class="cx">         self.assertFalse(self.service.queried)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_cacheonePrincipalsURLWithUsers(self):
</span><span class="cx">         self.dummyRecords()
</span><span class="cx"> 
</span><span class="lines">@@ -288,6 +305,7 @@
</span><span class="cx">         ) is not None)
</span><span class="cx">         self.assertFalse(self.service.queried)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_cacheoneauthid(self):
</span><span class="cx">         self.dummyRecords()
</span><span class="cx"> 
</span><span class="lines">@@ -309,6 +327,7 @@
</span><span class="cx">         ) is not None)
</span><span class="cx">         self.assertFalse(self.service.queried)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_negativeCaching(self):
</span><span class="cx">         self.dummyRecords()
</span><span class="cx"> 
</span><span class="lines">@@ -324,7 +343,6 @@
</span><span class="cx">         self.assertEquals(self.service.recordWithGUID(self.guidForShortName(&quot;missing&quot;)), None)
</span><span class="cx">         self.assertTrue(self.service.queried)
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         # However, if negativeCaching is on, a miss is recorded as such,
</span><span class="cx">         # preventing a similar queryDirectory( ) until cacheTimeout passes
</span><span class="cx">         self.service.negativeCaching = True
</span><span class="lines">@@ -345,6 +363,7 @@
</span><span class="cx">         self.assertEquals(self.service.recordWithGUID(self.guidForShortName(&quot;missing&quot;)), None)
</span><span class="cx">         self.assertTrue(self.service.queried)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_duplicateShortNames(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Verify that when looking up records having duplicate short-names, the record of the
</span><span class="lines">@@ -370,6 +389,7 @@
</span><span class="cx">             &quot;Duplicate&quot;)
</span><span class="cx">         self.assertEquals(record.recordType, DirectoryService.recordType_locations)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_generateMemcacheKey(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Verify keys are correctly generated based on the index type -- if index type is
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_digestpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_digest.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_digest.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_digest.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -55,7 +55,7 @@
</span><span class="cx"> challengeResponse = ('digest',
</span><span class="cx">                      {'nonce': challengeNonce,
</span><span class="cx">                       'qop': 'auth', 'realm': 'test realm',
</span><del>-                      'algorithm': 'md5',})
</del><ins>+                      'algorithm': 'md5', })
</ins><span class="cx"> 
</span><span class="cx"> cnonce = &quot;29fc54aa1641c6fa0e151419361c8f23&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -116,6 +116,7 @@
</span><span class="cx">                                           self.namespace2
</span><span class="cx">                                       ))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def getDigestResponse(self, challenge, ncount):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Calculate the response for the given challenge
</span><span class="lines">@@ -146,6 +147,7 @@
</span><span class="cx">                 )
</span><span class="cx">         return expected
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def getDigestResponseComma(self, challenge, ncount):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Calculate the response for the given challenge
</span><span class="lines">@@ -176,6 +178,7 @@
</span><span class="cx">                 )
</span><span class="cx">         return expected
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def assertRaisesDeferred(self, exception, f, *args, **kwargs):
</span><span class="cx">         try:
</span><span class="lines">@@ -191,6 +194,7 @@
</span><span class="cx">             raise self.failureException('%s not raised (%r returned)'
</span><span class="cx">                                         % (exception.__name__, result))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_getChallenge(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -203,14 +207,15 @@
</span><span class="cx">         self.assertEquals(challenge['qop'], 'auth')
</span><span class="cx">         self.assertEquals(challenge['realm'], 'test realm')
</span><span class="cx">         self.assertEquals(challenge['algorithm'], 'md5')
</span><del>-        self.assertTrue(challenge.has_key(&quot;nonce&quot;))
</del><ins>+        self.assertTrue(&quot;nonce&quot; in challenge)
</ins><span class="cx"> 
</span><span class="cx">         challenge = (yield self.credentialFactories[1].getChallenge(clientAddress))
</span><del>-        self.assertFalse(challenge.has_key('qop'))
</del><ins>+        self.assertFalse('qop' in challenge)
</ins><span class="cx">         self.assertEquals(challenge['realm'], 'test realm')
</span><span class="cx">         self.assertEquals(challenge['algorithm'], 'md5')
</span><del>-        self.assertTrue(challenge.has_key(&quot;nonce&quot;))
</del><ins>+        self.assertTrue(&quot;nonce&quot; in challenge)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_response(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -219,15 +224,16 @@
</span><span class="cx"> 
</span><span class="cx">         for ctr, factory in enumerate(self.credentialFactories):
</span><span class="cx">             challenge = (yield factory.getChallenge(clientAddress))
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse = authRequest1[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponse(challenge, &quot;00000001&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             creds = (yield factory.decode(clientResponse, _trivial_GET()))
</span><span class="cx">             self.failUnless(creds.checkPassword('password'))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_multiResponse(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -237,23 +243,24 @@
</span><span class="cx"> 
</span><span class="cx">         for ctr, factory in enumerate(self.credentialFactories):
</span><span class="cx">             challenge = (yield factory.getChallenge(clientAddress))
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse = authRequest1[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponse(challenge, &quot;00000001&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             creds = (yield factory.decode(clientResponse, _trivial_GET()))
</span><span class="cx">             self.failUnless(creds.checkPassword('password'))
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse = authRequest2[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponse(challenge, &quot;00000002&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             creds = (yield factory.decode(clientResponse, _trivial_GET()))
</span><span class="cx">             self.failUnless(creds.checkPassword('password'))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_failsWithDifferentMethod(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -263,16 +270,17 @@
</span><span class="cx"> 
</span><span class="cx">         for ctr, factory in enumerate(self.credentialFactories):
</span><span class="cx">             challenge = (yield factory.getChallenge(clientAddress))
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse = authRequest1[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponse(challenge, &quot;00000001&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             creds = (yield factory.decode(clientResponse,
</span><span class="cx">                                                   SimpleRequest(None, 'POST', '/')))
</span><span class="cx">             self.failIf(creds.checkPassword('password'))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_noUsername(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -287,7 +295,7 @@
</span><span class="cx">                                   namelessAuthRequest,
</span><span class="cx">                                   _trivial_GET()))
</span><span class="cx">             self.assertEquals(str(e), &quot;Invalid response, no username given.&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             # Check for an empty username
</span><span class="cx">             e = (yield self.assertRaisesDeferred(error.LoginFailed,
</span><span class="cx">                                   factory.decode,
</span><span class="lines">@@ -295,6 +303,7 @@
</span><span class="cx">                                   _trivial_GET()))
</span><span class="cx">             self.assertEquals(str(e), &quot;Invalid response, no username given.&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_noNonce(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -308,6 +317,7 @@
</span><span class="cx">                                   _trivial_GET()))
</span><span class="cx">             self.assertEquals(str(e), &quot;Invalid response, no nonce given.&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_emptyAttribute(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -323,6 +333,7 @@
</span><span class="cx">                                   _trivial_GET()))
</span><span class="cx">             self.assertEquals(str(e), &quot;Invalid response, no username given.&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_checkHash(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -332,20 +343,21 @@
</span><span class="cx"> 
</span><span class="cx">         for ctr, factory in enumerate(self.credentialFactories):
</span><span class="cx">             challenge = (yield factory.getChallenge(clientAddress))
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse = authRequest1[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponse(challenge, &quot;00000001&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             creds = (yield factory.decode(clientResponse, _trivial_GET()))
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.failUnless(creds.checkHash(
</span><span class="cx">                     md5('username:test realm:password').hexdigest()))
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.failIf(creds.checkHash(
</span><span class="cx">                     md5('username:test realm:bogus').hexdigest()))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_invalidNonceCount(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -359,20 +371,20 @@
</span><span class="cx"> 
</span><span class="cx">         for ctr, factory in enumerate(credentialFactories):
</span><span class="cx">             challenge = (yield factory.getChallenge(clientAddress))
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse1 = authRequest1[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponse(challenge, &quot;00000001&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse2 = authRequest2[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponse(challenge, &quot;00000002&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             yield factory.decode(clientResponse1, _trivial_GET())
</span><span class="cx">             yield factory.decode(clientResponse2, _trivial_GET())
</span><del>-    
</del><ins>+
</ins><span class="cx">             if challenge.get('qop') is not None:
</span><span class="cx">                 yield self.assertRaisesDeferred(
</span><span class="cx">                     error.LoginFailed,
</span><span class="lines">@@ -380,7 +392,7 @@
</span><span class="cx">                     clientResponse2,
</span><span class="cx">                     _trivial_GET()
</span><span class="cx">                 )
</span><del>-                
</del><ins>+
</ins><span class="cx">                 challenge = (yield factory.getChallenge(clientAddress))
</span><span class="cx"> 
</span><span class="cx">                 clientResponse1 = authRequest1[ctr] % (
</span><span class="lines">@@ -400,6 +412,7 @@
</span><span class="cx">                     _trivial_GET()
</span><span class="cx">                 )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_invalidNonce(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -415,12 +428,12 @@
</span><span class="cx">         for ctr, factory in enumerate(credentialFactories):
</span><span class="cx">             challenge = (yield factory.getChallenge(clientAddress))
</span><span class="cx">             challenge['nonce'] = &quot;noNoncense&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse = authRequest1[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponse(challenge, &quot;00000001&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             request = _trivial_GET()
</span><span class="cx">             yield self.assertRaisesDeferred(
</span><span class="cx">                 error.LoginFailed,
</span><span class="lines">@@ -431,11 +444,12 @@
</span><span class="cx"> 
</span><span class="cx">             factory._invalidate(FAKE_STATIC_NONCE)
</span><span class="cx">             response = (yield UnauthorizedResponse.makeResponse(
</span><del>-                {&quot;Digest&quot;:factory},
</del><ins>+                {&quot;Digest&quot;: factory},
</ins><span class="cx">                 request.remoteAddr
</span><span class="cx">             ))
</span><span class="cx">             response.headers.getHeader(&quot;www-authenticate&quot;)[0][1]
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_oldNonce(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -452,12 +466,12 @@
</span><span class="cx">             challenge = (yield factory.getChallenge(clientAddress))
</span><span class="cx">             nonce_count, timestamp = (yield factory.db.get(challenge['nonce']))
</span><span class="cx">             factory.db.set(challenge['nonce'], (nonce_count, timestamp - 2 * digest.DigestCredentialFactory.CHALLENGE_LIFETIME_SECS))
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse = authRequest1[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponse(challenge, &quot;00000001&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             request = _trivial_GET()
</span><span class="cx">             yield self.assertRaisesDeferred(
</span><span class="cx">                 error.LoginFailed,
</span><span class="lines">@@ -465,15 +479,16 @@
</span><span class="cx">                 clientResponse,
</span><span class="cx">                 request
</span><span class="cx">             )
</span><del>-            
</del><ins>+
</ins><span class="cx">             response = (yield UnauthorizedResponse.makeResponse(
</span><del>-                {&quot;Digest&quot;:factory},
</del><ins>+                {&quot;Digest&quot;: factory},
</ins><span class="cx">                 request.remoteAddr,
</span><span class="cx">             ))
</span><span class="cx">             wwwhdrs = response.headers.getHeader(&quot;www-authenticate&quot;)[0][1]
</span><span class="cx">             self.assertTrue('stale' in wwwhdrs, msg=&quot;No stale parameter in Digest WWW-Authenticate headers: %s&quot; % (wwwhdrs,))
</span><span class="cx">             self.assertEquals(wwwhdrs['stale'], 'true', msg=&quot;stale parameter not set to true in Digest WWW-Authenticate headers: %s&quot; % (wwwhdrs,))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_incompatibleCalcHA1Options(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Test that the appropriate error is raised when any of the
</span><span class="lines">@@ -500,6 +515,7 @@
</span><span class="cx">                 preHA1=preHA1
</span><span class="cx">                 )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_commaURI(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -508,15 +524,16 @@
</span><span class="cx"> 
</span><span class="cx">         for ctr, factory in enumerate(self.credentialFactories):
</span><span class="cx">             challenge = (yield factory.getChallenge(clientAddress))
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse = authRequestComma[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponseComma(challenge, &quot;00000001&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             creds = (yield factory.decode(clientResponse, _trivial_GET()))
</span><span class="cx">             self.failUnless(creds.checkPassword('password'))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_stale_response(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -526,20 +543,20 @@
</span><span class="cx">         class newtime(object):
</span><span class="cx">             def time(self):
</span><span class="cx">                 return theTime
</span><del>-        from twistedcaldav.directory import digest
-        self.patch(digest, &quot;time&quot;, newtime())
</del><ins>+        from twistedcaldav.directory import digest as ddigest
+        self.patch(ddigest, &quot;time&quot;, newtime())
</ins><span class="cx"> 
</span><span class="cx">         for ctr, factory in enumerate(self.credentialFactories):
</span><span class="cx">             challenge = (yield factory.getChallenge(clientAddress))
</span><del>-    
</del><ins>+
</ins><span class="cx">             clientResponse = authRequest1[ctr] % (
</span><span class="cx">                 challenge['nonce'],
</span><span class="cx">                 self.getDigestResponse(challenge, &quot;00000001&quot;),
</span><span class="cx">             )
</span><del>-    
</del><ins>+
</ins><span class="cx">             creds = (yield factory.decode(clientResponse, _trivial_GET()))
</span><span class="cx">             self.failUnless(creds.checkPassword('password'))
</span><del>-            
</del><ins>+
</ins><span class="cx">             theTime += DigestCredentialFactory.CHALLENGE_LIFETIME_SECS + 1
</span><span class="cx">             request = _trivial_GET()
</span><span class="cx">             try:
</span><span class="lines">@@ -555,8 +572,8 @@
</span><span class="cx">                 self.fail(&quot;Invalid exception from nonce timeout: %s&quot; % e)
</span><span class="cx">             challenge = (yield factory.getChallenge(request.remoteAddr))
</span><span class="cx">             self.assertTrue(challenge.get(&quot;stale&quot;) == &quot;true&quot;)
</span><del>-            
</del><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def _trivial_GET():
</span><span class="cx">     return SimpleRequest(None, 'GET', '/')
</span><del>-
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_directorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_directory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_directory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_directory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -121,7 +121,6 @@
</span><span class="cx">         self.count += 1
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     def test_expandedMembers(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Make sure expandedMembers( ) returns a complete, flattened set of
</span><span class="lines">@@ -889,7 +888,7 @@
</span><span class="cx">         }
</span><span class="cx">         members = pickle.loads(snapshotFile.getContent())
</span><span class="cx">         self.assertEquals(members, expected)
</span><del>-        
</del><ins>+
</ins><span class="cx">         # &quot;Corrupt&quot; the snapshot and verify it is regenerated properly
</span><span class="cx">         snapshotFile.setContent(&quot;xyzzy&quot;)
</span><span class="cx">         cache.delete(&quot;group-cacher-populated&quot;)
</span><span class="lines">@@ -900,8 +899,8 @@
</span><span class="cx">         self.assertTrue(snapshotFile.exists())
</span><span class="cx">         members = pickle.loads(snapshotFile.getContent())
</span><span class="cx">         self.assertEquals(members, expected)
</span><del>-        
</del><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_autoAcceptMembers(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         autoAcceptMembers( ) returns an empty list if no autoAcceptGroup is
</span><span class="lines">@@ -926,6 +925,7 @@
</span><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def testScheduling(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -934,6 +934,7 @@
</span><span class="cx"> 
</span><span class="cx">         groupCacher = StubGroupCacher()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">         def decorateTransaction(txn):
</span><span class="cx">             txn._groupCacher = groupCacher
</span><span class="cx"> 
</span><span class="lines">@@ -945,15 +946,19 @@
</span><span class="cx"> 
</span><span class="cx">     testScheduling.skip = &quot;Fix WorkProposal to track delayed calls and cancel them&quot;
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class StubGroupCacher(object):
</span><span class="cx">     def __init__(self):
</span><span class="cx">         self.called = False
</span><span class="cx">         self.updateSeconds = 99
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def updateCache(self):
</span><span class="cx">         self.called = True
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class RecordsMatchingTokensTests(TestCase):
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -1038,6 +1043,7 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class GUIDTests(TestCase):
</span><span class="cx"> 
</span><span class="cx">     def setUp(self):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_guidchangepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_guidchange.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_guidchange.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_guidchange.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -52,7 +52,7 @@
</span><span class="cx">         newUID = &quot;38D8AC00-5490-4425-BE3A-05FFB9862444&quot;
</span><span class="cx"> 
</span><span class="cx">         homeResource = &quot;/calendars/users/cdaboo/&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         def privs1(result):
</span><span class="cx">             # Change GUID in record
</span><span class="cx">             self.xmlFile.setContent(
</span><span class="lines">@@ -65,10 +65,10 @@
</span><span class="cx"> 
</span><span class="cx">             # Now force the calendar home resource to be reset
</span><span class="cx">             self.resetCalendars()
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Make sure new user cannot access old user's calendar home
</span><span class="cx">             return self._checkPrivileges(None, homeResource, davxml.HRef(&quot;/principals/__uids__/&quot; + newUID + &quot;/&quot;), davxml.Write, False)
</span><del>-            
</del><ins>+
</ins><span class="cx">         # Make sure current user has access to their calendar home
</span><span class="cx">         d = self._checkPrivileges(None, homeResource, davxml.HRef(&quot;/principals/__uids__/&quot; + oldUID + &quot;/&quot;), davxml.Write, True)
</span><span class="cx">         d.addCallback(privs1)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_ldapdirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_ldapdirectory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_ldapdirectory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_ldapdirectory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -276,6 +276,7 @@
</span><span class="cx">                     entry[&quot;expected&quot;]
</span><span class="cx">                 )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     class StubList(object):
</span><span class="cx">         def __init__(self, wrapper):
</span><span class="cx">             self.ldap = wrapper
</span><span class="lines">@@ -293,6 +294,7 @@
</span><span class="cx">             self.allResults = self.ldap.search_s(self.base, self.scope,
</span><span class="cx">                 self.filterstr, attrlist=self.attrList)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     class StubAsync(object):
</span><span class="cx">         def List(self, wrapper):
</span><span class="cx">             return StubList(wrapper)
</span><span class="lines">@@ -304,7 +306,6 @@
</span><span class="cx">         whatever you have previously called addTestResults( ) with.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         def __init__(self, actual, records):
</span><span class="cx">             self.actual = actual
</span><span class="cx">             self.async = StubAsync()
</span><span class="lines">@@ -587,9 +588,8 @@
</span><span class="cx">                     &quot;readOnlyProxyAttr&quot;: &quot;read-only-proxy&quot;,
</span><span class="cx">                     &quot;autoAcceptGroupAttr&quot;: None,
</span><span class="cx">                 },
</span><del>-                &quot;partitionSchema&quot;: {
</del><ins>+                &quot;poddingSchema&quot;: {
</ins><span class="cx">                     &quot;serverIdAttr&quot;: &quot;server-id&quot;, # maps to augments server-id
</span><del>-                    &quot;partitionIdAttr&quot;: &quot;partition-id&quot;, # maps to augments partition-id
</del><span class="cx">                 },
</span><span class="cx">             }
</span><span class="cx">         )
</span><span class="lines">@@ -803,9 +803,8 @@
</span><span class="cx">                     &quot;readOnlyProxyAttr&quot;: None,
</span><span class="cx">                     &quot;autoAcceptGroupAttr&quot;: None,
</span><span class="cx">                 },
</span><del>-                &quot;partitionSchema&quot;: {
</del><ins>+                &quot;poddingSchema&quot;: {
</ins><span class="cx">                     &quot;serverIdAttr&quot;: &quot;server-id&quot;, # maps to augments server-id
</span><del>-                    &quot;partitionIdAttr&quot;: &quot;partition-id&quot;, # maps to augments partition-id
</del><span class="cx">                 },
</span><span class="cx">             }
</span><span class="cx">         )
</span><span class="lines">@@ -1021,9 +1020,8 @@
</span><span class="cx">                     &quot;readOnlyProxyAttr&quot;: None,
</span><span class="cx">                     &quot;autoAcceptGroupAttr&quot;: None,
</span><span class="cx">                 },
</span><del>-                &quot;partitionSchema&quot;: {
</del><ins>+                &quot;poddingSchema&quot;: {
</ins><span class="cx">                     &quot;serverIdAttr&quot;: &quot;server-id&quot;, # maps to augments server-id
</span><del>-                    &quot;partitionIdAttr&quot;: &quot;partition-id&quot;, # maps to augments partition-id
</del><span class="cx">                 },
</span><span class="cx">             }
</span><span class="cx">         )
</span><span class="lines">@@ -1235,9 +1233,8 @@
</span><span class="cx">                     &quot;readOnlyProxyAttr&quot;: None,
</span><span class="cx">                     &quot;autoAcceptGroupAttr&quot;: None,
</span><span class="cx">                 },
</span><del>-                &quot;partitionSchema&quot;: {
</del><ins>+                &quot;poddingSchema&quot;: {
</ins><span class="cx">                     &quot;serverIdAttr&quot;: &quot;server-id&quot;, # maps to augments server-id
</span><del>-                    &quot;partitionIdAttr&quot;: &quot;partition-id&quot;, # maps to augments partition-id
</del><span class="cx">                 },
</span><span class="cx">             }
</span><span class="cx">         )
</span><span class="lines">@@ -1295,7 +1292,6 @@
</span><span class="cx">             self.assertEquals(record.firstName, 'Amanda')
</span><span class="cx">             self.assertEquals(record.lastName, 'Test')
</span><span class="cx">             self.assertEquals(record.serverID, None)
</span><del>-            self.assertEquals(record.partitionID, None)
</del><span class="cx">             self.assertFalse(record.enabledForCalendaring)
</span><span class="cx"> 
</span><span class="cx">             # User with enabled-for-calendaring specified
</span><span class="lines">@@ -1325,13 +1321,11 @@
</span><span class="cx">                 'apple-generateduid': [guid],
</span><span class="cx">                 'cn': ['Amanda Test'],
</span><span class="cx">                 'server-id' : [&quot;test-server-id&quot;],
</span><del>-                'partition-id' : [&quot;test-partition-id&quot;],
</del><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             record = self.service._ldapResultToRecord(dn, attrs,
</span><span class="cx">                 self.service.recordType_users)
</span><span class="cx">             self.assertEquals(record.serverID, &quot;test-server-id&quot;)
</span><del>-            self.assertEquals(record.partitionID, &quot;test-partition-id&quot;)
</del><span class="cx"> 
</span><span class="cx">             # User missing guidAttr
</span><span class="cx"> 
</span><span class="lines">@@ -1471,7 +1465,6 @@
</span><span class="cx">             self.assertFalse(record.autoSchedule)
</span><span class="cx">             self.assertEquals(record.autoAcceptGroup, &quot;&quot;)
</span><span class="cx"> 
</span><del>-
</del><span class="cx">             # Now switch off the resourceInfoAttr and switch to individual
</span><span class="cx">             # attributes...
</span><span class="cx">             self.service.resourceSchema = {
</span><span class="lines">@@ -1625,7 +1618,6 @@
</span><span class="cx">                 self.assertFalse(self.service.isAllowedByRestrictToGroup(dn, attrs))
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         @inlineCallbacks
</span><span class="cx">         def test_groupMembershipAliases(self):
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="lines">@@ -1680,7 +1672,6 @@
</span><span class="cx">             )
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         def test_splitIntoBatches(self):
</span><span class="cx">             self.setupService(self.nestedUsingDifferentAttributeUsingDN)
</span><span class="cx">             # Data is perfect multiple of size
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_livedirectorypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_livedirectory.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_livedirectory.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_livedirectory.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -142,8 +142,6 @@
</span><span class="cx">             record = self.svc.recordWithShortName(&quot;users&quot;, &quot;odtestcarlene&quot;)
</span><span class="cx">             self.assertTrue(record in records)
</span><span class="cx"> 
</span><del>-
-
</del><span class="cx">     if runLDAPTests:
</span><span class="cx"> 
</span><span class="cx">         from twistedcaldav.directory.ldapdirectory import LdapDirectoryService
</span><span class="lines">@@ -196,7 +194,6 @@
</span><span class="cx">                 }
</span><span class="cx">                 self.svc = LdapDirectoryService(params)
</span><span class="cx"> 
</span><del>-
</del><span class="cx">     if runODTests:
</span><span class="cx"> 
</span><span class="cx">         from twistedcaldav.directory.appleopendirectory import OpenDirectoryService
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_modifypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_modify.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_modify.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_modify.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -47,6 +47,7 @@
</span><span class="cx">         augmentsFile = os.path.join(testRoot, &quot;augments.xml&quot;)
</span><span class="cx">         config.AugmentService.params.xmlFiles = (augmentsFile,)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_createRecord(self):
</span><span class="cx">         directory = getDirectory()
</span><span class="cx"> 
</span><span class="lines">@@ -75,6 +76,7 @@
</span><span class="cx">         record = directory.recordWithUID(&quot;location01&quot;)
</span><span class="cx">         self.assertNotEquals(record, None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_destroyRecord(self):
</span><span class="cx">         directory = getDirectory()
</span><span class="cx"> 
</span><span class="lines">@@ -95,6 +97,7 @@
</span><span class="cx">         record = directory.recordWithUID(&quot;location01&quot;)
</span><span class="cx">         self.assertNotEquals(record, None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_updateRecord(self):
</span><span class="cx">         directory = getDirectory()
</span><span class="cx"> 
</span><span class="lines">@@ -124,12 +127,14 @@
</span><span class="cx">         record = directory.recordWithUID(&quot;location01&quot;)
</span><span class="cx">         self.assertNotEquals(record, None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_createDuplicateRecord(self):
</span><span class="cx">         directory = getDirectory()
</span><span class="cx"> 
</span><span class="cx">         directory.createRecord(&quot;resources&quot;, guid=&quot;resource01&quot;, shortNames=(&quot;resource01&quot;,), uid=&quot;resource01&quot;)
</span><span class="cx">         self.assertRaises(DirectoryError, directory.createRecord, &quot;resources&quot;, guid=&quot;resource01&quot;, shortNames=(&quot;resource01&quot;,), uid=&quot;resource01&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_missingShortNames(self):
</span><span class="cx">         directory = getDirectory()
</span><span class="cx"> 
</span><span class="lines">@@ -145,6 +150,7 @@
</span><span class="cx">         self.assertEquals(record.shortNames[0], &quot;resource01&quot;)
</span><span class="cx">         self.assertEquals(record.fullName, &quot;Resource #1&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_missingGUID(self):
</span><span class="cx">         directory = getDirectory()
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_opendirectorybackerpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_opendirectorybacker.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_opendirectorybacker.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_opendirectorybacker.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -21,7 +21,20 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_multiplePhoneNumbersAndEmailAddresses(self):
</span><del>-        attributes={u'dsAttrTypeStandard:AppleMetaRecordName': ['uid=odtestamanda,cn=users,dc=dalek,dc=example,dc=com'], u'dsAttrTypeStandard:ModificationTimestamp': '20111017170937Z', u'dsAttrTypeStandard:PhoneNumber': ['408 555-1212', '415 555-1212'], u'dsAttrTypeStandard:RecordType': ['dsRecTypeStandard:Users'], u'dsAttrTypeStandard:AppleMetaNodeLocation': ['/LDAPv3/127.0.0.1'], u'dsAttrTypeStandard:RecordName': ['odtestamanda'], u'dsAttrTypeStandard:FirstName': 'Amanda', u'dsAttrTypeStandard:GeneratedUID': '9DC04A70-E6DD-11DF-9492-0800200C9A66', u'dsAttrTypeStandard:LastName': 'Test', u'dsAttrTypeStandard:CreationTimestamp': '20110927182945Z', u'dsAttrTypeStandard:EMailAddress': ['amanda@example.com', 'second@example.com'], u'dsAttrTypeStandard:RealName': 'Amanda Test'}
</del><ins>+        attributes = {
+            u'dsAttrTypeStandard:AppleMetaRecordName': ['uid=odtestamanda,cn=users,dc=dalek,dc=example,dc=com'],
+            u'dsAttrTypeStandard:ModificationTimestamp': '20111017170937Z',
+            u'dsAttrTypeStandard:PhoneNumber': ['408 555-1212', '415 555-1212'],
+            u'dsAttrTypeStandard:RecordType': ['dsRecTypeStandard:Users'],
+            u'dsAttrTypeStandard:AppleMetaNodeLocation': ['/LDAPv3/127.0.0.1'],
+            u'dsAttrTypeStandard:RecordName': ['odtestamanda'],
+            u'dsAttrTypeStandard:FirstName': 'Amanda',
+            u'dsAttrTypeStandard:GeneratedUID': '9DC04A70-E6DD-11DF-9492-0800200C9A66',
+            u'dsAttrTypeStandard:LastName': 'Test',
+            u'dsAttrTypeStandard:CreationTimestamp': '20110927182945Z',
+            u'dsAttrTypeStandard:EMailAddress': ['amanda@example.com', 'second@example.com'],
+            u'dsAttrTypeStandard:RealName': 'Amanda Test',
+        }
</ins><span class="cx">         vcardRecord = VCardRecord(StubService(), attributes)
</span><span class="cx">         vcard = vcardRecord.vCard()
</span><span class="cx">         properties = set([prop.value() for prop in vcard.properties(&quot;TEL&quot;)])
</span><span class="lines">@@ -30,6 +43,7 @@
</span><span class="cx">         self.assertEquals(properties, set([&quot;amanda@example.com&quot;, &quot;second@example.com&quot;]))
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class StubService(object):
</span><span class="cx">     addDSAttrXProperties = False
</span><span class="cx">     directoryBackedAddressBook = None
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_proxyprincipaldbpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_proxyprincipaldb.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_proxyprincipaldb.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_proxyprincipaldb.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -17,7 +17,7 @@
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.directory import calendaruserproxy
</span><del>-from twistedcaldav.directory.calendaruserproxy import ProxySqliteDB,\
</del><ins>+from twistedcaldav.directory.calendaruserproxy import ProxySqliteDB, \
</ins><span class="cx">     ProxyPostgreSQLDB
</span><span class="cx"> from twistedcaldav.directory.calendaruserproxyloader import XMLCalendarUserProxyLoader
</span><span class="cx"> import twistedcaldav.test.util
</span><span class="lines">@@ -28,21 +28,21 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Directory service provisioned principals.
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">     class old_ProxyDB(ProxySqliteDB):
</span><del>-        
</del><ins>+
</ins><span class="cx">         def _db_version(self):
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="cx">             @return: the schema version assigned to this index.
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="cx">             return &quot;3&quot;
</span><del>-            
</del><ins>+
</ins><span class="cx">         def _db_init_data_tables(self):
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="cx">             Initialise the underlying database tables.
</span><span class="cx">             @param q:           a database cursor to use.
</span><span class="cx">             &quot;&quot;&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">             #
</span><span class="cx">             # GROUPS table
</span><span class="cx">             #
</span><span class="lines">@@ -55,70 +55,77 @@
</span><span class="cx">                 &quot;&quot;&quot;
</span><span class="cx">             )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     class new_ProxyDB(ProxySqliteDB):
</span><del>-        
</del><ins>+
</ins><span class="cx">         def _db_version(self):
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="cx">             @return: the schema version assigned to this index.
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="cx">             return &quot;11&quot;
</span><del>-            
</del><ins>+
+
</ins><span class="cx">     class newer_ProxyDB(ProxySqliteDB):
</span><del>-        
</del><ins>+
</ins><span class="cx">         def _db_version(self):
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="cx">             @return: the schema version assigned to this index.
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="cx">             return &quot;51&quot;
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_normalDB(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Get the DB
</span><span class="cx">         db_path = os.path.abspath(self.mktemp())
</span><span class="cx">         db = ProxySqliteDB(db_path)
</span><span class="cx">         yield db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><del>-        
</del><ins>+
</ins><span class="cx">         membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="cx">         membershipsB = yield db.getMemberships(&quot;B&quot;)
</span><del>-        
</del><ins>+
</ins><span class="cx">         self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">         self.assertEqual(membershipsB, set((&quot;A&quot;,)))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_normalDBNonAscii(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Get the DB
</span><span class="cx">         db_path = os.path.abspath(self.mktemp())
</span><span class="cx">         db = ProxySqliteDB(db_path)
</span><span class="cx">         principalID = &quot;Test \xe4\xbd\x90\xe8\x97\xa4&quot;
</span><span class="cx">         yield db.setGroupMembers(principalID, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><del>-        
</del><ins>+
</ins><span class="cx">         membersA = yield db.getMembers(principalID)
</span><span class="cx">         membershipsB = yield db.getMemberships(&quot;B&quot;)
</span><del>-        
</del><ins>+
</ins><span class="cx">         self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">         self.assertEqual(membershipsB, set((principalID,)))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_DBIndexed(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Get the DB
</span><span class="cx">         db_path = os.path.abspath(self.mktemp())
</span><span class="cx">         db = ProxySqliteDB(db_path)
</span><span class="cx">         self.assertEqual(set([row[1] for row in (yield db.query(&quot;PRAGMA index_list(GROUPS)&quot;))]), set((&quot;GROUPNAMES&quot;, &quot;MEMBERS&quot;)))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_OldDB(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Get the DB
</span><span class="cx">         db_path = os.path.abspath(self.mktemp())
</span><span class="cx">         db = self.old_ProxyDB(db_path)
</span><span class="cx">         self.assertEqual(set([row[1] for row in (yield db.query(&quot;PRAGMA index_list(GROUPS)&quot;))]), set())
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_DBUpgrade(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Get the DB
</span><span class="cx">         db_path = os.path.abspath(self.mktemp())
</span><span class="cx">         db = self.old_ProxyDB(db_path)
</span><span class="lines">@@ -132,7 +139,7 @@
</span><span class="cx">         self.assertEqual(set([row[1] for row in (yield db.query(&quot;PRAGMA index_list(GROUPS)&quot;))]), set())
</span><span class="cx">         db.close()
</span><span class="cx">         db = None
</span><del>-        
</del><ins>+
</ins><span class="cx">         db = ProxySqliteDB(db_path)
</span><span class="cx"> 
</span><span class="cx">         membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="lines">@@ -144,9 +151,10 @@
</span><span class="cx">         db.close()
</span><span class="cx">         db = None
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_DBUpgradeNewer(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Get the DB
</span><span class="cx">         db_path = os.path.abspath(self.mktemp())
</span><span class="cx">         db = self.old_ProxyDB(db_path)
</span><span class="lines">@@ -160,7 +168,7 @@
</span><span class="cx">         self.assertEqual(set([row[1] for row in (yield db.query(&quot;PRAGMA index_list(GROUPS)&quot;))]), set())
</span><span class="cx">         db.close()
</span><span class="cx">         db = None
</span><del>-        
</del><ins>+
</ins><span class="cx">         db = self.new_ProxyDB(db_path)
</span><span class="cx"> 
</span><span class="cx">         membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="lines">@@ -172,9 +180,10 @@
</span><span class="cx">         db.close()
</span><span class="cx">         db = None
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_DBNoUpgradeNewer(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Get the DB
</span><span class="cx">         db_path = os.path.abspath(self.mktemp())
</span><span class="cx">         db = self.new_ProxyDB(db_path)
</span><span class="lines">@@ -188,7 +197,7 @@
</span><span class="cx">         self.assertEqual(set([row[1] for row in (yield db.query(&quot;PRAGMA index_list(GROUPS)&quot;))]), set((&quot;GROUPNAMES&quot;, &quot;MEMBERS&quot;)))
</span><span class="cx">         db.close()
</span><span class="cx">         db = None
</span><del>-        
</del><ins>+
</ins><span class="cx">         db = self.newer_ProxyDB(db_path)
</span><span class="cx"> 
</span><span class="cx">         membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="lines">@@ -200,40 +209,41 @@
</span><span class="cx">         db.close()
</span><span class="cx">         db = None
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_cachingDBInsert(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         for processType in (&quot;Single&quot;, &quot;Combined&quot;,):
</span><span class="cx">             config.ProcessType = processType
</span><span class="cx"> 
</span><span class="cx">             # Get the DB
</span><span class="cx">             db_path = os.path.abspath(self.mktemp())
</span><span class="cx">             db = ProxySqliteDB(db_path)
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Do one insert and check the result
</span><span class="cx">             yield db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="cx">             membershipsB = yield db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield db.getMemberships(&quot;D&quot;)
</span><span class="cx">             membershipsE = yield db.getMemberships(&quot;E&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set((&quot;A&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsC, set((&quot;A&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsD, set((&quot;A&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsE, set(()))
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Change and check the result
</span><span class="cx">             yield db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;E&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="cx">             membershipsB = yield db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield db.getMemberships(&quot;D&quot;)
</span><span class="cx">             membershipsE = yield db.getMemberships(&quot;E&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;E&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set((&quot;A&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsC, set((&quot;A&quot;,)))
</span><span class="lines">@@ -242,41 +252,42 @@
</span><span class="cx"> 
</span><span class="cx">             yield db.clean()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_cachingDBRemove(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         for processType in (&quot;Single&quot;, &quot;Combined&quot;,):
</span><span class="cx">             config.ProcessType = processType
</span><span class="cx"> 
</span><span class="cx">             # Get the DB
</span><span class="cx">             db_path = os.path.abspath(self.mktemp())
</span><span class="cx">             db = ProxySqliteDB(db_path)
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Do one insert and check the result
</span><span class="cx">             yield db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><span class="cx">             yield db.setGroupMembers(&quot;X&quot;, (&quot;B&quot;, &quot;C&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="cx">             membersX = yield db.getMembers(&quot;X&quot;)
</span><span class="cx">             membershipsB = yield db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield db.getMemberships(&quot;D&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">             self.assertEqual(membersX, set((&quot;B&quot;, &quot;C&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set((&quot;A&quot;, &quot;X&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsC, set((&quot;A&quot;, &quot;X&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsD, set((&quot;A&quot;,)))
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Remove and check the result
</span><span class="cx">             yield db.removeGroup(&quot;A&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="cx">             membersX = yield db.getMembers(&quot;X&quot;)
</span><span class="cx">             membershipsB = yield db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield db.getMemberships(&quot;D&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set())
</span><span class="cx">             self.assertEqual(membersX, set((&quot;B&quot;, &quot;C&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set(&quot;X&quot;,))
</span><span class="lines">@@ -285,33 +296,34 @@
</span><span class="cx"> 
</span><span class="cx">             yield db.clean()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_cachingDBRemoveSpecial(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         for processType in (&quot;Single&quot;, &quot;Combined&quot;,):
</span><span class="cx">             config.ProcessType = processType
</span><span class="cx"> 
</span><span class="cx">             # Get the DB
</span><span class="cx">             db_path = os.path.abspath(self.mktemp())
</span><span class="cx">             db = ProxySqliteDB(db_path)
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Do one insert and check the result
</span><span class="cx">             yield db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><span class="cx">             yield db.setGroupMembers(&quot;X&quot;, (&quot;B&quot;, &quot;C&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membershipsB = yield db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield db.getMemberships(&quot;D&quot;)
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Remove and check the result
</span><span class="cx">             yield db.removeGroup(&quot;A&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="cx">             membersX = yield db.getMembers(&quot;X&quot;)
</span><span class="cx">             membershipsB = yield db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield db.getMemberships(&quot;D&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set())
</span><span class="cx">             self.assertEqual(membersX, set((&quot;B&quot;, &quot;C&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set(&quot;X&quot;,))
</span><span class="lines">@@ -320,41 +332,42 @@
</span><span class="cx"> 
</span><span class="cx">             yield db.clean()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_cachingDBRemovePrincipal(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         for processType in (&quot;Single&quot;, &quot;Combined&quot;,):
</span><span class="cx">             config.ProcessType = processType
</span><span class="cx"> 
</span><span class="cx">             # Get the DB
</span><span class="cx">             db_path = os.path.abspath(self.mktemp())
</span><span class="cx">             db = ProxySqliteDB(db_path)
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Do one insert and check the result
</span><span class="cx">             yield db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><span class="cx">             yield db.setGroupMembers(&quot;X&quot;, (&quot;B&quot;, &quot;C&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="cx">             membersX = yield db.getMembers(&quot;X&quot;)
</span><span class="cx">             membershipsB = yield db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield db.getMemberships(&quot;D&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">             self.assertEqual(membersX, set((&quot;B&quot;, &quot;C&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set((&quot;A&quot;, &quot;X&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsC, set((&quot;A&quot;, &quot;X&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsD, set((&quot;A&quot;,)))
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Remove and check the result
</span><span class="cx">             yield db.removePrincipal(&quot;B&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield db.getMembers(&quot;A&quot;)
</span><span class="cx">             membersX = yield db.getMembers(&quot;X&quot;)
</span><span class="cx">             membershipsB = yield db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield db.getMemberships(&quot;D&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set((&quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">             self.assertEqual(membersX, set((&quot;C&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set())
</span><span class="lines">@@ -363,29 +376,30 @@
</span><span class="cx"> 
</span><span class="cx">             yield db.clean()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_cachingDBInsertUncached(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         for processType in (&quot;Single&quot;, &quot;Combined&quot;,):
</span><span class="cx">             config.ProcessType = processType
</span><span class="cx"> 
</span><span class="cx">             # Get the DB
</span><span class="cx">             db_path = os.path.abspath(self.mktemp())
</span><span class="cx">             db = ProxySqliteDB(db_path)
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Do one insert and check the result for the one we will remove
</span><span class="cx">             yield db.setGroupMembers(&quot;AA&quot;, (&quot;BB&quot;, &quot;CC&quot;, &quot;DD&quot;,))
</span><span class="cx">             yield db.getMemberships(&quot;DD&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             # Change and check the result
</span><span class="cx">             yield db.setGroupMembers(&quot;AA&quot;, (&quot;BB&quot;, &quot;CC&quot;, &quot;EE&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersAA = yield db.getMembers(&quot;AA&quot;)
</span><span class="cx">             membershipsBB = yield db.getMemberships(&quot;BB&quot;)
</span><span class="cx">             membershipsCC = yield db.getMemberships(&quot;CC&quot;)
</span><span class="cx">             membershipsDD = yield db.getMemberships(&quot;DD&quot;)
</span><span class="cx">             membershipsEE = yield db.getMemberships(&quot;EE&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersAA, set((&quot;BB&quot;, &quot;CC&quot;, &quot;EE&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsBB, set((&quot;AA&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsCC, set((&quot;AA&quot;,)))
</span><span class="lines">@@ -394,11 +408,13 @@
</span><span class="cx"> 
</span><span class="cx">             yield db.clean()
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class ProxyPrincipalDBPostgreSQL (twistedcaldav.test.util.TestCase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Directory service provisioned principals.
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def setUp(self):
</span><span class="cx"> 
</span><span class="lines">@@ -406,209 +422,217 @@
</span><span class="cx">         self.db = ProxyPostgreSQLDB(host=&quot;localhost&quot;, database=&quot;proxies&quot;)
</span><span class="cx">         yield self.db.clean()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def tearDown(self):
</span><span class="cx">         yield self.db.close()
</span><span class="cx">         self.db = None
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_normalDB(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Get the DB
</span><span class="cx">         yield self.db.clean()
</span><del>-        
</del><ins>+
</ins><span class="cx">         calendaruserproxy.ProxyDBService = self.db
</span><span class="cx">         loader = XMLCalendarUserProxyLoader(&quot;/Volumes/Data/Users/cyrusdaboo/Documents/Development/Apple/eclipse/CalendarServer-3/conf/auth/proxies-test.xml&quot;)
</span><span class="cx">         yield loader.updateProxyDB()
</span><span class="cx"> 
</span><span class="cx">         yield self.db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><del>-        
</del><ins>+
</ins><span class="cx">         membersA = yield self.db.getMembers(&quot;A&quot;)
</span><span class="cx">         membershipsB = yield self.db.getMemberships(&quot;B&quot;)
</span><del>-        
</del><ins>+
</ins><span class="cx">         self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">         self.assertEqual(membershipsB, set((&quot;A&quot;,)))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_DBIndexed(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Get the DB
</span><span class="cx">         yield self.db.clean()
</span><span class="cx">         self.assertTrue((yield self.db.queryOne(&quot;select hasindexes from pg_tables where tablename = 'groups'&quot;)))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_cachingDBInsert(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         for processType in (&quot;Single&quot;, &quot;Combined&quot;,):
</span><span class="cx">             config.ProcessType = processType
</span><span class="cx"> 
</span><span class="cx">             # Get the DB
</span><span class="cx">             yield self.db.clean()
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Do one insert and check the result
</span><span class="cx">             yield self.db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield self.db.getMembers(&quot;A&quot;)
</span><span class="cx">             membershipsB = yield self.db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield self.db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield self.db.getMemberships(&quot;D&quot;)
</span><span class="cx">             membershipsE = yield self.db.getMemberships(&quot;E&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set((&quot;A&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsC, set((&quot;A&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsD, set((&quot;A&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsE, set(()))
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Change and check the result
</span><span class="cx">             yield self.db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;E&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield self.db.getMembers(&quot;A&quot;)
</span><span class="cx">             membershipsB = yield self.db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield self.db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield self.db.getMemberships(&quot;D&quot;)
</span><span class="cx">             membershipsE = yield self.db.getMemberships(&quot;E&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;E&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set((&quot;A&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsC, set((&quot;A&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsD, set())
</span><span class="cx">             self.assertEqual(membershipsE, set((&quot;A&quot;,)))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_cachingDBRemove(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         for processType in (&quot;Single&quot;, &quot;Combined&quot;,):
</span><span class="cx">             config.ProcessType = processType
</span><span class="cx"> 
</span><span class="cx">             # Get the DB
</span><span class="cx">             yield self.db.clean()
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Do one insert and check the result
</span><span class="cx">             yield self.db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><span class="cx">             yield self.db.setGroupMembers(&quot;X&quot;, (&quot;B&quot;, &quot;C&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield self.db.getMembers(&quot;A&quot;)
</span><span class="cx">             membersX = yield self.db.getMembers(&quot;X&quot;)
</span><span class="cx">             membershipsB = yield self.db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield self.db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield self.db.getMemberships(&quot;D&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">             self.assertEqual(membersX, set((&quot;B&quot;, &quot;C&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set((&quot;A&quot;, &quot;X&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsC, set((&quot;A&quot;, &quot;X&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsD, set((&quot;A&quot;,)))
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Remove and check the result
</span><span class="cx">             yield self.db.removeGroup(&quot;A&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield self.db.getMembers(&quot;A&quot;)
</span><span class="cx">             membersX = yield self.db.getMembers(&quot;X&quot;)
</span><span class="cx">             membershipsB = yield self.db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield self.db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield self.db.getMemberships(&quot;D&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set())
</span><span class="cx">             self.assertEqual(membersX, set((&quot;B&quot;, &quot;C&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set(&quot;X&quot;,))
</span><span class="cx">             self.assertEqual(membershipsC, set(&quot;X&quot;,))
</span><span class="cx">             self.assertEqual(membershipsD, set())
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_cachingDBRemoveSpecial(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         for processType in (&quot;Single&quot;, &quot;Combined&quot;,):
</span><span class="cx">             config.ProcessType = processType
</span><span class="cx"> 
</span><span class="cx">             # Get the DB
</span><span class="cx">             yield self.db.clean()
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Do one insert and check the result
</span><span class="cx">             yield self.db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><span class="cx">             yield self.db.setGroupMembers(&quot;X&quot;, (&quot;B&quot;, &quot;C&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membershipsB = yield self.db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield self.db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield self.db.getMemberships(&quot;D&quot;)
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Remove and check the result
</span><span class="cx">             yield self.db.removeGroup(&quot;A&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield self.db.getMembers(&quot;A&quot;)
</span><span class="cx">             membersX = yield self.db.getMembers(&quot;X&quot;)
</span><span class="cx">             membershipsB = yield self.db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield self.db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield self.db.getMemberships(&quot;D&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set())
</span><span class="cx">             self.assertEqual(membersX, set((&quot;B&quot;, &quot;C&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set(&quot;X&quot;,))
</span><span class="cx">             self.assertEqual(membershipsC, set(&quot;X&quot;,))
</span><span class="cx">             self.assertEqual(membershipsD, set())
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_cachingDBRemovePrincipal(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         for processType in (&quot;Single&quot;, &quot;Combined&quot;,):
</span><span class="cx">             config.ProcessType = processType
</span><span class="cx"> 
</span><span class="cx">             # Get the DB
</span><span class="cx">             yield self.db.clean()
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Do one insert and check the result
</span><span class="cx">             yield self.db.setGroupMembers(&quot;A&quot;, (&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,))
</span><span class="cx">             yield self.db.setGroupMembers(&quot;X&quot;, (&quot;B&quot;, &quot;C&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield self.db.getMembers(&quot;A&quot;)
</span><span class="cx">             membersX = yield self.db.getMembers(&quot;X&quot;)
</span><span class="cx">             membershipsB = yield self.db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield self.db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield self.db.getMemberships(&quot;D&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set((&quot;B&quot;, &quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">             self.assertEqual(membersX, set((&quot;B&quot;, &quot;C&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set((&quot;A&quot;, &quot;X&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsC, set((&quot;A&quot;, &quot;X&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsD, set((&quot;A&quot;,)))
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Remove and check the result
</span><span class="cx">             yield self.db.removePrincipal(&quot;B&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersA = yield self.db.getMembers(&quot;A&quot;)
</span><span class="cx">             membersX = yield self.db.getMembers(&quot;X&quot;)
</span><span class="cx">             membershipsB = yield self.db.getMemberships(&quot;B&quot;)
</span><span class="cx">             membershipsC = yield self.db.getMemberships(&quot;C&quot;)
</span><span class="cx">             membershipsD = yield self.db.getMemberships(&quot;D&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersA, set((&quot;C&quot;, &quot;D&quot;,)))
</span><span class="cx">             self.assertEqual(membersX, set((&quot;C&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsB, set())
</span><span class="cx">             self.assertEqual(membershipsC, set((&quot;A&quot;, &quot;X&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsD, set((&quot;A&quot;,),))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_cachingDBInsertUncached(self):
</span><del>-    
</del><ins>+
</ins><span class="cx">         for processType in (&quot;Single&quot;, &quot;Combined&quot;,):
</span><span class="cx">             config.ProcessType = processType
</span><span class="cx"> 
</span><span class="cx">             # Get the DB
</span><span class="cx">             yield self.db.clean()
</span><del>-            
</del><ins>+
</ins><span class="cx">             # Do one insert and check the result for the one we will remove
</span><span class="cx">             yield self.db.setGroupMembers(&quot;AA&quot;, (&quot;BB&quot;, &quot;CC&quot;, &quot;DD&quot;,))
</span><span class="cx">             yield self.db.getMemberships(&quot;DD&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             # Change and check the result
</span><span class="cx">             yield self.db.setGroupMembers(&quot;AA&quot;, (&quot;BB&quot;, &quot;CC&quot;, &quot;EE&quot;,))
</span><del>-    
</del><ins>+
</ins><span class="cx">             membersAA = yield self.db.getMembers(&quot;AA&quot;)
</span><span class="cx">             membershipsBB = yield self.db.getMemberships(&quot;BB&quot;)
</span><span class="cx">             membershipsCC = yield self.db.getMemberships(&quot;CC&quot;)
</span><span class="cx">             membershipsDD = yield self.db.getMemberships(&quot;DD&quot;)
</span><span class="cx">             membershipsEE = yield self.db.getMemberships(&quot;EE&quot;)
</span><del>-    
</del><ins>+
</ins><span class="cx">             self.assertEqual(membersAA, set((&quot;BB&quot;, &quot;CC&quot;, &quot;EE&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsBB, set((&quot;AA&quot;,)))
</span><span class="cx">             self.assertEqual(membershipsCC, set((&quot;AA&quot;,)))
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_resourcespy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_resources.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_resources.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_resources.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx"> #    def test_loadConfig(self):
</span><span class="cx"> #        directory = getDirectory()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordInPrimaryDirectory(self):
</span><span class="cx">         directory = getDirectory()
</span><span class="cx"> 
</span><span class="lines">@@ -48,6 +49,7 @@
</span><span class="cx">         record = directory.recordWithUID(&quot;user01&quot;)
</span><span class="cx">         self.assertNotEquals(record, None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordInSupplementalDirectory(self):
</span><span class="cx">         directory = getDirectory()
</span><span class="cx"> 
</span><span class="lines">@@ -55,6 +57,7 @@
</span><span class="cx">         record = directory.recordWithUID(&quot;resource01&quot;)
</span><span class="cx">         self.assertNotEquals(record, None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_augments(self):
</span><span class="cx">         directory = getDirectory()
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytesttest_xmlfilepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_xmlfile.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_xmlfile.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/test_xmlfile.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -38,49 +38,50 @@
</span><span class="cx">     ))
</span><span class="cx"> 
</span><span class="cx">     users = {
</span><del>-        &quot;admin&quot;      : { &quot;password&quot;: &quot;nimda&quot;,      &quot;guid&quot;: &quot;D11F03A0-97EA-48AF-9A6C-FAC7F3975766&quot;, &quot;addresses&quot;: () },
-        &quot;wsanchez&quot;   : { &quot;password&quot;: &quot;zehcnasw&quot;,   &quot;guid&quot;: &quot;6423F94A-6B76-4A3A-815B-D52CFD77935D&quot;, &quot;addresses&quot;: (&quot;mailto:wsanchez@example.com&quot;,) },
-        &quot;cdaboo&quot;     : { &quot;password&quot;: &quot;oobadc&quot;,     &quot;guid&quot;: &quot;5A985493-EE2C-4665-94CF-4DFEA3A89500&quot;, &quot;addresses&quot;: (&quot;mailto:cdaboo@example.com&quot;,)   },
-        &quot;lecroy&quot;     : { &quot;password&quot;: &quot;yorcel&quot;,     &quot;guid&quot;: &quot;8B4288F6-CC82-491D-8EF9-642EF4F3E7D0&quot;, &quot;addresses&quot;: (&quot;mailto:lecroy@example.com&quot;,)   },
-        &quot;dreid&quot;      : { &quot;password&quot;: &quot;dierd&quot;,      &quot;guid&quot;: &quot;5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1&quot;, &quot;addresses&quot;: (&quot;mailto:dreid@example.com&quot;,)    },
-        &quot;nocalendar&quot; : { &quot;password&quot;: &quot;radnelacon&quot;, &quot;guid&quot;: &quot;543D28BA-F74F-4D5F-9243-B3E3A61171E5&quot;, &quot;addresses&quot;: () },
-        &quot;user01&quot;     : { &quot;password&quot;: &quot;01user&quot;,     &quot;guid&quot;: None                                  , &quot;addresses&quot;: (&quot;mailto:c4ca4238a0@example.com&quot;,) },
-        &quot;user02&quot;     : { &quot;password&quot;: &quot;02user&quot;,     &quot;guid&quot;: None                                  , &quot;addresses&quot;: (&quot;mailto:c81e728d9d@example.com&quot;,) },
-    }
</del><ins>+        &quot;admin&quot;      : {&quot;password&quot;: &quot;nimda&quot;, &quot;guid&quot;: &quot;D11F03A0-97EA-48AF-9A6C-FAC7F3975766&quot;, &quot;addresses&quot;: ()},
+        &quot;wsanchez&quot;   : {&quot;password&quot;: &quot;zehcnasw&quot;, &quot;guid&quot;: &quot;6423F94A-6B76-4A3A-815B-D52CFD77935D&quot;, &quot;addresses&quot;: (&quot;mailto:wsanchez@example.com&quot;,)},
+        &quot;cdaboo&quot;     : {&quot;password&quot;: &quot;oobadc&quot;, &quot;guid&quot;: &quot;5A985493-EE2C-4665-94CF-4DFEA3A89500&quot;, &quot;addresses&quot;: (&quot;mailto:cdaboo@example.com&quot;,)  },
+        &quot;lecroy&quot;     : {&quot;password&quot;: &quot;yorcel&quot;, &quot;guid&quot;: &quot;8B4288F6-CC82-491D-8EF9-642EF4F3E7D0&quot;, &quot;addresses&quot;: (&quot;mailto:lecroy@example.com&quot;,)  },
+        &quot;dreid&quot;      : {&quot;password&quot;: &quot;dierd&quot;, &quot;guid&quot;: &quot;5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1&quot;, &quot;addresses&quot;: (&quot;mailto:dreid@example.com&quot;,)   },
+        &quot;nocalendar&quot; : {&quot;password&quot;: &quot;radnelacon&quot;, &quot;guid&quot;: &quot;543D28BA-F74F-4D5F-9243-B3E3A61171E5&quot;, &quot;addresses&quot;: ()},
+        &quot;user01&quot;     : {&quot;password&quot;: &quot;01user&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:c4ca4238a0@example.com&quot;,)},
+        &quot;user02&quot;     : {&quot;password&quot;: &quot;02user&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:c81e728d9d@example.com&quot;,)},
+   }
</ins><span class="cx"> 
</span><span class="cx">     groups = {
</span><del>-        &quot;admin&quot;      : { &quot;password&quot;: &quot;admin&quot;,       &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_groups, &quot;managers&quot;),)},
-        &quot;managers&quot;   : { &quot;password&quot;: &quot;managers&quot;,    &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_users , &quot;lecroy&quot;),)},
-        &quot;grunts&quot;     : { &quot;password&quot;: &quot;grunts&quot;,      &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_users , &quot;wsanchez&quot;),
</del><ins>+        &quot;admin&quot;      : {&quot;password&quot;: &quot;admin&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_groups, &quot;managers&quot;),)},
+        &quot;managers&quot;   : {&quot;password&quot;: &quot;managers&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_users , &quot;lecroy&quot;),)},
+        &quot;grunts&quot;     : {&quot;password&quot;: &quot;grunts&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_users , &quot;wsanchez&quot;),
</ins><span class="cx">                                                                                                (DirectoryService.recordType_users , &quot;cdaboo&quot;),
</span><span class="cx">                                                                                                (DirectoryService.recordType_users , &quot;dreid&quot;))},
</span><del>-        &quot;right_coast&quot;: { &quot;password&quot;: &quot;right_coast&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_users , &quot;cdaboo&quot;),)},
-        &quot;left_coast&quot; : { &quot;password&quot;: &quot;left_coast&quot;,  &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_users , &quot;wsanchez&quot;),
</del><ins>+        &quot;right_coast&quot;: {&quot;password&quot;: &quot;right_coast&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_users , &quot;cdaboo&quot;),)},
+        &quot;left_coast&quot; : {&quot;password&quot;: &quot;left_coast&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_users , &quot;wsanchez&quot;),
</ins><span class="cx">                                                                                                (DirectoryService.recordType_users , &quot;dreid&quot;),
</span><span class="cx">                                                                                                (DirectoryService.recordType_users , &quot;lecroy&quot;))},
</span><del>-        &quot;both_coasts&quot;: { &quot;password&quot;: &quot;both_coasts&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_groups, &quot;right_coast&quot;),
</del><ins>+        &quot;both_coasts&quot;: {&quot;password&quot;: &quot;both_coasts&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_groups, &quot;right_coast&quot;),
</ins><span class="cx">                                                                                                (DirectoryService.recordType_groups, &quot;left_coast&quot;))},
</span><del>-        &quot;recursive1_coasts&quot;:  { &quot;password&quot;: &quot;recursive1_coasts&quot;,  &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_groups, &quot;recursive2_coasts&quot;),
</del><ins>+        &quot;recursive1_coasts&quot;: {&quot;password&quot;: &quot;recursive1_coasts&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_groups, &quot;recursive2_coasts&quot;),
</ins><span class="cx">                                                                                                (DirectoryService.recordType_users, &quot;wsanchez&quot;))},
</span><del>-        &quot;recursive2_coasts&quot;:  { &quot;password&quot;: &quot;recursive2_coasts&quot;,  &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_groups, &quot;recursive1_coasts&quot;),
</del><ins>+        &quot;recursive2_coasts&quot;: {&quot;password&quot;: &quot;recursive2_coasts&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_groups, &quot;recursive1_coasts&quot;),
</ins><span class="cx">                                                                                                (DirectoryService.recordType_users, &quot;cdaboo&quot;))},
</span><del>-        &quot;non_calendar_group&quot;: { &quot;password&quot;: &quot;non_calendar_group&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_users , &quot;cdaboo&quot;),
</del><ins>+        &quot;non_calendar_group&quot;: {&quot;password&quot;: &quot;non_calendar_group&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (), &quot;members&quot;: ((DirectoryService.recordType_users , &quot;cdaboo&quot;),
</ins><span class="cx">                                                                                                (DirectoryService.recordType_users , &quot;lecroy&quot;))},
</span><del>-    }
</del><ins>+   }
</ins><span class="cx"> 
</span><span class="cx">     locations = {
</span><del>-        &quot;mercury&quot;: { &quot;password&quot;: &quot;mercury&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:mercury@example.com&quot;,) },
-        &quot;gemini&quot; : { &quot;password&quot;: &quot;gemini&quot;,  &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:gemini@example.com&quot;,)  },
-        &quot;apollo&quot; : { &quot;password&quot;: &quot;apollo&quot;,  &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:apollo@example.com&quot;,)  },
-        &quot;orion&quot;  : { &quot;password&quot;: &quot;orion&quot;,   &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:orion@example.com&quot;,)   },
-    }
</del><ins>+        &quot;mercury&quot;: {&quot;password&quot;: &quot;mercury&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:mercury@example.com&quot;,)},
+        &quot;gemini&quot; : {&quot;password&quot;: &quot;gemini&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:gemini@example.com&quot;,)},
+        &quot;apollo&quot; : {&quot;password&quot;: &quot;apollo&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:apollo@example.com&quot;,)},
+        &quot;orion&quot;  : {&quot;password&quot;: &quot;orion&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:orion@example.com&quot;,)},
+   }
</ins><span class="cx"> 
</span><span class="cx">     resources = {
</span><del>-        &quot;transporter&quot;        : { &quot;password&quot;: &quot;transporter&quot;,        &quot;guid&quot;: None,                 &quot;addresses&quot;: (&quot;mailto:transporter@example.com&quot;,)        },
-        &quot;ftlcpu&quot;             : { &quot;password&quot;: &quot;ftlcpu&quot;,             &quot;guid&quot;: None,                 &quot;addresses&quot;: (&quot;mailto:ftlcpu@example.com&quot;,)             },
-        &quot;non_calendar_proxy&quot; : { &quot;password&quot;: &quot;non_calendar_proxy&quot;, &quot;guid&quot;: &quot;non_calendar_proxy&quot;, &quot;addresses&quot;: (&quot;mailto:non_calendar_proxy@example.com&quot;,) },
-    }
</del><ins>+        &quot;transporter&quot;        : {&quot;password&quot;: &quot;transporter&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:transporter@example.com&quot;,)       },
+        &quot;ftlcpu&quot;             : {&quot;password&quot;: &quot;ftlcpu&quot;, &quot;guid&quot;: None, &quot;addresses&quot;: (&quot;mailto:ftlcpu@example.com&quot;,)            },
+        &quot;non_calendar_proxy&quot; : {&quot;password&quot;: &quot;non_calendar_proxy&quot;, &quot;guid&quot;: &quot;non_calendar_proxy&quot;, &quot;addresses&quot;: (&quot;mailto:non_calendar_proxy@example.com&quot;,)},
+   }
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def xmlFile(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Create a L{FilePath} that points to a temporary file containing a copy
</span><span class="lines">@@ -155,10 +156,10 @@
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx">         )
</span><span class="cx">         for recordType, expectedRecords in (
</span><del>-            ( DirectoryService.recordType_users     , (&quot;admin&quot;,) ),
-            ( DirectoryService.recordType_groups    , ()         ),
-            ( DirectoryService.recordType_locations , ()         ),
-            ( DirectoryService.recordType_resources , ()         ),
</del><ins>+            (DirectoryService.recordType_users     , (&quot;admin&quot;,)),
+            (DirectoryService.recordType_groups    , ()),
+            (DirectoryService.recordType_locations , ()),
+            (DirectoryService.recordType_resources , ()),
</ins><span class="cx">         ):
</span><span class="cx">             # Fault records in
</span><span class="cx">             for name in expectedRecords:
</span><span class="lines">@@ -169,6 +170,7 @@
</span><span class="cx">                 set(expectedRecords)
</span><span class="cx">             )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_okAutoSchedule(self):
</span><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><span class="lines">@@ -201,10 +203,10 @@
</span><span class="cx">         service.augmentService.refresh()
</span><span class="cx"> 
</span><span class="cx">         for recordType, expectedRecords in (
</span><del>-            ( DirectoryService.recordType_users     , ()             ),
-            ( DirectoryService.recordType_groups    , ()             ),
-            ( DirectoryService.recordType_locations , (&quot;my office&quot;,) ),
-            ( DirectoryService.recordType_resources , ()             ),
</del><ins>+            (DirectoryService.recordType_users     , ()),
+            (DirectoryService.recordType_groups    , ()),
+            (DirectoryService.recordType_locations , (&quot;my office&quot;,)),
+            (DirectoryService.recordType_resources , ()),
</ins><span class="cx">         ):
</span><span class="cx">             # Fault records in
</span><span class="cx">             for name in expectedRecords:
</span><span class="lines">@@ -239,12 +241,12 @@
</span><span class="cx"> &lt;/accounts&gt;
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx">         )
</span><del>-        
</del><ins>+
</ins><span class="cx">         for recordType, expectedRecords in (
</span><del>-            ( DirectoryService.recordType_users     , ()                       ),
-            ( DirectoryService.recordType_groups    , (&quot;enabled&quot;, &quot;disabled&quot;)  ),
-            ( DirectoryService.recordType_locations , ()                       ),
-            ( DirectoryService.recordType_resources , ()                       ),
</del><ins>+            (DirectoryService.recordType_users     , ()),
+            (DirectoryService.recordType_groups    , (&quot;enabled&quot;, &quot;disabled&quot;)),
+            (DirectoryService.recordType_locations , ()),
+            (DirectoryService.recordType_resources , ()),
</ins><span class="cx">         ):
</span><span class="cx">             # Fault records in
</span><span class="cx">             for name in expectedRecords:
</span><span class="lines">@@ -279,13 +281,14 @@
</span><span class="cx"> &lt;/accounts&gt;
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx">         )
</span><del>-        
</del><ins>+
</ins><span class="cx">         record = service.recordWithShortName(
</span><span class="cx">             DirectoryService.recordType_locations, &quot;my office&quot;)
</span><span class="cx">         self.assertEquals(record.guid, &quot;myoffice&quot;)
</span><span class="cx">         self.assertEquals(record.extras[&quot;comment&quot;], &quot;This is the comment&quot;)
</span><span class="cx">         self.assertEquals(record.extras[&quot;capacity&quot;], &quot;40&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_writeExtras(self):
</span><span class="cx">         service = self.service()
</span><span class="cx"> 
</span><span class="lines">@@ -302,7 +305,6 @@
</span><span class="cx">         self.assertEquals(record.extras[&quot;comment&quot;], &quot;Test comment&quot;)
</span><span class="cx">         self.assertEquals(record.extras[&quot;capacity&quot;], &quot;10&quot;)
</span><span class="cx"> 
</span><del>-
</del><span class="cx">         service.updateRecord(DirectoryService.recordType_locations, &quot;newguid&quot;,
</span><span class="cx">             shortNames=(&quot;New office&quot;,),
</span><span class="cx">             fullName=&quot;My Newer Office&quot;,
</span><span class="lines">@@ -333,6 +335,7 @@
</span><span class="cx">         self.assertNotEquals(None, service._lookupInIndex(service.recordType_locations, service.INDEX_TYPE_SHORTNAME, &quot;orion&quot;))
</span><span class="cx">         self.assertEquals(None, service._lookupInIndex(service.recordType_users, service.INDEX_TYPE_CUA, &quot;mailto:nobody@example.com&quot;))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_repeat(self):
</span><span class="cx">         service = self.service()
</span><span class="cx">         record = service.recordWithShortName(
</span><span class="lines">@@ -342,6 +345,8 @@
</span><span class="cx">         self.assertEquals(record.lastName, &quot;c4ca4238a User 01&quot;)
</span><span class="cx">         self.assertEquals(record.emailAddresses, set(['c4ca4238a0@example.com']))
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class XMLFileSubset (XMLFileBase, TestCase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Test the recordTypes subset feature of XMLFile service.
</span><span class="lines">@@ -351,6 +356,7 @@
</span><span class="cx">         DirectoryService.recordType_groups,
</span><span class="cx">     ))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordTypesSubset(self):
</span><span class="cx">         directory = XMLDirectoryService(
</span><span class="cx">             {
</span><span class="lines">@@ -366,4 +372,3 @@
</span><span class="cx">             alwaysStat=True
</span><span class="cx">         )
</span><span class="cx">         self.assertEquals(set((&quot;users&quot;, &quot;groups&quot;)), set(directory.recordTypes()))
</span><del>-    
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectorytestutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/util.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/util.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/test/util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -54,12 +54,14 @@
</span><span class="cx">     # For aggregator subclasses
</span><span class="cx">     recordTypePrefixes = (&quot;&quot;,)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_realm(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         IDirectoryService.realm
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         self.failUnless(self.service().realmName)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordTypes(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         IDirectoryService.recordTypes()
</span><span class="lines">@@ -69,15 +71,16 @@
</span><span class="cx"> 
</span><span class="cx">         self.assertEquals(set(self.service().recordTypes()), self.recordTypes)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordWithShortName(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         IDirectoryService.recordWithShortName()
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         for recordType, data in (
</span><del>-            ( DirectoryService.recordType_users    , self.users     ),
-            ( DirectoryService.recordType_groups   , self.groups    ),
-            ( DirectoryService.recordType_locations, self.locations ),
-            ( DirectoryService.recordType_resources, self.resources ),
</del><ins>+            (DirectoryService.recordType_users    , self.users),
+            (DirectoryService.recordType_groups   , self.groups),
+            (DirectoryService.recordType_locations, self.locations),
+            (DirectoryService.recordType_resources, self.resources),
</ins><span class="cx">         ):
</span><span class="cx">             if not data:
</span><span class="cx">                 raise SkipTest(&quot;No %s&quot; % (recordType,))
</span><span class="lines">@@ -95,6 +98,7 @@
</span><span class="cx">                     continue
</span><span class="cx">                 self.assertEquals(record, None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordWithUID(self):
</span><span class="cx">         service = self.service()
</span><span class="cx">         record = None
</span><span class="lines">@@ -108,6 +112,7 @@
</span><span class="cx">         if record is None:
</span><span class="cx">             raise SkipTest(&quot;No GUIDs provided to test&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_recordWithCalendarUserAddress(self):
</span><span class="cx">         service = self.service()
</span><span class="cx">         record = None
</span><span class="lines">@@ -120,6 +125,7 @@
</span><span class="cx">         if record is None:
</span><span class="cx">             raise SkipTest(&quot;No calendar user addresses provided to test&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_groupMembers(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         IDirectoryRecord.members()
</span><span class="lines">@@ -138,6 +144,7 @@
</span><span class="cx">                 &quot;Wrong membership for group %r: %s != %s&quot; % (group, result, expected)
</span><span class="cx">             )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_groupMemberships(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         IDirectoryRecord.groups()
</span><span class="lines">@@ -148,8 +155,8 @@
</span><span class="cx">             raise SkipTest(&quot;No groups&quot;)
</span><span class="cx"> 
</span><span class="cx">         for recordType, data in (
</span><del>-            ( DirectoryService.recordType_users , self.users  ),
-            ( DirectoryService.recordType_groups, self.groups ),
</del><ins>+            (DirectoryService.recordType_users , self.users),
+            (DirectoryService.recordType_groups, self.groups),
</ins><span class="cx">         ):
</span><span class="cx">             service = self.service()
</span><span class="cx">             for shortName, info in data.iteritems():
</span><span class="lines">@@ -162,6 +169,7 @@
</span><span class="cx">                     &quot;Wrong groups for %s %r: %s != %s&quot; % (record.recordType, shortName, result, expected)
</span><span class="cx">                 )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def recordNames(self, recordType):
</span><span class="cx">         service = self.service()
</span><span class="cx">         names = set()
</span><span class="lines">@@ -176,16 +184,18 @@
</span><span class="cx"> 
</span><span class="cx">         return names
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def allEntries(self):
</span><span class="cx">         for data, _ignore_recordType in (
</span><del>-            (self.users,     DirectoryService.recordType_users    ),
-            (self.groups,    DirectoryService.recordType_groups   ),
</del><ins>+            (self.users, DirectoryService.recordType_users),
+            (self.groups, DirectoryService.recordType_groups),
</ins><span class="cx">             (self.locations, DirectoryService.recordType_locations),
</span><span class="cx">             (self.resources, DirectoryService.recordType_resources),
</span><span class="cx">         ):
</span><span class="cx">             for item in data.iteritems():
</span><span class="cx">                 yield item
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def compare(self, record, shortName, data):
</span><span class="cx">         def value(key):
</span><span class="cx">             if key in data:
</span><span class="lines">@@ -217,6 +227,7 @@
</span><span class="cx">         if value(&quot;name&quot;):
</span><span class="cx">             self.assertEquals(record.fullName, value(&quot;name&quot;))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def servicePrefix(self):
</span><span class="cx">         service = self.service()
</span><span class="cx">         if hasattr(service, &quot;recordTypePrefix&quot;):
</span><span class="lines">@@ -224,6 +235,8 @@
</span><span class="cx">         else:
</span><span class="cx">             return &quot;&quot;
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class NonCachingTestCase (DirectoryTestCase):
</span><span class="cx"> 
</span><span class="cx">     def test_listRecords_user(self):
</span><span class="lines">@@ -235,6 +248,7 @@
</span><span class="cx"> 
</span><span class="cx">         self.assertEquals(self.recordNames(DirectoryService.recordType_users), set(self.users.keys()))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_listRecords_group(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         IDirectoryService.listRecords(DirectoryService.recordType_groups)
</span><span class="lines">@@ -244,6 +258,7 @@
</span><span class="cx"> 
</span><span class="cx">         self.assertEquals(self.recordNames(DirectoryService.recordType_groups), set(self.groups.keys()))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_listRecords_locations(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         IDirectoryService.listRecords(&quot;locations&quot;)
</span><span class="lines">@@ -253,6 +268,7 @@
</span><span class="cx"> 
</span><span class="cx">         self.assertEquals(self.recordNames(DirectoryService.recordType_locations), set(self.locations.keys()))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def test_listRecords_resources(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         IDirectoryService.listRecords(&quot;resources&quot;)
</span><span class="lines">@@ -263,6 +279,7 @@
</span><span class="cx">         self.assertEquals(self.recordNames(DirectoryService.recordType_resources), set(self.resources.keys()))
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class BasicTestCase (DirectoryTestCase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Tests a directory implementation with basic auth.
</span><span class="lines">@@ -279,6 +296,8 @@
</span><span class="cx">             userRecord = service.recordWithShortName(DirectoryService.recordType_users, user)
</span><span class="cx">             self.failUnless(userRecord.verifyCredentials(UsernamePassword(user, self.users[user][&quot;password&quot;])))
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> # authRequest = {
</span><span class="cx"> #    username=&quot;username&quot;,
</span><span class="cx"> #    realm=&quot;test realm&quot;,
</span><span class="lines">@@ -351,6 +370,8 @@
</span><span class="cx">                 else:
</span><span class="cx">                     self.failIf(userRecord.verifyCredentials(credentials))
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def maybeCommit(req):
</span><span class="cx">     class JustForCleanup(object):
</span><span class="cx">         def newTransaction(self, *whatever):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdirectoryxmlaugmentsparserpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/xmlaugmentsparser.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/xmlaugmentsparser.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/directory/xmlaugmentsparser.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -30,38 +30,36 @@
</span><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><del>-ELEMENT_AUGMENTS          = &quot;augments&quot;
-ELEMENT_RECORD            = &quot;record&quot;
</del><ins>+ELEMENT_AUGMENTS = &quot;augments&quot;
+ELEMENT_RECORD = &quot;record&quot;
</ins><span class="cx"> 
</span><del>-ELEMENT_UID               = &quot;uid&quot;
-ELEMENT_ENABLE            = &quot;enable&quot;
-ELEMENT_SERVERID          = &quot;server-id&quot;
-ELEMENT_PARTITIONID       = &quot;partition-id&quot;
-ELEMENT_HOSTEDAT          = &quot;hosted-at&quot;   # Backwards compatibility
-ELEMENT_ENABLECALENDAR    = &quot;enable-calendar&quot;
</del><ins>+ELEMENT_UID = &quot;uid&quot;
+ELEMENT_ENABLE = &quot;enable&quot;
+ELEMENT_SERVERID = &quot;server-id&quot;
+ELEMENT_PARTITIONID = &quot;partition-id&quot;   # Backwards compatibility
+ELEMENT_HOSTEDAT = &quot;hosted-at&quot;   # Backwards compatibility
+ELEMENT_ENABLECALENDAR = &quot;enable-calendar&quot;
</ins><span class="cx"> ELEMENT_ENABLEADDRESSBOOK = &quot;enable-addressbook&quot;
</span><del>-ELEMENT_ENABLELOGIN       = &quot;enable-login&quot;
-ELEMENT_AUTOSCHEDULE      = &quot;auto-schedule&quot;
</del><ins>+ELEMENT_ENABLELOGIN = &quot;enable-login&quot;
+ELEMENT_AUTOSCHEDULE = &quot;auto-schedule&quot;
</ins><span class="cx"> ELEMENT_AUTOSCHEDULE_MODE = &quot;auto-schedule-mode&quot;
</span><del>-ELEMENT_AUTOACCEPTGROUP   = &quot;auto-accept-group&quot;
</del><ins>+ELEMENT_AUTOACCEPTGROUP = &quot;auto-accept-group&quot;
</ins><span class="cx"> 
</span><del>-ATTRIBUTE_REPEAT          = &quot;repeat&quot;
</del><ins>+ATTRIBUTE_REPEAT = &quot;repeat&quot;
</ins><span class="cx"> 
</span><del>-VALUE_TRUE                = &quot;true&quot;
-VALUE_FALSE               = &quot;false&quot;
</del><ins>+VALUE_TRUE = &quot;true&quot;
+VALUE_FALSE = &quot;false&quot;
</ins><span class="cx"> 
</span><span class="cx"> ELEMENT_AUGMENTRECORD_MAP = {
</span><del>-    ELEMENT_UID:               &quot;uid&quot;,
-    ELEMENT_ENABLE:            &quot;enabled&quot;,
-    ELEMENT_SERVERID:          &quot;serverID&quot;,
-    ELEMENT_PARTITIONID:       &quot;partitionID&quot;,
-    ELEMENT_HOSTEDAT:          &quot;partitionID&quot;,   # Backwards compatibility
-    ELEMENT_ENABLECALENDAR:    &quot;enabledForCalendaring&quot;,
</del><ins>+    ELEMENT_UID: &quot;uid&quot;,
+    ELEMENT_ENABLE: &quot;enabled&quot;,
+    ELEMENT_SERVERID: &quot;serverID&quot;,
+    ELEMENT_ENABLECALENDAR: &quot;enabledForCalendaring&quot;,
</ins><span class="cx">     ELEMENT_ENABLEADDRESSBOOK: &quot;enabledForAddressBooks&quot;,
</span><del>-    ELEMENT_ENABLELOGIN:       &quot;enabledForLogin&quot;,
-    ELEMENT_AUTOSCHEDULE:      &quot;autoSchedule&quot;,
</del><ins>+    ELEMENT_ENABLELOGIN: &quot;enabledForLogin&quot;,
+    ELEMENT_AUTOSCHEDULE: &quot;autoSchedule&quot;,
</ins><span class="cx">     ELEMENT_AUTOSCHEDULE_MODE: &quot;autoScheduleMode&quot;,
</span><del>-    ELEMENT_AUTOACCEPTGROUP:   &quot;autoAcceptGroup&quot;,
</del><ins>+    ELEMENT_AUTOACCEPTGROUP: &quot;autoAcceptGroup&quot;,
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> class XMLAugmentsParser(object):
</span><span class="lines">@@ -71,6 +69,7 @@
</span><span class="cx">     def __repr__(self):
</span><span class="cx">         return &quot;&lt;%s %r&gt;&quot; % (self.__class__.__name__, self.xmlFile)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def __init__(self, xmlFile, items):
</span><span class="cx"> 
</span><span class="cx">         self.items = items
</span><span class="lines">@@ -84,13 +83,14 @@
</span><span class="cx"> 
</span><span class="cx">         self._parseXML(augments_node)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _parseXML(self, rootnode):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Parse the XML root node from the augments configuration document.
</span><span class="cx">         @param rootnode: the L{Element} to parse.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         for child in rootnode:
</span><del>-            
</del><ins>+
</ins><span class="cx">             if child.tag != ELEMENT_RECORD:
</span><span class="cx">                 raise RuntimeError(&quot;Unknown augment type: '%s' in augment file: '%s'&quot; % (child.tag, self.xmlFile,))
</span><span class="cx"> 
</span><span class="lines">@@ -98,7 +98,7 @@
</span><span class="cx"> 
</span><span class="cx">             fields = {}
</span><span class="cx">             for node in child:
</span><del>-                
</del><ins>+
</ins><span class="cx">                 if node.tag in (
</span><span class="cx">                     ELEMENT_UID,
</span><span class="cx">                     ELEMENT_SERVERID,
</span><span class="lines">@@ -118,33 +118,35 @@
</span><span class="cx">                     fields[node.tag] = node.text == VALUE_TRUE
</span><span class="cx">                 else:
</span><span class="cx">                     raise RuntimeError(&quot;Invalid element '%s' in augment file: '%s'&quot; % (node.tag, self.xmlFile,))
</span><del>-                    
</del><ins>+
</ins><span class="cx">             # Must have at least a uid
</span><span class="cx">             if ELEMENT_UID not in fields:
</span><span class="cx">                 raise RuntimeError(&quot;Invalid record '%s' without a uid in augment file: '%s'&quot; % (child, self.xmlFile,))
</span><del>-                
</del><ins>+
</ins><span class="cx">             if repeat &gt; 1:
</span><del>-                for i in xrange(1, repeat+1):
</del><ins>+                for i in xrange(1, repeat + 1):
</ins><span class="cx">                     self.buildRecord(fields, i)
</span><span class="cx">             else:
</span><span class="cx">                 self.buildRecord(fields)
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def buildRecord(self, fields, count=None):
</span><del>-        
</del><ins>+
</ins><span class="cx">         from twistedcaldav.directory.augment import AugmentRecord
</span><span class="cx"> 
</span><span class="cx">         def expandCount(value, count):
</span><del>-            
</del><ins>+
</ins><span class="cx">             if type(value) in types.StringTypes:
</span><span class="cx">                 return value % (count,) if count and &quot;%&quot; in value else value
</span><span class="cx">             elif type(value) == set:
</span><span class="cx">                 return set([item % (count,) if count and &quot;%&quot; in item else item for item in value])
</span><span class="cx">             else:
</span><span class="cx">                 return value
</span><del>-        
</del><ins>+
</ins><span class="cx">         actualFields = {}
</span><del>-        for k,v in fields.iteritems():
-            actualFields[ELEMENT_AUGMENTRECORD_MAP[k]] = expandCount(v, count)
</del><ins>+        for k, v in fields.iteritems():
+            if k in ELEMENT_AUGMENTRECORD_MAP:
+                actualFields[ELEMENT_AUGMENTRECORD_MAP[k]] = expandCount(v, count)
</ins><span class="cx"> 
</span><span class="cx">         record = AugmentRecord(**actualFields)
</span><span class="cx">         self.items[record.uid] = record
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavdropboxpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/dropbox.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/dropbox.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/dropbox.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -44,12 +44,15 @@
</span><span class="cx">     def resourceType(self):
</span><span class="cx">         return davxml.ResourceType.dropboxhome #@UndefinedVariable
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def isCollection(self):
</span><span class="cx">         return True
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def http_PUT(self, request):
</span><span class="cx">         return responsecode.FORBIDDEN
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def accessControlList(self, request, *args, **kwargs):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -57,7 +60,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         acl = (yield super(DropBoxHomeResource, self).accessControlList(request, *args, **kwargs))
</span><del>-        
</del><ins>+
</ins><span class="cx">         if config.EnableProxyPrincipals:
</span><span class="cx">             owner = (yield self.ownerPrincipal(request))
</span><span class="cx"> 
</span><span class="lines">@@ -75,10 +78,12 @@
</span><span class="cx">             )
</span><span class="cx"> 
</span><span class="cx">             returnValue(davxml.ACL(*newaces))
</span><del>-        
</del><ins>+
</ins><span class="cx">         else:
</span><span class="cx">             returnValue(acl)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class DropBoxCollectionResource (DAVResource):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Drop box resource.
</span><span class="lines">@@ -99,7 +104,7 @@
</span><span class="cx">         calendar collection have the same privileges unless explicitly overridden. The same applies
</span><span class="cx">         to drop box collections as we want all resources (attachments) to have the same privileges as
</span><span class="cx">         the drop box collection.
</span><del>-        
</del><ins>+
</ins><span class="cx">         @param newaces: C{list} of L{ACE} for ACL being set.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         # Add inheritable option to each ACE in the list
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavextensionspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/extensions.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/extensions.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/extensions.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -494,13 +494,13 @@
</span><span class="cx">             size = child.contentLength()
</span><span class="cx">             lastModified = child.lastModified()
</span><span class="cx">             rtypes = []
</span><del>-            fullrtype = child.resourceType()
</del><ins>+            fullrtype = child.resourceType() if hasattr(child, &quot;resourceType&quot;) else None
</ins><span class="cx">             if fullrtype is not None:
</span><span class="cx">                 for rtype in fullrtype.children:
</span><span class="cx">                     rtypes.append(rtype.name)
</span><span class="cx">             if rtypes:
</span><span class="cx">                 rtypes = &quot;(%s)&quot; % (&quot;, &quot;.join(rtypes),)
</span><del>-            if child.isCollection():
</del><ins>+            if child.isCollection() if hasattr(child, &quot;isCollection&quot;) else False:
</ins><span class="cx">                 contentType = rtypes
</span><span class="cx">             else:
</span><span class="cx">                 mimeType = child.contentType()
</span><span class="lines">@@ -1004,6 +1004,7 @@
</span><span class="cx">     return tokens, context, applyTo, clientLimit, propElement
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def validateTokens(tokens):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Make sure there is at least one token longer than one character
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavfreebusyurlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/freebusyurl.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/freebusyurl.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/freebusyurl.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -47,8 +47,8 @@
</span><span class="cx"> from txdav.caldav.datastore.scheduling.cuaddress import LocalCalendarUser
</span><span class="cx"> from txdav.caldav.datastore.scheduling.scheduler import Scheduler
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -189,15 +189,15 @@
</span><span class="cx">         # Start/end/duration must be valid iCalendar DATE-TIME UTC or DURATION values
</span><span class="cx">         try:
</span><span class="cx">             if self.start:
</span><del>-                self.start = PyCalendarDateTime.parseText(self.start)
</del><ins>+                self.start = DateTime.parseText(self.start)
</ins><span class="cx">                 if not self.start.utc():
</span><span class="cx">                     raise ValueError()
</span><span class="cx">             if self.end:
</span><del>-                self.end = PyCalendarDateTime.parseText(self.end)
</del><ins>+                self.end = DateTime.parseText(self.end)
</ins><span class="cx">                 if not self.end.utc():
</span><span class="cx">                     raise ValueError()
</span><span class="cx">             if self.duration:
</span><del>-                self.duration = PyCalendarDuration.parseText(self.duration)
</del><ins>+                self.duration = Duration.parseText(self.duration)
</ins><span class="cx">         except ValueError:
</span><span class="cx">             raise HTTPError(ErrorResponse(
</span><span class="cx">                 responsecode.BAD_REQUEST,
</span><span class="lines">@@ -225,12 +225,12 @@
</span><span class="cx"> 
</span><span class="cx">         # Now fill in the missing pieces
</span><span class="cx">         if self.start is None:
</span><del>-            self.start = PyCalendarDateTime.getNowUTC()
</del><ins>+            self.start = DateTime.getNowUTC()
</ins><span class="cx">             self.start.setHHMMSS(0, 0, 0)
</span><span class="cx">         if self.duration:
</span><span class="cx">             self.end = self.start + self.duration
</span><span class="cx">         if self.end is None:
</span><del>-            self.end = self.start + PyCalendarDuration(days=config.FreeBusyURL.TimePeriod)
</del><ins>+            self.end = self.start + Duration(days=config.FreeBusyURL.TimePeriod)
</ins><span class="cx"> 
</span><span class="cx">         # End &gt; start
</span><span class="cx">         if self.end &lt;= self.start:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavicalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/ical.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/ical.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/ical.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -28,7 +28,6 @@
</span><span class="cx">     &quot;tzexpand&quot;,
</span><span class="cx"> ]
</span><span class="cx"> 
</span><del>-import cStringIO as StringIO
</del><span class="cx"> import codecs
</span><span class="cx"> from difflib import unified_diff
</span><span class="cx"> import heapq
</span><span class="lines">@@ -46,31 +45,34 @@
</span><span class="cx"> from txdav.caldav.datastore.scheduling.cuaddress import normalizeCUAddr
</span><span class="cx"> from twistedcaldav.timezones import hasTZ, TimezoneException
</span><span class="cx"> 
</span><del>-from pycalendar import definitions
-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.calendar import PyCalendar
-from pycalendar.componentbase import PyCalendarComponentBase
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.exceptions import PyCalendarError
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.property import PyCalendarProperty
-from pycalendar.timezone import PyCalendarTimezone
-from pycalendar.utcoffsetvalue import PyCalendarUTCOffsetValue
</del><ins>+from pycalendar.icalendar import definitions
+from pycalendar.parameter import Parameter
+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.icalendar.component import Component as PyComponent
+from pycalendar.componentbase import ComponentBase
+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
+from pycalendar.exceptions import ErrorBase
+from pycalendar.period import Period
+from pycalendar.icalendar.property import Property as PyProperty
+from pycalendar.timezone import Timezone
+from pycalendar.utcoffsetvalue import UTCOffsetValue
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="cx"> iCalendarProductID = &quot;-//CALENDARSERVER.ORG//NONSGML Version 1//EN&quot;
</span><span class="cx"> 
</span><del>-allowedComponents = (
-    &quot;VEVENT&quot;,
-    &quot;VTODO&quot;,
-    &quot;VTIMEZONE&quot;,
-    # &quot;VJOURNAL&quot;,
-    &quot;VFREEBUSY&quot;,
-    # &quot;VAVAILABILITY&quot;,
-)
</del><ins>+allowedStoreComponents = (&quot;VEVENT&quot;, &quot;VTODO&quot;, &quot;VPOLL&quot;,)
+allowedSchedulingComponents = allowedStoreComponents + (&quot;VFREEBUSY&quot;,)
+allowedComponents = allowedSchedulingComponents + (&quot;VTIMEZONE&quot;,)
</ins><span class="cx"> 
</span><ins>+def _updateAllowedComponents(allowed):
+    global allowedStoreComponents, allowedSchedulingComponents, allowedComponents
+    allowedStoreComponents = allowed
+    allowedSchedulingComponents = allowedStoreComponents + (&quot;VFREEBUSY&quot;,)
+    allowedComponents = allowedSchedulingComponents + (&quot;VTIMEZONE&quot;,)
+
+
</ins><span class="cx"> # Additional per-user data components - see datafilters.peruserdata.py for details
</span><span class="cx"> PERUSER_COMPONENT = &quot;X-CALENDARSERVER-PERUSER&quot;
</span><span class="cx"> PERUSER_UID = &quot;X-CALENDARSERVER-PERUSER-UID&quot;
</span><span class="lines">@@ -134,19 +136,28 @@
</span><span class="cx">     &quot;LAST-MODIFIED&quot;: (None, {&quot;VALUE&quot;: &quot;DATE-TIME&quot;}),
</span><span class="cx">     &quot;SEQUENCE&quot;: (0, {&quot;VALUE&quot;: &quot;INTEGER&quot;}),
</span><span class="cx">     &quot;REQUEST-STATUS&quot;: (None, {&quot;VALUE&quot;: &quot;TEXT&quot;}),
</span><ins>+
+    &quot;VOTER&quot;: (None, {
+        &quot;VALUE&quot;: &quot;CAL-ADDRESS&quot;,
+        &quot;CUTYPE&quot;: &quot;INDIVIDUAL&quot;,
+        &quot;ROLE&quot;: &quot;REQ-PARTICIPANT&quot;,
+        &quot;RSVP&quot;: &quot;FALSE&quot;,
+        &quot;SCHEDULE-AGENT&quot;: &quot;SERVER&quot;,
+    }),
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # transformations to apply to property values
</span><span class="cx"> normalizePropsValue = {
</span><span class="cx">     &quot;ATTENDEE&quot;: normalizeCUAddr,
</span><span class="cx">     &quot;ORGANIZER&quot;: normalizeCUAddr,
</span><ins>+    &quot;VOTER&quot;: normalizeCUAddr,
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ignoredComponents = (&quot;VTIMEZONE&quot;, PERUSER_COMPONENT,)
</span><span class="cx"> 
</span><span class="cx"> # Used for min/max time-range query limits
</span><del>-minDateTime = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
-maxDateTime = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+minDateTime = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
+maxDateTime = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx"> 
</span><span class="cx"> class InvalidICalendarDataError(ValueError):
</span><span class="cx">     pass
</span><span class="lines">@@ -170,16 +181,16 @@
</span><span class="cx"> 
</span><span class="cx">             pyobj = kwargs[&quot;pycalendar&quot;]
</span><span class="cx"> 
</span><del>-            if not isinstance(pyobj, PyCalendarProperty):
-                raise TypeError(&quot;Not a PyCalendarProperty: %r&quot; % (property,))
</del><ins>+            if not isinstance(pyobj, PyProperty):
+                raise TypeError(&quot;Not a Property: %r&quot; % (property,))
</ins><span class="cx"> 
</span><span class="cx">             self._pycalendar = pyobj
</span><span class="cx">         else:
</span><span class="cx">             # Convert params dictionary to list of lists format used by pycalendar
</span><span class="cx">             valuetype = kwargs.get(&quot;valuetype&quot;)
</span><del>-            self._pycalendar = PyCalendarProperty(name, value, valuetype=valuetype)
</del><ins>+            self._pycalendar = PyProperty(name, value, valuetype=valuetype)
</ins><span class="cx">             for attrname, attrvalue in params.items():
</span><del>-                self._pycalendar.addAttribute(PyCalendarAttribute(attrname, attrvalue))
</del><ins>+                self._pycalendar.addParameter(Parameter(attrname, attrvalue))
</ins><span class="cx"> 
</span><span class="cx">         self._parent = parent
</span><span class="cx"> 
</span><span class="lines">@@ -267,7 +278,7 @@
</span><span class="cx">         Returns a set containing parameter names for this property.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         result = set()
</span><del>-        for pyattrlist in self._pycalendar.getAttributes().values():
</del><ins>+        for pyattrlist in self._pycalendar.getParameters().values():
</ins><span class="cx">             for pyattr in pyattrlist:
</span><span class="cx">                 result.add(pyattr.getName())
</span><span class="cx">         return result
</span><span class="lines">@@ -275,31 +286,40 @@
</span><span class="cx"> 
</span><span class="cx">     def parameterValue(self, name, default=None):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        Returns a single value for the given parameter.  Raises
-        InvalidICalendarDataError if the parameter has more than one value.
</del><ins>+        Returns a single value for the given parameter.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         try:
</span><del>-            return self._pycalendar.getAttributeValue(name)
</del><ins>+            return self._pycalendar.getParameterValue(name)
</ins><span class="cx">         except KeyError:
</span><span class="cx">             return default
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def parameterValues(self, name, default=None):
+        &quot;&quot;&quot;
+        Returns a multi-value C{list} for the given parameter.
+        &quot;&quot;&quot;
+        try:
+            return self._pycalendar.getParameterValues(name)
+        except KeyError:
+            return default
+
+
</ins><span class="cx">     def hasParameter(self, paramname):
</span><del>-        return self._pycalendar.hasAttribute(paramname)
</del><ins>+        return self._pycalendar.hasParameter(paramname)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def setParameter(self, paramname, paramvalue):
</span><del>-        self._pycalendar.replaceAttribute(PyCalendarAttribute(paramname, paramvalue))
</del><ins>+        self._pycalendar.replaceParameter(Parameter(paramname, paramvalue))
</ins><span class="cx">         self._markAsDirty()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def removeParameter(self, paramname):
</span><del>-        self._pycalendar.removeAttributes(paramname)
</del><ins>+        self._pycalendar.removeParameters(paramname)
</ins><span class="cx">         self._markAsDirty()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def removeAllParameters(self):
</span><del>-        self._pycalendar.setAttributes({})
</del><ins>+        self._pycalendar.setParameters({})
</ins><span class="cx">         self._markAsDirty()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -308,11 +328,11 @@
</span><span class="cx">         paramname = paramname.upper()
</span><span class="cx">         for attrName in self.parameterNames():
</span><span class="cx">             if attrName.upper() == paramname:
</span><del>-                for attr in tuple(self._pycalendar.getAttributes()[attrName]):
</del><ins>+                for attr in tuple(self._pycalendar.getParameters()[attrName]):
</ins><span class="cx">                     for value in attr.getValues():
</span><span class="cx">                         if value == paramvalue:
</span><span class="cx">                             if not attr.removeValue(value):
</span><del>-                                self._pycalendar.removeAttributes(paramname)
</del><ins>+                                self._pycalendar.removeParameters(paramname)
</ins><span class="cx">         self._markAsDirty()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -322,8 +342,8 @@
</span><span class="cx">         start/end period.
</span><span class="cx">         The only properties allowed for this query are: COMPLETED, CREATED, DTSTAMP and
</span><span class="cx">         LAST-MODIFIED (caldav -09).
</span><del>-        @param start: a L{PyCalendarDateTime} specifying the beginning of the given time span.
-        @param end: a L{PyCalendarDateTime} specifying the end of the given time span.
</del><ins>+        @param start: a L{DateTime} specifying the beginning of the given time span.
+        @param end: a L{DateTime} specifying the end of the given time span.
</ins><span class="cx">             C{end} may be None, indicating that there is no end date.
</span><span class="cx">         @param defaulttz: the default L{PyTimezone} to use in datetime comparisons.
</span><span class="cx">         @return: True if the property's date/date-time value is within the given time range,
</span><span class="lines">@@ -337,7 +357,7 @@
</span><span class="cx"> 
</span><span class="cx">         # get date/date-time value
</span><span class="cx">         dt = self._pycalendar.getValue().getValue()
</span><del>-        assert isinstance(dt, PyCalendarDateTime), &quot;Not a date/date-time value: %r&quot; % (self,)
</del><ins>+        assert isinstance(dt, DateTime), &quot;Not a date/date-time value: %r&quot; % (self,)
</ins><span class="cx"> 
</span><span class="cx">         return timeRangesOverlap(dt, None, start, end, defaulttz)
</span><span class="cx"> 
</span><span class="lines">@@ -375,66 +395,95 @@
</span><span class="cx">     # Hidden instance.
</span><span class="cx">     HIDDEN_INSTANCE_PROPERTY = &quot;X-CALENDARSERVER-HIDDEN-INSTANCE&quot;
</span><span class="cx"> 
</span><ins>+    allowedTypesList = None
+
+
</ins><span class="cx">     @classmethod
</span><del>-    def allFromString(clazz, string):
</del><ins>+    def allowedTypes(cls):
+        if cls.allowedTypesList is None:
+            cls.allowedTypesList = [&quot;text/calendar&quot;]
+            if config.EnableJSONData:
+                cls.allowedTypesList.append(&quot;application/calendar+json&quot;)
+        return cls.allowedTypesList
+
+
+    @classmethod
+    def allFromString(clazz, string, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Just default to reading a single VCALENDAR
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        return clazz.fromString(string)
</del><ins>+        return clazz.fromString(string, format)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><del>-    def allFromStream(clazz, stream):
</del><ins>+    def allFromStream(clazz, stream, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Just default to reading a single VCALENDAR
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        return clazz.fromStream(stream)
</del><ins>+        return clazz.fromStream(stream, format)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><del>-    def fromString(clazz, string):
</del><ins>+    def fromString(clazz, string, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Construct a L{Component} from a string.
</span><span class="cx">         @param string: a string containing iCalendar data.
</span><span class="cx">         @return: a L{Component} representing the first component described by
</span><span class="cx">             C{string}.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        if type(string) is unicode:
-            string = string.encode(&quot;utf-8&quot;)
-        else:
-            # Valid utf-8 please
-            string.decode(&quot;utf-8&quot;)
</del><ins>+        return clazz._fromData(string, False, format)
</ins><span class="cx"> 
</span><del>-        # No BOMs please
-        if string[:3] == codecs.BOM_UTF8:
-            string = string[3:]
</del><span class="cx"> 
</span><del>-        return clazz.fromStream(StringIO.StringIO(string))
</del><ins>+    @classmethod
+    def fromStream(clazz, stream, format=None):
+        &quot;&quot;&quot;
+        Construct a L{Component} from a stream.
+        @param stream: a C{read()}able stream containing iCalendar data.
+        @return: a L{Component} representing the first component described by
+            C{stream}.
+        &quot;&quot;&quot;
+        return clazz._fromData(stream, True, format)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><del>-    def fromStream(clazz, stream):
</del><ins>+    def _fromData(clazz, data, isstream, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Construct a L{Component} from a stream.
</span><span class="cx">         @param stream: a C{read()}able stream containing iCalendar data.
</span><ins>+        @param format: a C{str} indicating whether the data is iCalendar or jCal
</ins><span class="cx">         @return: a L{Component} representing the first component described by
</span><span class="cx">             C{stream}.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        cal = PyCalendar()
</del><ins>+
+        if isstream:
+            pass
+        else:
+            if type(data) is unicode:
+                data = data.encode(&quot;utf-8&quot;)
+            else:
+                # Valid utf-8 please
+                data.decode(&quot;utf-8&quot;)
+
+            # No BOMs please
+            if data[:3] == codecs.BOM_UTF8:
+                data = data[3:]
+
</ins><span class="cx">         errmsg = &quot;Unknown&quot;
</span><span class="cx">         try:
</span><del>-            result = cal.parse(stream)
-        except PyCalendarError, e:
</del><ins>+            result = Calendar.parseData(data, format)
+        except ErrorBase, e:
</ins><span class="cx">             errmsg = &quot;%s: %s&quot; % (e.mReason, e.mData,)
</span><span class="cx">             result = None
</span><span class="cx">         if not result:
</span><del>-            stream.seek(0)
-            raise InvalidICalendarDataError(&quot;%s\n%s&quot; % (errmsg, stream.read(),))
-        return clazz(None, pycalendar=cal)
</del><ins>+            if isstream:
+                data.seek(0)
+                data = data.read()
+            raise InvalidICalendarDataError(&quot;%s\n%s&quot; % (errmsg, data,))
+        return clazz(None, pycalendar=result)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><del>-    def fromIStream(clazz, stream):
</del><ins>+    def fromIStream(clazz, stream, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Construct a L{Component} from a stream.
</span><span class="cx">         @param stream: an L{IStream} containing iCalendar data.
</span><span class="lines">@@ -448,7 +497,7 @@
</span><span class="cx">         #   request stream.
</span><span class="cx">         #
</span><span class="cx">         def parse(data):
</span><del>-            return clazz.fromString(data)
</del><ins>+            return clazz.fromString(data, format)
</ins><span class="cx">         return allDataFromStream(IStream(stream), parse)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -480,8 +529,8 @@
</span><span class="cx">                 pyobj = kwargs[&quot;pycalendar&quot;]
</span><span class="cx"> 
</span><span class="cx">                 if pyobj is not None:
</span><del>-                    if not isinstance(pyobj, PyCalendarComponentBase):
-                        raise TypeError(&quot;Not a PyCalendarComponentBase: %r&quot; % (pyobj,))
</del><ins>+                    if not isinstance(pyobj, ComponentBase):
+                        raise TypeError(&quot;Not a ComponentBase: %r&quot; % (pyobj,))
</ins><span class="cx"> 
</span><span class="cx">                 self._pycalendar = pyobj
</span><span class="cx">             else:
</span><span class="lines">@@ -499,7 +548,7 @@
</span><span class="cx">                 self._parent = None
</span><span class="cx">         else:
</span><span class="cx">             # FIXME: figure out creating an arbitrary component
</span><del>-            self._pycalendar = PyCalendar(add_defaults=False) if name == &quot;VCALENDAR&quot; else PyCalendar.makeComponent(name, None)
</del><ins>+            self._pycalendar = Calendar(add_defaults=False) if name == &quot;VCALENDAR&quot; else PyComponent.makeComponent(name, None)
</ins><span class="cx">             self._parent = None
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -542,13 +591,20 @@
</span><span class="cx">         return self._pycalendar == other._pycalendar
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def getTextWithTimezones(self, includeTimezones):
</del><ins>+    def getText(self, format=None):
+        return self.getTextWithTimezones(False, format)
+
+
+    def getTextWithTimezones(self, includeTimezones, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><del>-        Return text representation and include timezones if the option is on
</del><ins>+        Return text representation and include timezones if the option is on.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         assert self.name() == &quot;VCALENDAR&quot;, &quot;Must be a VCALENDAR: %r&quot; % (self,)
</span><span class="cx"> 
</span><del>-        return self._pycalendar.getText(includeTimezones=includeTimezones)
</del><ins>+        result = self._pycalendar.getText(includeTimezones=includeTimezones, format=format)
+        if result is None:
+            raise ValueError(&quot;Unknown format requested for calendar data.&quot;)
+        return result
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     # FIXME: Should this not be in __eq__?
</span><span class="lines">@@ -627,14 +683,14 @@
</span><span class="cx">         This also returns the matching master component if recurrence_id is C{None}.
</span><span class="cx"> 
</span><span class="cx">         @param recurrence_id: The RECURRENCE-ID property value to match.
</span><del>-        @type recurrence_id: L{PyCalendarDateTime}
</del><ins>+        @type recurrence_id: L{DateTime}
</ins><span class="cx">         @return: the L{Component} for the overridden component,
</span><span class="cx">             or C{None} if there isn't one.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         assert self.name() == &quot;VCALENDAR&quot;, &quot;Must be a VCALENDAR: %r&quot; % (self,)
</span><span class="cx"> 
</span><span class="cx">         if isinstance(recurrence_id, str):
</span><del>-            recurrence_id = PyCalendarDateTime.parseText(recurrence_id) if recurrence_id else None
</del><ins>+            recurrence_id = DateTime.parseText(recurrence_id) if recurrence_id else None
</ins><span class="cx"> 
</span><span class="cx">         for component in self.subcomponents():
</span><span class="cx">             if component.name() in ignoredComponents:
</span><span class="lines">@@ -760,7 +816,7 @@
</span><span class="cx">         Return the start date or date-time for the specified component
</span><span class="cx">         converted to UTC.
</span><span class="cx">         @param component: the Component whose start should be returned.
</span><del>-        @return: the L{PyCalendarDateTime} for the start.
</del><ins>+        @return: the L{DateTime} for the start.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         dtstart = self.propertyValue(&quot;DTSTART&quot;)
</span><span class="cx">         return dtstart.duplicateAsUTC() if dtstart is not None else None
</span><span class="lines">@@ -772,7 +828,7 @@
</span><span class="cx">         taking into account the presence or absence of DTEND/DURATION properties.
</span><span class="cx">         The returned date-time is converted to UTC.
</span><span class="cx">         @param component: the Component whose end should be returned.
</span><del>-        @return: the L{PyCalendarDateTime} for the end.
</del><ins>+        @return: the L{DateTime} for the end.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         dtend = self.propertyValue(&quot;DTEND&quot;)
</span><span class="cx">         if dtend is None:
</span><span class="lines">@@ -789,7 +845,7 @@
</span><span class="cx">         Return the due date or date-time for the specified component
</span><span class="cx">         converted to UTC. Use DTSTART/DURATION if no DUE property.
</span><span class="cx">         @param component: the Component whose start should be returned.
</span><del>-        @return: the L{PyCalendarDateTime} for the start.
</del><ins>+        @return: the L{DateTime} for the start.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         due = self.propertyValue(&quot;DUE&quot;)
</span><span class="cx">         if due is None:
</span><span class="lines">@@ -827,7 +883,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Return the recurrence-id for the specified component.
</span><span class="cx">         @param component: the Component whose r-id should be returned.
</span><del>-        @return: the L{PyCalendarDateTime} for the r-id.
</del><ins>+        @return: the L{DateTime} for the r-id.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         rid = self.propertyValue(&quot;RECURRENCE-ID&quot;)
</span><span class="cx">         return rid.duplicateAsUTC() if rid is not None else None
</span><span class="lines">@@ -1086,7 +1142,7 @@
</span><span class="cx">         to match the new limit, remove RDATEs/EXDATEs and overridden components beyond the limit.
</span><span class="cx"> 
</span><span class="cx">         @param rid: the recurrence-id limit
</span><del>-        @type rid: L{PyCalendarDateTime}
</del><ins>+        @type rid: L{DateTime}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         if not self.isRecurring():
</span><span class="lines">@@ -1148,7 +1204,7 @@
</span><span class="cx">         match any RRULE pattern.
</span><span class="cx"> 
</span><span class="cx">         @param rid: the recurrence-id limit
</span><del>-        @type rid: L{PyCalendarDateTime}
</del><ins>+        @type rid: L{DateTime}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         if not self.isRecurring():
</span><span class="lines">@@ -1169,7 +1225,7 @@
</span><span class="cx">                     rrule_expanded = []
</span><span class="cx">                     rrule.expand(
</span><span class="cx">                         master.propertyValue(&quot;DTSTART&quot;),
</span><del>-                        PyCalendarPeriod(PyCalendarDateTime(1900, 1, 1), upperlimit),
</del><ins>+                        Period(DateTime(1900, 1, 1), upperlimit),
</ins><span class="cx">                         rrule_expanded,
</span><span class="cx">                     )
</span><span class="cx">                     for i in sorted(rrule_expanded):
</span><span class="lines">@@ -1244,14 +1300,14 @@
</span><span class="cx">         instance in the specified range. Date-times are converted to UTC. A
</span><span class="cx">         new calendar object is returned.
</span><span class="cx"> 
</span><del>-        @param start: the L{PyCalendarDateTime} for the start of the range.
-        @param end: the L{PyCalendarDateTime} for the end of the range.
-        @param timezone: the L{Component} or L{PyCalendarTimezone} of the VTIMEZONE to use for floating/all-day.
</del><ins>+        @param start: the L{DateTime} for the start of the range.
+        @param end: the L{DateTime} for the end of the range.
+        @param timezone: the L{Component} or L{Timezone} of the VTIMEZONE to use for floating/all-day.
</ins><span class="cx">         @return: the L{Component} for the new calendar with expanded instances.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         if timezone is not None and isinstance(timezone, Component):
</span><del>-            pytz = PyCalendarTimezone(tzid=timezone.propertyValue(&quot;TZID&quot;))
</del><ins>+            pytz = Timezone(tzid=timezone.propertyValue(&quot;TZID&quot;))
</ins><span class="cx">         else:
</span><span class="cx">             pytz = timezone
</span><span class="cx"> 
</span><span class="lines">@@ -1297,7 +1353,7 @@
</span><span class="cx">         # Convert all datetime properties to UTC unless they are floating
</span><span class="cx">         for property in newcomp.properties():
</span><span class="cx">             value = property.value()
</span><del>-            if isinstance(value, PyCalendarDateTime) and value.local():
</del><ins>+            if isinstance(value, DateTime) and value.local():
</ins><span class="cx">                 property.removeParameter(&quot;TZID&quot;)
</span><span class="cx">                 property.setValue(value.duplicateAsUTC())
</span><span class="cx"> 
</span><span class="lines">@@ -1324,7 +1380,7 @@
</span><span class="cx">         breathing room to return results for future instances.
</span><span class="cx"> 
</span><span class="cx">         @param limit: the max datetime to cache up to.
</span><del>-        @type limit: L{PyCalendarDateTime}
</del><ins>+        @type limit: L{DateTime}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Checked for cached values first
</span><span class="lines">@@ -1335,7 +1391,7 @@
</span><span class="cx">                 # so return cached instances
</span><span class="cx">                 return self.cachedInstances
</span><span class="cx"> 
</span><del>-        lookAheadLimit = limit + PyCalendarDuration(days=365)
</del><ins>+        lookAheadLimit = limit + Duration(days=365)
</ins><span class="cx">         self.cachedInstances = self.expandTimeRanges(
</span><span class="cx">             lookAheadLimit,
</span><span class="cx">             ignoreInvalidInstances=ignoreInvalidInstances
</span><span class="lines">@@ -1349,7 +1405,7 @@
</span><span class="cx">         contained within this VCALENDAR component. We will assume
</span><span class="cx">         that this component has already been validated as a CalDAV resource
</span><span class="cx">         (i.e. only one type of component, all with the same UID)
</span><del>-        @param limit: L{PyCalendarDateTime} value representing the end of the expansion.
</del><ins>+        @param limit: L{DateTime} value representing the end of the expansion.
</ins><span class="cx">         @param ignoreInvalidInstances: C{bool} whether to ignore instance errors.
</span><span class="cx">         @return: a set of Instances for each recurrence in the set.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -1368,14 +1424,14 @@
</span><span class="cx">         @param componentSet: the set of components that are to make up the
</span><span class="cx">                 recurrence set. These MUST all be components with the same UID
</span><span class="cx">                 and type, forming a proper recurring set.
</span><del>-        @param limit: L{PyCalendarDateTime} value representing the end of the expansion.
</del><ins>+        @param limit: L{DateTime} value representing the end of the expansion.
</ins><span class="cx"> 
</span><span class="cx">         @param componentSet: the set of components that are to make up the recurrence set.
</span><span class="cx">             These MUST all be components with the same UID and type, forming a proper
</span><span class="cx">             recurring set.
</span><span class="cx">         @type componentSet: C{list}
</span><span class="cx">         @param limit: the end of the expansion
</span><del>-        @type limit: L{PyCalendarDateTime}
</del><ins>+        @type limit: L{DateTime}
</ins><span class="cx">         @param ignoreInvalidInstances: whether or not invalid recurrences raise an exception
</span><span class="cx">         @type ignoreInvalidInstances: C{bool}
</span><span class="cx">         @param normalizeFunction: a function used to normalize date/time values in instances
</span><span class="lines">@@ -1451,7 +1507,7 @@
</span><span class="cx">         There is always some new thing that will surprise you.
</span><span class="cx"> 
</span><span class="cx">         @param rid: recurrence-id value
</span><del>-        @type rid: L{PyCalendarDateTime} or C{str}
</del><ins>+        @type rid: L{DateTime} or C{str}
</ins><span class="cx">         @param allowCancelled: whether to allow a STATUS:CANCELLED override
</span><span class="cx">         @type allowCancelled: C{bool}
</span><span class="cx">         @param allowExcluded: whether to derive an instance for an existing EXDATE
</span><span class="lines">@@ -1469,7 +1525,7 @@
</span><span class="cx">             return None
</span><span class="cx"> 
</span><span class="cx">         if isinstance(rid, str):
</span><del>-            rid = PyCalendarDateTime.parseText(rid) if rid else None
</del><ins>+            rid = DateTime.parseText(rid) if rid else None
</ins><span class="cx"> 
</span><span class="cx">         # TODO: Check that the recurrence-id is a valid instance
</span><span class="cx">         # For now we just check that there is no matching EXDATE
</span><span class="lines">@@ -1586,7 +1642,7 @@
</span><span class="cx">             # Pre-cache instance expansion up to the highest rid
</span><span class="cx">             highest_rid = max(non_master_rids)
</span><span class="cx">             self.cacheExpandedTimeRanges(
</span><del>-                highest_rid + PyCalendarDuration(days=1),
</del><ins>+                highest_rid + Duration(days=1),
</ins><span class="cx">                 ignoreInvalidInstances=ignoreInvalidInstances
</span><span class="cx">             )
</span><span class="cx">         for rid in rids:
</span><span class="lines">@@ -1600,7 +1656,7 @@
</span><span class="cx">         Test whether the specified recurrence-id is a valid instance in this event.
</span><span class="cx"> 
</span><span class="cx">         @param rid: recurrence-id value
</span><del>-        @type rid: L{PyCalendarDateTime}
</del><ins>+        @type rid: L{DateTime}
</ins><span class="cx"> 
</span><span class="cx">         @return: C{bool}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -1984,12 +2040,12 @@
</span><span class="cx"> 
</span><span class="cx">     def gettimezone(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        Get the PyCalendarTimezone for a Timezone component.
</del><ins>+        Get the Timezone for a Timezone component.
</ins><span class="cx"> 
</span><del>-        @return: L{PyCalendarTimezone} if this is a VTIMEZONE, otherwise None.
</del><ins>+        @return: L{Timezone} if this is a VTIMEZONE, otherwise None.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         if self.name() == &quot;VTIMEZONE&quot;:
</span><del>-            return PyCalendarTimezone(tzid=self._pycalendar.getID())
</del><ins>+            return Timezone(tzid=self._pycalendar.getID())
</ins><span class="cx">         elif self.name() == &quot;VCALENDAR&quot;:
</span><span class="cx">             for component in self.subcomponents():
</span><span class="cx">                 if component.name() == &quot;VTIMEZONE&quot;:
</span><span class="lines">@@ -2137,6 +2193,10 @@
</span><span class="cx">         return is_server
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def recipientPropertyName(self):
+        return &quot;VOTER&quot; if self.name() == &quot;VPOLL&quot; else &quot;ATTENDEE&quot;
+
+
</ins><span class="cx">     def getAttendees(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Get the attendee value. Works on either a VCALENDAR or on a component.
</span><span class="lines">@@ -2152,7 +2212,7 @@
</span><span class="cx">                     return component.getAttendees()
</span><span class="cx">         else:
</span><span class="cx">             # Find the property values
</span><del>-            return [p.value() for p in self.properties(&quot;ATTENDEE&quot;)]
</del><ins>+            return [p.value() for p in self.properties(self.recipientPropertyName())]
</ins><span class="cx"> 
</span><span class="cx">         return None
</span><span class="cx"> 
</span><span class="lines">@@ -2179,7 +2239,7 @@
</span><span class="cx">             result = ()
</span><span class="cx">             attendees = set()
</span><span class="cx">             rid = self.getRecurrenceIDUTC()
</span><del>-            for attendee in tuple(self.properties(&quot;ATTENDEE&quot;)):
</del><ins>+            for attendee in tuple(self.properties(self.recipientPropertyName())):
</ins><span class="cx"> 
</span><span class="cx">                 if onlyScheduleAgentServer:
</span><span class="cx">                     if attendee.hasParameter(&quot;SCHEDULE-AGENT&quot;):
</span><span class="lines">@@ -2195,6 +2255,27 @@
</span><span class="cx">             return result
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def getVoterProperty(self, match):
+        &quot;&quot;&quot;
+        Get the voters matching a value.
+
+        @param match: a C{list} of calendar user address strings to try and match.
+        @return: the matching Voter property, or None
+        &quot;&quot;&quot;
+
+        # Need to normalize http/https cu addresses
+        test = set()
+        for item in match:
+            test.add(normalizeCUAddr(item))
+
+        # Find the primary subcomponent
+        for voter in self.properties(&quot;VOTER&quot;):
+            if normalizeCUAddr(voter.value()) in test:
+                return voter
+
+        return None
+
+
</ins><span class="cx">     def getAttendeeProperty(self, match):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Get the attendees matching a value. Works on either a VCALENDAR or on a component.
</span><span class="lines">@@ -2217,7 +2298,7 @@
</span><span class="cx">                         return attendee
</span><span class="cx">         else:
</span><span class="cx">             # Find the primary subcomponent
</span><del>-            for attendee in self.properties(&quot;ATTENDEE&quot;):
</del><ins>+            for attendee in self.properties(self.recipientPropertyName()):
</ins><span class="cx">                 if normalizeCUAddr(attendee.value()) in test:
</span><span class="cx">                     return attendee
</span><span class="cx"> 
</span><span class="lines">@@ -2260,7 +2341,7 @@
</span><span class="cx">                         yield attendee
</span><span class="cx">         else:
</span><span class="cx">             # Find the primary subcomponent
</span><del>-            for attendee in self.properties(&quot;ATTENDEE&quot;):
</del><ins>+            for attendee in self.properties(self.recipientPropertyName()):
</ins><span class="cx">                 yield attendee
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -2641,7 +2722,7 @@
</span><span class="cx">         for component in self.subcomponents():
</span><span class="cx">             if component.name() in ignoredComponents:
</span><span class="cx">                 continue
</span><del>-            [component.removeProperty(p) for p in tuple(component.properties(&quot;ATTENDEE&quot;)) if p.value().lower() != attendee.lower()]
</del><ins>+            [component.removeProperty(p) for p in tuple(component.properties(component.recipientPropertyName())) if p.value().lower() != attendee.lower()]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def removeAllButTheseAttendees(self, attendees):
</span><span class="lines">@@ -2656,7 +2737,7 @@
</span><span class="cx">         for component in self.subcomponents():
</span><span class="cx">             if component.name() in ignoredComponents:
</span><span class="cx">                 continue
</span><del>-            [component.removeProperty(p) for p in tuple(component.properties(&quot;ATTENDEE&quot;)) if p.value().lower() not in attendees]
</del><ins>+            [component.removeProperty(p) for p in tuple(component.properties(component.recipientPropertyName())) if p.value().lower() not in attendees]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def hasAlarm(self):
</span><span class="lines">@@ -2977,7 +3058,7 @@
</span><span class="cx">             # Bump all components
</span><span class="cx">             self.replacePropertyInAllComponents(Property(&quot;SEQUENCE&quot;, newseq))
</span><span class="cx"> 
</span><del>-        self.replacePropertyInAllComponents(Property(&quot;DTSTAMP&quot;, PyCalendarDateTime.getNowUTC()))
</del><ins>+        self.replacePropertyInAllComponents(Property(&quot;DTSTAMP&quot;, DateTime.getNowUTC()))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def sequenceInSync(self, oldcalendar):
</span><span class="lines">@@ -3059,7 +3140,7 @@
</span><span class="cx">             dtend = self.getProperty(&quot;DTEND&quot;)
</span><span class="cx">             duration = self.getProperty(&quot;DURATION&quot;)
</span><span class="cx"> 
</span><del>-            timeRange = PyCalendarPeriod(
</del><ins>+            timeRange = Period(
</ins><span class="cx">                 start=dtstart.value(),
</span><span class="cx">                 end=dtend.value()    if dtend is not None else None,
</span><span class="cx">                 duration=duration.value() if duration is not None else None,
</span><span class="lines">@@ -3163,7 +3244,8 @@
</span><span class="cx">                 continue
</span><span class="cx">             for prop in itertools.chain(
</span><span class="cx">                 component.properties(&quot;ORGANIZER&quot;),
</span><del>-                component.properties(&quot;ATTENDEE&quot;)
</del><ins>+                component.properties(&quot;ATTENDEE&quot;),
+                component.properties(&quot;VOTER&quot;)
</ins><span class="cx">             ):
</span><span class="cx"> 
</span><span class="cx">                 # Check that we can lookup this calendar user address - if not
</span><span class="lines">@@ -3261,7 +3343,11 @@
</span><span class="cx">                     else:
</span><span class="cx">                         prop.removeParameter(&quot;EMAIL&quot;)
</span><span class="cx"> 
</span><ins>+            # For VPOLL also do immediate children
+            if component.name() == &quot;VPOLL&quot;:
+                component.normalizeCalendarUserAddresses(lookupFunction, principalFunction, toUUID)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def allPerUserUIDs(self):
</span><span class="cx"> 
</span><span class="cx">         results = set()
</span><span class="lines">@@ -3311,7 +3397,7 @@
</span><span class="cx">         Determine whether an event exists completely prior to a given moment.
</span><span class="cx"> 
</span><span class="cx">         @param limit: the moment to compare against.
</span><del>-        @type limit: L{PyCalendarDateTime}
</del><ins>+        @type limit: L{DateTime}
</ins><span class="cx"> 
</span><span class="cx">         @return: a C{bool}, True if the event has any instances occurring after
</span><span class="cx">         limit, False otherwise.
</span><span class="lines">@@ -3369,13 +3455,13 @@
</span><span class="cx">     start.setDateOnly(False)
</span><span class="cx">     if tzexpanded:
</span><span class="cx">         if start != tzexpanded[0][0]:
</span><del>-            results.append((str(start), PyCalendarUTCOffsetValue(tzexpanded[0][1]).getText(),))
</del><ins>+            results.append((str(start), UTCOffsetValue(tzexpanded[0][1]).getText(),))
</ins><span class="cx">     else:
</span><del>-        results.append((str(start), PyCalendarUTCOffsetValue(tzcomp._pycalendar.getTimezoneOffsetSeconds(start)).getText(),))
</del><ins>+        results.append((str(start), UTCOffsetValue(tzcomp._pycalendar.getTimezoneOffsetSeconds(start)).getText(),))
</ins><span class="cx">     for tzstart, _ignore_tzoffsetfrom, tzoffsetto in tzexpanded:
</span><span class="cx">         results.append((
</span><span class="cx">             tzstart.getText(),
</span><del>-            PyCalendarUTCOffsetValue(tzoffsetto).getText(),
</del><ins>+            UTCOffsetValue(tzoffsetto).getText(),
</ins><span class="cx">         ))
</span><span class="cx"> 
</span><span class="cx">     return results
</span><span class="lines">@@ -3388,7 +3474,7 @@
</span><span class="cx">     time range.
</span><span class="cx"> 
</span><span class="cx">     @param tzdata: the iCalendar data containing a VTIMEZONE.
</span><del>-    @type tzdata: L{PyCalendar}
</del><ins>+    @type tzdata: L{Calendar}
</ins><span class="cx">     @param start: date for the start of the expansion.
</span><span class="cx">     @type start: C{date}
</span><span class="cx">     @param end: date for the end of the expansion.
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavicaldavpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/icaldav.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/icaldav.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/icaldav.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -29,14 +29,14 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     CalDAV resource.
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    def isCalendarCollection():
</del><ins>+    def isCalendarCollection(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         (CalDAV-access-10, Section 4.2)
</span><span class="cx">         @return: True if this resource is a calendar collection, False
</span><span class="cx">             otherwise.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def isSpecialCollection(collectiontype):
</del><ins>+    def isSpecialCollection(collectiontype): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         (CalDAV-access-10, Section 4.2)
</span><span class="cx">         @param collectiontype: L{WebDAVElement} for the collection type to test for.
</span><span class="lines">@@ -44,30 +44,30 @@
</span><span class="cx">             False otherwise.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def isPseudoCalendarCollection():
</del><ins>+    def isPseudoCalendarCollection(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: True if this resource is a calendar collection like (e.g.
</span><span class="cx">             a regular calendar collection or schedule inbox/outbox), False
</span><span class="cx">             otherwise.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def findCalendarCollections(depth):
</del><ins>+    def findCalendarCollections(depth): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Returns an iterable of child calendar collection resources for the given
</span><span class="cx">         depth.
</span><del>-        Because resources do not know their request URIs, chidren are returned
</del><ins>+        Because resources do not know their request URIs, children are returned
</ins><span class="cx">         as tuples C{(resource, uri)}, where C{resource} is the child resource
</span><span class="cx">         and C{uri} is a URL path relative to this resource.
</span><span class="cx">         @param depth: the search depth (one of &quot;0&quot;, &quot;1&quot;, or &quot;infinity&quot;)
</span><span class="cx">         @return: an iterable of tuples C{(resource, uri)}.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def createCalendar(request):
</del><ins>+    def createCalendar(request): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Create a calendar collection for this resource.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def iCalendar():
</del><ins>+    def iCalendar(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Instantiate an iCalendar component object representing this resource or
</span><span class="cx">         its child with the given name.
</span><span class="lines">@@ -78,52 +78,42 @@
</span><span class="cx">         @return: a L{twistedcaldav.ical.Component} of type C{&quot;VCALENDAR&quot;}.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def iCalendarText():
-        &quot;&quot;&quot;
-        Obtains the iCalendar text representing this resource or its child with
-        the given name.
-        The behavior of this method is not specified if it is called on a
-        resource that is not a calendar collection or a calendar resource within
-        a calendar collection.
</del><span class="cx"> 
</span><del>-        @return: a string containing iCalendar text with a top-level component
-            of type C{&quot;VCALENDAR&quot;}.
-        &quot;&quot;&quot;
</del><span class="cx"> 
</span><span class="cx"> class ICalendarPrincipalResource(IDAVResource):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     CalDAV principle resource.
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    def principalUID():
</del><ins>+    def principalUID(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the user id for this principal.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def calendarHomeURLs():
</del><ins>+    def calendarHomeURLs(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: a list of calendar home URLs for this principal's calendar user.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def calendarUserAddresses():
</del><ins>+    def calendarUserAddresses(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: a list of calendar user addresses for this principal's calendar
</span><span class="cx">             user.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def calendarFreeBusyURIs(self, request):
</del><ins>+    def calendarFreeBusyURIs(request): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param request: the request being processed.
</span><span class="cx">         @return: a L{Deferred} list of URIs for calendars that contribute to
</span><span class="cx">             free-busy for this principal's calendar user.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def scheduleInboxURL():
</del><ins>+    def scheduleInboxURL(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Get the schedule INBOX URL for this principal's calendar user.
</span><span class="cx">         @return: a string containing the URL from the schedule-inbox-URL property.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def scheduleOutboxURL():
</del><ins>+    def scheduleOutboxURL(): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Get the schedule OUTBOX URL for this principal's calendar user.
</span><span class="cx">         @return: a string containing the URL from the schedule-outbox-URL property.
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavinstancepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/instance.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/instance.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/instance.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -21,10 +21,10 @@
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.dateops import normalizeForIndex, differenceDateTime
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
+from pycalendar.period import Period
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> class TooManyInstancesError(Exception):
</span><span class="cx"> 
</span><span class="lines">@@ -80,7 +80,7 @@
</span><span class="cx">             (trigger, related, repeat, duration) = alarm.getTriggerDetails()
</span><span class="cx"> 
</span><span class="cx">             # Handle relative vs absolute triggers
</span><del>-            if isinstance(trigger, PyCalendarDateTime):
</del><ins>+            if isinstance(trigger, DateTime):
</ins><span class="cx">                 # Absolute trigger
</span><span class="cx">                 start = trigger
</span><span class="cx">             else:
</span><span class="lines">@@ -135,7 +135,7 @@
</span><span class="cx">         @param componentSet: the set of components that are to make up the
</span><span class="cx">                 recurrence set. These MUST all be components with the same UID
</span><span class="cx">                 and type, forming a proper recurring set.
</span><del>-        @param limit: L{PyCalendarDateTime} value representing the end of the expansion.
</del><ins>+        @param limit: L{DateTime} value representing the end of the expansion.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Look at each component type
</span><span class="lines">@@ -232,10 +232,10 @@
</span><span class="cx">         if end is None:
</span><span class="cx">             if not start.isDateOnly():
</span><span class="cx">                 # Timed event with zero duration
</span><del>-                duration = PyCalendarDuration(days=0)
</del><ins>+                duration = Duration(days=0)
</ins><span class="cx">             else:
</span><span class="cx">                 # All day event default duration is one day
</span><del>-                duration = PyCalendarDuration(days=1)
</del><ins>+                duration = Duration(days=1)
</ins><span class="cx">             end = start + duration
</span><span class="cx">         else:
</span><span class="cx">             duration = differenceDateTime(start, end)
</span><span class="lines">@@ -248,7 +248,7 @@
</span><span class="cx">         Add the specified master VEVENT Component to the instance list, expanding it
</span><span class="cx">         within the supplied time range.
</span><span class="cx">         @param component: the Component to expand
</span><del>-        @param limit: the end L{PyCalendarDateTime} for expansion
</del><ins>+        @param limit: the end L{DateTime} for expansion
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         details = self._getMasterEventDetails(component)
</span><span class="lines">@@ -330,7 +330,7 @@
</span><span class="cx">         Add the specified master VTODO Component to the instance list, expanding it
</span><span class="cx">         within the supplied time range.
</span><span class="cx">         @param component: the Component to expand
</span><del>-        @param limit: the end L{PyCalendarDateTime} for expansion
</del><ins>+        @param limit: the end L{DateTime} for expansion
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         details = self._getMasterToDoDetails(component)
</span><span class="cx">         if details is None:
</span><span class="lines">@@ -370,7 +370,7 @@
</span><span class="cx">             # than the master DTSTART, and if we exclude those, the associated
</span><span class="cx">             # overridden instances will cause an InvalidOverriddenInstance.
</span><span class="cx">             limited = rrules.expand(rulestart,
</span><del>-                PyCalendarPeriod(PyCalendarDateTime(1900, 1, 1), upperlimit), expanded)
</del><ins>+                Period(DateTime(1900, 1, 1), upperlimit), expanded)
</ins><span class="cx">             for startDate in expanded:
</span><span class="cx">                 startDate = self.normalizeFunction(startDate)
</span><span class="cx">                 endDate = startDate + duration
</span><span class="lines">@@ -478,7 +478,7 @@
</span><span class="cx">         Add the specified master VFREEBUSY Component to the instance list, expanding it
</span><span class="cx">         within the supplied time range.
</span><span class="cx">         @param component: the Component to expand
</span><del>-        @param limit: the end L{PyCalendarDateTime} for expansion
</del><ins>+        @param limit: the end L{DateTime} for expansion
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         start = component.getStartDateUTC()
</span><span class="lines">@@ -519,7 +519,7 @@
</span><span class="cx">         depending on the presence of the properties. If unbounded at one or both ends, we will
</span><span class="cx">         set the time to 1/1/1900 in the past and 1/1/3000 in the future.
</span><span class="cx">         @param component: the Component to expand
</span><del>-        @param limit: the end L{PyCalendarDateTime} for expansion
</del><ins>+        @param limit: the end L{DateTime} for expansion
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         start = component.getStartDateUTC()
</span><span class="lines">@@ -531,7 +531,7 @@
</span><span class="cx">             # If the availability is beyond the end of the range we want, ignore it
</span><span class="cx">             return
</span><span class="cx">         if start is None:
</span><del>-            start = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+            start = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         start = self.normalizeFunction(start)
</span><span class="cx"> 
</span><span class="cx">         end = component.getEndDateUTC()
</span><span class="lines">@@ -539,7 +539,7 @@
</span><span class="cx">             # If the availability is before the start of the range we want, ignore it
</span><span class="cx">             return
</span><span class="cx">         if end is None:
</span><del>-            end = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+            end = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         end = self.normalizeFunction(end)
</span><span class="cx"> 
</span><span class="cx">         self.addInstance(Instance(component, start, end))
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavlinkresourcepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/linkresource.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/linkresource.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/linkresource.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -47,16 +47,17 @@
</span><span class="cx">     case of a missing underlying resource (broken link) as indicated by self._linkedResource being None.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     log = Logger()
</span><del>-    
</del><ins>+
</ins><span class="cx">     def __init__(self, parent, link_url):
</span><span class="cx">         self.parent = parent
</span><span class="cx">         self.linkURL = link_url
</span><span class="cx">         self.loopDetect = set()
</span><span class="cx">         super(LinkResource, self).__init__(self.parent.principalCollections())
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def linkedResource(self, request):
</span><del>-        
</del><ins>+
</ins><span class="cx">         if not hasattr(self, &quot;_linkedResource&quot;):
</span><span class="cx">             if self.linkURL in self.loopDetect:
</span><span class="cx">                 raise HTTPError(StatusResponse(responsecode.LOOP_DETECTED, &quot;Recursive link target: %s&quot; % (self.linkURL,)))
</span><span class="lines">@@ -67,17 +68,20 @@
</span><span class="cx"> 
</span><span class="cx">         if self._linkedResource is None:
</span><span class="cx">             raise HTTPError(StatusResponse(responsecode.NOT_FOUND, &quot;Missing link target: %s&quot; % (self.linkURL,)))
</span><del>-            
</del><ins>+
</ins><span class="cx">         returnValue(self._linkedResource)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def isCollection(self):
</span><span class="cx">         return True if hasattr(self, &quot;_linkedResource&quot;) else False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def resourceType(self):
</span><span class="cx">         return self._linkedResource.resourceType() if hasattr(self, &quot;_linkedResource&quot;) else davxml.ResourceType.link
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def locateChild(self, request, segments):
</span><del>-        
</del><ins>+
</ins><span class="cx">         def _defer(result):
</span><span class="cx">             if result is None:
</span><span class="cx">                 return (self, server.StopTraversal)
</span><span class="lines">@@ -87,6 +91,7 @@
</span><span class="cx">         d.addCallback(_defer)
</span><span class="cx">         return d
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def renderHTTP(self, request):
</span><span class="cx">         linked_to = (yield self.linkedResource(request))
</span><span class="lines">@@ -95,27 +100,33 @@
</span><span class="cx">         else:
</span><span class="cx">             returnValue(http.StatusResponse(responsecode.OK, &quot;Link resource with missing target: %s&quot; % (self.linkURL,)))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def getChild(self, name):
</span><span class="cx">         return self._linkedResource.getChild(name) if hasattr(self, &quot;_linkedResource&quot;) else None
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def hasProperty(self, property, request):
</span><span class="cx">         hosted = (yield self.linkedResource(request))
</span><span class="cx">         result = (yield hosted.hasProperty(property, request)) if hosted else False
</span><span class="cx">         returnValue(result)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def readProperty(self, property, request):
</span><span class="cx">         hosted = (yield self.linkedResource(request))
</span><span class="cx">         result = (yield hosted.readProperty(property, request)) if hosted else None
</span><span class="cx">         returnValue(result)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def writeProperty(self, property, request):
</span><span class="cx">         hosted = (yield self.linkedResource(request))
</span><span class="cx">         result = (yield hosted.writeProperty(property, request)) if hosted else None
</span><span class="cx">         returnValue(result)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class LinkFollowerMixIn(object):
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -128,6 +139,5 @@
</span><span class="cx">             if linked_to is None:
</span><span class="cx">                 break
</span><span class="cx">             resource = linked_to
</span><del>-        
</del><ins>+
</ins><span class="cx">         returnValue((resource, path))
</span><del>-        
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavlocalizationpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/localization.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/localization.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/localization.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -24,7 +24,7 @@
</span><span class="cx"> from locale import normalize
</span><span class="cx"> 
</span><span class="cx"> from twext.python.log import Logger
</span><del>-from pycalendar.duration import PyCalendarDuration
</del><ins>+from pycalendar.duration import Duration
</ins><span class="cx"> 
</span><span class="cx"> try:
</span><span class="cx">     from Foundation import (
</span><span class="lines">@@ -89,12 +89,12 @@
</span><span class="cx"> helper methods for date formatting:
</span><span class="cx"> 
</span><span class="cx">     with translationTo('en') as trans:
</span><del>-        print(trans.dtDate(PyCalendarDateTime.getToday()))
</del><ins>+        print(trans.dtDate(DateTime.getToday()))
</ins><span class="cx"> 
</span><span class="cx">     ... Thursday, October 23, 2008
</span><span class="cx"> 
</span><span class="cx">     with translationTo('fr') as trans:
</span><del>-        print(trans.dtDate(PyCalendarDateTime.getToday()))
</del><ins>+        print(trans.dtDate(DateTime.getToday()))
</ins><span class="cx"> 
</span><span class="cx">     ... Jeudi, Octobre 23, 2008
</span><span class="cx"> 
</span><span class="lines">@@ -124,12 +124,13 @@
</span><span class="cx">                 localedir=localeDir, languages=[lang, 'en'], fallback=True)
</span><span class="cx">             self.translations[key] = self.translation
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def __enter__(self):
</span><span class="cx">         # Get the caller's globals so we can rebind their '_' to our translator
</span><span class="cx">         caller_globals = inspect.stack()[1][0].f_globals
</span><span class="cx"> 
</span><span class="cx">         # Store whatever '_' is already bound to so we can restore it later
</span><del>-        if caller_globals.has_key('_'):
</del><ins>+        if '_' in caller_globals:
</ins><span class="cx">             self.prev = caller_globals['_']
</span><span class="cx"> 
</span><span class="cx">         # Rebind '_' to our translator
</span><span class="lines">@@ -138,6 +139,7 @@
</span><span class="cx">         # What we return here is accessible to the caller via the 'as' clause
</span><span class="cx">         return self
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def __exit__(self, type, value, traceback):
</span><span class="cx">         # Restore '_' if it previously had a value
</span><span class="cx">         if hasattr(self, 'prev'):
</span><span class="lines">@@ -146,13 +148,16 @@
</span><span class="cx">         # Don't swallow exceptions
</span><span class="cx">         return False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def monthAbbreviation(self, monthNumber):
</span><span class="cx">         return self.translation.ugettext(monthsAbbrev[monthNumber])
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def date(self, component):
</span><span class="cx">         dtStart = component.propertyValue(&quot;DTSTART&quot;)
</span><span class="cx">         return self.dtDate(dtStart)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def time(self, component):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Examples:
</span><span class="lines">@@ -191,9 +196,9 @@
</span><span class="cx">             else:
</span><span class="cx">                 if dtStart.isDateOnly():
</span><span class="cx">                     dtEnd = None
</span><del>-                    duration = PyCalendarDuration(days=1)
</del><ins>+                    duration = Duration(days=1)
</ins><span class="cx">                 else:
</span><del>-                    dtEnd = dtStart + PyCalendarDuration(days=1)
</del><ins>+                    dtEnd = dtStart + Duration(days=1)
</ins><span class="cx">                     dtEnd.setHHMMSS(0, 0, 0)
</span><span class="cx">                     duration = dtEnd - dtStart
</span><span class="cx"> 
</span><span class="lines">@@ -225,6 +230,7 @@
</span><span class="cx">             }
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def dtTime(self, val, includeTimezone=True):
</span><span class="cx">         if val.isDateOnly():
</span><span class="cx">             return &quot;&quot;
</span><span class="lines">@@ -252,6 +258,7 @@
</span><span class="cx"> 
</span><span class="cx">         return result
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def dtDuration(self, val):
</span><span class="cx"> 
</span><span class="cx">         # Bind to '_' so pygettext.py will pick this up for translation
</span><span class="lines">@@ -265,7 +272,7 @@
</span><span class="cx">             parts.append(_(&quot;1 day&quot;))
</span><span class="cx">         elif days &gt; 1:
</span><span class="cx">             parts.append(_(&quot;%(dayCount)d days&quot;) %
</span><del>-                { 'dayCount' : days })
</del><ins>+                {'dayCount' : days})
</ins><span class="cx"> 
</span><span class="cx">         hours = divmod(total / 3600, 24)[1]
</span><span class="cx">         minutes = divmod(total / 60, 60)[1]
</span><span class="lines">@@ -275,19 +282,19 @@
</span><span class="cx">             parts.append(_(&quot;1 hour&quot;))
</span><span class="cx">         elif hours &gt; 1:
</span><span class="cx">             parts.append(_(&quot;%(hourCount)d hours&quot;) %
</span><del>-                { 'hourCount' : hours })
</del><ins>+                {'hourCount' : hours})
</ins><span class="cx"> 
</span><span class="cx">         if minutes == 1:
</span><span class="cx">             parts.append(_(&quot;1 minute&quot;))
</span><span class="cx">         elif minutes &gt; 1:
</span><span class="cx">             parts.append(_(&quot;%(minuteCount)d minutes&quot;) %
</span><del>-                { 'minuteCount' : minutes })
</del><ins>+                {'minuteCount' : minutes})
</ins><span class="cx"> 
</span><span class="cx">         if seconds == 1:
</span><span class="cx">             parts.append(_(&quot;1 second&quot;))
</span><span class="cx">         elif seconds &gt; 1:
</span><span class="cx">             parts.append(_(&quot;%(secondCount)d seconds&quot;) %
</span><del>-                { 'secondCount' : seconds })
</del><ins>+                {'secondCount' : seconds})
</ins><span class="cx"> 
</span><span class="cx">         return &quot; &quot;.join(parts)
</span><span class="cx"> 
</span><span class="lines">@@ -398,12 +405,14 @@
</span><span class="cx">                     else:
</span><span class="cx">                         log.info(&quot;%s is up to date&quot; % (moFile,))
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class ParseError(Exception):
</span><span class="cx">     pass
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def convertStringsFile(src, dest):
</span><del>-    strings = { }
</del><span class="cx"> 
</span><span class="cx">     dir = os.path.dirname(dest)
</span><span class="cx"> 
</span><span class="lines">@@ -458,13 +467,13 @@
</span><span class="cx"> 
</span><span class="cx">     result = struct.pack(
</span><span class="cx">         &quot;Iiiiiii&quot;,
</span><del>-        0x950412DEL,         # magic number
-        0,                   # file format revision
-        len(originals),      # number of strings
-        28,                  # offset of table with original strings
-        28+len(originals)*8, # offset of table with translation strings
-        0,                   # size of hashing table
-        0                    # offset of hashing table
</del><ins>+        0x950412DEL,           # magic number
+        0,                     # file format revision
+        len(originals),        # number of strings
+        28,                    # offset of table with original strings
+        28 + len(originals) * 8, # offset of table with translation strings
+        0,                     # size of hashing table
+        0                      # offset of hashing table
</ins><span class="cx">     )
</span><span class="cx">     result += array.array(&quot;i&quot;, keyDescriptors).tostring()
</span><span class="cx">     result += array.array(&quot;i&quot;, valueDescriptors).tostring()
</span><span class="lines">@@ -475,6 +484,7 @@
</span><span class="cx">         outFile.write(result)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def getLanguage(config):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     If the language has been specified explicitly in the config, return it.  Otherwise
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmemcachelockpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/memcachelock.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/memcachelock.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/memcachelock.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -15,7 +15,7 @@
</span><span class="cx"> ##
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav.memcacher import Memcacher
</span><del>-from twisted.internet.defer import inlineCallbacks, Deferred, returnValue,\
</del><ins>+from twisted.internet.defer import inlineCallbacks, Deferred, returnValue, \
</ins><span class="cx">     succeed
</span><span class="cx"> from twisted.internet import reactor
</span><span class="cx"> import time
</span><span class="lines">@@ -24,7 +24,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, namespace, locktoken, timeout=5.0, retry_interval=0.1, expire_time=0):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         @param namespace: a unique namespace for this lock's tokens
</span><span class="cx">         @type namespace: C{str}
</span><span class="cx">         @param locktoken: the name of the locktoken
</span><span class="lines">@@ -44,31 +44,33 @@
</span><span class="cx">         self._expire_time = expire_time
</span><span class="cx">         self._hasLock = False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _getMemcacheProtocol(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         result = super(MemcacheLock, self)._getMemcacheProtocol()
</span><span class="cx"> 
</span><span class="cx">         if isinstance(result, Memcacher.nullCacher):
</span><span class="cx">             raise AssertionError(&quot;No implementation of shared locking without memcached&quot;)
</span><del>-        
</del><ins>+
</ins><span class="cx">         return result
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def acquire(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         assert not self._hasLock, &quot;Lock already acquired.&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">         timeout_at = time.time() + self._timeout
</span><span class="cx">         waiting = False
</span><span class="cx">         while True:
</span><del>-            
</del><ins>+
</ins><span class="cx">             result = (yield self.add(self._locktoken, &quot;1&quot;, expireTime=self._expire_time))
</span><span class="cx">             if result:
</span><span class="cx">                 self._hasLock = True
</span><span class="cx">                 if waiting:
</span><span class="cx">                     self.log.debug(&quot;Got lock after waiting on %s&quot; % (self._locktoken,))
</span><span class="cx">                 break
</span><del>-            
</del><ins>+
</ins><span class="cx">             if self._timeout and time.time() &lt; timeout_at:
</span><span class="cx">                 waiting = True
</span><span class="cx">                 self.log.debug(&quot;Waiting for lock on %s&quot; % (self._locktoken,))
</span><span class="lines">@@ -80,13 +82,14 @@
</span><span class="cx">             else:
</span><span class="cx">                 self.log.debug(&quot;Timed out lock after waiting on %s&quot; % (self._locktoken,))
</span><span class="cx">                 raise MemcacheLockTimeoutError()
</span><del>-        
</del><ins>+
</ins><span class="cx">         returnValue(True)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def release(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         assert self._hasLock, &quot;Lock not acquired.&quot;
</span><del>-    
</del><ins>+
</ins><span class="cx">         def _done(result):
</span><span class="cx">             self._hasLock = False
</span><span class="cx">             return result
</span><span class="lines">@@ -95,18 +98,20 @@
</span><span class="cx">         d.addCallback(_done)
</span><span class="cx">         return d
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def clean(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         if self._hasLock:
</span><span class="cx">             return self.release()
</span><span class="cx">         else:
</span><span class="cx">             return succeed(True)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def locked(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Test if the lock is currently being held.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         def _gotit(value):
</span><span class="cx">             return value is not None
</span><span class="cx"> 
</span><span class="lines">@@ -114,5 +119,7 @@
</span><span class="cx">         d.addCallback(_gotit)
</span><span class="cx">         return d
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class MemcacheLockTimeoutError(Exception):
</span><span class="cx">     pass
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmemcachepoolpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/memcachepool.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/memcachepool.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/memcachepool.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -99,6 +99,7 @@
</span><span class="cx">             connector,
</span><span class="cx">             reason)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def buildProtocol(self, addr):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Attach the C{self.connectionPool} to the protocol so it can tell it,
</span><span class="lines">@@ -167,6 +168,7 @@
</span><span class="cx">         self._pendingConnects = 0
</span><span class="cx">         self._commands = []
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _isIdle(self):
</span><span class="cx">         return (
</span><span class="cx">             len(self._busyClients) == 0 and
</span><span class="lines">@@ -174,6 +176,7 @@
</span><span class="cx">             self._pendingConnects == 0
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _shutdownCallback(self):
</span><span class="cx">         self.shutdown_requested = True
</span><span class="cx">         if self._isIdle():
</span><span class="lines">@@ -181,13 +184,14 @@
</span><span class="cx">         self.shutdown_deferred = Deferred()
</span><span class="cx">         return self.shutdown_deferred
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _newClientConnection(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Create a new client connection.
</span><span class="cx"> 
</span><span class="cx">         @return: A L{Deferred} that fires with the L{IProtocol} instance.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        self.log.debug(&quot;Initating new client connection to: %r&quot; % (
</del><ins>+        self.log.debug(&quot;Initiating new client connection to: %r&quot; % (
</ins><span class="cx">                 self._endpoint,))
</span><span class="cx">         self._logClientStats()
</span><span class="cx"> 
</span><span class="lines">@@ -219,7 +223,7 @@
</span><span class="cx"> 
</span><span class="cx">         @param command: A C{str} representing an attribute of
</span><span class="cx">             L{MemCacheProtocol}.
</span><del>-        @parma args: Any positional arguments that should be passed to
</del><ins>+        @param args: Any positional arguments that should be passed to
</ins><span class="cx">             C{command}.
</span><span class="cx">         @param kwargs: Any keyword arguments that should be passed to
</span><span class="cx">             C{command}.
</span><span class="lines">@@ -258,7 +262,7 @@
</span><span class="cx"> 
</span><span class="cx">         @param command: A C{str} representing an attribute of
</span><span class="cx">             L{MemCacheProtocol}.
</span><del>-        @parma args: Any positional arguments that should be passed to
</del><ins>+        @param args: Any positional arguments that should be passed to
</ins><span class="cx">             C{command}.
</span><span class="cx">         @param kwargs: Any keyword arguments that should be passed to
</span><span class="cx">             C{command}.
</span><span class="lines">@@ -371,24 +375,31 @@
</span><span class="cx">     def get(self, *args, **kwargs):
</span><span class="cx">         return self.performRequest('get', *args, **kwargs)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def set(self, *args, **kwargs):
</span><span class="cx">         return self.performRequest('set', *args, **kwargs)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def checkAndSet(self, *args, **kwargs):
</span><span class="cx">         return self.performRequest('checkAndSet', *args, **kwargs)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def delete(self, *args, **kwargs):
</span><span class="cx">         return self.performRequest('delete', *args, **kwargs)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def add(self, *args, **kwargs):
</span><span class="cx">         return self.performRequest('add', *args, **kwargs)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def incr(self, *args, **kwargs):
</span><span class="cx">         return self.performRequest('increment', *args, **kwargs)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def decr(self, *args, **kwargs):
</span><span class="cx">         return self.performRequest('decrement', *args, **kwargs)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def flushAll(self, *args, **kwargs):
</span><span class="cx">         return self.performRequest('flushAll', *args, **kwargs)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmethodgetpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/get.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/get.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/get.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -25,7 +25,7 @@
</span><span class="cx"> from txdav.xml import element as davxml
</span><span class="cx"> from twext.web2.dav.http import ErrorResponse
</span><span class="cx"> from twext.web2.dav.util import parentForURL
</span><del>-from twext.web2.http import HTTPError
</del><ins>+from twext.web2.http import HTTPError, StatusResponse
</ins><span class="cx"> from twext.web2.http import Response
</span><span class="cx"> from twext.web2.http_headers import MimeType
</span><span class="cx"> from twext.web2.stream import MemoryStream
</span><span class="lines">@@ -34,8 +34,10 @@
</span><span class="cx"> from twistedcaldav.customxml import calendarserver_namespace
</span><span class="cx"> from twistedcaldav.datafilters.hiddeninstance import HiddenInstanceFilter
</span><span class="cx"> from twistedcaldav.datafilters.privateevents import PrivateEventFilter
</span><ins>+from twistedcaldav.ical import Component
</ins><span class="cx"> from twistedcaldav.resource import isPseudoCalendarCollectionResource, \
</span><span class="cx">     CalDAVResource
</span><ins>+from twistedcaldav.util import bestAcceptType
</ins><span class="cx"> 
</span><span class="cx"> @inlineCallbacks
</span><span class="cx"> def http_GET(self, request):
</span><span class="lines">@@ -70,6 +72,8 @@
</span><span class="cx">                 returnValue(response)
</span><span class="cx"> 
</span><span class="cx">         else:
</span><ins>+            # FIXME: this should be implemented in storebridge.CalendarObject.render
+
</ins><span class="cx">             # Look for calendar access restriction on existing resource.
</span><span class="cx">             parentURL = parentForURL(request.uri)
</span><span class="cx">             parent = (yield request.locateResource(parentURL))
</span><span class="lines">@@ -78,6 +82,11 @@
</span><span class="cx">                 # Check authorization first
</span><span class="cx">                 yield self.authorize(request, (davxml.Read(),))
</span><span class="cx"> 
</span><ins>+                # Accept header handling
+                accepted_type = bestAcceptType(request.headers.getHeader(&quot;accept&quot;), Component.allowedTypes())
+                if accepted_type is None:
+                    raise HTTPError(StatusResponse(responsecode.NOT_ACCEPTABLE, &quot;Cannot generate requested data type&quot;))
+
</ins><span class="cx">                 caldata = (yield self.iCalendarForUser(request))
</span><span class="cx"> 
</span><span class="cx">                 # Filter any attendee hidden instances
</span><span class="lines">@@ -92,8 +101,8 @@
</span><span class="cx">                     caldata = PrivateEventFilter(self.accessMode, isowner).filter(caldata)
</span><span class="cx"> 
</span><span class="cx">                 response = Response()
</span><del>-                response.stream = MemoryStream(caldata.getTextWithTimezones(includeTimezones=not config.EnableTimezonesByReference))
-                response.headers.setHeader(&quot;content-type&quot;, MimeType.fromString(&quot;text/calendar; charset=utf-8&quot;))
</del><ins>+                response.stream = MemoryStream(caldata.getTextWithTimezones(includeTimezones=not config.EnableTimezonesByReference, format=accepted_type))
+                response.headers.setHeader(&quot;content-type&quot;, MimeType.fromString(&quot;%s; charset=utf-8&quot; % (accepted_type,)))
</ins><span class="cx"> 
</span><span class="cx">                 # Add Schedule-Tag header if property is present
</span><span class="cx">                 if self.scheduleTag:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmethodpropfindpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/propfind.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/propfind.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/propfind.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -98,7 +98,7 @@
</span><span class="cx">             search_properties = &quot;names&quot;
</span><span class="cx">         elif isinstance(container, davxml.PropertyContainer):
</span><span class="cx">             properties = container.children
</span><del>-            search_properties = [(p.namespace, p.name) for p in properties]
</del><ins>+            search_properties = properties
</ins><span class="cx">         else:
</span><span class="cx">             raise AssertionError(&quot;Unexpected element type in %s: %s&quot;
</span><span class="cx">                                  % (davxml.PropertyFind.sname(), container))
</span><span class="lines">@@ -245,7 +245,11 @@
</span><span class="cx"> # Utilities
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-def propertyName(name):
</del><ins>+def propertyName(prop):
+    if type(prop) is tuple:
+        name = prop
+    else:
+        name = prop.qname()
</ins><span class="cx">     property_namespace, property_name = name
</span><span class="cx">     pname = davxml.WebDAVUnknownElement()
</span><span class="cx">     pname.namespace = property_namespace
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmethodreport_calendar_querypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_calendar_query.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_calendar_query.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_calendar_query.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -32,7 +32,8 @@
</span><span class="cx"> from twext.web2.http import HTTPError, StatusResponse
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav import caldavxml
</span><del>-from twistedcaldav.caldavxml import caldav_namespace, MaxInstances
</del><ins>+from twistedcaldav.caldavxml import caldav_namespace, MaxInstances, \
+    CalendarTimeZone
</ins><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from txdav.common.icommondatastore import IndexedSearchException, \
</span><span class="cx">     ConcurrentModification
</span><span class="lines">@@ -171,10 +172,10 @@
</span><span class="cx">         if calresource.isPseudoCalendarCollection():
</span><span class="cx">             # Get the timezone property from the collection if one was not set in the query,
</span><span class="cx">             # and store in the query filter for later use
</span><del>-            has_prop = (yield calresource.hasProperty((caldav_namespace, &quot;calendar-timezone&quot;), request))
</del><ins>+            has_prop = (yield calresource.hasProperty(CalendarTimeZone(), request))
</ins><span class="cx">             timezone = query_timezone
</span><span class="cx">             if query_tz is None and has_prop:
</span><del>-                tz = (yield calresource.readProperty((caldav_namespace, &quot;calendar-timezone&quot;), request))
</del><ins>+                tz = (yield calresource.readProperty(CalendarTimeZone(), request))
</ins><span class="cx">                 filter.settimezone(tz)
</span><span class="cx">                 timezone = tuple(tz.calendar().subcomponents())[0]
</span><span class="cx"> 
</span><span class="lines">@@ -233,9 +234,9 @@
</span><span class="cx">                 parent = (yield calresource.locateParent(request, uri))
</span><span class="cx">                 assert parent is not None and parent.isPseudoCalendarCollection()
</span><span class="cx"> 
</span><del>-                has_prop = (yield parent.hasProperty((caldav_namespace, &quot;calendar-timezone&quot;), request))
</del><ins>+                has_prop = (yield parent.hasProperty(CalendarTimeZone(), request))
</ins><span class="cx">                 if has_prop:
</span><del>-                    tz = (yield parent.readProperty((caldav_namespace, &quot;calendar-timezone&quot;), request))
</del><ins>+                    tz = (yield parent.readProperty(CalendarTimeZone(), request))
</ins><span class="cx">                     filter.settimezone(tz)
</span><span class="cx">                     timezone = tuple(tz.calendar().subcomponents())[0]
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmethodreport_commonpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_common.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_common.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_common.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -52,7 +52,7 @@
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav import caldavxml
</span><span class="cx"> from twistedcaldav import carddavxml
</span><del>-from twistedcaldav.caldavxml import caldav_namespace, CalendarData, TimeRange
</del><ins>+from twistedcaldav.caldavxml import CalendarData, CalendarTimeZone, TimeRange
</ins><span class="cx"> from twistedcaldav.carddavxml import AddressData
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.datafilters.calendardata import CalendarDataFilter
</span><span class="lines">@@ -69,10 +69,10 @@
</span><span class="cx"> 
</span><span class="cx"> from txdav.common.icommondatastore import IndexedSearchException
</span><span class="cx"> 
</span><del>-from pycalendar.duration import PyCalendarDuration
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
-from pycalendar.period import PyCalendarPeriod
</del><ins>+from pycalendar.duration import Duration
+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
+from pycalendar.period import Period
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -299,7 +299,7 @@
</span><span class="cx">     generate_calendar_data = False
</span><span class="cx">     for property in prop.children:
</span><span class="cx">         if isinstance(property, caldavxml.CalendarData):
</span><del>-            if not property.verifyTypeVersion([(&quot;text/calendar&quot;, &quot;2.0&quot;)]):
</del><ins>+            if not property.verifyTypeVersion():
</ins><span class="cx">                 result = False
</span><span class="cx">                 message = &quot;Calendar-data element type/version not supported: content-type: %s, version: %s&quot; % (property.content_type, property.version)
</span><span class="cx">             generate_calendar_data = True
</span><span class="lines">@@ -324,7 +324,7 @@
</span><span class="cx">     generate_address_data = False
</span><span class="cx">     for property in prop.children:
</span><span class="cx">         if isinstance(property, carddavxml.AddressData):
</span><del>-            if not property.verifyTypeVersion([(&quot;text/vcard&quot;, &quot;3.0&quot;)]):
</del><ins>+            if not property.verifyTypeVersion():
</ins><span class="cx">                 result = False
</span><span class="cx">                 message = &quot;Address-data element type/version not supported: content-type: %s, version: %s&quot; % (property.content_type, property.version)
</span><span class="cx">             generate_address_data = True
</span><span class="lines">@@ -371,7 +371,7 @@
</span><span class="cx">             filtered = HiddenInstanceFilter().filter(calendar)
</span><span class="cx">             filtered = PrivateEventFilter(resource.accessMode, isowner).filter(filtered)
</span><span class="cx">             filtered = CalendarDataFilter(property, timezone).filter(filtered)
</span><del>-            propvalue = CalendarData().fromCalendar(filtered)
</del><ins>+            propvalue = CalendarData.fromCalendar(filtered, format=property.content_type)
</ins><span class="cx">             properties_by_status[responsecode.OK].append(propvalue)
</span><span class="cx">             continue
</span><span class="cx"> 
</span><span class="lines">@@ -379,7 +379,7 @@
</span><span class="cx">             if vcard is None:
</span><span class="cx">                 vcard = (yield resource.vCard())
</span><span class="cx">             filtered = AddressDataFilter(property).filter(vcard)
</span><del>-            propvalue = AddressData().fromAddress(filtered)
</del><ins>+            propvalue = AddressData.fromAddress(filtered, format=property.content_type)
</ins><span class="cx">             properties_by_status[responsecode.OK].append(propvalue)
</span><span class="cx">             continue
</span><span class="cx"> 
</span><span class="lines">@@ -392,7 +392,7 @@
</span><span class="cx"> 
</span><span class="cx">         if has:
</span><span class="cx">             try:
</span><del>-                prop = (yield resource.readProperty(qname, request))
</del><ins>+                prop = (yield resource.readProperty(property, request))
</ins><span class="cx">                 if prop is not None:
</span><span class="cx">                     properties_by_status[responsecode.OK].append(prop)
</span><span class="cx">                 elif not returnMinimal:
</span><span class="lines">@@ -436,8 +436,8 @@
</span><span class="cx">         if entry:
</span><span class="cx"> 
</span><span class="cx">             # Offset one day at either end to account for floating
</span><del>-            cached_start = entry.timerange.start + PyCalendarDuration(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
-            cached_end = entry.timerange.end - PyCalendarDuration(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
</del><ins>+            cached_start = entry.timerange.start + Duration(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
+            cached_end = entry.timerange.end - Duration(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
</ins><span class="cx"> 
</span><span class="cx">             # Verify that the requested timerange lies within the cache timerange
</span><span class="cx">             if compareDateTime(timerange.end, cached_end) &lt;= 0 and compareDateTime(timerange.start, cached_start) &gt;= 0:
</span><span class="lines">@@ -515,9 +515,9 @@
</span><span class="cx">         useruid = &quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     # Get the timezone property from the collection.
</span><del>-    has_prop = (yield calresource.hasProperty((caldav_namespace, &quot;calendar-timezone&quot;), request))
</del><ins>+    has_prop = (yield calresource.hasProperty(CalendarTimeZone(), request))
</ins><span class="cx">     if has_prop:
</span><del>-        tz = (yield calresource.readProperty((caldav_namespace, &quot;calendar-timezone&quot;), request))
</del><ins>+        tz = (yield calresource.readProperty(CalendarTimeZone(), request))
</ins><span class="cx">     else:
</span><span class="cx">         tz = None
</span><span class="cx"> 
</span><span class="lines">@@ -559,8 +559,8 @@
</span><span class="cx">             request.extendedLogItems[&quot;fb-uncached&quot;] = request.extendedLogItems.get(&quot;fb-uncached&quot;, 0) + 1
</span><span class="cx"> 
</span><span class="cx">             # We want to cache a large range of time based on the current date
</span><del>-            cache_start = normalizeToUTC(PyCalendarDateTime.getToday() + PyCalendarDuration(days=0 - config.FreeBusyCacheDaysBack))
-            cache_end = normalizeToUTC(PyCalendarDateTime.getToday() + PyCalendarDuration(days=config.FreeBusyCacheDaysForward))
</del><ins>+            cache_start = normalizeToUTC(DateTime.getToday() + Duration(days=0 - config.FreeBusyCacheDaysBack))
+            cache_end = normalizeToUTC(DateTime.getToday() + Duration(days=config.FreeBusyCacheDaysForward))
</ins><span class="cx"> 
</span><span class="cx">             # If the requested timerange would fit in our allowed cache range, trigger the cache creation
</span><span class="cx">             if compareDateTime(timerange.start, cache_start) &gt;= 0 and compareDateTime(timerange.end, cache_end) &lt;= 0:
</span><span class="lines">@@ -602,7 +602,7 @@
</span><span class="cx">         request.extendedLogItems[&quot;fb-cached&quot;] = request.extendedLogItems.get(&quot;fb-cached&quot;, 0) + 1
</span><span class="cx"> 
</span><span class="cx">         # Determine appropriate timezone (UTC is the default)
</span><del>-        tzinfo = tz.gettimezone() if tz is not None else PyCalendarTimezone(utc=True)
</del><ins>+        tzinfo = tz.gettimezone() if tz is not None else Timezone(utc=True)
</ins><span class="cx"> 
</span><span class="cx">     # We care about separate instances for VEVENTs only
</span><span class="cx">     aggregated_resources = {}
</span><span class="lines">@@ -645,15 +645,15 @@
</span><span class="cx">                 if float == 'Y':
</span><span class="cx">                     fbstart.setTimezone(tzinfo)
</span><span class="cx">                 else:
</span><del>-                    fbstart.setTimezone(PyCalendarTimezone(utc=True))
</del><ins>+                    fbstart.setTimezone(Timezone(utc=True))
</ins><span class="cx">                 fbend = parseSQLTimestampToPyCalendar(end)
</span><span class="cx">                 if float == 'Y':
</span><span class="cx">                     fbend.setTimezone(tzinfo)
</span><span class="cx">                 else:
</span><del>-                    fbend.setTimezone(PyCalendarTimezone(utc=True))
</del><ins>+                    fbend.setTimezone(Timezone(utc=True))
</ins><span class="cx"> 
</span><span class="cx">                 # Clip instance to time range
</span><del>-                clipped = clipPeriod(PyCalendarPeriod(fbstart, duration=fbend - fbstart), PyCalendarPeriod(timerange.start, timerange.end))
</del><ins>+                clipped = clipPeriod(Period(fbstart, duration=fbend - fbstart), Period(timerange.start, timerange.end))
</ins><span class="cx"> 
</span><span class="cx">                 # Double check for overlap
</span><span class="cx">                 if clipped:
</span><span class="lines">@@ -735,7 +735,7 @@
</span><span class="cx">     @param timerange: the time-range in which to expand
</span><span class="cx">     @type timerange: L{TimeRange}
</span><span class="cx">     @param tzinfo: timezone for floating time calculations
</span><del>-    @type tzinfo: L{PyCalendarTimezone}
</del><ins>+    @type tzinfo: L{Timezone}
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     # First expand the component
</span><span class="lines">@@ -775,7 +775,7 @@
</span><span class="cx">     @param calendar: the L{Component} that is the VCALENDAR containing the VEVENT's.
</span><span class="cx">     @param fbinfo: the tuple used to store the three types of fb data.
</span><span class="cx">     @param timerange: the time range to restrict free busy data to.
</span><del>-    @param tzinfo: the L{PyCalendarTimezone} for the timezone to use for floating/all-day events.
</del><ins>+    @param tzinfo: the L{Timezone} for the timezone to use for floating/all-day events.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     # Expand out the set of instances for the event with in the required range
</span><span class="lines">@@ -820,10 +820,10 @@
</span><span class="cx">         # Clip period for this instance - use duration for period end if that
</span><span class="cx">         # is what original component used
</span><span class="cx">         if instance.component.hasProperty(&quot;DURATION&quot;):
</span><del>-            period = PyCalendarPeriod(fbstart, duration=fbend - fbstart)
</del><ins>+            period = Period(fbstart, duration=fbend - fbstart)
</ins><span class="cx">         else:
</span><del>-            period = PyCalendarPeriod(fbstart, fbend)
-        clipped = clipPeriod(period, PyCalendarPeriod(timerange.start, timerange.end))
</del><ins>+            period = Period(fbstart, fbend)
+        clipped = clipPeriod(period, Period(timerange.start, timerange.end))
</ins><span class="cx"> 
</span><span class="cx">         # Double check for overlap
</span><span class="cx">         if clipped:
</span><span class="lines">@@ -861,7 +861,7 @@
</span><span class="cx">             assert isinstance(fb.value(), list), &quot;FREEBUSY property does not contain a list of values: %r&quot; % (fb,)
</span><span class="cx">             for period in fb.value():
</span><span class="cx">                 # Clip period for this instance
</span><del>-                clipped = clipPeriod(period.getValue(), PyCalendarPeriod(timerange.start, timerange.end))
</del><ins>+                clipped = clipPeriod(period.getValue(), Period(timerange.start, timerange.end))
</ins><span class="cx">                 if clipped:
</span><span class="cx">                     fbinfo[fbtype_mapper.get(fbtype, 0)].append(clipped)
</span><span class="cx"> 
</span><span class="lines">@@ -880,12 +880,12 @@
</span><span class="cx">         # Get overall start/end
</span><span class="cx">         start = vav.getStartDateUTC()
</span><span class="cx">         if start is None:
</span><del>-            start = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+            start = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         end = vav.getEndDateUTC()
</span><span class="cx">         if end is None:
</span><del>-            end = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
-        period = PyCalendarPeriod(start, end)
-        overall = clipPeriod(period, PyCalendarPeriod(timerange.start, timerange.end))
</del><ins>+            end = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
+        period = Period(start, end)
+        overall = clipPeriod(period, Period(timerange.start, timerange.end))
</ins><span class="cx">         if overall is None:
</span><span class="cx">             continue
</span><span class="cx"> 
</span><span class="lines">@@ -897,10 +897,10 @@
</span><span class="cx">         last_end = timerange.start
</span><span class="cx">         for period in periods:
</span><span class="cx">             if last_end &lt; period.getStart():
</span><del>-                busyperiods.append(PyCalendarPeriod(last_end, period.getStart()))
</del><ins>+                busyperiods.append(Period(last_end, period.getStart()))
</ins><span class="cx">             last_end = period.getEnd()
</span><span class="cx">         if last_end &lt; timerange.end:
</span><del>-            busyperiods.append(PyCalendarPeriod(last_end, timerange.end))
</del><ins>+            busyperiods.append(Period(last_end, timerange.end))
</ins><span class="cx"> 
</span><span class="cx">         # Add to actual results mapped by busy type
</span><span class="cx">         fbtype = vav.propertyValue(&quot;BUSYTYPE&quot;)
</span><span class="lines">@@ -947,10 +947,10 @@
</span><span class="cx">             # Clip period for this instance - use duration for period end if that
</span><span class="cx">             # is what original component used
</span><span class="cx">             if instance.component.hasProperty(&quot;DURATION&quot;):
</span><del>-                period = PyCalendarPeriod(start, duration=end - start)
</del><ins>+                period = Period(start, duration=end - start)
</ins><span class="cx">             else:
</span><del>-                period = PyCalendarPeriod(start, end)
-            clipped = clipPeriod(period, PyCalendarPeriod(timerange.start, timerange.end))
</del><ins>+                period = Period(start, end)
+            clipped = clipPeriod(period, Period(timerange.start, timerange.end))
</ins><span class="cx">             if clipped:
</span><span class="cx">                 periods.append(clipped)
</span><span class="cx"> 
</span><span class="lines">@@ -993,7 +993,7 @@
</span><span class="cx">         fb.addProperty(attendee)
</span><span class="cx">     fb.addProperty(Property(&quot;DTSTART&quot;, timerange.start))
</span><span class="cx">     fb.addProperty(Property(&quot;DTEND&quot;, timerange.end))
</span><del>-    fb.addProperty(Property(&quot;DTSTAMP&quot;, PyCalendarDateTime.getNowUTC()))
</del><ins>+    fb.addProperty(Property(&quot;DTSTAMP&quot;, DateTime.getNowUTC()))
</ins><span class="cx">     if len(fbinfo[0]) != 0:
</span><span class="cx">         fb.addProperty(Property(&quot;FREEBUSY&quot;, fbinfo[0], {&quot;FBTYPE&quot;: &quot;BUSY&quot;}))
</span><span class="cx">     if len(fbinfo[1]) != 0:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmethodreport_freebusypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_freebusy.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_freebusy.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/method/report_freebusy.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -31,7 +31,9 @@
</span><span class="cx"> from twext.web2.stream import MemoryStream
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav import caldavxml
</span><ins>+from twistedcaldav.ical import Component
</ins><span class="cx"> from twistedcaldav.method import report_common
</span><ins>+from twistedcaldav.util import bestAcceptType
</ins><span class="cx"> 
</span><span class="cx"> from txdav.caldav.icalendarstore import TimeRangeLowerLimit, TimeRangeUpperLimit
</span><span class="cx"> from txdav.xml import element as davxml
</span><span class="lines">@@ -60,6 +62,11 @@
</span><span class="cx"> 
</span><span class="cx">     matchcount = [0]
</span><span class="cx"> 
</span><ins>+    accepted_type = bestAcceptType(request.headers.getHeader(&quot;accept&quot;), Component.allowedTypes())
+    if accepted_type is None:
+        raise HTTPError(StatusResponse(responsecode.NOT_ACCEPTABLE, &quot;Cannot generate requested data type&quot;))
+
+
</ins><span class="cx">     def generateFreeBusyInfo(calresource, uri): #@UnusedVariable
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Run a free busy report on the specified calendar collection
</span><span class="lines">@@ -104,7 +111,7 @@
</span><span class="cx">     fbcalendar = report_common.buildFreeBusyResult(fbinfo, timerange)
</span><span class="cx"> 
</span><span class="cx">     response = Response()
</span><del>-    response.stream = MemoryStream(str(fbcalendar))
-    response.headers.setHeader(&quot;content-type&quot;, MimeType.fromString(&quot;text/calendar; charset=utf-8&quot;))
</del><ins>+    response.stream = MemoryStream(fbcalendar.getText(accepted_type))
+    response.headers.setHeader(&quot;content-type&quot;, MimeType.fromString(&quot;%s; charset=utf-8&quot; % (accepted_type,)))
</ins><span class="cx"> 
</span><span class="cx">     returnValue(response)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavmkcolxmlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/mkcolxml.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/mkcolxml.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/mkcolxml.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -45,11 +45,12 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     name = &quot;mkcol&quot;
</span><span class="cx"> 
</span><del>-    allowed_children = { (davxml.dav_namespace, &quot;set&quot;): (0, 1) }
</del><ins>+    allowed_children = {(davxml.dav_namespace, &quot;set&quot;): (0, 1)}
</ins><span class="cx"> 
</span><del>-    child_types = { &quot;WebDAVUnknownElement&quot;: (0, None) }
</del><ins>+    child_types = {&quot;WebDAVUnknownElement&quot;: (0, None)}
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> @registerElement
</span><span class="cx"> class MakeCollectionResponse (davxml.WebDAVElement):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -58,4 +59,4 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     name = &quot;mkcol-response&quot;
</span><span class="cx"> 
</span><del>-    allowed_children = { davxml.WebDAVElement: (0, None) }
</del><ins>+    allowed_children = {davxml.WebDAVElement: (0, None)}
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavnotificationspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/notifications.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/notifications.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/notifications.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -48,43 +48,53 @@
</span><span class="cx">         self._parent = parent
</span><span class="cx">         CalDAVResource.__init__(self)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def principalCollections(self):
</span><span class="cx">         return self._parent.principalCollections()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def isCollection(self):
</span><span class="cx">         return False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def resourceName(self):
</span><span class="cx">         raise NotImplementedError
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def http_PUT(self, request):
</span><span class="cx">         return responsecode.FORBIDDEN
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def http_DELETE(self, request):
</span><del>-        
</del><ins>+
</ins><span class="cx">         response = (yield super(NotificationResource, self).http_DELETE(request))
</span><span class="cx">         if response == responsecode.NO_CONTENT:
</span><span class="cx">             yield self._parent.removedNotifictionMessage(request, self.resourceName())
</span><span class="cx">         returnValue(response)
</span><del>-    
</del><ins>+
+
+
</ins><span class="cx"> class NotificationCollectionResource(ReadOnlyNoCopyResourceMixIn, CalDAVResource):
</span><span class="cx"> 
</span><span class="cx">     def notificationsDB(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         if not hasattr(self, &quot;_notificationsDB&quot;):
</span><span class="cx">             self._notificationsDB = NotificationsDatabase(self)
</span><span class="cx">         return self._notificationsDB
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def isCollection(self):
</span><span class="cx">         return True
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def resourceType(self):
</span><span class="cx">         return davxml.ResourceType.notification
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def addNotification(self, request, uid, xmltype, xmldata):
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Write data to file
</span><span class="cx">         rname = uid + &quot;.xml&quot;
</span><span class="cx">         yield self._writeNotification(request, uid, rname, xmltype, xmldata)
</span><span class="lines">@@ -103,7 +113,7 @@
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def deleteNotifictionMessageByUID(self, request, uid):
</span><del>-        
</del><ins>+
</ins><span class="cx">         # See if it exists and delete the resource
</span><span class="cx">         record = yield self.notificationsDB().recordForUID(uid)
</span><span class="cx">         if record:
</span><span class="lines">@@ -117,7 +127,7 @@
</span><span class="cx">         record = yield self.notificationsDB().recordForName(rname)
</span><span class="cx">         if record:
</span><span class="cx">             yield self.deleteNotification(request, record)
</span><del>-        
</del><ins>+
</ins><span class="cx">         returnValue(None)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -131,13 +141,16 @@
</span><span class="cx">         return maybeDeferred(self.notificationsDB().removeRecordForName, rname)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class NotificationRecord(object):
</span><del>-    
</del><ins>+
</ins><span class="cx">     def __init__(self, uid, name, xmltype):
</span><span class="cx">         self.uid = uid
</span><span class="cx">         self.name = name
</span><span class="cx">         self.xmltype = xmltype
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class NotificationsDatabase(AbstractSQLDatabase):
</span><span class="cx">     log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -154,35 +167,40 @@
</span><span class="cx">         db_filename = os.path.join(self.resource.fp.path, NotificationsDatabase.db_basename)
</span><span class="cx">         super(NotificationsDatabase, self).__init__(db_filename, True, autocommit=True)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def allRecords(self):
</span><del>-        
</del><ins>+
</ins><span class="cx">         records = self._db_execute(&quot;select * from NOTIFICATIONS&quot;)
</span><span class="cx">         return [self._makeRecord(row) for row in (records if records is not None else ())]
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def recordForUID(self, uid):
</span><del>-        
</del><ins>+
</ins><span class="cx">         row = self._db_execute(&quot;select * from NOTIFICATIONS where UID = :1&quot;, uid)
</span><span class="cx">         return self._makeRecord(row[0]) if row else None
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def addOrUpdateRecord(self, record):
</span><span class="cx"> 
</span><span class="cx">         self._db_execute(&quot;&quot;&quot;insert or replace into NOTIFICATIONS (UID, NAME, TYPE)
</span><span class="cx">             values (:1, :2, :3)
</span><span class="cx">             &quot;&quot;&quot;, record.uid, record.name, record.xmltype,
</span><span class="cx">         )
</span><del>-            
</del><ins>+
</ins><span class="cx">         self._db_execute(
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="cx">             insert or replace into REVISIONS (NAME, REVISION, DELETED)
</span><span class="cx">             values (:1, :2, :3)
</span><span class="cx">             &quot;&quot;&quot;, record.name, self.bumpRevision(fast=True), 'N',
</span><span class="cx">         )
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def removeRecordForUID(self, uid):
</span><span class="cx"> 
</span><span class="cx">         record = self.recordForUID(uid)
</span><span class="cx">         self.removeRecordForName(record.name)
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def removeRecordForName(self, rname):
</span><span class="cx"> 
</span><span class="cx">         self._db_execute(&quot;delete from NOTIFICATIONS where NAME = :1&quot;, rname)
</span><span class="lines">@@ -192,12 +210,13 @@
</span><span class="cx">             where NAME = :3
</span><span class="cx">             &quot;&quot;&quot;, self.bumpRevision(fast=True), 'Y', rname
</span><span class="cx">         )
</span><del>-    
</del><ins>+
+
</ins><span class="cx">     def whatchanged(self, revision):
</span><span class="cx"> 
</span><span class="cx">         results = [(name.encode(&quot;utf-8&quot;), deleted) for name, deleted in self._db_execute(&quot;select NAME, DELETED from REVISIONS where REVISION &gt; :1&quot;, revision)]
</span><del>-        results.sort(key=lambda x:x[1])
-        
</del><ins>+        results.sort(key=lambda x: x[1])
+
</ins><span class="cx">         changed = []
</span><span class="cx">         deleted = []
</span><span class="cx">         for name, wasdeleted in results:
</span><span class="lines">@@ -209,14 +228,16 @@
</span><span class="cx">                     changed.append(name)
</span><span class="cx">             else:
</span><span class="cx">                 raise SyncTokenValidException
</span><del>-        
</del><ins>+
</ins><span class="cx">         return changed, deleted,
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def lastRevision(self):
</span><span class="cx">         return self._db_value_for_sql(
</span><span class="cx">             &quot;select REVISION from REVISION_SEQUENCE&quot;
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def bumpRevision(self, fast=False):
</span><span class="cx">         self._db_execute(
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="lines">@@ -230,18 +251,21 @@
</span><span class="cx">             &quot;&quot;&quot;,
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_version(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the schema version assigned to this index.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return NotificationsDatabase.schema_version
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_type(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the collection type assigned to this index.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return NotificationsDatabase.db_type
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_init_data_tables(self, q):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Initialise the underlying database tables.
</span><span class="lines">@@ -302,6 +326,7 @@
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_upgrade_data_tables(self, q, old_version):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Upgrade the data from an older version of the DB.
</span><span class="lines">@@ -310,7 +335,7 @@
</span><span class="cx">         # Nothing to do as we have not changed the schema
</span><span class="cx">         pass
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _makeRecord(self, row):
</span><del>-        
</del><ins>+
</ins><span class="cx">         return NotificationRecord(*[str(item) if type(item) == types.UnicodeType else item for item in row])
</span><del>-
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavquerycalendarqueryfilterpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/calendarqueryfilter.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/calendarqueryfilter.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/calendarqueryfilter.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -28,8 +28,8 @@
</span><span class="cx"> from twistedcaldav.dateops import timeRangesOverlap
</span><span class="cx"> from twistedcaldav.ical import Component, Property
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -89,7 +89,7 @@
</span><span class="cx">                     instances = None
</span><span class="cx">                 else:
</span><span class="cx">                     # Expand the instances up to infinity
</span><del>-                    instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), ignoreInvalidInstances=True)
</del><ins>+                    instances = component.expandTimeRanges(DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)), ignoreInvalidInstances=True)
</ins><span class="cx">             else:
</span><span class="cx">                 instances = component.expandTimeRanges(maxend, ignoreInvalidInstances=True)
</span><span class="cx">         else:
</span><span class="lines">@@ -117,7 +117,7 @@
</span><span class="cx">         Set the default timezone to use with this query.
</span><span class="cx">         @param calendar: a L{Component} for the VCALENDAR containing the one
</span><span class="cx">             VTIMEZONE that we want
</span><del>-        @return: the L{PyCalendarTimezone} derived from the VTIMEZONE or utc.
</del><ins>+        @return: the L{Timezone} derived from the VTIMEZONE or utc.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         if tzelement is None:
</span><span class="lines">@@ -127,7 +127,7 @@
</span><span class="cx">         elif isinstance(tzelement, Component):
</span><span class="cx">             tz = tzelement.gettimezone()
</span><span class="cx">         if tz is None:
</span><del>-            tz = PyCalendarTimezone(utc=True)
</del><ins>+            tz = Timezone(utc=True)
</ins><span class="cx">         self.child.settzinfo(tz)
</span><span class="cx">         return tz
</span><span class="cx"> 
</span><span class="lines">@@ -357,7 +357,7 @@
</span><span class="cx">     def settzinfo(self, tzinfo):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Set the default timezone to use with this query.
</span><del>-        @param tzinfo: a L{PyCalendarTimezone} to use.
</del><ins>+        @param tzinfo: a L{Timezone} to use.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Give tzinfo to any TimeRange we have
</span><span class="lines">@@ -374,7 +374,7 @@
</span><span class="cx">         Get the date farthest into the future in any time-range elements
</span><span class="cx"> 
</span><span class="cx">         @param currentMaximum: current future value to compare with
</span><del>-        @type currentMaximum: L{PyCalendarDateTime}
</del><ins>+        @type currentMaximum: L{DateTime}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Give tzinfo to any TimeRange we have
</span><span class="lines">@@ -471,7 +471,7 @@
</span><span class="cx">     def settzinfo(self, tzinfo):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Set the default timezone to use with this query.
</span><del>-        @param tzinfo: a L{PyCalendarTimezone} to use.
</del><ins>+        @param tzinfo: a L{Timezone} to use.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Give tzinfo to any TimeRange we have
</span><span class="lines">@@ -484,7 +484,7 @@
</span><span class="cx">         Get the date farthest into the future in any time-range elements
</span><span class="cx"> 
</span><span class="cx">         @param currentMaximum: current future value to compare with
</span><del>-        @type currentMaximum: L{PyCalendarDateTime}
</del><ins>+        @type currentMaximum: L{DateTime}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Give tzinfo to any TimeRange we have
</span><span class="lines">@@ -652,15 +652,15 @@
</span><span class="cx">         if &quot;start&quot; not in xml_element.attributes and &quot;end&quot; not in xml_element.attributes:
</span><span class="cx">             raise ValueError(&quot;One of 'start' or 'end' must be present in CALDAV:time-range&quot;)
</span><span class="cx"> 
</span><del>-        self.start = PyCalendarDateTime.parseText(xml_element.attributes[&quot;start&quot;]) if &quot;start&quot; in xml_element.attributes else None
-        self.end = PyCalendarDateTime.parseText(xml_element.attributes[&quot;end&quot;]) if &quot;end&quot; in xml_element.attributes else None
</del><ins>+        self.start = DateTime.parseText(xml_element.attributes[&quot;start&quot;]) if &quot;start&quot; in xml_element.attributes else None
+        self.end = DateTime.parseText(xml_element.attributes[&quot;end&quot;]) if &quot;end&quot; in xml_element.attributes else None
</ins><span class="cx">         self.tzinfo = None
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def settzinfo(self, tzinfo):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Set the default timezone to use with this query.
</span><del>-        @param tzinfo: a L{PyCalendarTimezone} to use.
</del><ins>+        @param tzinfo: a L{Timezone} to use.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Give tzinfo to any TimeRange we have
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavquerytesttest_calendarquerypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/test/test_calendarquery.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/test/test_calendarquery.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/test/test_calendarquery.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -17,7 +17,7 @@
</span><span class="cx"> from twistedcaldav import caldavxml
</span><span class="cx"> from twistedcaldav.query import calendarqueryfilter
</span><span class="cx"> import twistedcaldav.test.util
</span><del>-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.timezone import Timezone
</ins><span class="cx"> from twistedcaldav.query.calendarquery import sqlcalendarquery
</span><span class="cx"> 
</span><span class="cx"> class Tests(twistedcaldav.test.util.TestCase):
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx">             )
</span><span class="cx">         )
</span><span class="cx">         filter = calendarqueryfilter.Filter(filter)
</span><del>-        filter.child.settzinfo(PyCalendarTimezone(tzid=&quot;America/New_York&quot;))
</del><ins>+        filter.child.settzinfo(Timezone(tzid=&quot;America/New_York&quot;))
</ins><span class="cx"> 
</span><span class="cx">         sql, args = sqlcalendarquery(filter)
</span><span class="cx">         self.assertTrue(sql.find(&quot;RESOURCE&quot;) != -1)
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx">             )
</span><span class="cx">         )
</span><span class="cx">         filter = calendarqueryfilter.Filter(filter)
</span><del>-        filter.child.settzinfo(PyCalendarTimezone(tzid=&quot;America/New_York&quot;))
</del><ins>+        filter.child.settzinfo(Timezone(tzid=&quot;America/New_York&quot;))
</ins><span class="cx"> 
</span><span class="cx">         sql, args = sqlcalendarquery(filter)
</span><span class="cx">         self.assertTrue(sql.find(&quot;RESOURCE&quot;) != -1)
</span><span class="lines">@@ -88,7 +88,7 @@
</span><span class="cx">             )
</span><span class="cx">         )
</span><span class="cx">         filter = calendarqueryfilter.Filter(filter)
</span><del>-        filter.child.settzinfo(PyCalendarTimezone(tzid=&quot;America/New_York&quot;))
</del><ins>+        filter.child.settzinfo(Timezone(tzid=&quot;America/New_York&quot;))
</ins><span class="cx"> 
</span><span class="cx">         sql, args = sqlcalendarquery(filter)
</span><span class="cx">         self.assertTrue(sql.find(&quot;RESOURCE&quot;) != -1)
</span><span class="lines">@@ -119,7 +119,7 @@
</span><span class="cx">             )
</span><span class="cx">         )
</span><span class="cx">         filter = calendarqueryfilter.Filter(filter)
</span><del>-        filter.child.settzinfo(PyCalendarTimezone(tzid=&quot;America/New_York&quot;))
</del><ins>+        filter.child.settzinfo(Timezone(tzid=&quot;America/New_York&quot;))
</ins><span class="cx"> 
</span><span class="cx">         sql, args = sqlcalendarquery(filter)
</span><span class="cx">         self.assertTrue(sql.find(&quot;RESOURCE&quot;) != -1)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavquerytesttest_queryfilterpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/test/test_queryfilter.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/test/test_queryfilter.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/query/test/test_queryfilter.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> from twistedcaldav.query import calendarqueryfilter
</span><span class="cx"> import twistedcaldav.test.util
</span><span class="cx"> from twistedcaldav.caldavxml import TimeZone
</span><del>-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> class Tests(twistedcaldav.test.util.TestCase):
</span><span class="cx"> 
</span><span class="lines">@@ -227,4 +227,4 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;))
</span><span class="cx"> 
</span><del>-        self.assertTrue(isinstance(tz, PyCalendarTimezone))
</del><ins>+        self.assertTrue(isinstance(tz, Timezone))
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavresourcepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/resource.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/resource.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/resource.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -71,6 +71,7 @@
</span><span class="cx"> from twistedcaldav.directory.internal import InternalDirectoryRecord
</span><span class="cx"> from twistedcaldav.extensions import DAVResource, DAVPrincipalResource, \
</span><span class="cx">     DAVResourceWithChildrenMixin
</span><ins>+from twistedcaldav import ical
</ins><span class="cx"> from twistedcaldav.ical import Component
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
</span><span class="lines">@@ -257,10 +258,11 @@
</span><span class="cx">                 # Redirect to include trailing '/' in URI
</span><span class="cx">                 return RedirectResponse(request.unparseURL(path=urllib.quote(urllib.unquote(request.path), safe=':/') + '/'))
</span><span class="cx"> 
</span><del>-            def _defer(data):
</del><ins>+            def _defer(result):
+                data, accepted_type = result
</ins><span class="cx">                 response = Response()
</span><del>-                response.stream = MemoryStream(str(data))
-                response.headers.setHeader(&quot;content-type&quot;, MimeType.fromString(&quot;text/calendar&quot;))
</del><ins>+                response.stream = MemoryStream(data.getText(accepted_type))
+                response.headers.setHeader(&quot;content-type&quot;, MimeType.fromString(&quot;%s; charset=utf-8&quot; % (accepted_type,)))
</ins><span class="cx">                 return response
</span><span class="cx"> 
</span><span class="cx">             d = self.iCalendarRolledup(request)
</span><span class="lines">@@ -375,7 +377,7 @@
</span><span class="cx">                                   (self,))
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def storeStream(self, stream):
</del><ins>+    def storeStream(self, stream, format):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Store the content of the stream in this resource, as it would via a PUT.
</span><span class="cx"> 
</span><span class="lines">@@ -385,8 +387,7 @@
</span><span class="cx">         @return: a L{Deferred} which fires with an HTTP response.
</span><span class="cx">         @rtype: L{Deferred}
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        raise NotImplementedError(&quot;%s does not implement storeStream&quot; %
-                                  (self,))
</del><ins>+        raise NotImplementedError(&quot;%s does not implement storeStream&quot; % (self,))
</ins><span class="cx"> 
</span><span class="cx">     # End transitional new-store interface
</span><span class="cx"> 
</span><span class="lines">@@ -605,12 +606,21 @@
</span><span class="cx">             returnValue(self.getSupportedComponentSet())
</span><span class="cx"> 
</span><span class="cx">         elif qname == caldavxml.SupportedCalendarData.qname() and self.isPseudoCalendarCollection():
</span><del>-            returnValue(caldavxml.SupportedCalendarData(
</del><ins>+            dataTypes = []
+            dataTypes.append(
</ins><span class="cx">                 caldavxml.CalendarData(**{
</span><span class="cx">                     &quot;content-type&quot;: &quot;text/calendar&quot;,
</span><span class="cx">                     &quot;version&quot;     : &quot;2.0&quot;,
</span><span class="cx">                 }),
</span><del>-            ))
</del><ins>+            )
+            if config.EnableJSONData:
+                dataTypes.append(
+                    caldavxml.CalendarData(**{
+                        &quot;content-type&quot;: &quot;application/calendar+json&quot;,
+                        &quot;version&quot;     : &quot;2.0&quot;,
+                    }),
+                )
+            returnValue(caldavxml.SupportedCalendarData(*dataTypes))
</ins><span class="cx"> 
</span><span class="cx">         elif qname == caldavxml.MaxResourceSize.qname() and self.isPseudoCalendarCollection():
</span><span class="cx">             if config.MaxResourceSize:
</span><span class="lines">@@ -642,12 +652,21 @@
</span><span class="cx"> 
</span><span class="cx">         elif qname == carddavxml.SupportedAddressData.qname() and self.isAddressBookCollection():
</span><span class="cx">             # CardDAV, section 6.2.2
</span><del>-            returnValue(carddavxml.SupportedAddressData(
</del><ins>+            dataTypes = []
+            dataTypes.append(
</ins><span class="cx">                 carddavxml.AddressDataType(**{
</span><span class="cx">                     &quot;content-type&quot;: &quot;text/vcard&quot;,
</span><span class="cx">                     &quot;version&quot;     : &quot;3.0&quot;,
</span><span class="cx">                 }),
</span><del>-            ))
</del><ins>+            )
+            if config.EnableJSONData:
+                dataTypes.append(
+                    carddavxml.AddressDataType(**{
+                        &quot;content-type&quot;: &quot;application/vcard+json&quot;,
+                        &quot;version&quot;     : &quot;3.0&quot;,
+                    }),
+                )
+            returnValue(carddavxml.SupportedAddressData(*dataTypes))
</ins><span class="cx"> 
</span><span class="cx">         elif qname == carddavxml.MaxResourceSize.qname() and self.isAddressBookCollection() and not self.isDirectoryBackedAddressBookCollection():
</span><span class="cx">             # CardDAV, section 6.2.3
</span><span class="lines">@@ -1446,11 +1465,6 @@
</span><span class="cx">         returnValue(caldata)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def iCalendarText(self):
-        # storebridge handles this method
-        raise NotImplementedError()
-
-
</del><span class="cx">     def iCalendar(self):
</span><span class="cx">         # storebridge handles this method
</span><span class="cx">         raise NotImplementedError()
</span><span class="lines">@@ -2446,18 +2460,13 @@
</span><span class="cx"> 
</span><span class="cx">         if qname == caldavxml.SupportedCalendarComponentSets.qname():
</span><span class="cx">             if config.RestrictCalendarsToOneComponentType:
</span><del>-                prop = caldavxml.SupportedCalendarComponentSets(
</del><ins>+                prop = caldavxml.SupportedCalendarComponentSets(*[
</ins><span class="cx">                     caldavxml.SupportedCalendarComponentSet(
</span><span class="cx">                         caldavxml.CalendarComponent(
</span><del>-                            name=&quot;VEVENT&quot;,
</del><ins>+                            name=name,
</ins><span class="cx">                         ),
</span><del>-                    ),
-                    caldavxml.SupportedCalendarComponentSet(
-                        caldavxml.CalendarComponent(
-                            name=&quot;VTODO&quot;,
-                        ),
-                    ),
-                )
</del><ins>+                    ) for name in ical.allowedStoreComponents
+                ])
</ins><span class="cx">             else:
</span><span class="cx">                 prop = caldavxml.SupportedCalendarComponentSets()
</span><span class="cx">             returnValue(prop)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavscheduling_storecaldavresourcepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/scheduling_store/caldav/resource.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/scheduling_store/caldav/resource.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/scheduling_store/caldav/resource.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx"> from twistedcaldav import caldavxml, customxml
</span><span class="cx"> from twistedcaldav.caldavxml import caldav_namespace, CalendarFreeBusySet
</span><span class="cx"> from twistedcaldav.customxml import calendarserver_namespace
</span><del>-from twistedcaldav.ical import allowedComponents, Component
</del><ins>+from twistedcaldav.ical import Component, allowedSchedulingComponents
</ins><span class="cx"> from twistedcaldav.resource import CalDAVResource
</span><span class="cx"> from twistedcaldav.resource import isCalendarCollectionResource
</span><span class="cx"> 
</span><span class="lines">@@ -300,8 +300,14 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Write either the default VEVENT or VTODO calendar property, validating and canonicalizing the value
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        tasks = property.qname() == customxml.ScheduleDefaultTasksURL
-        error_element = (calendarserver_namespace, &quot;valid-schedule-default-tasks-URL&quot;) if tasks else (caldav_namespace, &quot;valid-schedule-default-calendar-URL&quot;)
</del><ins>+        if property.qname() == caldavxml.ScheduleDefaultCalendarURL.qname():
+            ctype = &quot;VEVENT&quot;
+            error_element = (caldav_namespace, &quot;valid-schedule-default-calendar-URL&quot;)
+        elif property.qname() == customxml.ScheduleDefaultTasksURL.qname():
+            ctype = &quot;VTODO&quot;
+            error_element = (calendarserver_namespace, &quot;valid-schedule-default-tasks-URL&quot;)
+        else:
+            returnValue(None)
</ins><span class="cx"> 
</span><span class="cx">         # Verify that the calendar added in the PROPPATCH is valid.
</span><span class="cx">         property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children]
</span><span class="lines">@@ -325,7 +331,7 @@
</span><span class="cx"> 
</span><span class="cx">         try:
</span><span class="cx">             # Now set it on the new store object
</span><del>-            yield self.parent._newStoreHome.setDefaultCalendar(cal._newStoreObject, tasks)
</del><ins>+            yield self.parent._newStoreHome.setDefaultCalendar(cal._newStoreObject, ctype)
</ins><span class="cx">         except InvalidDefaultCalendar as e:
</span><span class="cx">             raise HTTPError(ErrorResponse(
</span><span class="cx">                 responsecode.CONFLICT,
</span><span class="lines">@@ -390,7 +396,7 @@
</span><span class="cx"> 
</span><span class="cx">     def getSupportedComponentSet(self):
</span><span class="cx">         return caldavxml.SupportedCalendarComponentSet(
</span><del>-            *[caldavxml.CalendarComponent(name=item) for item in allowedComponents]
</del><ins>+            *[caldavxml.CalendarComponent(name=item) for item in allowedSchedulingComponents]
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -407,7 +413,7 @@
</span><span class="cx">         # Check authentication and access controls
</span><span class="cx">         yield self.authorize(request, (caldavxml.ScheduleSend(),))
</span><span class="cx"> 
</span><del>-        calendar = (yield self.loadCalendarFromRequest(request))
</del><ins>+        calendar, format = (yield self.loadCalendarFromRequest(request))
</ins><span class="cx">         originator = (yield self.loadOriginatorFromRequestDetails(request))
</span><span class="cx">         recipients = self.loadRecipientsFromCalendarData(calendar)
</span><span class="cx"> 
</span><span class="lines">@@ -431,14 +437,25 @@
</span><span class="cx"> 
</span><span class="cx">         # Do the POST processing treating
</span><span class="cx">         result = (yield scheduler.doSchedulingViaPOST(originator, recipients, calendar))
</span><del>-        returnValue(result.response())
</del><ins>+        returnValue(result.response(format=format))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def determineType(self, content_type):
+        &quot;&quot;&quot;
+        Determine if the supplied content-type is valid for storing and return the matching PyCalendar type.
+        &quot;&quot;&quot;
+        format = None
+        if content_type is not None:
+            format = &quot;%s/%s&quot; % (content_type.mediaType, content_type.mediaSubtype,)
+        return format if format in Component.allowedTypes() else None
+
+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def loadCalendarFromRequest(self, request):
</span><span class="cx">         # Must be content-type text/calendar
</span><span class="cx">         contentType = request.headers.getHeader(&quot;content-type&quot;)
</span><del>-        if contentType is not None and (contentType.mediaType, contentType.mediaSubtype) != (&quot;text&quot;, &quot;calendar&quot;):
</del><ins>+        format = self.determineType(contentType)
+        if format is None:
</ins><span class="cx">             self.log.error(&quot;MIME type %s not allowed in calendar collection&quot; % (contentType,))
</span><span class="cx">             raise HTTPError(ErrorResponse(
</span><span class="cx">                 responsecode.FORBIDDEN,
</span><span class="lines">@@ -448,7 +465,7 @@
</span><span class="cx"> 
</span><span class="cx">         # Parse the calendar object from the HTTP request stream
</span><span class="cx">         try:
</span><del>-            calendar = (yield Component.fromIStream(request.stream))
</del><ins>+            calendar = (yield Component.fromIStream(request.stream, format=format))
</ins><span class="cx">         except:
</span><span class="cx">             # FIXME: Bare except
</span><span class="cx">             self.log.error(&quot;Error while handling POST: %s&quot; % (Failure(),))
</span><span class="lines">@@ -458,7 +475,7 @@
</span><span class="cx">                 description=&quot;Can't parse calendar data&quot;
</span><span class="cx">             ))
</span><span class="cx"> 
</span><del>-        returnValue(calendar)
</del><ins>+        returnValue((calendar, format,))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavsharingpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/sharing.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/sharing.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/sharing.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx"> from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
</span><span class="cx"> from twistedcaldav.linkresource import LinkFollowerMixIn
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> # FIXME: Get rid of these imports
</span><span class="lines">@@ -740,7 +740,7 @@
</span><span class="cx">         typeAttr = {'shared-type': self.sharedResourceType()}
</span><span class="cx">         xmltype = customxml.InviteNotification(**typeAttr)
</span><span class="cx">         xmldata = customxml.Notification(
</span><del>-            customxml.DTStamp.fromString(PyCalendarDateTime.getNowUTC().getText()),
</del><ins>+            customxml.DTStamp.fromString(DateTime.getNowUTC().getText()),
</ins><span class="cx">             customxml.InviteNotification(
</span><span class="cx">                 customxml.UID.fromString(invitation.uid()),
</span><span class="cx">                 element.HRef.fromString(userid),
</span><span class="lines">@@ -1362,7 +1362,7 @@
</span><span class="cx">         record = shareePrincipal.record
</span><span class="cx"> 
</span><span class="cx">         xmldata = customxml.Notification(
</span><del>-            customxml.DTStamp.fromString(PyCalendarDateTime.getNowUTC().getText()),
</del><ins>+            customxml.DTStamp.fromString(DateTime.getNowUTC().getText()),
</ins><span class="cx">             customxml.InviteReply(
</span><span class="cx">                 *(
</span><span class="cx">                     (
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavsqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/sql.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/sql.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/sql.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> Generic SQL database access object.
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-__all__ = [ 
</del><ins>+__all__ = [
</ins><span class="cx">     &quot;db_prefix&quot;,
</span><span class="cx">     &quot;DatabaseError&quot;,
</span><span class="cx">     &quot;AbstractSQLDatabase&quot;,
</span><span class="lines">@@ -50,7 +50,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, dbpath, persistent, autocommit=False):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         @param dbpath: the path where the db file is stored.
</span><span class="cx">         @type dbpath: str
</span><span class="cx">         @param persistent: C{True} if the data in the DB must be perserved during upgrades,
</span><span class="lines">@@ -63,21 +63,25 @@
</span><span class="cx">         self.persistent = persistent
</span><span class="cx">         self.autocommit = autocommit
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def __repr__(self):
</span><span class="cx">         return &quot;&lt;%s %r&gt;&quot; % (self.__class__.__name__, self.dbpath)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_version(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the schema version assigned to this index.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         raise NotImplementedError
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def _db_type(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the collection type assigned to this index.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         raise NotImplementedError
</span><del>-        
</del><ins>+
+
</ins><span class="cx">     def _db(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Access the underlying database.
</span><span class="lines">@@ -108,7 +112,7 @@
</span><span class="cx">                 # Create CALDAV table if needed
</span><span class="cx"> 
</span><span class="cx">                 if self._test_schema_table(q):
</span><del>-                    
</del><ins>+
</ins><span class="cx">                     version, dbtype = self._get_schema_version(q)
</span><span class="cx"> 
</span><span class="cx">                     if (version != self._db_version()) or (dbtype != self._db_type()):
</span><span class="lines">@@ -130,7 +134,7 @@
</span><span class="cx">                         if version != self._db_version():
</span><span class="cx">                             log.error(&quot;Database %s has different schema (v.%s vs. v.%s)&quot;
</span><span class="cx">                                       % (db_filename, version, self._db_version()))
</span><del>-                            
</del><ins>+
</ins><span class="cx">                             # Upgrade the DB
</span><span class="cx">                             return self._db_upgrade(version)
</span><span class="cx"> 
</span><span class="lines">@@ -139,9 +143,11 @@
</span><span class="cx"> 
</span><span class="cx">                 self._db_connection.commit()
</span><span class="cx">             finally:
</span><del>-                if q is not None: q.close()
</del><ins>+                if q is not None:
+                    q.close()
</ins><span class="cx">         return self._db_connection
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _test_schema_table(self, q):
</span><span class="cx">         q.execute(&quot;&quot;&quot;
</span><span class="cx">         select (1) from SQLITE_MASTER
</span><span class="lines">@@ -149,6 +155,7 @@
</span><span class="cx">         &quot;&quot;&quot;)
</span><span class="cx">         return q.fetchone()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _get_schema_version(self, q):
</span><span class="cx">         q.execute(
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="lines">@@ -157,7 +164,8 @@
</span><span class="cx">             &quot;&quot;&quot;)
</span><span class="cx">         version = q.fetchone()
</span><span class="cx"> 
</span><del>-        if version is not None: version = version[0]
</del><ins>+        if version is not None:
+            version = version[0]
</ins><span class="cx"> 
</span><span class="cx">         q.execute(
</span><span class="cx">             &quot;&quot;&quot;
</span><span class="lines">@@ -166,10 +174,12 @@
</span><span class="cx">             &quot;&quot;&quot;)
</span><span class="cx">         dbtype = q.fetchone()
</span><span class="cx"> 
</span><del>-        if dbtype is not None: dbtype = dbtype[0]
</del><ins>+        if dbtype is not None:
+            dbtype = dbtype[0]
</ins><span class="cx"> 
</span><span class="cx">         return version, dbtype
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_init(self, db_filename, q):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Initialise the underlying database tables.
</span><span class="lines">@@ -183,7 +193,7 @@
</span><span class="cx">         old_isolation = self._db_connection.isolation_level
</span><span class="cx">         self._db_connection.isolation_level = None
</span><span class="cx">         q.execute(&quot;begin exclusive transaction&quot;)
</span><del>-        
</del><ins>+
</ins><span class="cx">         # We re-check whether the schema table is present again AFTER we've got an exclusive
</span><span class="cx">         # lock as some other server process may have snuck in and already created it
</span><span class="cx">         # before we got the lock, or whilst we were waiting for it.
</span><span class="lines">@@ -199,6 +209,7 @@
</span><span class="cx"> 
</span><span class="cx">         self._db_connection.isolation_level = old_isolation
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_init_schema_table(self, q):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Initialise the underlying database tables.
</span><span class="lines">@@ -229,6 +240,7 @@
</span><span class="cx">             &quot;&quot;&quot;, [self._db_type()]
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_init_data_tables(self, q):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Initialise the underlying database tables.
</span><span class="lines">@@ -237,6 +249,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         raise NotImplementedError
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_recreate(self, do_commit=True):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Recreate the database tables.
</span><span class="lines">@@ -246,15 +259,17 @@
</span><span class="cx">         if do_commit:
</span><span class="cx">             self._db_commit()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_can_upgrade(self, old_version):
</span><del>-        
</del><ins>+
</ins><span class="cx">         return self.persistent
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_upgrade(self, old_version):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Upgrade the database tables.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         if self._db_can_upgrade(old_version):
</span><span class="cx">             self._db_connection = sqlite.connect(self.dbpath, isolation_level=None)
</span><span class="cx">             q = self._db_connection.cursor()
</span><span class="lines">@@ -278,6 +293,7 @@
</span><span class="cx"> 
</span><span class="cx">         return self._db()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_upgrade_data_tables(self, q, old_version):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Upgrade the data from an older version of the DB.
</span><span class="lines">@@ -286,6 +302,7 @@
</span><span class="cx">         # cannot be thrown away.
</span><span class="cx">         raise NotImplementedError(&quot;Persistent databases MUST support an upgrade method.&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_upgrade_schema(self, q):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Upgrade the stored schema version to the current one.
</span><span class="lines">@@ -297,11 +314,13 @@
</span><span class="cx">             &quot;&quot;&quot;, [self._db_version()]
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_close(self):
</span><span class="cx">         if hasattr(self, &quot;_db_connection&quot;):
</span><span class="cx">             self._db_connection.close()
</span><span class="cx">             del self._db_connection
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_values_for_sql(self, sql, *query_params):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Execute an SQL query and obtain the resulting values.
</span><span class="lines">@@ -313,6 +332,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return (row[0] for row in self._db_execute(sql, *query_params))
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_value_for_sql(self, sql, *query_params):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Execute an SQL query and obtain a single value.
</span><span class="lines">@@ -328,6 +348,7 @@
</span><span class="cx">             value = row
</span><span class="cx">         return value
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _db_execute(self, sql, *query_params):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Execute an SQL query and obtain the resulting values.
</span><span class="lines">@@ -347,5 +368,10 @@
</span><span class="cx">         finally:
</span><span class="cx">             q.close()
</span><span class="cx"> 
</span><del>-    def _db_commit  (self): self._db_connection.commit()
-    def _db_rollback(self): self._db_connection.rollback()
</del><ins>+
+    def _db_commit(self):
+        self._db_connection.commit()
+
+
+    def _db_rollback(self):
+        self._db_connection.rollback()
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavstdconfigpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/stdconfig.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/stdconfig.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/stdconfig.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> from twistedcaldav.util import computeProcessCount
</span><span class="cx"> 
</span><span class="cx"> from calendarserver.push.util import getAPNTopicFromCertificate
</span><ins>+from twistedcaldav import ical
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -156,9 +157,8 @@
</span><span class="cx">             &quot;resourceInfoAttr&quot;: None, # contains location/resource info
</span><span class="cx">             &quot;autoAcceptGroupAttr&quot;: None, # auto accept group
</span><span class="cx">         },
</span><del>-        &quot;partitionSchema&quot;: {
</del><ins>+        &quot;poddingSchema&quot;: {
</ins><span class="cx">             &quot;serverIdAttr&quot;: None, # maps to augments server-id
</span><del>-            &quot;partitionIdAttr&quot;: None, # maps to augments partition-id
</del><span class="cx">         },
</span><span class="cx">     },
</span><span class="cx"> }
</span><span class="lines">@@ -304,7 +304,7 @@
</span><span class="cx">                                     # the master process, rather than having
</span><span class="cx">                                     # each client make its connections directly.
</span><span class="cx"> 
</span><del>-    &quot;FailIfUpgradeNeeded&quot;  : True, # Set to True to prevent the server or utility tools
</del><ins>+    &quot;FailIfUpgradeNeeded&quot;  : True, # Set to True to prevent the server or utility
</ins><span class="cx">                                    # tools from running if the database needs a schema
</span><span class="cx">                                    # upgrade.
</span><span class="cx">     &quot;StopAfterUpgradeTriggerFile&quot; : &quot;stop_after_upgrade&quot;,   # if this file exists in ConfigRoot, stop
</span><span class="lines">@@ -546,6 +546,11 @@
</span><span class="cx">     &quot;EnableManagedAttachments&quot;    : False, # Support Managed Attachments
</span><span class="cx"> 
</span><span class="cx">     #
</span><ins>+    # Generic CalDAV/CardDAV extensions
+    #
+    &quot;EnableJSONData&quot;          : True, # Allow clients to send/receive JSON jCal and jCard format data
+
+    #
</ins><span class="cx">     # Non-standard CalDAV extensions
</span><span class="cx">     #
</span><span class="cx">     &quot;EnableDropBox&quot;           : False, # Calendar Drop Box
</span><span class="lines">@@ -595,6 +600,12 @@
</span><span class="cx">                                                    # If on, it will also cause new accounts to provision with separate
</span><span class="cx">                                                    # calendars for events and tasks.
</span><span class="cx"> 
</span><ins>+    &quot;SupportedComponents&quot; : [                      # Set of supported iCalendar components
+        &quot;VEVENT&quot;,
+        &quot;VTODO&quot;,
+        #&quot;VPOLL&quot;,
+    ],
+
</ins><span class="cx">     &quot;ParallelUpgrades&quot; : False, # Perform upgrades - currently only the
</span><span class="cx">                                    # database -&gt; filesystem migration - but in
</span><span class="cx">                                    # the future, hopefully all relevant
</span><span class="lines">@@ -806,11 +817,11 @@
</span><span class="cx">     # Support multiple hosts within a domain
</span><span class="cx">     #
</span><span class="cx">     &quot;Servers&quot; : {
</span><del>-        &quot;Enabled&quot;: False, # Multiple servers/partitions enabled or not
-        &quot;ConfigFile&quot;: &quot;localservers.xml&quot;, # File path for server information
-        &quot;MaxClients&quot;: 5, # Pool size for connections to each partition
</del><ins>+        &quot;Enabled&quot;: False,                   # Multiple servers enabled or not
+        &quot;ConfigFile&quot;: &quot;localservers.xml&quot;,   # File path for server information
+        &quot;MaxClients&quot;: 5,                    # Pool size for connections to between servers
+        &quot;InboxName&quot;: &quot;podding&quot;,             # Name for top-level inbox resource
</ins><span class="cx">     },
</span><del>-    &quot;ServerPartitionID&quot;: &quot;&quot;, # Unique ID for this server's partition instance.
</del><span class="cx"> 
</span><span class="cx">     #
</span><span class="cx">     # Performance tuning
</span><span class="lines">@@ -881,7 +892,8 @@
</span><span class="cx"> 
</span><span class="cx">     # Support for Content-Encoding compression options as specified in
</span><span class="cx">     # RFC2616 Section 3.5
</span><del>-    &quot;ResponseCompression&quot;: True,
</del><ins>+    # Defaults off, because it weakens TLS (CRIME attack).
+    &quot;ResponseCompression&quot;: False,
</ins><span class="cx"> 
</span><span class="cx">     # The retry-after value (in seconds) to return with a 503 error
</span><span class="cx">     &quot;HTTPRetryAfter&quot;: 180,
</span><span class="lines">@@ -1011,7 +1023,8 @@
</span><span class="cx">     # means no automatic shutdown.
</span><span class="cx">     &quot;AgentInactivityTimeoutSeconds&quot;  : 4 * 60 * 60,
</span><span class="cx"> 
</span><del>-    # These two aren't relative to ConfigRoot:
</del><ins>+    # These aren't relative to ConfigRoot:
+    &quot;ImportConfig&quot;: &quot;&quot;, # Config to read first and merge
</ins><span class="cx">     &quot;Includes&quot;: [], # Other plists to parse after this one
</span><span class="cx">     &quot;WritableConfigFile&quot; : &quot;&quot;, # which config file calendarserver_config should
</span><span class="cx">         # write to for changes; empty string means the main config file.
</span><span class="lines">@@ -1043,18 +1056,41 @@
</span><span class="cx">         if self._configFileName:
</span><span class="cx">             configDict = self._parseConfigFromFile(self._configFileName)
</span><span class="cx">         configDict = ConfigDict(configDict)
</span><del>-        # Now check for Includes and parse and add each of those
-        if &quot;Includes&quot; in configDict:
-            for include in configDict.Includes:
-                # Includes are not relative to ConfigRoot
-                path = _expandPath(include)
</del><ins>+
+        def _loadImport(childDict):
+            # Look for an import and read that one as the main config and merge the current one into that
+            if &quot;ImportConfig&quot; in childDict and childDict.ImportConfig:
+                configRoot = os.path.join(childDict.ServerRoot, childDict.ConfigRoot)
+                path = _expandPath(fullServerPath(configRoot, childDict.ImportConfig))
</ins><span class="cx">                 if os.path.exists(path):
</span><del>-                    additionalDict = ConfigDict(self._parseConfigFromFile(path))
-                    if additionalDict:
-                        log.info(&quot;Adding configuration from file: '%s'&quot; % (path,))
-                        mergeData(configDict, additionalDict)
-                else:
-                    log.debug(&quot;Missing configuration file: '%s'&quot; % (path,))
</del><ins>+                    importDict = ConfigDict(self._parseConfigFromFile(path))
+                    if importDict:
+                        self.importedFiles.append(path)
+                        importDict = _loadImport(importDict)
+                        mergeData(importDict, childDict)
+                        return importDict
+                raise ConfigurationError(&quot;Import configuration file '{path}' must exist and be valid.&quot;.format(path=path))
+            else:
+                return childDict
+
+        def _loadIncludes(parentDict):
+            # Now check for Includes and parse and add each of those
+            if &quot;Includes&quot; in parentDict:
+                configRoot = os.path.join(parentDict.ServerRoot, parentDict.ConfigRoot)
+                for include in parentDict.Includes:
+                    # Includes are not relative to ConfigRoot
+                    path = _expandPath(fullServerPath(configRoot, include))
+                    if os.path.exists(path):
+                        additionalDict = ConfigDict(self._parseConfigFromFile(path))
+                        if additionalDict:
+                            self.includedFiles.append(path)
+                            _loadIncludes(additionalDict)
+                            mergeData(parentDict, additionalDict)
+                    else:
+                        self.missingFiles.append(path)
+
+        configDict = _loadImport(configDict)
+        _loadIncludes(configDict)
</ins><span class="cx">         return configDict
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1479,6 +1515,14 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+def _updateICalendar(configDict, reloading=False):
+    &quot;&quot;&quot;
+    Updated support iCalendar components.
+    &quot;&quot;&quot;
+    ical._updateAllowedComponents(tuple(configDict.SupportedComponents))
+
+
+
</ins><span class="cx"> def _updateScheduling(configDict, reloading=False):
</span><span class="cx">     #
</span><span class="cx">     # Scheduling
</span><span class="lines">@@ -1518,8 +1562,7 @@
</span><span class="cx">     from txdav.caldav.datastore.scheduling.ischedule.localservers import Servers
</span><span class="cx">     if configDict.Servers.Enabled:
</span><span class="cx">         Servers.load()
</span><del>-        Servers.getThisServer().installReverseProxies(
-            configDict.ServerPartitionID,
</del><ins>+        Servers.installReverseProxies(
</ins><span class="cx">             configDict.Servers.MaxClients,
</span><span class="cx">         )
</span><span class="cx">     else:
</span><span class="lines">@@ -1590,6 +1633,7 @@
</span><span class="cx">     _updateRejectClients,
</span><span class="cx">     _updateLogLevels,
</span><span class="cx">     _updateNotifications,
</span><ins>+    _updateICalendar,
</ins><span class="cx">     _updateScheduling,
</span><span class="cx">     _updateServers,
</span><span class="cx">     _updateCompliance,
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavstorebridgepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/storebridge.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/storebridge.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/storebridge.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -15,7 +15,7 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx"> from twext.web2.dav.http import ErrorResponse, ResponseQueue, MultiStatusResponse
</span><span class="lines">@@ -36,14 +36,14 @@
</span><span class="cx"> from twisted.python.hashlib import md5
</span><span class="cx"> from twisted.python.util import FancyEqMixin
</span><span class="cx"> 
</span><del>-from twistedcaldav import customxml, carddavxml, caldavxml
</del><ins>+from twistedcaldav import customxml, carddavxml, caldavxml, ical
</ins><span class="cx"> from twistedcaldav.caldavxml import caldav_namespace, MaxAttendeesPerInstance, \
</span><span class="cx">     MaxInstances, NoUIDConflict
</span><span class="cx"> from twistedcaldav.carddavxml import carddav_namespace, NoUIDConflict as NovCardUIDConflict
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
</span><span class="cx"> from twistedcaldav.ical import Component as VCalendar, Property as VProperty, \
</span><del>-    InvalidICalendarDataError, iCalendarProductID, allowedComponents, Component
</del><ins>+    InvalidICalendarDataError, iCalendarProductID, Component
</ins><span class="cx"> from twistedcaldav.memcachelock import MemcacheLockTimeoutError
</span><span class="cx"> from twistedcaldav.notifications import NotificationCollectionResource, NotificationResource
</span><span class="cx"> from twistedcaldav.resource import CalDAVResource, GlobalAddressBookResource, \
</span><span class="lines">@@ -82,6 +82,7 @@
</span><span class="cx"> from twistedcaldav.customxml import calendarserver_namespace
</span><span class="cx"> from twistedcaldav.instance import InvalidOverriddenInstanceError, \
</span><span class="cx">     TooManyInstancesError
</span><ins>+from twistedcaldav.util import bestAcceptType
</ins><span class="cx"> import collections
</span><span class="cx"> 
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="lines">@@ -626,14 +627,17 @@
</span><span class="cx">         # Read in all data
</span><span class="cx">         data = (yield allDataFromStream(request.stream))
</span><span class="cx"> 
</span><del>-        components = self.componentsFromData(data)
</del><ins>+        format = request.headers.getHeader(&quot;content-type&quot;)
+        if format:
+            format = &quot;%s/%s&quot; % (format.mediaType, format.mediaSubtype,)
+        components = self.componentsFromData(data, format)
</ins><span class="cx">         if components is None:
</span><span class="cx">             raise HTTPError(StatusResponse(BAD_REQUEST, &quot;Could not parse valid data from request body&quot;))
</span><span class="cx"> 
</span><span class="cx">         # Build response
</span><span class="cx">         xmlresponses = [None] * len(components)
</span><span class="cx">         indexedComponents = [idxComponent for idxComponent in enumerate(components)]
</span><del>-        yield self.bulkCreate(indexedComponents, request, return_changed, xmlresponses)
</del><ins>+        yield self.bulkCreate(indexedComponents, request, return_changed, xmlresponses, format)
</ins><span class="cx"> 
</span><span class="cx">         result = MultiStatusResponse(xmlresponses)
</span><span class="cx"> 
</span><span class="lines">@@ -650,7 +654,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def bulkCreate(self, indexedComponents, request, return_changed, xmlresponses):
</del><ins>+    def bulkCreate(self, indexedComponents, request, return_changed, xmlresponses, format):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Do create from simpleBatchPOST or crudCreate()
</span><span class="cx">         Subclasses may override
</span><span class="lines">@@ -664,7 +668,7 @@
</span><span class="cx">                 # Get a resource for the new item
</span><span class="cx">                 newchildURL = joinURL(request.path, name)
</span><span class="cx">                 newchild = (yield request.locateResource(newchildURL))
</span><del>-                changedData = (yield self.storeResourceData(newchild, component, returnChangedData=return_changed))
</del><ins>+                changedComponent = (yield self.storeResourceData(newchild, component, returnChangedData=return_changed))
</ins><span class="cx"> 
</span><span class="cx">             except HTTPError, e:
</span><span class="cx">                 # Extract the pre-condition
</span><span class="lines">@@ -674,30 +678,30 @@
</span><span class="cx">                     error = (error.namespace, error.name,)
</span><span class="cx"> 
</span><span class="cx">                 xmlresponses[index] = (
</span><del>-                    yield self.bulkCreateResponse(component, newchildURL, newchild, None, code, error)
</del><ins>+                    yield self.bulkCreateResponse(component, newchildURL, newchild, None, code, error, format)
</ins><span class="cx">                 )
</span><span class="cx"> 
</span><span class="cx">             except Exception:
</span><span class="cx">                 xmlresponses[index] = (
</span><del>-                    yield self.bulkCreateResponse(component, newchildURL, newchild, None, code=BAD_REQUEST, error=None)
</del><ins>+                    yield self.bulkCreateResponse(component, newchildURL, newchild, None, BAD_REQUEST, None, format)
</ins><span class="cx">                 )
</span><span class="cx"> 
</span><span class="cx">             else:
</span><span class="cx">                 if not return_changed:
</span><del>-                    changedData = None
</del><ins>+                    changedComponent = None
</ins><span class="cx">                 xmlresponses[index] = (
</span><del>-                    yield self.bulkCreateResponse(component, newchildURL, newchild, changedData, code=None, error=None)
</del><ins>+                    yield self.bulkCreateResponse(component, newchildURL, newchild, changedComponent, None, None, format)
</ins><span class="cx">                 )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def bulkCreateResponse(self, component, newchildURL, newchild, changedData, code, error):
</del><ins>+    def bulkCreateResponse(self, component, newchildURL, newchild, changedComponent, code, error, format):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         generate one xmlresponse for bulk create
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         if code is None:
</span><span class="cx">             etag = (yield newchild.etag())
</span><del>-            if changedData is None:
</del><ins>+            if changedComponent is None:
</ins><span class="cx">                 returnValue(
</span><span class="cx">                     davxml.PropertyStatusResponse(
</span><span class="cx">                         davxml.HRef.fromString(newchildURL),
</span><span class="lines">@@ -717,7 +721,7 @@
</span><span class="cx">                         davxml.PropertyStatus(
</span><span class="cx">                             davxml.PropertyContainer(
</span><span class="cx">                                 davxml.GETETag.fromString(etag.generate()),
</span><del>-                                self.xmlDataElementType().fromTextData(changedData),
</del><ins>+                                self.xmlDataElementType().fromComponent(changedComponent, format),
</ins><span class="cx">                             ),
</span><span class="cx">                             davxml.Status.fromResponseCode(OK),
</span><span class="cx">                         )
</span><span class="lines">@@ -822,6 +826,7 @@
</span><span class="cx">             for index, xmldata in crudCreateInfo:
</span><span class="cx"> 
</span><span class="cx">                 component = xmldata.generateComponent()
</span><ins>+                format = xmldata.content_type
</ins><span class="cx"> 
</span><span class="cx">                 if hasPrivilege is not True:
</span><span class="cx">                     e = hasPrivilege # use same code pattern as exception
</span><span class="lines">@@ -830,13 +835,13 @@
</span><span class="cx">                         error = e.response.error
</span><span class="cx">                         error = (error.namespace, error.name,)
</span><span class="cx"> 
</span><del>-                    xmlresponse = yield self.bulkCreateResponse(component, None, None, None, code, error)
</del><ins>+                    xmlresponse = yield self.bulkCreateResponse(component, None, None, None, code, error, format)
</ins><span class="cx">                     xmlresponses[index] = xmlresponse
</span><span class="cx"> 
</span><span class="cx">                 else:
</span><span class="cx">                     indexedComponents.append((index, component,))
</span><span class="cx"> 
</span><del>-            yield self.bulkCreate(indexedComponents, request, return_changed, xmlresponses)
</del><ins>+            yield self.bulkCreate(indexedComponents, request, return_changed, xmlresponses, format)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -847,8 +852,8 @@
</span><span class="cx">             code = None
</span><span class="cx">             error = None
</span><span class="cx">             try:
</span><del>-                componentdata = xmldata.textData()
</del><span class="cx">                 component = xmldata.generateComponent()
</span><ins>+                format = xmldata.content_type
</ins><span class="cx"> 
</span><span class="cx">                 updateResource = (yield request.locateResource(href))
</span><span class="cx">                 if not updateResource.exists():
</span><span class="lines">@@ -862,7 +867,7 @@
</span><span class="cx">                 if ifmatch and ifmatch != etag.generate():
</span><span class="cx">                     raise HTTPError(PRECONDITION_FAILED)
</span><span class="cx"> 
</span><del>-                changedData = yield self.storeResourceData(updateResource, component, componentdata)
</del><ins>+                changedComponent = yield self.storeResourceData(updateResource, component, returnChangedData=return_changed)
</ins><span class="cx"> 
</span><span class="cx">             except HTTPError, e:
</span><span class="cx">                 # Extract the pre-condition
</span><span class="lines">@@ -875,7 +880,7 @@
</span><span class="cx">                 code = BAD_REQUEST
</span><span class="cx"> 
</span><span class="cx">             if code is None:
</span><del>-                if not return_changed or changedData is None:
</del><ins>+                if changedComponent is None:
</ins><span class="cx">                     xmlresponses[index] = davxml.PropertyStatusResponse(
</span><span class="cx">                         davxml.HRef.fromString(href),
</span><span class="cx">                         davxml.PropertyStatus(
</span><span class="lines">@@ -891,7 +896,7 @@
</span><span class="cx">                         davxml.PropertyStatus(
</span><span class="cx">                             davxml.PropertyContainer(
</span><span class="cx">                                 davxml.GETETag.fromString(etag.generate()),
</span><del>-                                self.xmlDataElementType().fromTextData(changedData),
</del><ins>+                                self.xmlDataElementType().fromComponentData(changedComponent, format),
</ins><span class="cx">                             ),
</span><span class="cx">                             davxml.Status.fromResponseCode(OK),
</span><span class="cx">                         )
</span><span class="lines">@@ -989,7 +994,7 @@
</span><span class="cx">         if comps:
</span><span class="cx">             comps = comps.split(&quot;,&quot;)
</span><span class="cx">         else:
</span><del>-            comps = allowedComponents
</del><ins>+            comps = ical.allowedStoreComponents
</ins><span class="cx">         return caldavxml.SupportedCalendarComponentSet(
</span><span class="cx">             *[caldavxml.CalendarComponent(name=item) for item in comps]
</span><span class="cx">         )
</span><span class="lines">@@ -1016,7 +1021,7 @@
</span><span class="cx">         if comps:
</span><span class="cx">             comps = comps.split(&quot;,&quot;)
</span><span class="cx">         else:
</span><del>-            comps = allowedComponents
</del><ins>+            comps = ical.allowedStoreComponents
</ins><span class="cx">         return comps
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1053,6 +1058,8 @@
</span><span class="cx"> 
</span><span class="cx">         if config.EnableBatchUpload:
</span><span class="cx">             self._postHandlers[(&quot;text&quot;, &quot;calendar&quot;)] = _CommonHomeChildCollectionMixin.simpleBatchPOST
</span><ins>+            if config.EnableJSONData:
+                self._postHandlers[(&quot;application&quot;, &quot;calendar+json&quot;)] = _CommonHomeChildCollectionMixin.simpleBatchPOST
</ins><span class="cx">             self.xmlDocHandlers[customxml.Multiput] = _CommonHomeChildCollectionMixin.crudBatchPOST
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1088,6 +1095,11 @@
</span><span class="cx">     def iCalendarRolledup(self, request):
</span><span class="cx">         # FIXME: uncached: implement cache in the storage layer
</span><span class="cx"> 
</span><ins>+        # Accept header handling
+        accepted_type = bestAcceptType(request.headers.getHeader(&quot;accept&quot;), Component.allowedTypes())
+        if accepted_type is None:
+            raise HTTPError(StatusResponse(responsecode.NOT_ACCEPTABLE, &quot;Cannot generate requested data type&quot;))
+
</ins><span class="cx">         # Generate a monolithic calendar
</span><span class="cx">         calendar = VCalendar(&quot;VCALENDAR&quot;)
</span><span class="cx">         calendar.addProperty(VProperty(&quot;VERSION&quot;, &quot;2.0&quot;))
</span><span class="lines">@@ -1138,17 +1150,13 @@
</span><span class="cx"> 
</span><span class="cx">                     calendar.addComponent(component)
</span><span class="cx"> 
</span><del>-        # Cache the data
-        data = str(calendar)
-        data = (yield self.getInternalSyncToken()) + &quot;\r\n&quot; + data
</del><ins>+        returnValue((calendar, accepted_type,))
</ins><span class="cx"> 
</span><del>-        returnValue(calendar)
-
</del><span class="cx">     createCalendarCollection = _CommonHomeChildCollectionMixin.createCollection
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><del>-    def componentsFromData(cls, data):
</del><ins>+    def componentsFromData(cls, data, format):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Need to split a single VCALENDAR into separate ones based on UID with the
</span><span class="cx">         appropriate VTIEMZONES included.
</span><span class="lines">@@ -1158,7 +1166,7 @@
</span><span class="cx"> 
</span><span class="cx">         # Split into components by UID and TZID
</span><span class="cx">         try:
</span><del>-            vcal = VCalendar.fromString(data)
</del><ins>+            vcal = VCalendar.fromString(data, format)
</ins><span class="cx">         except InvalidICalendarDataError:
</span><span class="cx">             return None
</span><span class="cx"> 
</span><span class="lines">@@ -1242,7 +1250,8 @@
</span><span class="cx"> 
</span><span class="cx">         elif qname == caldavxml.CalendarTimeZone.qname():
</span><span class="cx">             timezone = self._newStoreObject.getTimezone()
</span><del>-            returnValue(caldavxml.CalendarTimeZone.fromString(str(timezone)) if timezone else None)
</del><ins>+            format = property.content_type if isinstance(property, caldavxml.CalendarTimeZone) else None
+            returnValue(caldavxml.CalendarTimeZone.fromCalendar(timezone, format=format) if timezone else None)
</ins><span class="cx"> 
</span><span class="cx">         result = (yield super(CalendarCollectionResource, self).readProperty(property, request))
</span><span class="cx">         returnValue(result)
</span><span class="lines">@@ -1288,7 +1297,7 @@
</span><span class="cx">         yield newchild.storeComponent(component)
</span><span class="cx">         if returnChangedData and newchild._newStoreObject._componentChanged:
</span><span class="cx">             result = (yield newchild.componentForUser())
</span><del>-            returnValue(str(result))
</del><ins>+            returnValue(result)
</ins><span class="cx">         else:
</span><span class="cx">             returnValue(None)
</span><span class="cx"> 
</span><span class="lines">@@ -2210,16 +2219,38 @@
</span><span class="cx">         return self._newStoreObject.component()
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def allowedTypes(self):
+        &quot;&quot;&quot;
+        Return a dict of allowed MIME types for storing, mapped to equivalent PyCalendar types.
+        &quot;&quot;&quot;
+        raise NotImplementedError
+
+
+    def determineType(self, content_type):
+        &quot;&quot;&quot;
+        Determine if the supplied content-type is valid for storing and return the matching PyCalendar type.
+        &quot;&quot;&quot;
+        format = None
+        if content_type is not None:
+            format = &quot;%s/%s&quot; % (content_type.mediaType, content_type.mediaSubtype,)
+        return format if format in self.allowedTypes() else None
+
+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def render(self, request):
</span><span class="cx">         if not self.exists():
</span><span class="cx">             log.debug(&quot;Resource not found: %s&quot; % (self,))
</span><span class="cx">             raise HTTPError(NOT_FOUND)
</span><span class="cx"> 
</span><ins>+        # Accept header handling
+        accepted_type = bestAcceptType(request.headers.getHeader(&quot;accept&quot;), self.allowedTypes())
+        if accepted_type is None:
+            raise HTTPError(StatusResponse(responsecode.NOT_ACCEPTABLE, &quot;Cannot generate requested data type&quot;))
+
</ins><span class="cx">         output = yield self.component()
</span><span class="cx"> 
</span><del>-        response = Response(OK, {}, str(output))
-        response.headers.setHeader(&quot;content-type&quot;, self.contentType())
</del><ins>+        response = Response(OK, {}, output.getText(accepted_type))
+        response.headers.setHeader(&quot;content-type&quot;, MimeType.fromString(&quot;%s; charset=utf-8&quot; % (accepted_type,)))
</ins><span class="cx">         returnValue(response)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -2379,10 +2410,10 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def storeStream(self, stream):
</del><ins>+    def storeStream(self, stream, format):
</ins><span class="cx"> 
</span><span class="cx">         # FIXME: direct tests
</span><del>-        component = self._componentFromStream((yield allDataFromStream(stream)))
</del><ins>+        component = self._componentFromStream((yield allDataFromStream(stream)), format)
</ins><span class="cx">         result = (yield self.storeComponent(component))
</span><span class="cx">         returnValue(result)
</span><span class="cx"> 
</span><span class="lines">@@ -2514,6 +2545,13 @@
</span><span class="cx"> 
</span><span class="cx">     _componentFromStream = VCalendar.fromString
</span><span class="cx"> 
</span><ins>+    def allowedTypes(self):
+        &quot;&quot;&quot;
+        Return a tuple of allowed MIME types for storing.
+        &quot;&quot;&quot;
+        return Component.allowedTypes()
+
+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def inNewTransaction(self, request, label=&quot;&quot;):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -2541,12 +2579,6 @@
</span><span class="cx">         self._initializeWithObject(newObject, newParent)
</span><span class="cx">         returnValue(txn)
</span><span class="cx"> 
</span><del>-
-    @inlineCallbacks
-    def iCalendarText(self):
-        data = yield self.iCalendar()
-        returnValue(str(data))
-
</del><span class="cx">     iCalendar = _CommonObjectResource.component
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -2710,7 +2742,8 @@
</span><span class="cx"> 
</span><span class="cx">         # Content-type check
</span><span class="cx">         content_type = request.headers.getHeader(&quot;content-type&quot;)
</span><del>-        if content_type is not None and (content_type.mediaType, content_type.mediaSubtype) != (&quot;text&quot;, &quot;calendar&quot;):
</del><ins>+        format = self.determineType(content_type)
+        if format is None:
</ins><span class="cx">             log.error(&quot;MIME type {content_type} not allowed in calendar collection&quot;, content_type=content_type)
</span><span class="cx">             raise HTTPError(ErrorResponse(
</span><span class="cx">                 responsecode.FORBIDDEN,
</span><span class="lines">@@ -2745,13 +2778,13 @@
</span><span class="cx">                 ))
</span><span class="cx"> 
</span><span class="cx">             try:
</span><del>-                component = Component.fromString(calendardata)
</del><ins>+                component = Component.fromString(calendardata, format)
</ins><span class="cx">             except ValueError, e:
</span><span class="cx">                 log.error(str(e))
</span><span class="cx">                 raise HTTPError(ErrorResponse(
</span><span class="cx">                     responsecode.FORBIDDEN,
</span><span class="cx">                     (caldav_namespace, &quot;valid-calendar-data&quot;),
</span><del>-                    &quot;Can't parse calendar data&quot;
</del><ins>+                    &quot;Can't parse calendar data: %s&quot; % (str(e),)
</ins><span class="cx">                 ))
</span><span class="cx"> 
</span><span class="cx">             # storeComponent needs to know who the auth'd user is for access control
</span><span class="lines">@@ -2864,7 +2897,7 @@
</span><span class="cx">             if rids is not None:
</span><span class="cx">                 rids = rids[0].split(&quot;,&quot;)
</span><span class="cx">                 try:
</span><del>-                    rids = [PyCalendarDateTime.parseText(rid) if rid != &quot;M&quot; else None for rid in rids]
</del><ins>+                    rids = [DateTime.parseText(rid) if rid != &quot;M&quot; else None for rid in rids]
</ins><span class="cx">                 except ValueError:
</span><span class="cx">                     raise HTTPError(ErrorResponse(
</span><span class="cx">                         FORBIDDEN,
</span><span class="lines">@@ -3001,6 +3034,8 @@
</span><span class="cx"> 
</span><span class="cx">         if config.EnableBatchUpload:
</span><span class="cx">             self._postHandlers[(&quot;text&quot;, &quot;vcard&quot;)] = AddressBookCollectionResource.simpleBatchPOST
</span><ins>+            if config.EnableJSONData:
+                self._postHandlers[(&quot;application&quot;, &quot;vcard+json&quot;)] = _CommonHomeChildCollectionMixin.simpleBatchPOST
</ins><span class="cx">             self.xmlDocHandlers[customxml.Multiput] = AddressBookCollectionResource.crudBatchPOST
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -3032,9 +3067,9 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><del>-    def componentsFromData(cls, data):
</del><ins>+    def componentsFromData(cls, data, format):
</ins><span class="cx">         try:
</span><del>-            return VCard.allFromString(data)
</del><ins>+            return VCard.allFromString(data, format)
</ins><span class="cx">         except InvalidVCardDataError:
</span><span class="cx">             return None
</span><span class="cx"> 
</span><span class="lines">@@ -3055,7 +3090,7 @@
</span><span class="cx">         yield newchild.storeComponent(component)
</span><span class="cx">         if returnChangedData and newchild._newStoreObject._componentChanged:
</span><span class="cx">             result = (yield newchild.component())
</span><del>-            returnValue(str(result))
</del><ins>+            returnValue(result)
</ins><span class="cx">         else:
</span><span class="cx">             returnValue(None)
</span><span class="cx"> 
</span><span class="lines">@@ -3096,7 +3131,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def bulkCreate(self, indexedComponents, request, return_changed, xmlresponses):
</del><ins>+    def bulkCreate(self, indexedComponents, request, return_changed, xmlresponses, format):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         bulk create allowing groups to contain member UIDs added during the same bulk create
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -3111,7 +3146,7 @@
</span><span class="cx">                 # Get a resource for the new item
</span><span class="cx">                 newchildURL = joinURL(request.path, name)
</span><span class="cx">                 newchild = (yield request.locateResource(newchildURL))
</span><del>-                changedData = (yield self.storeResourceData(newchild, component, returnChangedData=return_changed))
</del><ins>+                changedComponent = (yield self.storeResourceData(newchild, component, returnChangedData=return_changed))
</ins><span class="cx"> 
</span><span class="cx">             except GroupWithUnsharedAddressNotAllowedError, e:
</span><span class="cx">                 # save off info and try again below
</span><span class="lines">@@ -3126,20 +3161,20 @@
</span><span class="cx">                     error = (error.namespace, error.name,)
</span><span class="cx"> 
</span><span class="cx">                 xmlresponses[index] = (
</span><del>-                    yield self.bulkCreateResponse(component, newchildURL, newchild, None, code, error)
</del><ins>+                    yield self.bulkCreateResponse(component, newchildURL, newchild, None, code, error, format)
</ins><span class="cx">                 )
</span><span class="cx"> 
</span><span class="cx">             except Exception:
</span><span class="cx">                 xmlresponses[index] = (
</span><del>-                    yield self.bulkCreateResponse(component, newchildURL, newchild, None, code=BAD_REQUEST, error=None)
</del><ins>+                    yield self.bulkCreateResponse(component, newchildURL, newchild, None, BAD_REQUEST, None, format)
</ins><span class="cx">                 )
</span><span class="cx"> 
</span><span class="cx">             else:
</span><span class="cx">                 if not return_changed:
</span><del>-                    changedData = None
</del><ins>+                    changedComponent = None
</ins><span class="cx">                 coaddedUIDs |= set([component.resourceUID()])
</span><span class="cx">                 xmlresponses[index] = (
</span><del>-                    yield self.bulkCreateResponse(component, newchildURL, newchild, changedData, code=None, error=None)
</del><ins>+                    yield self.bulkCreateResponse(component, newchildURL, newchild, changedComponent, None, None, format)
</ins><span class="cx">                 )
</span><span class="cx"> 
</span><span class="cx">         if groupRetries:
</span><span class="lines">@@ -3157,7 +3192,7 @@
</span><span class="cx">                 # give FORBIDDEN response
</span><span class="cx">                 index, component, newchildURL, newchild, missingUIDs = groupRetry
</span><span class="cx">                 xmlresponses[index] = (
</span><del>-                    yield self.bulkCreateResponse(component, newchildURL, newchild, changedData=None, code=FORBIDDEN, error=None)
</del><ins>+                    yield self.bulkCreateResponse(component, newchildURL, newchild, None, FORBIDDEN, None, format)
</ins><span class="cx">                 )
</span><span class="cx">                 coaddedUIDs -= set([component.resourceUID()]) # group uid not added
</span><span class="cx">                 groupRetries.remove(groupRetry) # remove this retry
</span><span class="lines">@@ -3167,11 +3202,11 @@
</span><span class="cx">                 newchild._metadata[&quot;coaddedUIDs&quot;] = coaddedUIDs
</span><span class="cx"> 
</span><span class="cx">                 # don't catch errors, abort the whole transaction
</span><del>-                changedData = yield self.storeResourceData(newchild, component, returnChangedData=return_changed)
</del><ins>+                changedComponent = yield self.storeResourceData(newchild, component, returnChangedData=return_changed)
</ins><span class="cx">                 if not return_changed:
</span><del>-                    changedData = None
</del><ins>+                    changedComponent = None
</ins><span class="cx">                 xmlresponses[index] = (
</span><del>-                    yield self.bulkCreateResponse(component, newchildURL, newchild, changedData, code=None, error=None)
</del><ins>+                    yield self.bulkCreateResponse(component, newchildURL, newchild, changedComponent, None, None, format)
</ins><span class="cx">                 )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -3266,6 +3301,13 @@
</span><span class="cx"> 
</span><span class="cx">     _componentFromStream = VCard.fromString
</span><span class="cx"> 
</span><ins>+    def allowedTypes(self):
+        &quot;&quot;&quot;
+        Return a tuple of allowed MIME types for storing.
+        &quot;&quot;&quot;
+        return VCard.allowedTypes()
+
+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def vCardText(self):
</span><span class="cx">         data = yield self.vCard()
</span><span class="lines">@@ -3340,7 +3382,8 @@
</span><span class="cx"> 
</span><span class="cx">         # Content-type check
</span><span class="cx">         content_type = request.headers.getHeader(&quot;content-type&quot;)
</span><del>-        if content_type is not None and (content_type.mediaType, content_type.mediaSubtype) != (&quot;text&quot;, &quot;vcard&quot;):
</del><ins>+        format = self.determineType(content_type)
+        if format is None:
</ins><span class="cx">             log.error(&quot;MIME type {content_type} not allowed in vcard collection&quot;, content_type=content_type)
</span><span class="cx">             raise HTTPError(ErrorResponse(
</span><span class="cx">                 responsecode.FORBIDDEN,
</span><span class="lines">@@ -3365,7 +3408,7 @@
</span><span class="cx">                 ))
</span><span class="cx"> 
</span><span class="cx">             try:
</span><del>-                component = VCard.fromString(vcarddata)
</del><ins>+                component = VCard.fromString(vcarddata, format)
</ins><span class="cx">             except ValueError, e:
</span><span class="cx">                 log.error(str(e))
</span><span class="cx">                 raise HTTPError(ErrorResponse(
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_addressbookmultigetpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_addressbookmultiget.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_addressbookmultiget.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_addressbookmultiget.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -19,17 +19,19 @@
</span><span class="cx"> from twext.web2 import responsecode
</span><span class="cx"> from twext.web2.iweb import IResponse
</span><span class="cx"> from twext.web2.stream import MemoryStream
</span><del>-from txdav.xml import element as davxml
</del><span class="cx"> from twext.web2.dav.util import davXMLFromStream, joinURL
</span><ins>+from twext.web2.http_headers import Headers, MimeType
</ins><span class="cx"> 
</span><span class="cx"> from twistedcaldav import carddavxml
</span><span class="cx"> from twistedcaldav import vcard
</span><del>-
</del><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.test.util import StoreTestCase, SimpleStoreRequest
</span><ins>+
</ins><span class="cx"> from twisted.python.filepath import FilePath
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, returnValue
</span><span class="cx"> 
</span><ins>+from txdav.xml import element as davxml
+
</ins><span class="cx"> class AddressBookMultiget (StoreTestCase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     addressbook-multiget REPORT
</span><span class="lines">@@ -214,7 +216,13 @@
</span><span class="cx">             '''
</span><span class="cx">             if data:
</span><span class="cx">                 for filename, icaldata in data.iteritems():
</span><del>-                    request = SimpleStoreRequest(self, &quot;PUT&quot;, joinURL(addressbook_uri, filename + &quot;.vcf&quot;), authid=&quot;wsanchez&quot;)
</del><ins>+                    request = SimpleStoreRequest(
+                        self,
+                        &quot;PUT&quot;,
+                        joinURL(addressbook_uri, filename + &quot;.vcf&quot;),
+                        headers=Headers({&quot;content-type&quot;: MimeType.fromString(&quot;text/vcard&quot;)}),
+                        authid=&quot;wsanchez&quot;
+                    )
</ins><span class="cx">                     request.stream = MemoryStream(icaldata)
</span><span class="cx">                     yield self.send(request)
</span><span class="cx">             else:
</span><span class="lines">@@ -222,7 +230,13 @@
</span><span class="cx">                 for child in FilePath(self.vcards_dir).children():
</span><span class="cx">                     if os.path.splitext(child.basename())[1] != &quot;.vcf&quot;:
</span><span class="cx">                         continue
</span><del>-                    request = SimpleStoreRequest(self, &quot;PUT&quot;, joinURL(addressbook_uri, child.basename()), authid=&quot;wsanchez&quot;)
</del><ins>+                    request = SimpleStoreRequest(
+                        self,
+                        &quot;PUT&quot;,
+                        joinURL(addressbook_uri, child.basename()),
+                        headers=Headers({&quot;content-type&quot;: MimeType.fromString(&quot;text/vcard&quot;)}),
+                        authid=&quot;wsanchez&quot;
+                    )
</ins><span class="cx">                     request.stream = MemoryStream(child.getContent())
</span><span class="cx">                     yield self.send(request)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_caldavxmlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_caldavxml.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_caldavxml.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_caldavxml.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -14,9 +14,16 @@
</span><span class="cx"> # limitations under the License.
</span><span class="cx"> ##
</span><span class="cx"> 
</span><ins>+import twistedcaldav.test.util
</ins><span class="cx"> from twistedcaldav import caldavxml
</span><del>-import twistedcaldav.test.util
</del><ins>+from twistedcaldav.caldavxml import CalendarData
+from twistedcaldav.ical import normalize_iCalStr, Component
</ins><span class="cx"> 
</span><ins>+def normalizeJSON(j):
+    return &quot;&quot;.join(map(str.strip, j.splitlines())).replace(&quot;, &quot;, &quot;,&quot;).replace(&quot;: &quot;, &quot;:&quot;)
+
+
+
</ins><span class="cx"> class CustomXML (twistedcaldav.test.util.TestCase):
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -50,3 +57,99 @@
</span><span class="cx"> 
</span><span class="cx">         tr = caldavxml.CalDAVTimeRangeElement(start=&quot;20110201T120000Z&quot;, end=&quot;20110202&quot;)
</span><span class="cx">         self.assertFalse(tr.valid())
</span><ins>+
+
+    def test_CalendarDataTextAndJSON(self):
+        &quot;&quot;&quot;
+        Text that we can both parse and generate CalendarData elements with both text and json formats.
+        &quot;&quot;&quot;
+        dataText = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ATTENDEE:mailto:user1@example.com
+ATTENDEE:mailto:user2@example.com
+DTSTAMP:20080601T120000Z
+EXDATE:20080602T120000Z
+EXDATE:20080603T120000Z
+ORGANIZER;CN=User 01:mailto:user1@example.com
+RRULE:FREQ=DAILY;COUNT=400
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;.replace(&quot;\n&quot;, &quot;\r\n&quot;)
+
+        dataXML = &quot;&quot;&quot;&lt;?xml version='1.0' encoding='UTF-8'?&gt;
+&lt;calendar-data xmlns='urn:ietf:params:xml:ns:caldav'&gt;&lt;![CDATA[%s]]&gt;&lt;/calendar-data&gt;&quot;&quot;&quot; % (dataText,)
+
+        jsonText = &quot;&quot;&quot;[
+  &quot;vcalendar&quot;,
+  [
+    [&quot;version&quot;, {}, &quot;text&quot;, &quot;2.0&quot;],
+    [&quot;prodid&quot;, {}, &quot;text&quot;, &quot;-//CALENDARSERVER.ORG//NONSGML Version 1//EN&quot;]
+  ],
+  [
+    [&quot;vevent&quot;,
+      [
+        [&quot;uid&quot;, {}, &quot;text&quot;, &quot;12345-67890&quot;],
+        [&quot;dtstart&quot;, {}, &quot;date-time&quot;, &quot;2008-06-01T12:00:00Z&quot;],
+        [&quot;dtend&quot;, {}, &quot;date-time&quot;, &quot;2008-06-01T13:00:00Z&quot;],
+        [&quot;attendee&quot;, {}, &quot;cal-address&quot;, &quot;mailto:user1@example.com&quot;],
+        [&quot;attendee&quot;, {}, &quot;cal-address&quot;, &quot;mailto:user2@example.com&quot;],
+        [&quot;dtstamp&quot;, {}, &quot;date-time&quot;, &quot;2008-06-01T12:00:00Z&quot;],
+        [&quot;exdate&quot;, {}, &quot;date-time&quot;, &quot;2008-06-02T12:00:00Z&quot;],
+        [&quot;exdate&quot;, {}, &quot;date-time&quot;, &quot;2008-06-03T12:00:00Z&quot;],
+        [&quot;organizer&quot;, {&quot;cn&quot;: &quot;User 01&quot;}, &quot;cal-address&quot;, &quot;mailto:user1@example.com&quot;],
+        [&quot;rrule&quot;, {}, &quot;recur&quot;, {&quot;count&quot;: 400, &quot;freq&quot;: &quot;DAILY&quot;}],
+        [&quot;summary&quot;, {}, &quot;text&quot;, &quot;Test&quot;]
+      ],
+      [
+      ]
+    ]
+  ]
+]
+&quot;&quot;&quot;
+
+        jsonXML = &quot;&quot;&quot;&lt;?xml version='1.0' encoding='UTF-8'?&gt;
+&lt;calendar-data content-type='application/calendar+json' xmlns='urn:ietf:params:xml:ns:caldav'&gt;&lt;![CDATA[%s]]&gt;&lt;/calendar-data&gt;&quot;&quot;&quot; % (jsonText,)
+
+        cd = CalendarData.fromTextData(dataText)
+        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format=&quot;text/calendar&quot;)), normalize_iCalStr(dataText))
+        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format=&quot;application/calendar+json&quot;)), normalizeJSON(jsonText))
+        self.assertEqual(cd.content_type, &quot;text/calendar&quot;)
+        self.assertEqual(cd.toxml(), dataXML)
+
+        comp = Component.fromString(dataText)
+        cd = CalendarData.fromCalendar(comp)
+        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format=&quot;text/calendar&quot;)), normalize_iCalStr(dataText))
+        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format=&quot;application/calendar+json&quot;)), normalizeJSON(jsonText))
+        self.assertEqual(cd.content_type, &quot;text/calendar&quot;)
+        self.assertEqual(cd.toxml(), dataXML)
+
+        cd = CalendarData.fromCalendar(comp, format=&quot;application/calendar+json&quot;)
+        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format=&quot;text/calendar&quot;)), normalize_iCalStr(dataText))
+        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format=&quot;application/calendar+json&quot;)), normalizeJSON(jsonText))
+        self.assertEqual(cd.content_type, &quot;application/calendar+json&quot;)
+        self.assertEqual(normalizeJSON(cd.toxml()), normalizeJSON(jsonXML))
+
+        cd = CalendarData.fromTextData(jsonText, format=&quot;application/calendar+json&quot;)
+        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format=&quot;text/calendar&quot;)), normalize_iCalStr(dataText))
+        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format=&quot;application/calendar+json&quot;)), normalizeJSON(jsonText))
+        self.assertEqual(cd.content_type, &quot;application/calendar+json&quot;)
+        self.assertEqual(cd.toxml(), jsonXML)
+
+        comp = Component.fromString(jsonText, format=&quot;application/calendar+json&quot;)
+        cd = CalendarData.fromCalendar(comp)
+        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format=&quot;text/calendar&quot;)), normalize_iCalStr(dataText))
+        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format=&quot;application/calendar+json&quot;)), normalizeJSON(jsonText))
+        self.assertEqual(cd.content_type, &quot;text/calendar&quot;)
+        self.assertEqual(cd.toxml(), dataXML)
+
+        cd = CalendarData.fromCalendar(comp, format=&quot;application/calendar+json&quot;)
+        self.assertEqual(normalize_iCalStr(cd.calendar().getTextWithTimezones(True, format=&quot;text/calendar&quot;)), normalize_iCalStr(dataText))
+        self.assertEqual(normalizeJSON(cd.calendar().getTextWithTimezones(True, format=&quot;application/calendar+json&quot;)), normalizeJSON(jsonText))
+        self.assertEqual(cd.content_type, &quot;application/calendar+json&quot;)
+        self.assertEqual(normalizeJSON(cd.toxml()), normalizeJSON(jsonXML))
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_calendarquerypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_calendarquery.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_calendarquery.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_calendarquery.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -32,7 +32,7 @@
</span><span class="cx"> from twistedcaldav.test.util import StoreTestCase, SimpleStoreRequest
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, returnValue
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> from twistedcaldav.ical import Component
</span><span class="cx"> from txdav.caldav.icalendarstore import ComponentUpdateState
</span><span class="cx"> from twistedcaldav.directory.directory import DirectoryService
</span><span class="lines">@@ -124,8 +124,8 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         query_timerange = caldavxml.TimeRange(
</span><del>-            start=&quot;%04d1001T000000Z&quot; % (PyCalendarDateTime.getToday().getYear(),),
-            end=&quot;%04d1101T000000Z&quot; % (PyCalendarDateTime.getToday().getYear(),),
</del><ins>+            start=&quot;%04d1001T000000Z&quot; % (DateTime.getToday().getYear(),),
+            end=&quot;%04d1101T000000Z&quot; % (DateTime.getToday().getYear(),),
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         query = caldavxml.CalendarQuery(
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_configpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_config.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_config.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_config.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -34,7 +34,7 @@
</span><span class="cx"> &lt;dict&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;key&gt;ResponseCompression&lt;/key&gt;
</span><del>-  &lt;false/&gt;
</del><ins>+  &lt;true/&gt;
</ins><span class="cx"> 
</span><span class="cx">   &lt;key&gt;HTTPPort&lt;/key&gt;
</span><span class="cx">   &lt;integer&gt;8008&lt;/integer&gt;
</span><span class="lines">@@ -73,7 +73,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> def _testResponseCompression(testCase):
</span><del>-    testCase.assertEquals(config.ResponseCompression, False)
</del><ins>+    testCase.assertEquals(config.ResponseCompression, True)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -114,19 +114,19 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def testLoadConfig(self):
</span><del>-        self.assertEquals(config.ResponseCompression, True)
</del><ins>+        self.assertEquals(config.ResponseCompression, False)
</ins><span class="cx"> 
</span><span class="cx">         config.load(self.testConfig)
</span><span class="cx"> 
</span><del>-        self.assertEquals(config.ResponseCompression, False)
</del><ins>+        self.assertEquals(config.ResponseCompression, True)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def testScoping(self):
</span><del>-        self.assertEquals(config.ResponseCompression, True)
</del><ins>+        self.assertEquals(config.ResponseCompression, False)
</ins><span class="cx"> 
</span><span class="cx">         config.load(self.testConfig)
</span><span class="cx"> 
</span><del>-        self.assertEquals(config.ResponseCompression, False)
</del><ins>+        self.assertEquals(config.ResponseCompression, True)
</ins><span class="cx"> 
</span><span class="cx">         _testResponseCompression(self)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_dateopspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_dateops.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_dateops.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_dateops.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx"> 
</span><span class="cx"> import twistedcaldav.test.util
</span><span class="cx"> from twisted.trial.unittest import SkipTest
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from twistedcaldav.dateops import parseSQLTimestampToPyCalendar, \
</span><span class="cx">     parseSQLDateToPyCalendar, pyCalendarTodatetime, \
</span><span class="lines">@@ -24,7 +24,7 @@
</span><span class="cx"> 
</span><span class="cx"> import datetime
</span><span class="cx"> import dateutil
</span><del>-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.timezone import Timezone
</ins><span class="cx"> from twistedcaldav.timezones import TimezoneCache
</span><span class="cx"> 
</span><span class="cx"> class Dateops(twistedcaldav.test.util.TestCase):
</span><span class="lines">@@ -43,10 +43,10 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         data = (
</span><del>-            (PyCalendarDateTime(2012, 1, 1), PyCalendarDateTime(2012, 1, 1, 0, 0, 0)),
-            (PyCalendarDateTime(2012, 1, 1, 10, 0, 0), PyCalendarDateTime(2012, 1, 1, 10, 0, 0)),
-            (PyCalendarDateTime(2012, 1, 1, 11, 0, 0, tzid=PyCalendarTimezone(utc=True)), PyCalendarDateTime(2012, 1, 1, 11, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-            (PyCalendarDateTime(2012, 1, 1, 12, 0, 0, tzid=PyCalendarTimezone(tzid=&quot;America/New_York&quot;)), PyCalendarDateTime(2012, 1, 1, 17, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+            (DateTime(2012, 1, 1), DateTime(2012, 1, 1, 0, 0, 0)),
+            (DateTime(2012, 1, 1, 10, 0, 0), DateTime(2012, 1, 1, 10, 0, 0)),
+            (DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True)), DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True))),
+            (DateTime(2012, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)), DateTime(2012, 1, 1, 17, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for value, result in data:
</span><span class="lines">@@ -59,10 +59,10 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         data = (
</span><del>-            (PyCalendarDateTime(2012, 1, 1), PyCalendarDateTime(2012, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-            (PyCalendarDateTime(2012, 1, 1, 10, 0, 0), PyCalendarDateTime(2012, 1, 1, 10, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-            (PyCalendarDateTime(2012, 1, 1, 11, 0, 0, tzid=PyCalendarTimezone(utc=True)), PyCalendarDateTime(2012, 1, 1, 11, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-            (PyCalendarDateTime(2012, 1, 1, 12, 0, 0, tzid=PyCalendarTimezone(tzid=&quot;America/New_York&quot;)), PyCalendarDateTime(2012, 1, 1, 17, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+            (DateTime(2012, 1, 1), DateTime(2012, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))),
+            (DateTime(2012, 1, 1, 10, 0, 0), DateTime(2012, 1, 1, 10, 0, 0, tzid=Timezone(utc=True))),
+            (DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True)), DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True))),
+            (DateTime(2012, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)), DateTime(2012, 1, 1, 17, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for value, result in data:
</span><span class="lines">@@ -75,10 +75,10 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         data = (
</span><del>-            (PyCalendarDateTime(2012, 1, 1), PyCalendarDateTime(2012, 1, 1)),
-            (PyCalendarDateTime(2012, 1, 1, 10, 0, 0), PyCalendarDateTime(2012, 1, 1, 10, 0, 0)),
-            (PyCalendarDateTime(2012, 1, 1, 11, 0, 0, tzid=PyCalendarTimezone(utc=True)), PyCalendarDateTime(2012, 1, 1, 11, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-            (PyCalendarDateTime(2012, 1, 1, 12, 0, 0, tzid=PyCalendarTimezone(tzid=&quot;America/New_York&quot;)), PyCalendarDateTime(2012, 1, 1, 17, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+            (DateTime(2012, 1, 1), DateTime(2012, 1, 1)),
+            (DateTime(2012, 1, 1, 10, 0, 0), DateTime(2012, 1, 1, 10, 0, 0)),
+            (DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True)), DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True))),
+            (DateTime(2012, 1, 1, 12, 0, 0, tzid=Timezone(tzid=&quot;America/New_York&quot;)), DateTime(2012, 1, 1, 17, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for value, result in data:
</span><span class="lines">@@ -107,132 +107,132 @@
</span><span class="cx">             # Timed
</span><span class="cx">             (
</span><span class="cx">                 &quot;Start within, end within - overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 1, 11, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 1, 12, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 True,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Start before, end before - no overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 1, 11, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 3, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 1, 12, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 3, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 False,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Start before, end right before - no overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 1, 23, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 3, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 1, 23, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 3, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 False,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Start before, end within - overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 1, 11, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 11, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 3, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 11, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 3, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 True,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Start after, end after - no overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 2, 11, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 2, 11, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 12, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 False,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Start right after, end after - no overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 1, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 False,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Start within, end after - overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 1, 12, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 12, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 True,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Start before, end after - overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 1, 11, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 3, 11, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 2, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 3, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 3, 11, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 3, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 True,
</span><span class="cx">             ),
</span><span class="cx"> 
</span><span class="cx">             # All day
</span><span class="cx">             (
</span><span class="cx">                 &quot;All day: Start within, end within - overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 9),
-                PyCalendarDateTime(2012, 1, 10),
-                PyCalendarDateTime(2012, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 9),
+                DateTime(2012, 1, 10),
+                DateTime(2012, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 15, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 True,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;All day: Start before, end before - no overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 1),
-                PyCalendarDateTime(2012, 1, 2),
-                PyCalendarDateTime(2012, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 1),
+                DateTime(2012, 1, 2),
+                DateTime(2012, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 15, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 False,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;All day: Start before, end right before - no overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 7),
-                PyCalendarDateTime(2012, 1, 8),
-                PyCalendarDateTime(2012, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 7),
+                DateTime(2012, 1, 8),
+                DateTime(2012, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 15, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 False,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;All day: Start before, end within - overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 7),
-                PyCalendarDateTime(2012, 1, 9),
-                PyCalendarDateTime(2012, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 7),
+                DateTime(2012, 1, 9),
+                DateTime(2012, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 15, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 True,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;All day: Start after, end after - no overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 16),
-                PyCalendarDateTime(2012, 1, 17),
-                PyCalendarDateTime(2012, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 16),
+                DateTime(2012, 1, 17),
+                DateTime(2012, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 15, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 False,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;All day: Start right after, end after - no overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 15),
-                PyCalendarDateTime(2012, 1, 16),
-                PyCalendarDateTime(2012, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 15),
+                DateTime(2012, 1, 16),
+                DateTime(2012, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 15, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 False,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;All day: Start within, end after - overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 14),
-                PyCalendarDateTime(2012, 1, 16),
-                PyCalendarDateTime(2012, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 14),
+                DateTime(2012, 1, 16),
+                DateTime(2012, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 15, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 True,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;All day: Start before, end after - overlap&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 7),
-                PyCalendarDateTime(2012, 1, 16),
-                PyCalendarDateTime(2012, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                PyCalendarDateTime(2012, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2012, 1, 7),
+                DateTime(2012, 1, 16),
+                DateTime(2012, 1, 8, 0, 0, 0, tzid=Timezone(utc=True)),
+                DateTime(2012, 1, 15, 0, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 True,
</span><span class="cx">             ),
</span><span class="cx">         )
</span><span class="lines">@@ -254,8 +254,8 @@
</span><span class="cx">         dateops.pyCalendarTodatetime
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         tests = (
</span><del>-            (PyCalendarDateTime(2012, 4, 4, 12, 34, 56), datetime.datetime(2012, 4, 4, 12, 34, 56, tzinfo=dateutil.tz.tzutc())),
-            (PyCalendarDateTime(2012, 12, 31), datetime.date(2012, 12, 31)),
</del><ins>+            (DateTime(2012, 4, 4, 12, 34, 56), datetime.datetime(2012, 4, 4, 12, 34, 56, tzinfo=dateutil.tz.tzutc())),
+            (DateTime(2012, 12, 31), datetime.date(2012, 12, 31)),
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for pycal, result in tests:
</span><span class="lines">@@ -267,8 +267,8 @@
</span><span class="cx">         dateops.parseSQLTimestampToPyCalendar
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         tests = (
</span><del>-            (&quot;2012-04-04 12:34:56&quot;, PyCalendarDateTime(2012, 4, 4, 12, 34, 56)),
-            (&quot;2012-12-31 01:01:01&quot;, PyCalendarDateTime(2012, 12, 31, 1, 1, 1)),
</del><ins>+            (&quot;2012-04-04 12:34:56&quot;, DateTime(2012, 4, 4, 12, 34, 56)),
+            (&quot;2012-12-31 01:01:01&quot;, DateTime(2012, 12, 31, 1, 1, 1)),
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for sqlStr, result in tests:
</span><span class="lines">@@ -281,8 +281,8 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         tests = (
</span><del>-            (&quot;2012-04-04&quot;, PyCalendarDateTime(2012, 4, 4)),
-            (&quot;2012-12-31 00:00:00&quot;, PyCalendarDateTime(2012, 12, 31)),
</del><ins>+            (&quot;2012-04-04&quot;, DateTime(2012, 4, 4)),
+            (&quot;2012-12-31 00:00:00&quot;, DateTime(2012, 12, 31)),
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for sqlStr, result in tests:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_icalendarpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_icalendar.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_icalendar.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_icalendar.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -21,16 +21,16 @@
</span><span class="cx"> from twisted.trial.unittest import SkipTest
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav.ical import Component, Property, InvalidICalendarDataError, \
</span><del>-    normalizeCUAddress
</del><ins>+    normalizeCUAddress, normalize_iCalStr
</ins><span class="cx"> from twistedcaldav.instance import InvalidOverriddenInstanceError
</span><span class="cx"> import twistedcaldav.test.util
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> from twistedcaldav.ical import iCalendarProductID
</span><del>-from pycalendar.duration import PyCalendarDuration
</del><ins>+from pycalendar.duration import Duration
</ins><span class="cx"> from twistedcaldav.dateops import normalizeForExpand
</span><del>-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.value import Value
</ins><span class="cx"> 
</span><span class="cx"> class iCalendar (twistedcaldav.test.util.TestCase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -469,7 +469,7 @@
</span><span class="cx">         calendar.validCalendarData(doFix=False, validateRecurrences=True)
</span><span class="cx"> 
</span><span class="cx">         # Verify expansion works, even for an RDATE prior to master DTSTART:
</span><del>-        calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
</del><ins>+        calendar.expandTimeRanges(DateTime(2100, 1, 1))
</ins><span class="cx"> 
</span><span class="cx">         # Test EXDATEs *prior* to master (as the result of client splitting a
</span><span class="cx">         # a recurring event and copying *all* EXDATEs to new event):
</span><span class="lines">@@ -568,13 +568,13 @@
</span><span class="cx"> 
</span><span class="cx">         year = 2004
</span><span class="cx"> 
</span><del>-        instances = calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
</del><ins>+        instances = calendar.expandTimeRanges(DateTime(2100, 1, 1))
</ins><span class="cx">         for key in instances:
</span><span class="cx">             instance = instances[key]
</span><span class="cx">             start = instance.start
</span><span class="cx">             end = instance.end
</span><del>-            self.assertEqual(start, PyCalendarDateTime(year, 7, 4))
-            self.assertEqual(end  , PyCalendarDateTime(year, 7, 5))
</del><ins>+            self.assertEqual(start, DateTime(year, 7, 4))
+            self.assertEqual(end  , DateTime(year, 7, 5))
</ins><span class="cx">             if year == 2050:
</span><span class="cx">                 break
</span><span class="cx">             year += 1
</span><span class="lines">@@ -594,14 +594,14 @@
</span><span class="cx">         }
</span><span class="cx">         year = 2004
</span><span class="cx"> 
</span><del>-        instances = calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
</del><ins>+        instances = calendar.expandTimeRanges(DateTime(2100, 1, 1))
</ins><span class="cx">         for key in instances:
</span><span class="cx">             instance = instances[key]
</span><span class="cx">             start = instance.start
</span><span class="cx">             end = instance.end
</span><span class="cx">             if year in results:
</span><del>-                self.assertEqual(start, PyCalendarDateTime(year, results[year][0], results[year][1]))
-                self.assertEqual(end  , PyCalendarDateTime(year, results[year][0], results[year][2]))
</del><ins>+                self.assertEqual(start, DateTime(year, results[year][0], results[year][1]))
+                self.assertEqual(end  , DateTime(year, results[year][0], results[year][2]))
</ins><span class="cx">             if year == 2050:
</span><span class="cx">                 break
</span><span class="cx">             year += 1
</span><span class="lines">@@ -621,14 +621,14 @@
</span><span class="cx">         }
</span><span class="cx">         year = 2002
</span><span class="cx"> 
</span><del>-        instances = calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
</del><ins>+        instances = calendar.expandTimeRanges(DateTime(2100, 1, 1))
</ins><span class="cx">         for key in instances:
</span><span class="cx">             instance = instances[key]
</span><span class="cx">             start = instance.start
</span><span class="cx">             end = instance.end
</span><span class="cx">             if year in results:
</span><del>-                self.assertEqual(start, PyCalendarDateTime(year, results[year][0], results[year][1]))
-                self.assertEqual(end  , PyCalendarDateTime(year, results[year][0], results[year][2]))
</del><ins>+                self.assertEqual(start, DateTime(year, results[year][0], results[year][1]))
+                self.assertEqual(end  , DateTime(year, results[year][0], results[year][2]))
</ins><span class="cx">             if year == 2050:
</span><span class="cx">                 break
</span><span class="cx">             year += 1
</span><span class="lines">@@ -642,13 +642,13 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         calendar = Component.fromStream(file(os.path.join(self.data_dir, &quot;Holidays&quot;, &quot;C318ABFE-1ED0-11D9-A5E0-000A958A3252.ics&quot;)))
</span><span class="cx"> 
</span><del>-        instances = calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
</del><ins>+        instances = calendar.expandTimeRanges(DateTime(2100, 1, 1))
</ins><span class="cx">         for key in instances:
</span><span class="cx">             instance = instances[key]
</span><span class="cx">             start = instance.start
</span><span class="cx">             end = instance.end
</span><del>-            self.assertEqual(start, PyCalendarDateTime(2004, 11, 25))
-            self.assertEqual(end, PyCalendarDateTime(2004, 11, 27))
</del><ins>+            self.assertEqual(start, DateTime(2004, 11, 25))
+            self.assertEqual(end, DateTime(2004, 11, 27))
</ins><span class="cx">             break
</span><span class="cx"> 
</span><span class="cx">     # test_component_timerange.todo = &quot;recurrence expansion should give us no end date here&quot;
</span><span class="lines">@@ -658,44 +658,44 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         parse_date()
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        self.assertEqual(PyCalendarDateTime.parseText(&quot;19970714&quot;), PyCalendarDateTime(1997, 7, 14))
</del><ins>+        self.assertEqual(DateTime.parseText(&quot;19970714&quot;), DateTime(1997, 7, 14))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_parse_datetime(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         parse_datetime()
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        dt = PyCalendarDateTime.parseText(&quot;19980118T230000&quot;)
-        self.assertEqual(dt, PyCalendarDateTime(1998, 1, 18, 23, 0, 0))
</del><ins>+        dt = DateTime.parseText(&quot;19980118T230000&quot;)
+        self.assertEqual(dt, DateTime(1998, 1, 18, 23, 0, 0))
</ins><span class="cx">         self.assertTrue(dt.floating())
</span><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime.parseText(&quot;19980119T070000Z&quot;)
-        self.assertEqual(dt, PyCalendarDateTime(1998, 1, 19, 7, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        dt = DateTime.parseText(&quot;19980119T070000Z&quot;)
+        self.assertEqual(dt, DateTime(1998, 1, 19, 7, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_parse_date_or_datetime(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         parse_date_or_datetime()
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        self.assertEqual(PyCalendarDateTime.parseText(&quot;19970714&quot;), PyCalendarDateTime(1997, 7, 14))
</del><ins>+        self.assertEqual(DateTime.parseText(&quot;19970714&quot;), DateTime(1997, 7, 14))
</ins><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime.parseText(&quot;19980118T230000&quot;)
-        self.assertEqual(dt, PyCalendarDateTime(1998, 1, 18, 23, 0, 0))
</del><ins>+        dt = DateTime.parseText(&quot;19980118T230000&quot;)
+        self.assertEqual(dt, DateTime(1998, 1, 18, 23, 0, 0))
</ins><span class="cx">         self.assertTrue(dt.floating())
</span><span class="cx"> 
</span><del>-        dt = PyCalendarDateTime.parseText(&quot;19980119T070000Z&quot;)
-        self.assertEqual(dt, PyCalendarDateTime(1998, 1, 19, 7, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        dt = DateTime.parseText(&quot;19980119T070000Z&quot;)
+        self.assertEqual(dt, DateTime(1998, 1, 19, 7, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_parse_duration(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         parse_duration()
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        self.assertEqual(PyCalendarDuration.parseText(&quot;P15DT5H0M20S&quot;), PyCalendarDuration(days=15, hours=5, minutes=0, seconds=20))
-        self.assertEqual(PyCalendarDuration.parseText(&quot;+P15DT5H0M20S&quot;), PyCalendarDuration(days=15, hours=5, minutes=0, seconds=20))
-        self.assertEqual(PyCalendarDuration.parseText(&quot;-P15DT5H0M20S&quot;), PyCalendarDuration(days=15 * -1, hours=5 * -1, minutes=0, seconds=20 * -1))
</del><ins>+        self.assertEqual(Duration.parseText(&quot;P15DT5H0M20S&quot;), Duration(days=15, hours=5, minutes=0, seconds=20))
+        self.assertEqual(Duration.parseText(&quot;+P15DT5H0M20S&quot;), Duration(days=15, hours=5, minutes=0, seconds=20))
+        self.assertEqual(Duration.parseText(&quot;-P15DT5H0M20S&quot;), Duration(days=15 * -1, hours=5 * -1, minutes=0, seconds=20 * -1))
</ins><span class="cx"> 
</span><del>-        self.assertEqual(PyCalendarDuration.parseText(&quot;P7W&quot;), PyCalendarDuration(weeks=7))
</del><ins>+        self.assertEqual(Duration.parseText(&quot;P7W&quot;), Duration(weeks=7))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_correct_attendee_properties(self):
</span><span class="lines">@@ -807,7 +807,7 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (&quot;mailto:user1@example.com&quot;, None),
</span><del>-                    (&quot;mailto:user1@example.com&quot;, PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+                    (&quot;mailto:user1@example.com&quot;, DateTime(2008, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -833,7 +833,7 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (&quot;mailto:user1@example.com&quot;, None),
</span><del>-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2009, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+                    (&quot;mailto:user3@example.com&quot;, DateTime(2009, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -946,8 +946,8 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (&quot;mailto:user2@example.com&quot;, None),
</span><del>-                    (&quot;mailto:user2@example.com&quot;, PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+                    (&quot;mailto:user2@example.com&quot;, DateTime(2008, 11, 14, 0, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user3@example.com&quot;, DateTime(2008, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -1152,6 +1152,82 @@
</span><span class="cx">             self.assertEqual(result, str(component).replace(&quot;\r&quot;, &quot;&quot;))
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def test_parameter_multi_values(self):
+        caldata = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user01@example.com
+ATTENDEE;MEMBER=&quot;urn:uuid:group01&quot;,&quot;urn:uuid:group02&quot;;PARTSTAT=NEEDS-ACTION:mailto:user02@example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER:mailto:user01@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        caldata2 = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user01@example.com
+ATTENDEE;MEMBER=&quot;urn:uuid:group01&quot;,&quot;urn:uuid:group02&quot;,&quot;urn:uuid:group03&quot;;PARTSTAT=NEEDS-ACTION:mailto:user02@example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER:mailto:user01@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        caldata3 = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user01@example.com
+ATTENDEE;MEMBER=&quot;urn:uuid:group01&quot;;PARTSTAT=NEEDS-ACTION:mailto:user02@example.com
+DTSTAMP:20080601T120000Z
+ORGANIZER:mailto:user01@example.com
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        component = Component.fromString(caldata)
+        attendee = component.masterComponent().getAttendeeProperty([&quot;mailto:user02@example.com&quot;, ])
+        self.assertTrue(attendee is not None)
+
+        # Single value retrieved as multi-value
+        partstat = attendee.parameterValues(&quot;PARTSTAT&quot;)
+        self.assertEqual(partstat, [&quot;NEEDS-ACTION&quot;])
+
+        # Multi-value retrieved as single-value
+        member = attendee.parameterValue(&quot;MEMBER&quot;)
+        self.assertEqual(member, &quot;urn:uuid:group01&quot;)
+
+        # Multi-value retrieved as multi-value
+        members = attendee.parameterValues(&quot;MEMBER&quot;)
+        self.assertEqual(members, [&quot;urn:uuid:group01&quot;, &quot;urn:uuid:group02&quot;])
+
+        # Multi-value add a new value
+        members = attendee.parameterValues(&quot;MEMBER&quot;)
+        members.append(&quot;urn:uuid:group03&quot;)
+        attendee.setParameter(&quot;MEMBER&quot;, members)
+        members = attendee.parameterValues(&quot;MEMBER&quot;)
+        self.assertEqual(members, [&quot;urn:uuid:group01&quot;, &quot;urn:uuid:group02&quot;, &quot;urn:uuid:group03&quot;])
+        self.assertEqual(normalize_iCalStr(str(component)), normalize_iCalStr(caldata2))
+
+        # Multi-value back to one
+        members = attendee.parameterValues(&quot;MEMBER&quot;)
+        del members[1:]
+        attendee.setParameter(&quot;MEMBER&quot;, members)
+        members = attendee.parameterValues(&quot;MEMBER&quot;)
+        self.assertEqual(members, [&quot;urn:uuid:group01&quot;])
+        self.assertEqual(normalize_iCalStr(str(component)), normalize_iCalStr(caldata3))
+
+
</ins><span class="cx">     def test_add_property_with_valuetype(self):
</span><span class="cx">         data = &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="lines">@@ -1177,7 +1253,7 @@
</span><span class="cx"> 
</span><span class="cx">         component = Component.fromString(data)
</span><span class="cx">         vevent = component.mainComponent()
</span><del>-        vevent.addProperty(Property(&quot;ATTACH&quot;, &quot;foobar&quot;, valuetype=PyCalendarValue.VALUETYPE_BINARY))
</del><ins>+        vevent.addProperty(Property(&quot;ATTACH&quot;, &quot;foobar&quot;, valuetype=Value.VALUETYPE_BINARY))
</ins><span class="cx">         self.assertEqual(str(component), result)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -2277,8 +2353,8 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2299,12 +2375,12 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2326,16 +2402,16 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 16, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 16, 2, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 16, 1, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 16, 2, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2357,12 +2433,12 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 16, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 16, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 16, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 16, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2384,12 +2460,12 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 16, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 16, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 16, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 16, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2417,12 +2493,12 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 15, 2, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 15, 2, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2474,12 +2550,12 @@
</span><span class="cx">                 True,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2488,9 +2564,9 @@
</span><span class="cx">         for description, original, ignoreInvalidInstances, results in data:
</span><span class="cx">             component = Component.fromString(original)
</span><span class="cx">             if results is None:
</span><del>-                self.assertRaises(InvalidOverriddenInstanceError, component.expandTimeRanges, PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances)
</del><ins>+                self.assertRaises(InvalidOverriddenInstanceError, component.expandTimeRanges, DateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances)
</ins><span class="cx">             else:
</span><del>-                instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances)
</del><ins>+                instances = component.expandTimeRanges(DateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances)
</ins><span class="cx">                 self.assertTrue(len(instances.instances) == len(results), &quot;%s: wrong number of instances&quot; % (description,))
</span><span class="cx">                 periods = tuple([(instance.start, instance.end) for instance in sorted(instances.instances.values(), key=lambda x:x.start)])
</span><span class="cx">                 self.assertEqual(periods, results)
</span><span class="lines">@@ -2518,8 +2594,8 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2539,8 +2615,8 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15),
-                        PyCalendarDateTime(2007, 11, 16),
</del><ins>+                        DateTime(2007, 11, 15),
+                        DateTime(2007, 11, 16),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2561,12 +2637,12 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2587,12 +2663,12 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15),
-                        PyCalendarDateTime(2007, 11, 16),
</del><ins>+                        DateTime(2007, 11, 15),
+                        DateTime(2007, 11, 16),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 16),
-                        PyCalendarDateTime(2007, 11, 17),
</del><ins>+                        DateTime(2007, 11, 16),
+                        DateTime(2007, 11, 17),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2614,16 +2690,16 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 16, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 16, 2, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 16, 1, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 16, 2, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2645,16 +2721,16 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15),
-                        PyCalendarDateTime(2007, 11, 16),
</del><ins>+                        DateTime(2007, 11, 15),
+                        DateTime(2007, 11, 16),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 16),
-                        PyCalendarDateTime(2007, 11, 17),
</del><ins>+                        DateTime(2007, 11, 16),
+                        DateTime(2007, 11, 17),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 18),
-                        PyCalendarDateTime(2007, 11, 19),
</del><ins>+                        DateTime(2007, 11, 18),
+                        DateTime(2007, 11, 19),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2676,12 +2752,12 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 16, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 16, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 16, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 16, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2703,12 +2779,12 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15),
-                        PyCalendarDateTime(2007, 11, 16),
</del><ins>+                        DateTime(2007, 11, 15),
+                        DateTime(2007, 11, 16),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 17),
-                        PyCalendarDateTime(2007, 11, 18),
</del><ins>+                        DateTime(2007, 11, 17),
+                        DateTime(2007, 11, 18),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2736,12 +2812,12 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 15, 2, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 15, 2, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2769,12 +2845,12 @@
</span><span class="cx">                 False,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15),
-                        PyCalendarDateTime(2007, 11, 16),
</del><ins>+                        DateTime(2007, 11, 15),
+                        DateTime(2007, 11, 16),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 16),
-                        PyCalendarDateTime(2007, 11, 18),
</del><ins>+                        DateTime(2007, 11, 16),
+                        DateTime(2007, 11, 18),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -2831,9 +2907,9 @@
</span><span class="cx">         for description, original, ignoreInvalidInstances, results in data:
</span><span class="cx">             component = Component.fromString(original)
</span><span class="cx">             if results is None:
</span><del>-                self.assertRaises(InvalidOverriddenInstanceError, component.expandTimeRanges, PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances)
</del><ins>+                self.assertRaises(InvalidOverriddenInstanceError, component.expandTimeRanges, DateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances)
</ins><span class="cx">             else:
</span><del>-                instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances, normalizeFunction=normalizeForExpand)
</del><ins>+                instances = component.expandTimeRanges(DateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances, normalizeFunction=normalizeForExpand)
</ins><span class="cx">                 self.assertTrue(len(instances.instances) == len(results), &quot;%s: wrong number of instances&quot; % (description,))
</span><span class="cx">                 periods = tuple([(instance.start, instance.end) for instance in sorted(instances.instances.values(), key=lambda x:x.start)])
</span><span class="cx">                 self.assertEqual(periods, results)
</span><span class="lines">@@ -2861,8 +2937,8 @@
</span><span class="cx">                 None,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 ),
</span><span class="cx">                 None,
</span><span class="lines">@@ -2880,11 +2956,11 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2007, 1, 1),
</del><ins>+                DateTime(2007, 1, 1),
</ins><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 ),
</span><span class="cx">                 None,
</span><span class="lines">@@ -2902,9 +2978,9 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2010, 1, 1),
</del><ins>+                DateTime(2010, 1, 1),
</ins><span class="cx">                 (),
</span><del>-                PyCalendarDateTime(2010, 1, 1),
</del><ins>+                DateTime(2010, 1, 1),
</ins><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Simple recurring - no limit&quot;,
</span><span class="lines">@@ -2923,20 +2999,20 @@
</span><span class="cx">                 None,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2008, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2008, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2008, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2009, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2009, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2009, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2009, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2010, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2010, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2010, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2010, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 ),
</span><span class="cx">                 None,
</span><span class="lines">@@ -2955,23 +3031,23 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2007, 1, 1),
</del><ins>+                DateTime(2007, 1, 1),
</ins><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2008, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2008, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2008, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2009, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2009, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2009, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2009, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2010, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2010, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2010, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2010, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 ),
</span><span class="cx">                 None,
</span><span class="lines">@@ -2990,14 +3066,14 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2010, 1, 1),
</del><ins>+                DateTime(2010, 1, 1),
</ins><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2010, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2010, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2010, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2010, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 ),
</span><del>-                PyCalendarDateTime(2010, 1, 1),
</del><ins>+                DateTime(2010, 1, 1),
</ins><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Simple recurring - limit effective full&quot;,
</span><span class="lines">@@ -3013,9 +3089,9 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 1),
</del><ins>+                DateTime(2012, 1, 1),
</ins><span class="cx">                 (),
</span><del>-                PyCalendarDateTime(2012, 1, 1),
</del><ins>+                DateTime(2012, 1, 1),
</ins><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Complex recurring - no limit&quot;,
</span><span class="lines">@@ -3048,20 +3124,20 @@
</span><span class="cx">                 None,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2008, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2008, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2008, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2008, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2009, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2009, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2009, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2009, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2010, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2010, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2010, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2010, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 ),
</span><span class="cx">                 None,
</span><span class="lines">@@ -3094,23 +3170,23 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2007, 1, 1),
</del><ins>+                DateTime(2007, 1, 1),
</ins><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2008, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2008, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2008, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2008, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2009, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2009, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2009, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2009, 11, 14, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2010, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2010, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2010, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2010, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 ),
</span><span class="cx">                 None,
</span><span class="lines">@@ -3143,14 +3219,14 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2010, 1, 1),
</del><ins>+                DateTime(2010, 1, 1),
</ins><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2010, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2010, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2010, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2010, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 ),
</span><del>-                PyCalendarDateTime(2010, 1, 1),
</del><ins>+                DateTime(2010, 1, 1),
</ins><span class="cx">             ),
</span><span class="cx">             (
</span><span class="cx">                 &quot;Complex recurring - limit effective full&quot;,
</span><span class="lines">@@ -3180,15 +3256,15 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2012, 1, 1),
</del><ins>+                DateTime(2012, 1, 1),
</ins><span class="cx">                 (),
</span><del>-                PyCalendarDateTime(2012, 1, 1),
</del><ins>+                DateTime(2012, 1, 1),
</ins><span class="cx">             ),
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx">         for description, original, lowerLimit, results, limited in data:
</span><span class="cx">             component = Component.fromString(original)
</span><del>-            instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1), lowerLimit=lowerLimit)
</del><ins>+            instances = component.expandTimeRanges(DateTime(2100, 1, 1), lowerLimit=lowerLimit)
</ins><span class="cx">             self.assertTrue(len(instances.instances) == len(results), &quot;%s: wrong number of instances&quot; % (description,))
</span><span class="cx">             periods = tuple([(instance.start, instance.end) for instance in sorted(instances.instances.values(), key=lambda x:x.start)])
</span><span class="cx">             self.assertEqual(periods, results)
</span><span class="lines">@@ -4040,7 +4116,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 2, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 1, 2, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="cx"> UID:12345-67890-1
</span><span class="cx"> RECURRENCE-ID:20090102T080000Z
</span><span class="lines">@@ -4065,7 +4141,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 2, 18, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 1, 2, 18, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="cx"> UID:12345-67890-1
</span><span class="cx"> RECURRENCE-ID:20090102T180000Z
</span><span class="lines">@@ -4091,7 +4167,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 3, 18, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 1, 3, 18, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="cx"> UID:12345-67890-1
</span><span class="cx"> RECURRENCE-ID:20090103T180000Z
</span><span class="lines">@@ -4115,7 +4191,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 2, 9, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 1, 2, 9, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 None,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4133,7 +4209,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 2, 19, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 1, 2, 19, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 None,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4152,7 +4228,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 3, 19, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 1, 3, 19, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 None,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4169,7 +4245,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 8),
</del><ins>+                DateTime(2009, 1, 8),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="cx"> UID:12345-67890-1
</span><span class="cx"> RECURRENCE-ID;VALUE=DATE:20090108
</span><span class="lines">@@ -4194,7 +4270,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 3),
</del><ins>+                DateTime(2009, 1, 3),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="cx"> UID:12345-67890-1
</span><span class="cx"> RECURRENCE-ID;VALUE=DATE:20090103
</span><span class="lines">@@ -4220,7 +4296,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 10),
</del><ins>+                DateTime(2009, 1, 10),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="cx"> UID:12345-67890-1
</span><span class="cx"> RECURRENCE-ID;VALUE=DATE:20090110
</span><span class="lines">@@ -4244,7 +4320,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 3),
</del><ins>+                DateTime(2009, 1, 3),
</ins><span class="cx">                 None,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4262,7 +4338,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 5),
</del><ins>+                DateTime(2009, 1, 5),
</ins><span class="cx">                 None,
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4281,7 +4357,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 19),
</del><ins>+                DateTime(2009, 1, 19),
</ins><span class="cx">                 None,
</span><span class="cx">             ),
</span><span class="cx">         )
</span><span class="lines">@@ -4311,8 +4387,8 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    PyCalendarDateTime(2009, 1, 2, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                    PyCalendarDateTime(2009, 1, 4, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                    DateTime(2009, 1, 2, 8, 0, 0, tzid=Timezone(utc=True)),
+                    DateTime(2009, 1, 4, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 ),
</span><span class="cx">                 (
</span><span class="cx">                     &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="lines">@@ -4349,8 +4425,8 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    PyCalendarDateTime(2009, 1, 2, 18, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                    PyCalendarDateTime(2009, 1, 4, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                    DateTime(2009, 1, 2, 18, 0, 0, tzid=Timezone(utc=True)),
+                    DateTime(2009, 1, 4, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 ),
</span><span class="cx">                 (
</span><span class="cx">                     &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="lines">@@ -4388,8 +4464,8 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    PyCalendarDateTime(2009, 1, 3, 18, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                    PyCalendarDateTime(2009, 1, 5, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                    DateTime(2009, 1, 3, 18, 0, 0, tzid=Timezone(utc=True)),
+                    DateTime(2009, 1, 5, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 ),
</span><span class="cx">                 (
</span><span class="cx">                     &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="lines">@@ -4425,8 +4501,8 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    PyCalendarDateTime(2009, 1, 2, 9, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                    PyCalendarDateTime(2009, 1, 3, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                    DateTime(2009, 1, 2, 9, 0, 0, tzid=Timezone(utc=True)),
+                    DateTime(2009, 1, 3, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 ),
</span><span class="cx">                 (
</span><span class="cx">                     None,
</span><span class="lines">@@ -4456,8 +4532,8 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    PyCalendarDateTime(2009, 1, 2, 19, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                    PyCalendarDateTime(2009, 1, 3, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                    DateTime(2009, 1, 2, 19, 0, 0, tzid=Timezone(utc=True)),
+                    DateTime(2009, 1, 3, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 ),
</span><span class="cx">                 (
</span><span class="cx">                     None,
</span><span class="lines">@@ -4488,8 +4564,8 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    PyCalendarDateTime(2009, 1, 3, 19, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                    PyCalendarDateTime(2009, 1, 3, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                    DateTime(2009, 1, 3, 19, 0, 0, tzid=Timezone(utc=True)),
+                    DateTime(2009, 1, 3, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 ),
</span><span class="cx">                 (
</span><span class="cx">                     None,
</span><span class="lines">@@ -4534,7 +4610,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 2, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 1, 2, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="cx"> UID:12345-67890-1
</span><span class="cx"> RECURRENCE-ID:20090102T080000Z
</span><span class="lines">@@ -4561,7 +4637,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 2, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 1, 2, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VEVENT
</span><span class="cx"> UID:12345-67890-1
</span><span class="cx"> RECURRENCE-ID:20090102T080000Z
</span><span class="lines">@@ -4604,19 +4680,19 @@
</span><span class="cx">         self.assertFalse(hasattr(ical, &quot;cachedInstances&quot;))
</span><span class="cx"> 
</span><span class="cx">         # Derive one day apart - no re-cache
</span><del>-        ical.deriveInstance(PyCalendarDateTime(2009, 1, 2, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        ical.deriveInstance(DateTime(2009, 1, 2, 8, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertTrue(hasattr(ical, &quot;cachedInstances&quot;))
</span><span class="cx">         oldLimit = ical.cachedInstances.limit
</span><del>-        ical.deriveInstance(PyCalendarDateTime(2009, 1, 3, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        ical.deriveInstance(DateTime(2009, 1, 3, 8, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertEqual(ical.cachedInstances.limit, oldLimit)
</span><span class="cx"> 
</span><span class="cx">         # Derive several years ahead - re-cached
</span><del>-        ical.deriveInstance(PyCalendarDateTime(2011, 1, 1, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        ical.deriveInstance(DateTime(2011, 1, 1, 8, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertNotEqual(ical.cachedInstances.limit, oldLimit)
</span><span class="cx">         oldLimit = ical.cachedInstances.limit
</span><span class="cx"> 
</span><span class="cx">         # Check one day ahead again - no re-cache
</span><del>-        ical.deriveInstance(PyCalendarDateTime(2011, 1, 2, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)))
</del><ins>+        ical.deriveInstance(DateTime(2011, 1, 2, 8, 0, 0, tzid=Timezone(utc=True)))
</ins><span class="cx">         self.assertEqual(ical.cachedInstances.limit, oldLimit)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -4661,13 +4737,13 @@
</span><span class="cx">         masterDerived = ical.masterDerived()
</span><span class="cx"> 
</span><span class="cx">         # Derive one day apart - no re-cache
</span><del>-        result = ical.deriveInstance(PyCalendarDateTime(2009, 1, 2, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)), newcomp=masterDerived)
</del><ins>+        result = ical.deriveInstance(DateTime(2009, 1, 2, 8, 0, 0, tzid=Timezone(utc=True)), newcomp=masterDerived)
</ins><span class="cx">         self.assertEqual(str(result), derived1)
</span><span class="cx"> 
</span><del>-        result = ical.deriveInstance(PyCalendarDateTime(2009, 2, 3, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)), newcomp=masterDerived)
</del><ins>+        result = ical.deriveInstance(DateTime(2009, 2, 3, 8, 0, 0, tzid=Timezone(utc=True)), newcomp=masterDerived)
</ins><span class="cx">         self.assertEqual(str(result), derived2)
</span><span class="cx"> 
</span><del>-        result = ical.deriveInstance(PyCalendarDateTime(2009, 3, 3, 9, 0, 0, tzid=PyCalendarTimezone(utc=True)), newcomp=masterDerived)
</del><ins>+        result = ical.deriveInstance(DateTime(2009, 3, 3, 9, 0, 0, tzid=Timezone(utc=True)), newcomp=masterDerived)
</ins><span class="cx">         self.assertEqual(result, None)
</span><span class="cx"> 
</span><span class="cx">         self.assertEqual(str(ical), event)
</span><span class="lines">@@ -4847,8 +4923,8 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (None, True),
</span><del>-                    (PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
</del><ins>+                    (DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 0, 0, 0, tzid=Timezone(utc=True)), False),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4866,9 +4942,9 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (None, True),
</span><del>-                    (PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 5, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
</del><ins>+                    (DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 5, 0, 0, 0, tzid=Timezone(utc=True)), False),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4886,10 +4962,10 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (None, True),
</span><del>-                    (PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
</del><ins>+                    (DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 1, 0, 0, tzid=Timezone(utc=True)), False),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4908,11 +4984,11 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (None, True),
</span><del>-                    (PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 2, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
</del><ins>+                    (DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 1, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 2, 0, 0, tzid=Timezone(utc=True)), False),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4932,12 +5008,12 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (None, True),
</span><del>-                    (PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 2, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
-                    (PyCalendarDateTime(2009, 10, 3, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
</del><ins>+                    (DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 1, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 2, 0, 0, tzid=Timezone(utc=True)), False),
+                    (DateTime(2009, 10, 3, 0, 0, 0, tzid=Timezone(utc=True)), False),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4960,11 +5036,11 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (None, True),
</span><del>-                    (PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2007, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
-                    (PyCalendarDateTime(2009, 10, 4, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
</del><ins>+                    (DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2007, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)), False),
+                    (DateTime(2009, 10, 4, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 1, 0, 0, tzid=Timezone(utc=True)), False),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -4989,12 +5065,12 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (None, True),
</span><del>-                    (PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2007, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2007, 11, 15, 2, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
-                    (PyCalendarDateTime(2009, 10, 4, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
</del><ins>+                    (DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2007, 11, 15, 1, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2007, 11, 15, 2, 0, 0, tzid=Timezone(utc=True)), False),
+                    (DateTime(2009, 10, 4, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 1, 0, 0, tzid=Timezone(utc=True)), False),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -5012,9 +5088,9 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (None, False),
</span><del>-                    (PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
-                    (PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
-                    (PyCalendarDateTime(2009, 10, 4, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
</del><ins>+                    (DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)), False),
+                    (DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)), True),
+                    (DateTime(2009, 10, 4, 0, 0, 0, tzid=Timezone(utc=True)), False),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -5046,7 +5122,7 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    (PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), True),
</del><ins>+                    (DateTime(2007, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)), True),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -5062,7 +5138,7 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    (PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
</del><ins>+                    (DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)), False),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -5084,7 +5160,7 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    (PyCalendarDateTime(2007, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)), False),
</del><ins>+                    (DateTime(2007, 11, 15, 0, 0, 0, tzid=Timezone(utc=True)), False),
</ins><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="cx">         )
</span><span class="lines">@@ -5396,12 +5472,12 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 14, 20, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 14, 21, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 14, 20, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 14, 21, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                     (
</span><del>-                        PyCalendarDateTime(2007, 11, 15, 21, 0, 0, tzid=PyCalendarTimezone(utc=True)),
-                        PyCalendarDateTime(2007, 11, 15, 22, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                        DateTime(2007, 11, 15, 21, 0, 0, tzid=Timezone(utc=True)),
+                        DateTime(2007, 11, 15, 22, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                     ),
</span><span class="cx">                 )
</span><span class="cx">             ),
</span><span class="lines">@@ -5409,7 +5485,7 @@
</span><span class="cx"> 
</span><span class="cx">         for description, original, fixed, results in data:
</span><span class="cx">             component = Component.fromString(original)
</span><del>-            instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances=False)
</del><ins>+            instances = component.expandTimeRanges(DateTime(2100, 1, 1), ignoreInvalidInstances=False)
</ins><span class="cx">             self.assertTrue(len(instances.instances) == len(results), &quot;%s: wrong number of instances&quot; % (description,))
</span><span class="cx">             periods = tuple([(instance.start, instance.end) for instance in sorted(instances.instances.values(), key=lambda x:x.start)])
</span><span class="cx">             self.assertEqual(periods, results)
</span><span class="lines">@@ -5696,7 +5772,7 @@
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 2, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 2, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, False,),
</span><span class="cx">                                 ),
</span><span class="lines">@@ -5741,7 +5817,7 @@
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 2, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 2, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, False,),
</span><span class="cx">                                     (&quot;user01&quot;, False,),
</span><span class="lines">@@ -5795,7 +5871,7 @@
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 2, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 2, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, False,),
</span><span class="cx">                                     (&quot;user01&quot;, False,),
</span><span class="lines">@@ -5841,19 +5917,19 @@
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 2, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 2, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, False,),
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 3, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 3, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, True,),
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 4, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 4, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, True,),
</span><span class="cx">                                 ),
</span><span class="lines">@@ -5916,21 +5992,21 @@
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 2, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 2, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, False,),
</span><span class="cx">                                     (&quot;user01&quot;, True,),
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 3, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 3, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, False,),
</span><span class="cx">                                     (&quot;user01&quot;, True,),
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 4, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 4, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, False,),
</span><span class="cx">                                     (&quot;user01&quot;, False,),
</span><span class="lines">@@ -6015,7 +6091,7 @@
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 2, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 2, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, False,),
</span><span class="cx">                                     (&quot;user01&quot;, True,),
</span><span class="lines">@@ -6023,7 +6099,7 @@
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 3, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 3, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, False,),
</span><span class="cx">                                     (&quot;user01&quot;, True,),
</span><span class="lines">@@ -6031,7 +6107,7 @@
</span><span class="cx">                                 ),
</span><span class="cx">                             ),
</span><span class="cx">                             (
</span><del>-                                PyCalendarDateTime(2008, 6, 4, 12, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                                DateTime(2008, 6, 4, 12, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                                 (
</span><span class="cx">                                     (&quot;&quot;, False,),
</span><span class="cx">                                     (&quot;user01&quot;, False,),
</span><span class="lines">@@ -7415,7 +7491,7 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">             ),
</span><span class="cx">         )
</span><del>-        cutoff = PyCalendarDateTime(2011, 11, 30, 0, 0, 0)
</del><ins>+        cutoff = DateTime(2011, 11, 30, 0, 0, 0)
</ins><span class="cx">         for _ignore_title, expected, body in data:
</span><span class="cx">             ical = Component.fromString(body)
</span><span class="cx">             self.assertEquals(expected, ical.hasInstancesAfter(cutoff))
</span><span class="lines">@@ -9437,7 +9513,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 2, 1, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 2, 1, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="cx"> PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
</span><span class="lines">@@ -9505,7 +9581,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 2, 1, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 2, 1, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="cx"> PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
</span><span class="lines">@@ -9577,7 +9653,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 2, 1, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 2, 1, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="cx"> PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
</span><span class="lines">@@ -9626,7 +9702,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 2, 1, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 2, 1, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="cx"> PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
</span><span class="lines">@@ -9676,7 +9752,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 31, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 1, 31, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="cx"> PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
</span><span class="lines">@@ -9725,7 +9801,7 @@
</span><span class="cx"> END:VEVENT
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 1, 31, 6, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 1, 31, 6, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="cx"> PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
</span><span class="lines">@@ -9795,7 +9871,7 @@
</span><span class="cx"> END:X-CALENDARSERVER-PERUSER
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 2, 1, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 2, 1, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="cx"> PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
</span><span class="lines">@@ -9944,7 +10020,7 @@
</span><span class="cx"> END:X-CALENDARSERVER-PERUSER
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><del>-                PyCalendarDateTime(2009, 2, 1, 8, 0, 0, tzid=PyCalendarTimezone(utc=True)),
</del><ins>+                DateTime(2009, 2, 1, 8, 0, 0, tzid=Timezone(utc=True)),
</ins><span class="cx">                 &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="cx"> PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_localizationpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_localization.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_localization.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_localization.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -20,7 +20,8 @@
</span><span class="cx"> from twistedcaldav.ical import Component
</span><span class="cx"> from twistedcaldav.test.util import TestCase
</span><span class="cx"> from twistedcaldav.config import ConfigDict
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from twistedcaldav.timezones import TimezoneCache
+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> import os
</span><span class="cx"> 
</span><span class="lines">@@ -52,6 +53,11 @@
</span><span class="cx"> 
</span><span class="cx"> class LocalizationTests(TestCase):
</span><span class="cx"> 
</span><ins>+    def setUp(self):
+        super(LocalizationTests, self).setUp()
+        TimezoneCache.create()
+
+
</ins><span class="cx">     def test_BasicStringLocalization(self):
</span><span class="cx"> 
</span><span class="cx">         with translationTo('pig', localeDir=localeDir):
</span><span class="lines">@@ -68,22 +74,22 @@
</span><span class="cx"> 
</span><span class="cx">         with translationTo('en', localeDir=localeDir) as t:
</span><span class="cx"> 
</span><del>-            self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 0, 0, 0)), &quot;12:00 AM&quot;)
-            self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 12, 0, 0)), &quot;12:00 PM&quot;)
-            self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 23, 59, 0)), &quot;11:59 PM&quot;)
-            self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 6, 5, 0)), &quot;6:05 AM&quot;)
-            self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 16, 5, 0)), &quot;4:05 PM&quot;)
</del><ins>+            self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 0, 0, 0)), &quot;12:00 AM&quot;)
+            self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 12, 0, 0)), &quot;12:00 PM&quot;)
+            self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 23, 59, 0)), &quot;11:59 PM&quot;)
+            self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 6, 5, 0)), &quot;6:05 AM&quot;)
+            self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 16, 5, 0)), &quot;4:05 PM&quot;)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_TimeFormatting24Hour(self):
</span><span class="cx"> 
</span><span class="cx">         with translationTo('pig', localeDir=localeDir) as t:
</span><span class="cx"> 
</span><del>-            self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 0, 0, 0)), &quot;00:00&quot;)
-            self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 12, 0, 0)), &quot;12:00&quot;)
-            self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 23, 59, 0)), &quot;23:59&quot;)
-            self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 6, 5, 0)), &quot;06:05&quot;)
-            self.assertEquals(t.dtTime(PyCalendarDateTime(2000, 1, 1, 16, 5, 0)), &quot;16:05&quot;)
</del><ins>+            self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 0, 0, 0)), &quot;00:00&quot;)
+            self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 12, 0, 0)), &quot;12:00&quot;)
+            self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 23, 59, 0)), &quot;23:59&quot;)
+            self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 6, 5, 0)), &quot;06:05&quot;)
+            self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 16, 5, 0)), &quot;16:05&quot;)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_CalendarFormatting(self):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_multigetpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_multiget.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_multiget.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_multiget.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,6 +16,7 @@
</span><span class="cx"> from twext.python.filepath import CachingFilePath as FilePath
</span><span class="cx"> from twext.web2 import responsecode
</span><span class="cx"> from twext.web2.dav.util import davXMLFromStream, joinURL
</span><ins>+from twext.web2.http_headers import Headers, MimeType
</ins><span class="cx"> from twext.web2.iweb import IResponse
</span><span class="cx"> from twext.web2.stream import MemoryStream
</span><span class="cx"> 
</span><span class="lines">@@ -268,7 +269,13 @@
</span><span class="cx"> 
</span><span class="cx">             if data:
</span><span class="cx">                 for filename, icaldata in data.iteritems():
</span><del>-                    request = SimpleStoreRequest(self, &quot;PUT&quot;, joinURL(calendar_uri, filename + &quot;.ics&quot;), authid=&quot;wsanchez&quot;)
</del><ins>+                    request = SimpleStoreRequest(
+                        self,
+                        &quot;PUT&quot;,
+                        joinURL(calendar_uri, filename + &quot;.ics&quot;),
+                        headers=Headers({&quot;content-type&quot;: MimeType.fromString(&quot;text/calendar&quot;)}),
+                        authid=&quot;wsanchez&quot;
+                    )
</ins><span class="cx">                     request.stream = MemoryStream(icaldata)
</span><span class="cx">                     yield self.send(request)
</span><span class="cx">             else:
</span><span class="lines">@@ -276,7 +283,13 @@
</span><span class="cx">                 for child in FilePath(self.holidays_dir).children():
</span><span class="cx">                     if os.path.splitext(child.basename())[1] != &quot;.ics&quot;:
</span><span class="cx">                         continue
</span><del>-                    request = SimpleStoreRequest(self, &quot;PUT&quot;, joinURL(calendar_uri, child.basename()), authid=&quot;wsanchez&quot;)
</del><ins>+                    request = SimpleStoreRequest(
+                        self,
+                        &quot;PUT&quot;,
+                        joinURL(calendar_uri, child.basename()),
+                        headers=Headers({&quot;content-type&quot;: MimeType.fromString(&quot;text/calendar&quot;)}),
+                        authid=&quot;wsanchez&quot;
+                    )
</ins><span class="cx">                     request.stream = MemoryStream(child.getContent())
</span><span class="cx">                     yield self.send(request)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_propspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_props.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_props.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_props.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -88,7 +88,7 @@
</span><span class="cx">                         self.fail(&quot;Expected CalDAV:supported-calendar-data element; but got none.&quot;)
</span><span class="cx"> 
</span><span class="cx">                     for calendar in supported_calendar.children:
</span><del>-                        if calendar.content_type != &quot;text/calendar&quot;:
</del><ins>+                        if calendar.content_type not in (&quot;text/calendar&quot;, &quot;application/calendar+json&quot;):
</ins><span class="cx">                             self.fail(&quot;Expected a text/calendar calendar-data type restriction&quot;)
</span><span class="cx">                         if calendar.version != &quot;2.0&quot;:
</span><span class="cx">                             self.fail(&quot;Expected a version 2.0 calendar-data restriction&quot;)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_timezonespy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_timezones.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_timezones.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_timezones.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -19,8 +19,8 @@
</span><span class="cx"> from twistedcaldav.ical import Component
</span><span class="cx"> from twistedcaldav.timezones import TimezoneCache, TimezoneException
</span><span class="cx"> from twistedcaldav.timezones import readTZ, listTZs
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> import os
</span><span class="cx"> import threading
</span><span class="lines">@@ -49,7 +49,7 @@
</span><span class="cx">         if calendar.name() != &quot;VCALENDAR&quot;:
</span><span class="cx">             self.fail(&quot;Calendar is not a VCALENDAR&quot;)
</span><span class="cx"> 
</span><del>-        instances = calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
</del><ins>+        instances = calendar.expandTimeRanges(DateTime(2100, 1, 1))
</ins><span class="cx">         for key in instances:
</span><span class="cx">             instance = instances[key]
</span><span class="cx">             start = instance.start
</span><span class="lines">@@ -69,8 +69,8 @@
</span><span class="cx"> 
</span><span class="cx">         self.doTest(
</span><span class="cx">             &quot;TruncatedApr01.ics&quot;,
</span><del>-            PyCalendarDateTime(2007, 04, 01, 16, 0, 0, PyCalendarTimezone(utc=True)),
-            PyCalendarDateTime(2007, 04, 01, 17, 0, 0, PyCalendarTimezone(utc=True))
</del><ins>+            DateTime(2007, 04, 01, 16, 0, 0, Timezone(utc=True)),
+            DateTime(2007, 04, 01, 17, 0, 0, Timezone(utc=True))
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -84,8 +84,8 @@
</span><span class="cx"> 
</span><span class="cx">         self.doTest(
</span><span class="cx">             &quot;TruncatedDec10.ics&quot;,
</span><del>-            PyCalendarDateTime(2007, 12, 10, 17, 0, 0, PyCalendarTimezone(utc=True)),
-            PyCalendarDateTime(2007, 12, 10, 18, 0, 0, PyCalendarTimezone(utc=True))
</del><ins>+            DateTime(2007, 12, 10, 17, 0, 0, Timezone(utc=True)),
+            DateTime(2007, 12, 10, 18, 0, 0, Timezone(utc=True))
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -99,13 +99,13 @@
</span><span class="cx"> 
</span><span class="cx">         self.doTest(
</span><span class="cx">             &quot;TruncatedApr01.ics&quot;,
</span><del>-            PyCalendarDateTime(2007, 04, 01, 16, 0, 0, PyCalendarTimezone(utc=True)),
-            PyCalendarDateTime(2007, 04, 01, 17, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+            DateTime(2007, 04, 01, 16, 0, 0, Timezone(utc=True)),
+            DateTime(2007, 04, 01, 17, 0, 0, Timezone(utc=True)),
</ins><span class="cx">         )
</span><span class="cx">         self.doTest(
</span><span class="cx">             &quot;TruncatedDec10.ics&quot;,
</span><del>-            PyCalendarDateTime(2007, 12, 10, 17, 0, 0, PyCalendarTimezone(utc=True)),
-            PyCalendarDateTime(2007, 12, 10, 18, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+            DateTime(2007, 12, 10, 17, 0, 0, Timezone(utc=True)),
+            DateTime(2007, 12, 10, 18, 0, 0, Timezone(utc=True)),
</ins><span class="cx">             testEqual=False
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -119,13 +119,13 @@
</span><span class="cx"> 
</span><span class="cx">         self.doTest(
</span><span class="cx">             &quot;TruncatedApr01.ics&quot;,
</span><del>-            PyCalendarDateTime(2007, 04, 01, 16, 0, 0, PyCalendarTimezone(utc=True)),
-            PyCalendarDateTime(2007, 04, 01, 17, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+            DateTime(2007, 04, 01, 16, 0, 0, Timezone(utc=True)),
+            DateTime(2007, 04, 01, 17, 0, 0, Timezone(utc=True)),
</ins><span class="cx">         )
</span><span class="cx">         self.doTest(
</span><span class="cx">             &quot;TruncatedDec10.ics&quot;,
</span><del>-            PyCalendarDateTime(2007, 12, 10, 17, 0, 0, PyCalendarTimezone(utc=True)),
-            PyCalendarDateTime(2007, 12, 10, 18, 0, 0, PyCalendarTimezone(utc=True)),
</del><ins>+            DateTime(2007, 12, 10, 17, 0, 0, Timezone(utc=True)),
+            DateTime(2007, 12, 10, 18, 0, 0, Timezone(utc=True)),
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -139,13 +139,13 @@
</span><span class="cx"> 
</span><span class="cx">         self.doTest(
</span><span class="cx">             &quot;TruncatedDec10.ics&quot;,
</span><del>-            PyCalendarDateTime(2007, 12, 10, 17, 0, 0, PyCalendarTimezone(utc=True)),
-            PyCalendarDateTime(2007, 12, 10, 18, 0, 0, PyCalendarTimezone(utc=True))
</del><ins>+            DateTime(2007, 12, 10, 17, 0, 0, Timezone(utc=True)),
+            DateTime(2007, 12, 10, 18, 0, 0, Timezone(utc=True))
</ins><span class="cx">         )
</span><span class="cx">         self.doTest(
</span><span class="cx">             &quot;TruncatedApr01.ics&quot;,
</span><del>-            PyCalendarDateTime(2007, 04, 01, 16, 0, 0, PyCalendarTimezone(utc=True)),
-            PyCalendarDateTime(2007, 04, 01, 17, 0, 0, PyCalendarTimezone(utc=True))
</del><ins>+            DateTime(2007, 04, 01, 16, 0, 0, Timezone(utc=True)),
+            DateTime(2007, 04, 01, 17, 0, 0, Timezone(utc=True))
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -201,13 +201,13 @@
</span><span class="cx">         calendar = Component.fromString(data)
</span><span class="cx">         if calendar.name() != &quot;VCALENDAR&quot;:
</span><span class="cx">             self.fail(&quot;Calendar is not a VCALENDAR&quot;)
</span><del>-        instances = calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
</del><ins>+        instances = calendar.expandTimeRanges(DateTime(2100, 1, 1))
</ins><span class="cx">         for key in instances:
</span><span class="cx">             instance = instances[key]
</span><span class="cx">             start = instance.start
</span><span class="cx">             end = instance.end
</span><del>-            self.assertEqual(start, PyCalendarDateTime(2007, 12, 25, 05, 0, 0, PyCalendarTimezone(utc=True)))
-            self.assertEqual(end, PyCalendarDateTime(2007, 12, 25, 06, 0, 0, PyCalendarTimezone(utc=True)))
</del><ins>+            self.assertEqual(start, DateTime(2007, 12, 25, 05, 0, 0, Timezone(utc=True)))
+            self.assertEqual(end, DateTime(2007, 12, 25, 06, 0, 0, Timezone(utc=True)))
</ins><span class="cx">             break
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_upgradepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_upgrade.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_upgrade.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_upgrade.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1675,8 +1675,8 @@
</span><span class="cx"> ATTENDEE;CN=Double 'quotey' Quotes;CUTYPE=INDIVIDUAL;EMAIL=doublequotes@ex
</span><span class="cx">  ample.com;PARTSTAT=ACCEPTED:urn:uuid:8E04787E-336D-41ED-A70B-D233AD0DCE6F
</span><span class="cx"> ATTENDEE;CN=Cyrus Daboo;CUTYPE=INDIVIDUAL;EMAIL=cdaboo@example.com;PARTSTA
</span><del>- T=ACCEPTED;ROLE=REQ-PARTICIPANT:urn:uuid:5A985493-EE2C-4665-94CF-4DFEA3A89
- 500
</del><ins>+ T=ACCEPTED;ROLE=REQ-PARTICIPANT:urn:uuid:5A985493-EE2C-4665-94CF-4DFEA3A8
+ 9500
</ins><span class="cx"> CREATED:20090203T181910Z
</span><span class="cx"> DESCRIPTION:This has &quot; Bad Quotes &quot; in it
</span><span class="cx"> DTSTAMP:20090203T181924Z
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtesttest_utilpyfromrev12016CalendarServertrunktwistedcaldavtesttest_utilpy"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_util.py (from rev 12016, CalendarServer/trunk/twistedcaldav/test/test_util.py) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_util.py                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/test/test_util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,144 @@
</span><ins>+##
+# Copyright (c) 2005-2013 Apple Inc. 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 twext.web2.http_headers import Headers
+
+import twistedcaldav.test.util
+from twistedcaldav.util import bestAcceptType
+
+class AcceptType(twistedcaldav.test.util.TestCase):
+    &quot;&quot;&quot;
+    L{bestAcceptType} tests
+    &quot;&quot;&quot;
+    def test_bestAcceptType(self):
+
+        data = (
+            (
+                &quot;#1.1&quot;,
+                (&quot;Accept&quot;, &quot;text/plain&quot;),
+                [&quot;text/plain&quot;],
+                &quot;text/plain&quot;,
+            ),
+            (
+                &quot;#1.2&quot;,
+                (&quot;Accept&quot;, &quot;text/plain&quot;),
+                [&quot;text/calendar&quot;],
+                None,
+            ),
+            (
+                &quot;#1.3&quot;,
+                (&quot;Accept&quot;, &quot;text/*&quot;),
+                [&quot;text/plain&quot;],
+                &quot;text/plain&quot;,
+            ),
+            (
+                &quot;#1.4&quot;,
+                (&quot;Accept&quot;, &quot;*/*&quot;),
+                [&quot;text/plain&quot;],
+                &quot;text/plain&quot;,
+            ),
+            (
+                &quot;#2.1&quot;,
+                (&quot;Accept&quot;, &quot;text/plain&quot;),
+                [&quot;text/plain&quot;, &quot;application/text&quot;, ],
+                &quot;text/plain&quot;,
+            ),
+            (
+                &quot;#2.2&quot;,
+                (&quot;Accept&quot;, &quot;text/plain&quot;),
+                [&quot;text/calendar&quot;, &quot;application/text&quot;, ],
+                None,
+            ),
+            (
+                &quot;#2.3&quot;,
+                (&quot;Accept&quot;, &quot;text/*&quot;),
+                [&quot;text/plain&quot;, &quot;application/text&quot;, ],
+                &quot;text/plain&quot;,
+            ),
+            (
+                &quot;#2.4&quot;,
+                (&quot;Accept&quot;, &quot;*/*&quot;),
+                [&quot;text/plain&quot;, &quot;application/text&quot;, ],
+                &quot;text/plain&quot;,
+            ),
+            (
+                &quot;#2.5&quot;,
+                (&quot;Accept&quot;, &quot;application/text&quot;),
+                [&quot;text/plain&quot;, &quot;application/text&quot;, ],
+                &quot;application/text&quot;,
+            ),
+            (
+                &quot;#2.6&quot;,
+                (&quot;Accept&quot;, &quot;application/*&quot;),
+                [&quot;text/plain&quot;, &quot;application/text&quot;, ],
+                &quot;application/text&quot;,
+            ),
+            (
+                &quot;#3.1&quot;,
+                (&quot;Accept&quot;, &quot;text/plain;q=0.5, application/text;q=0.3&quot;),
+                [&quot;text/plain&quot;, &quot;application/text&quot;, ],
+                &quot;text/plain&quot;,
+            ),
+            (
+                &quot;#3.2&quot;,
+                (&quot;Accept&quot;, &quot;text/plain;q=0.5, application/text;q=0.3&quot;),
+                [&quot;text/calendar&quot;, &quot;application/calendar&quot;, ],
+                None,
+            ),
+            (
+                &quot;#3.3&quot;,
+                (&quot;Accept&quot;, &quot;text/plain;q=0.5, application/text;q=0.3&quot;),
+                [&quot;text/plain&quot;, &quot;application/text&quot;, ],
+                &quot;text/plain&quot;,
+            ),
+            (
+                &quot;#3.4&quot;,
+                (&quot;Accept&quot;, &quot;text/plain;q=0.5, application/text;q=0.3&quot;),
+                [&quot;text/plain&quot;, &quot;application/text&quot;, ],
+                &quot;text/plain&quot;,
+            ),
+            (
+                &quot;#3.5&quot;,
+                (&quot;Accept&quot;, &quot;text/plain;q=0.3, application/text;q=0.5&quot;),
+                [&quot;text/plain&quot;, &quot;application/text&quot;, ],
+                &quot;application/text&quot;,
+            ),
+            (
+                &quot;#3.6&quot;,
+                (&quot;Accept&quot;, &quot;text/plain;q=0.5, application/*;q=0.3&quot;),
+                [&quot;text/plain&quot;, &quot;application/text&quot;, ],
+                &quot;text/plain&quot;,
+            ),
+            (
+                &quot;#4.1&quot;,
+                (&quot;Accept&quot;, &quot;text/plain;q=0.5, application/text;q=0.2, text/*;q=0.3&quot;),
+                [&quot;text/calendar&quot;, &quot;application/text&quot;, ],
+                &quot;text/calendar&quot;,
+            ),
+            (
+                &quot;#5.1&quot;,
+                None,
+                [&quot;text/calendar&quot;, &quot;application/text&quot;, ],
+                &quot;text/calendar&quot;,
+            ),
+        )
+
+        for title, hdr, allowedTypes, result in data:
+            hdrs = Headers()
+            if hdr:
+                hdrs.addRawHeader(*hdr)
+            check = bestAcceptType(hdrs.getHeader(&quot;accept&quot;), allowedTypes)
+            self.assertEqual(check, result, msg=&quot;Failed %s&quot; % (title,))
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtimezonespy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezones.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezones.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezones.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -22,7 +22,7 @@
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> 
</span><del>-from pycalendar.timezonedb import PyCalendarTimezoneDatabase
</del><ins>+from pycalendar.timezonedb import TimezoneDatabase
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -95,7 +95,7 @@
</span><span class="cx">             TimezoneCache.dirName = None
</span><span class="cx">             TimezoneCache.validatePath()
</span><span class="cx">         TimezoneCache.version = TimezoneCache.getTZVersion(TimezoneCache.getDBPath())
</span><del>-        PyCalendarTimezoneDatabase.createTimezoneDatabase(TimezoneCache.getDBPath())
</del><ins>+        TimezoneDatabase.createTimezoneDatabase(TimezoneCache.getDBPath())
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="lines">@@ -171,7 +171,7 @@
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><span class="cx">     def clear():
</span><del>-        PyCalendarTimezoneDatabase.clearTimezoneDatabase()
</del><ins>+        TimezoneDatabase.clearTimezoneDatabase()
</ins><span class="cx"> 
</span><span class="cx"> # zoneinfo never changes in a running instance so cache all this data as we use it
</span><span class="cx"> cachedTZs = {}
</span><span class="lines">@@ -207,7 +207,7 @@
</span><span class="cx"> 
</span><span class="cx">     if tzid not in cachedVTZs:
</span><span class="cx"> 
</span><del>-        tzcal = PyCalendarTimezoneDatabase.getTimezoneInCalendar(tzid)
</del><ins>+        tzcal = TimezoneDatabase.getTimezoneInCalendar(tzid)
</ins><span class="cx">         if tzcal:
</span><span class="cx">             cachedVTZs[tzid] = tzcal
</span><span class="cx">         else:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtimezoneservicepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezoneservice.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezoneservice.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezoneservice.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx"> from twistedcaldav.timezones import listTZs
</span><span class="cx"> from twistedcaldav.timezones import readTZ
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> class TimezoneServiceResource (ReadOnlyNoCopyResourceMixIn, DAVResourceWithoutChildrenMixin, DAVResource):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -66,20 +66,25 @@
</span><span class="cx">         self.parent = parent
</span><span class="cx">         self.cache = {}
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def deadProperties(self):
</span><span class="cx">         if not hasattr(self, &quot;_dead_properties&quot;):
</span><span class="cx">             self._dead_properties = NonePropertyStore(self)
</span><span class="cx">         return self._dead_properties
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def etag(self):
</span><span class="cx">         return succeed(None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def checkPreconditions(self, request):
</span><span class="cx">         return None
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def checkPrivileges(self, request, privileges, recurse=False, principal=None, inherited_aces=None):
</span><span class="cx">         return succeed(None)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def defaultAccessControlList(self):
</span><span class="cx">         return davxml.ACL(
</span><span class="cx">             # DAV:Read for all principals (includes anonymous)
</span><span class="lines">@@ -92,21 +97,27 @@
</span><span class="cx">             ),
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def contentType(self):
</span><span class="cx">         return MimeType.fromString(&quot;text/xml&quot;)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def resourceType(self):
</span><span class="cx">         return davxml.ResourceType.timezones
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def isCollection(self):
</span><span class="cx">         return False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def isCalendarCollection(self):
</span><span class="cx">         return False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def isPseudoCalendarCollection(self):
</span><span class="cx">         return False
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def render(self, request):
</span><span class="cx">         output = &quot;&quot;&quot;&lt;html&gt;
</span><span class="cx"> &lt;head&gt;
</span><span class="lines">@@ -127,10 +138,11 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         The timezone service POST method.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         # GET and POST do the same thing
</span><span class="cx">         return self.http_POST(request)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def http_POST(self, request):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         The timezone service POST method.
</span><span class="lines">@@ -138,11 +150,11 @@
</span><span class="cx"> 
</span><span class="cx">         # Check authentication and access controls
</span><span class="cx">         def _gotResult(_):
</span><del>-            
</del><ins>+
</ins><span class="cx">             if not request.args:
</span><span class="cx">                 # Do normal GET behavior
</span><span class="cx">                 return self.render(request)
</span><del>-    
</del><ins>+
</ins><span class="cx">             method = request.args.get(&quot;method&quot;, (&quot;&quot;,))
</span><span class="cx">             if len(method) != 1:
</span><span class="cx">                 raise HTTPError(ErrorResponse(
</span><span class="lines">@@ -151,41 +163,43 @@
</span><span class="cx">                     &quot;Invalid method query parameter&quot;,
</span><span class="cx">                 ))
</span><span class="cx">             method = method[0]
</span><del>-                
</del><ins>+
</ins><span class="cx">             action = {
</span><span class="cx">                 &quot;list&quot;   : self.doPOSTList,
</span><span class="cx">                 &quot;get&quot;    : self.doPOSTGet,
</span><span class="cx">                 &quot;expand&quot; : self.doPOSTExpand,
</span><span class="cx">             }.get(method, None)
</span><del>-            
</del><ins>+
</ins><span class="cx">             if action is None:
</span><span class="cx">                 raise HTTPError(ErrorResponse(
</span><span class="cx">                     responsecode.BAD_REQUEST,
</span><span class="cx">                     (calendarserver_namespace, &quot;supported-method&quot;),
</span><span class="cx">                     &quot;Unknown method query parameter&quot;,
</span><span class="cx">                 ))
</span><del>-    
</del><ins>+
</ins><span class="cx">             return action(request)
</span><del>-            
</del><ins>+
</ins><span class="cx">         d = self.authorize(request, (davxml.Read(),))
</span><span class="cx">         d.addCallback(_gotResult)
</span><span class="cx">         return d
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def doPOSTList(self, request):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Return a list of all timezones known to the server.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         tzids = listTZs()
</span><span class="cx">         tzids.sort()
</span><span class="cx">         result = customxml.TZIDs(*[customxml.TZID(tzid) for tzid in tzids])
</span><span class="cx">         return XMLResponse(responsecode.OK, result)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def doPOSTGet(self, request):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Return the specified timezone data.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        
</del><ins>+
</ins><span class="cx">         tzid = request.args.get(&quot;tzid&quot;, ())
</span><span class="cx">         if len(tzid) != 1:
</span><span class="cx">             raise HTTPError(ErrorResponse(
</span><span class="lines">@@ -209,6 +223,7 @@
</span><span class="cx">         response.headers.setHeader(&quot;content-type&quot;, MimeType.fromString(&quot;text/calendar; charset=utf-8&quot;))
</span><span class="cx">         return response
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def doPOSTExpand(self, request):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Expand a timezone within specified start/end dates.
</span><span class="lines">@@ -235,7 +250,7 @@
</span><span class="cx">             start = request.args.get(&quot;start&quot;, ())
</span><span class="cx">             if len(start) != 1:
</span><span class="cx">                 raise ValueError()
</span><del>-            start = PyCalendarDateTime.parseText(start[0])
</del><ins>+            start = DateTime.parseText(start[0])
</ins><span class="cx">         except ValueError:
</span><span class="cx">             raise HTTPError(ErrorResponse(
</span><span class="cx">                 responsecode.BAD_REQUEST,
</span><span class="lines">@@ -247,7 +262,7 @@
</span><span class="cx">             end = request.args.get(&quot;end&quot;, ())
</span><span class="cx">             if len(end) != 1:
</span><span class="cx">                 raise ValueError()
</span><del>-            end = PyCalendarDateTime.parseText(end[0])
</del><ins>+            end = DateTime.parseText(end[0])
</ins><span class="cx">             if end &lt;= start:
</span><span class="cx">                 raise ValueError()
</span><span class="cx">         except ValueError:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavtimezonestdservicepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezonestdservice.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezonestdservice.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/timezonestdservice.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -49,9 +49,9 @@
</span><span class="cx">     addVTZ
</span><span class="cx"> from twistedcaldav.xmlutil import addSubElement
</span><span class="cx"> 
</span><del>-from pycalendar.calendar import PyCalendar
-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.exceptions import PyCalendarInvalidData
</del><ins>+from pycalendar.icalendar.calendar import Calendar
+from pycalendar.datetime import DateTime
+from pycalendar.exceptions import InvalidData
</ins><span class="cx"> 
</span><span class="cx"> import hashlib
</span><span class="cx"> import itertools
</span><span class="lines">@@ -89,7 +89,13 @@
</span><span class="cx">         else:
</span><span class="cx">             raise ValueError(&quot;Invalid TimezoneService mode: %s&quot; % (config.TimezoneService.Mode,))
</span><span class="cx"> 
</span><ins>+        self.formats = []
+        self.formats.append(&quot;text/calendar&quot;)
+        self.formats.append(&quot;text/plain&quot;)
+        if config.EnableJSONData:
+            self.formats.append(&quot;application/calendar+json&quot;)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def _initPrimaryService(self):
</span><span class="cx">         tzpath = TimezoneCache.getDBPath()
</span><span class="cx">         xmlfile = os.path.join(tzpath, &quot;timezones.xml&quot;)
</span><span class="lines">@@ -268,7 +274,7 @@
</span><span class="cx">                 {
</span><span class="cx">                     &quot;name&quot;: &quot;get&quot;,
</span><span class="cx">                     &quot;parameters&quot;: [
</span><del>-                        {&quot;name&quot;: &quot;format&quot;, &quot;required&quot;: False, &quot;multi&quot;: False, &quot;values&quot;: [&quot;text/calendar&quot;, &quot;text/plain&quot;, ], },
</del><ins>+                        {&quot;name&quot;: &quot;format&quot;, &quot;required&quot;: False, &quot;multi&quot;: False, &quot;values&quot;: self.formats, },
</ins><span class="cx">                         {&quot;name&quot;: &quot;tzid&quot;, &quot;required&quot;: True, &quot;multi&quot;: False, },
</span><span class="cx">                     ],
</span><span class="cx">                 },
</span><span class="lines">@@ -303,7 +309,7 @@
</span><span class="cx">             # Validate a date-time stamp
</span><span class="cx">             changedsince = changedsince[0]
</span><span class="cx">             try:
</span><del>-                dt = PyCalendarDateTime.parseText(changedsince)
</del><ins>+                dt = DateTime.parseText(changedsince)
</ins><span class="cx">             except ValueError:
</span><span class="cx">                 raise HTTPError(JSONResponse(
</span><span class="cx">                     responsecode.BAD_REQUEST,
</span><span class="lines">@@ -348,7 +354,7 @@
</span><span class="cx">             ))
</span><span class="cx"> 
</span><span class="cx">         format = request.args.get(&quot;format&quot;, (&quot;text/calendar&quot;,))
</span><del>-        if len(format) != 1 or format[0] not in (&quot;text/calendar&quot;, &quot;text/plain&quot;,):
</del><ins>+        if len(format) != 1 or format[0] not in self.formats:
</ins><span class="cx">             raise HTTPError(JSONResponse(
</span><span class="cx">                 responsecode.BAD_REQUEST,
</span><span class="cx">                 {
</span><span class="lines">@@ -368,7 +374,7 @@
</span><span class="cx">                 }
</span><span class="cx">             ))
</span><span class="cx"> 
</span><del>-        tzdata = calendar.getText()
</del><ins>+        tzdata = calendar.getText(format=format if format != &quot;text/plain&quot; else None)
</ins><span class="cx"> 
</span><span class="cx">         response = Response()
</span><span class="cx">         response.stream = MemoryStream(tzdata)
</span><span class="lines">@@ -396,9 +402,9 @@
</span><span class="cx">             if len(start) &gt; 1:
</span><span class="cx">                 raise ValueError()
</span><span class="cx">             elif len(start) == 1:
</span><del>-                start = PyCalendarDateTime.parseText(start[0])
</del><ins>+                start = DateTime.parseText(start[0])
</ins><span class="cx">             else:
</span><del>-                start = PyCalendarDateTime.getToday()
</del><ins>+                start = DateTime.getToday()
</ins><span class="cx">                 start.setDay(1)
</span><span class="cx">                 start.setMonth(1)
</span><span class="cx">         except ValueError:
</span><span class="lines">@@ -415,9 +421,9 @@
</span><span class="cx">             if len(end) &gt; 1:
</span><span class="cx">                 raise ValueError()
</span><span class="cx">             elif len(end) == 1:
</span><del>-                end = PyCalendarDateTime.parseText(end[0])
</del><ins>+                end = DateTime.parseText(end[0])
</ins><span class="cx">             else:
</span><del>-                end = PyCalendarDateTime.getToday()
</del><ins>+                end = DateTime.getToday()
</ins><span class="cx">                 end.setDay(1)
</span><span class="cx">                 end.setMonth(1)
</span><span class="cx">                 end.offsetYear(10)
</span><span class="lines">@@ -558,7 +564,7 @@
</span><span class="cx">         Generate a PyCalendar containing the requested timezone.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         # We will just use our existing TimezoneCache here
</span><del>-        calendar = PyCalendar()
</del><ins>+        calendar = Calendar()
</ins><span class="cx">         try:
</span><span class="cx">             vtz = readVTZ(tzid)
</span><span class="cx">             calendar.addComponent(vtz.getComponents()[0].duplicate())
</span><span class="lines">@@ -618,7 +624,7 @@
</span><span class="cx">         Create a new DB xml file from scratch by scanning zoneinfo.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        self.dtstamp = PyCalendarDateTime.getNowUTC().getXMLText()
</del><ins>+        self.dtstamp = DateTime.getNowUTC().getXMLText()
</ins><span class="cx">         self._scanTZs(&quot;&quot;)
</span><span class="cx">         self._dumpTZs()
</span><span class="cx"> 
</span><span class="lines">@@ -672,7 +678,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Update existing DB info by comparing md5's.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        self.dtstamp = PyCalendarDateTime.getNowUTC().getXMLText()
</del><ins>+        self.dtstamp = DateTime.getNowUTC().getXMLText()
</ins><span class="cx">         self.changeCount = 0
</span><span class="cx">         self.changed = set()
</span><span class="cx">         self._scanTZs(&quot;&quot;, checkIfChanged=True)
</span><span class="lines">@@ -847,8 +853,8 @@
</span><span class="cx"> 
</span><span class="cx">         ical = response.data
</span><span class="cx">         try:
</span><del>-            calendar = PyCalendar.parseText(ical)
-        except PyCalendarInvalidData:
</del><ins>+            calendar = Calendar.parseText(ical)
+        except InvalidData:
</ins><span class="cx">             log.error(&quot;Invalid calendar data for tzid: %s&quot; % (tzinfo.tzid,))
</span><span class="cx">             returnValue(None)
</span><span class="cx">         ical = calendar.getText()
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavupgradepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/upgrade.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/upgrade.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/upgrade.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1065,7 +1065,6 @@
</span><span class="cx">             # Migrate mail tokens from sqlite to store
</span><span class="cx">             yield migrateTokensToStore(self.config.DataRoot, self.store)
</span><span class="cx"> 
</span><del>-            
</del><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def processInboxItems(self):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/util.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/util.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -517,3 +517,52 @@
</span><span class="cx">         cuas = principal.record.calendarUserAddresses
</span><span class="cx"> 
</span><span class="cx">         return (fullName, rec.guid, cuas)
</span><ins>+
+
+
+def bestAcceptType(accepts, allowedTypes):
+    &quot;&quot;&quot;
+    Given a set of Accept headers and the set of types the server can return, determine the best choice
+    of format to return to the client.
+
+    @param accepts: parsed accept headers
+    @type accepts: C{dict}
+    @param allowedTypes: list of allowed types in server preferred order
+    @type allowedTypes: C{list}
+    &quot;&quot;&quot;
+
+    # If no Accept present just use the first allowed type - the server's preference
+    if not accepts:
+        return allowedTypes[0]
+
+    # Get mapping for ordered top-level types for use in subtype wildcard match
+    toptypes = {}
+    for allowed in allowedTypes:
+        mediaType = allowed.split(&quot;/&quot;)[0]
+        if mediaType not in toptypes:
+            toptypes[mediaType] = allowed
+
+    result = None
+    result_qval = 0.0
+    for content_type, qval in accepts.items():
+        # Exact match
+        ctype = &quot;%s/%s&quot; % (content_type.mediaType, content_type.mediaSubtype,)
+        if ctype in allowedTypes:
+            if qval &gt; result_qval:
+                result = ctype
+                result_qval = qval
+
+        # Subtype wildcard match
+        elif content_type.mediaType != &quot;*&quot; and content_type.mediaSubtype == &quot;*&quot;:
+            if content_type.mediaType in toptypes:
+                if qval &gt; result_qval:
+                    result = toptypes[content_type.mediaType]
+                    result_qval = qval
+
+        # Full wildcard match
+        elif content_type.mediaType == &quot;*&quot; and content_type.mediaSubtype == &quot;*&quot;:
+            if qval &gt; result_qval:
+                result = allowedTypes[0]
+                result_qval = qval
+
+    return result
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavvcardpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/vcard.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/vcard.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/vcard.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -31,9 +31,11 @@
</span><span class="cx"> from twext.web2.stream import IStream
</span><span class="cx"> from twext.web2.dav.util import allDataFromStream
</span><span class="cx"> 
</span><del>-from pycalendar.attribute import PyCalendarAttribute
-from pycalendar.componentbase import PyCalendarComponentBase
-from pycalendar.exceptions import PyCalendarError
</del><ins>+from twistedcaldav.config import config
+
+from pycalendar.parameter import Parameter
+from pycalendar.componentbase import ComponentBase
+from pycalendar.exceptions import ErrorBase
</ins><span class="cx"> from pycalendar.vcard.card import Card
</span><span class="cx"> from pycalendar.vcard.property import Property as pyProperty
</span><span class="cx"> 
</span><span class="lines">@@ -44,6 +46,8 @@
</span><span class="cx"> class InvalidVCardDataError(ValueError):
</span><span class="cx">     pass
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class Property (object):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     vCard Property
</span><span class="lines">@@ -73,31 +77,55 @@
</span><span class="cx">             for attrname, attrvalue in params.items():
</span><span class="cx">                 if isinstance(attrvalue, unicode):
</span><span class="cx">                     attrvalue = attrvalue.encode(&quot;utf-8&quot;)
</span><del>-                self._pycard.addAttribute(PyCalendarAttribute(attrname, attrvalue))
</del><ins>+                self._pycard.addParameter(Parameter(attrname, attrvalue))
</ins><span class="cx"> 
</span><del>-    def __str__ (self): return str(self._pycard)
-    def __repr__(self): return &quot;&lt;%s: %r: %r&gt;&quot; % (self.__class__.__name__, self.name(), self.value())
</del><span class="cx"> 
</span><del>-    def __hash__(self): return hash(str(self))
</del><ins>+    def __str__(self):
+        return str(self._pycard)
</ins><span class="cx"> 
</span><del>-    def __ne__(self, other): return not self.__eq__(other)
</del><ins>+
+    def __repr__(self):
+        return &quot;&lt;%s: %r: %r&gt;&quot; % (self.__class__.__name__, self.name(), self.value())
+
+
+    def __hash__(self):
+        return hash(str(self))
+
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+
</ins><span class="cx">     def __eq__(self, other):
</span><del>-        if not isinstance(other, Property): return False
</del><ins>+        if not isinstance(other, Property):
+            return False
</ins><span class="cx">         return self._pycard == other._pycard
</span><span class="cx"> 
</span><del>-    def __gt__(self, other): return not (self.__eq__(other) or self.__lt__(other))
</del><ins>+
+    def __gt__(self, other):
+        return not (self.__eq__(other) or self.__lt__(other))
+
+
</ins><span class="cx">     def __lt__(self, other):
</span><span class="cx">         my_name = self.name()
</span><span class="cx">         other_name = other.name()
</span><span class="cx"> 
</span><del>-        if my_name &lt; other_name: return True
-        if my_name &gt; other_name: return False
</del><ins>+        if my_name &lt; other_name:
+            return True
+        if my_name &gt; other_name:
+            return False
</ins><span class="cx"> 
</span><span class="cx">         return self.value() &lt; other.value()
</span><span class="cx"> 
</span><del>-    def __ge__(self, other): return self.__eq__(other) or self.__gt__(other)
-    def __le__(self, other): return self.__eq__(other) or self.__lt__(other)
</del><span class="cx"> 
</span><ins>+    def __ge__(self, other):
+        return self.__eq__(other) or self.__gt__(other)
+
+
+    def __le__(self, other):
+        return self.__eq__(other) or self.__lt__(other)
+
+
</ins><span class="cx">     def duplicate(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Duplicate this object and all its contents.
</span><span class="lines">@@ -105,35 +133,45 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return Property(None, None, params=None, pycard=self._pycard.duplicate())
</span><span class="cx"> 
</span><del>-    def name  (self): return self._pycard.getName()
</del><span class="cx"> 
</span><del>-    def value (self): return self._pycard.getValue().getValue()
</del><ins>+    def name(self):
+        return self._pycard.getName()
</ins><span class="cx"> 
</span><del>-    def strvalue (self): return str(self._pycard.getValue())
</del><span class="cx"> 
</span><ins>+    def value(self):
+        return self._pycard.getValue().getValue()
+
+
+    def strvalue(self):
+        return str(self._pycard.getValue())
+
+
</ins><span class="cx">     def setValue(self, value):
</span><span class="cx">         self._pycard.setValue(value)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def parameterNames(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Returns a set containing parameter names for this property.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         result = set()
</span><del>-        for pyattrlist in self._pycard.getAttributes().values():
</del><ins>+        for pyattrlist in self._pycard.getParameters().values():
</ins><span class="cx">             for pyattr in pyattrlist:
</span><span class="cx">                 result.add(pyattr.getName())
</span><span class="cx">         return result
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def parameterValue(self, name, default=None):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Returns a single value for the given parameter.  Raises
</span><span class="cx">         InvalidICalendarDataError if the parameter has more than one value.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         try:
</span><del>-            return self._pycard.getAttributeValue(name)
</del><ins>+            return self._pycard.getParameterValue(name)
</ins><span class="cx">         except KeyError:
</span><span class="cx">             return default
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def parameterValues(self, name):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Returns a single value for the given parameter.  Raises
</span><span class="lines">@@ -141,7 +179,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         results = []
</span><span class="cx">         try:
</span><del>-            attrs = self._pycard.getAttributes()[name.upper()]
</del><ins>+            attrs = self._pycard.getParameters()[name.upper()]
</ins><span class="cx">         except KeyError:
</span><span class="cx">             return []
</span><span class="cx"> 
</span><span class="lines">@@ -149,28 +187,33 @@
</span><span class="cx">             results.extend(attr.getValues())
</span><span class="cx">         return results
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def hasParameter(self, paramname):
</span><del>-        return self._pycard.hasAttribute(paramname)
</del><ins>+        return self._pycard.hasParameter(paramname)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def setParameter(self, paramname, paramvalue):
</span><del>-        self._pycard.replaceAttribute(PyCalendarAttribute(paramname, paramvalue))
</del><ins>+        self._pycard.replaceParameter(Parameter(paramname, paramvalue))
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def removeParameter(self, paramname):
</span><del>-        self._pycard.removeAttributes(paramname)
</del><ins>+        self._pycard.removeParameters(paramname)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def removeAllParameters(self):
</span><del>-        self._pycard.setAttributes({})
</del><ins>+        self._pycard.setParameters({})
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def removeParameterValue(self, paramname, paramvalue):
</span><span class="cx"> 
</span><span class="cx">         paramname = paramname.upper()
</span><span class="cx">         for attrName in self.parameterNames():
</span><span class="cx">             if attrName.upper() == paramname:
</span><del>-                for attr in tuple(self._pycard.getAttributes()[attrName]):
</del><ins>+                for attr in tuple(self._pycard.getParameters()[attrName]):
</ins><span class="cx">                     for value in attr.getValues():
</span><span class="cx">                         if value == paramvalue:
</span><span class="cx">                             if not attr.removeValue(value):
</span><del>-                                self._pycard.removeAttributes(paramname)
</del><ins>+                                self._pycard.removeParameters(paramname)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -178,8 +221,20 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     X{vCard} component.
</span><span class="cx">     &quot;&quot;&quot;
</span><ins>+    allowedTypesList = None
+
+
</ins><span class="cx">     @classmethod
</span><del>-    def allFromString(clazz, string):
</del><ins>+    def allowedTypes(cls):
+        if cls.allowedTypesList is None:
+            cls.allowedTypesList = [&quot;text/vcard&quot;]
+            if config.EnableJSONData:
+                cls.allowedTypesList.append(&quot;application/vcard+json&quot;)
+        return cls.allowedTypesList
+
+
+    @classmethod
+    def allFromString(clazz, string, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         FIXME: Just default to reading a single VCARD - actually need more
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -193,62 +248,85 @@
</span><span class="cx">         if string[:3] == codecs.BOM_UTF8:
</span><span class="cx">             string = string[3:]
</span><span class="cx"> 
</span><del>-        return clazz.allFromStream(StringIO.StringIO(string))
</del><ins>+        return clazz.allFromStream(StringIO.StringIO(string), format)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @classmethod
</span><del>-    def allFromStream(clazz, stream):
</del><ins>+    def allFromStream(clazz, stream, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         FIXME: Just default to reading a single VCARD - actually need more
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         try:
</span><del>-            results = Card.parseMultiple(stream)
-        except PyCalendarError:
</del><ins>+            results = Card.parseMultipleData(stream, format)
+        except ErrorBase:
</ins><span class="cx">             results = None
</span><span class="cx">         if not results:
</span><span class="cx">             stream.seek(0)
</span><span class="cx">             raise InvalidVCardDataError(&quot;%s&quot; % (stream.read(),))
</span><span class="cx">         return [clazz(None, pycard=result) for result in results]
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @classmethod
</span><del>-    def fromString(clazz, string):
</del><ins>+    def fromString(clazz, string, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Construct a L{Component} from a string.
</span><span class="cx">         @param string: a string containing vCard data.
</span><span class="cx">         @return: a L{Component} representing the first component described by
</span><span class="cx">             C{string}.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        if type(string) is unicode:
-            string = string.encode(&quot;utf-8&quot;)
-        else:
-            # Valid utf-8 please
-            string.decode(&quot;utf-8&quot;)
</del><ins>+        return clazz._fromData(string, False, format)
</ins><span class="cx"> 
</span><del>-        # No BOMs please
-        if string[:3] == codecs.BOM_UTF8:
-            string = string[3:]
</del><span class="cx"> 
</span><del>-        return clazz.fromStream(StringIO.StringIO(string))
</del><ins>+    @classmethod
+    def fromStream(clazz, stream, format=None):
+        &quot;&quot;&quot;
+        Construct a L{Component} from a stream.
+        @param stream: a C{read()}able stream containing vCard data.
+        @return: a L{Component} representing the first component described by
+            C{stream}.
+        &quot;&quot;&quot;
+        return clazz._fromData(stream, True, format)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @classmethod
</span><del>-    def fromStream(clazz, stream):
</del><ins>+    def _fromData(clazz, data, isstream, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Construct a L{Component} from a stream.
</span><span class="cx">         @param stream: a C{read()}able stream containing vCard data.
</span><ins>+        @param format: a C{str} indicating whether the data is vCard or jCard
</ins><span class="cx">         @return: a L{Component} representing the first component described by
</span><span class="cx">             C{stream}.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        cal = Card()
</del><ins>+
+        if isstream:
+            pass
+        else:
+            if type(data) is unicode:
+                data = data.encode(&quot;utf-8&quot;)
+            else:
+                # Valid utf-8 please
+                data.decode(&quot;utf-8&quot;)
+
+            # No BOMs please
+            if data[:3] == codecs.BOM_UTF8:
+                data = data[3:]
+
+        errmsg = &quot;Unknown&quot;
</ins><span class="cx">         try:
</span><del>-            result = cal.parse(stream)
-        except PyCalendarError:
</del><ins>+            result = Card.parseData(data, format)
+        except ErrorBase, e:
+            errmsg = &quot;%s: %s&quot; % (e.mReason, e.mData,)
</ins><span class="cx">             result = None
</span><span class="cx">         if not result:
</span><del>-            stream.seek(0)
-            raise InvalidVCardDataError(&quot;%s&quot; % (stream.read(),))
-        return clazz(None, pycard=cal)
</del><ins>+            if isstream:
+                data.seek(0)
+                data = data.read()
+            raise InvalidVCardDataError(&quot;%s\n%s&quot; % (errmsg, data,))
+        return clazz(None, pycard=result)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @classmethod
</span><del>-    def fromIStream(clazz, stream):
</del><ins>+    def fromIStream(clazz, stream, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Construct a L{Component} from a stream.
</span><span class="cx">         @param stream: an L{IStream} containing vCard data.
</span><span class="lines">@@ -261,9 +339,11 @@
</span><span class="cx">         #   A better solution would parse directly and incrementally from the
</span><span class="cx">         #   request stream.
</span><span class="cx">         #
</span><del>-        def parse(data): return clazz.fromString(data)
</del><ins>+        def parse(data):
+            return clazz.fromString(data, format)
</ins><span class="cx">         return allDataFromStream(IStream(stream), parse)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def __init__(self, name, **kwargs):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Use this constructor to initialize an empty L{Component}.
</span><span class="lines">@@ -277,8 +357,8 @@
</span><span class="cx">                 pyobj = kwargs[&quot;pycard&quot;]
</span><span class="cx"> 
</span><span class="cx">                 if pyobj is not None:
</span><del>-                    if not isinstance(pyobj, PyCalendarComponentBase):
-                        raise TypeError(&quot;Not a PyCalendarComponentBase: %r&quot; % (pyobj,))
</del><ins>+                    if not isinstance(pyobj, ComponentBase):
+                        raise TypeError(&quot;Not a ComponentBase: %r&quot; % (pyobj,))
</ins><span class="cx"> 
</span><span class="cx">                 self._pycard = pyobj
</span><span class="cx">             else:
</span><span class="lines">@@ -302,28 +382,53 @@
</span><span class="cx">         else:
</span><span class="cx">             raise ValueError(&quot;VCards have no child components&quot;)
</span><span class="cx"> 
</span><del>-    def __str__ (self): return str(self._pycard)
-    def __repr__(self): return &quot;&lt;%s: %r&gt;&quot; % (self.__class__.__name__, str(self._pycard))
</del><span class="cx"> 
</span><ins>+    def __str__(self):
+        return str(self._pycard)
+
+
+    def __repr__(self):
+        return &quot;&lt;%s: %r&gt;&quot; % (self.__class__.__name__, str(self._pycard))
+
+
</ins><span class="cx">     def __hash__(self):
</span><span class="cx">         return hash(str(self))
</span><span class="cx"> 
</span><del>-    def __ne__(self, other): return not self.__eq__(other)
</del><ins>+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+
</ins><span class="cx">     def __eq__(self, other):
</span><span class="cx">         if not isinstance(other, Component):
</span><span class="cx">             return False
</span><span class="cx">         return self._pycard == other._pycard
</span><span class="cx"> 
</span><ins>+
+    def getText(self, format=None):
+        &quot;&quot;&quot;
+        Return text representation
+        &quot;&quot;&quot;
+        assert self.name() == &quot;VCARD&quot;, &quot;Must be a VCARD: %r&quot; % (self,)
+
+        result = self._pycard.getText(format)
+        if result is None:
+            raise ValueError(&quot;Unknown format requested for address data.&quot;)
+        return result
+
+
</ins><span class="cx">     # FIXME: Should this not be in __eq__?
</span><span class="cx">     def same(self, other):
</span><span class="cx">         return self._pycard == other._pycard
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def name(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        @return: the name of the iCalendar type of this component.
</del><ins>+        @return: the name of the vCard type of this component.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return self._pycard.getType()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def duplicate(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Duplicate this object and all its contents.
</span><span class="lines">@@ -331,6 +436,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return Component(None, pycard=self._pycard.duplicate())
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def hasProperty(self, name):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param name: the name of the property whose existence is being tested.
</span><span class="lines">@@ -338,6 +444,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         return self._pycard.hasProperty(name)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def getProperty(self, name):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Get one property from the property list.
</span><span class="lines">@@ -346,10 +453,13 @@
</span><span class="cx">         @raise: L{ValueError} if there is more than one property of the given name.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         properties = tuple(self.properties(name))
</span><del>-        if len(properties) == 1: return properties[0]
-        if len(properties) &gt; 1: raise InvalidVCardDataError(&quot;More than one %s property in component %r&quot; % (name, self))
</del><ins>+        if len(properties) == 1:
+            return properties[0]
+        if len(properties) &gt; 1:
+            raise InvalidVCardDataError(&quot;More than one %s property in component %r&quot; % (name, self))
</ins><span class="cx">         return None
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def properties(self, name=None):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param name: if given and not C{None}, restricts the returned properties
</span><span class="lines">@@ -368,6 +478,7 @@
</span><span class="cx">             for p in properties
</span><span class="cx">         )
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def propertyValue(self, name):
</span><span class="cx">         properties = tuple(self.properties(name))
</span><span class="cx">         if len(properties) == 1:
</span><span class="lines">@@ -385,6 +496,7 @@
</span><span class="cx">         self._pycard.addProperty(property._pycard)
</span><span class="cx">         self._pycard.finalise()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def removeProperty(self, property):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Remove a property from this component.
</span><span class="lines">@@ -393,6 +505,7 @@
</span><span class="cx">         self._pycard.removeProperty(property._pycard)
</span><span class="cx">         self._pycard.finalise()
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def removeProperties(self, name):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         remove all properties with name
</span><span class="lines">@@ -400,6 +513,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         self._pycard.removeProperties(name)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def replaceProperty(self, property):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Add or replace a property in this component.
</span><span class="lines">@@ -410,6 +524,7 @@
</span><span class="cx">         self._pycard.removeProperties(property.name())
</span><span class="cx">         self.addProperty(property)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def resourceUID(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the UID of the subcomponents in this component.
</span><span class="lines">@@ -421,6 +536,7 @@
</span><span class="cx"> 
</span><span class="cx">         return self._resource_uid
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def resourceKind(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: the kind of the subcomponents in this component.
</span><span class="lines">@@ -432,6 +548,7 @@
</span><span class="cx"> 
</span><span class="cx">         return self._resource_kind
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def resourceMemberAddresses(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: an iterable of X-ADDRESSBOOKSERVER-MEMBER property values
</span><span class="lines">@@ -440,6 +557,7 @@
</span><span class="cx"> 
</span><span class="cx">         return [prop.value() for prop in list(self.properties(&quot;X-ADDRESSBOOKSERVER-MEMBER&quot;))]
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def validVCardData(self, doFix=True, doRaise=True):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @return: tuple of fixed, unfixed issues
</span><span class="lines">@@ -454,17 +572,19 @@
</span><span class="cx">         if unfixed:
</span><span class="cx">             log.debug(&quot;vCard data had unfixable problems:\n  %s&quot; % (&quot;\n  &quot;.join(unfixed),))
</span><span class="cx">             if doRaise:
</span><del>-                raise InvalidVCardDataError(&quot;Calendar data had unfixable problems:\n  %s&quot; % (&quot;\n  &quot;.join(unfixed),))
</del><ins>+                raise InvalidVCardDataError(&quot;Address data had unfixable problems:\n  %s&quot; % (&quot;\n  &quot;.join(unfixed),))
</ins><span class="cx">         if fixed:
</span><span class="cx">             log.debug(&quot;vCard data had fixable problems:\n  %s&quot; % (&quot;\n  &quot;.join(fixed),))
</span><span class="cx"> 
</span><span class="cx">         return fixed, unfixed
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">     def validForCardDAV(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @raise ValueError: if the given vcard data is not valid.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        if self.name() != &quot;VCARD&quot;: raise InvalidVCardDataError(&quot;Not a vcard&quot;)
</del><ins>+        if self.name() != &quot;VCARD&quot;:
+            raise InvalidVCardDataError(&quot;Not a vcard&quot;)
</ins><span class="cx"> 
</span><span class="cx">         version = self.propertyValue(&quot;VERSION&quot;)
</span><span class="cx">         if version != &quot;3.0&quot;:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavxmlutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/xmlutil.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/xmlutil.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/xmlutil.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -24,17 +24,21 @@
</span><span class="cx"> except ImportError:
</span><span class="cx">     from xml.parsers.expat import ExpatError as XMLParseError
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> # Utilities for working with ElementTree
</span><span class="cx"> 
</span><span class="cx"> def readXMLString(xmldata, expectedRootTag=None):
</span><span class="cx">     io = StringIO.StringIO(xmldata)
</span><span class="cx">     return readXML(io, expectedRootTag)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def readXML(xmlfile, expectedRootTag=None):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Read in XML data from a file and parse into ElementTree. Optionally verify
</span><span class="cx">     the root node is what we expect.
</span><del>-    
</del><ins>+
</ins><span class="cx">     @param xmlfile: file to read from
</span><span class="cx">     @type xmlfile: C{File}
</span><span class="cx">     @param expectedRootTag: root tag (qname) to test or C{None}
</span><span class="lines">@@ -52,14 +56,18 @@
</span><span class="cx">         root = etree.getroot()
</span><span class="cx">         if root.tag != expectedRootTag:
</span><span class="cx">             raise ValueError(&quot;Ignoring file '%s' because it is not a %s file&quot; % (xmlfile, expectedRootTag,))
</span><del>-    
</del><ins>+
</ins><span class="cx">     return etree, etree.getroot()
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def elementToXML(element):
</span><span class="cx">     return XML.tostring(element, &quot;utf-8&quot;)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def writeXML(xmlfile, root):
</span><del>-    
</del><ins>+
</ins><span class="cx">     data = &quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</span><span class="cx"> &lt;!DOCTYPE %s SYSTEM &quot;%s.dtd&quot;&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -69,7 +77,7 @@
</span><span class="cx"> 
</span><span class="cx">     # Generate indentation
</span><span class="cx">     def _indentNode(node, level=0):
</span><del>-        
</del><ins>+
</ins><span class="cx">         if node.text is not None and node.text.strip():
</span><span class="cx">             return
</span><span class="cx">         elif len(node):
</span><span class="lines">@@ -87,27 +95,35 @@
</span><span class="cx">     with open(xmlfile, &quot;w&quot;) as f:
</span><span class="cx">         f.write(data)
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def newElementTreeWithRoot(roottag):
</span><span class="cx"> 
</span><span class="cx">     root = createElement(roottag)
</span><span class="cx">     etree = XML.ElementTree(root)
</span><del>-    
</del><ins>+
</ins><span class="cx">     return etree, root
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def createElement(tag, text=None, **attrs):
</span><span class="cx"> 
</span><span class="cx">     child = XML.Element(tag, attrs)
</span><span class="cx">     child.text = text
</span><span class="cx">     return child
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def addSubElement(parent, tag, text=None):
</span><span class="cx"> 
</span><span class="cx">     child = XML.SubElement(parent, tag)
</span><span class="cx">     child.text = text
</span><span class="cx">     return child
</span><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> def changeSubElementText(parent, tag, text):
</span><del>-    
</del><ins>+
</ins><span class="cx">     child = parent.find(tag)
</span><span class="cx">     if child is not None:
</span><span class="cx">         child.text = text
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAfricaCasablancaics"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/Casablanca.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/Casablanca.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/Casablanca.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -54,6 +54,7 @@
</span><span class="cx"> RDATE:20100808T000000
</span><span class="cx"> RDATE:20110731T000000
</span><span class="cx"> RDATE:20120720T030000
</span><ins>+RDATE:20120930T030000
</ins><span class="cx"> RDATE:20130707T030000
</span><span class="cx"> RDATE:20140629T030000
</span><span class="cx"> RDATE:20150618T030000
</span><span class="lines">@@ -61,6 +62,9 @@
</span><span class="cx"> RDATE:20170527T030000
</span><span class="cx"> RDATE:20180516T030000
</span><span class="cx"> RDATE:20190506T030000
</span><ins>+RDATE:20200424T030000
+RDATE:20210413T030000
+RDATE:20220403T030000
</ins><span class="cx"> TZNAME:WET
</span><span class="cx"> TZOFFSETFROM:+0100
</span><span class="cx"> TZOFFSETTO:+0000
</span><span class="lines">@@ -88,17 +92,24 @@
</span><span class="cx"> END:STANDARD
</span><span class="cx"> BEGIN:DAYLIGHT
</span><span class="cx"> DTSTART:20120429T020000
</span><del>-RRULE:FREQ=YEARLY;UNTIL=20190428T020000Z;BYDAY=-1SU;BYMONTH=4
</del><ins>+RRULE:FREQ=YEARLY;UNTIL=20130428T020000Z;BYDAY=-1SU;BYMONTH=4
</ins><span class="cx"> TZNAME:WEST
</span><span class="cx"> TZOFFSETFROM:+0000
</span><span class="cx"> TZOFFSETTO:+0100
</span><span class="cx"> END:DAYLIGHT
</span><span class="cx"> BEGIN:STANDARD
</span><del>-DTSTART:20120930T030000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=9
</del><ins>+DTSTART:20131027T030000
+RRULE:FREQ=YEARLY;UNTIL=20221030T020000Z;BYDAY=-1SU;BYMONTH=10
</ins><span class="cx"> TZNAME:WET
</span><span class="cx"> TZOFFSETFROM:+0100
</span><span class="cx"> TZOFFSETTO:+0000
</span><span class="cx"> END:STANDARD
</span><ins>+BEGIN:DAYLIGHT
+DTSTART:20140330T020000
+RRULE:FREQ=YEARLY;UNTIL=20220327T020000Z;BYDAY=-1SU;BYMONTH=3
+TZNAME:WEST
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+END:DAYLIGHT
</ins><span class="cx"> END:VTIMEZONE
</span><span class="cx"> END:VCALENDAR
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAfricaEl_Aaiunics"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/El_Aaiun.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/El_Aaiun.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/El_Aaiun.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -15,9 +15,84 @@
</span><span class="cx"> BEGIN:STANDARD
</span><span class="cx"> DTSTART:19760414T000000
</span><span class="cx"> RDATE:19760414T000000
</span><del>-TZNAME:WET
</del><ins>+TZNAME:WEST
</ins><span class="cx"> TZOFFSETFROM:-0100
</span><span class="cx"> TZOFFSETTO:+0000
</span><span class="cx"> END:STANDARD
</span><ins>+BEGIN:DAYLIGHT
+DTSTART:19760501T000000
+RRULE:FREQ=YEARLY;UNTIL=19770501T000000Z;BYMONTH=5
+TZNAME:WEST
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:19760801T000000
+RDATE:19760801T000000
+RDATE:19770928T000000
+RDATE:19780804T000000
+RDATE:20080901T000000
+RDATE:20090821T000000
+RDATE:20100808T000000
+RDATE:20110731T000000
+RDATE:20120720T030000
+RDATE:20120930T030000
+RDATE:20130707T030000
+RDATE:20140629T030000
+RDATE:20150618T030000
+RDATE:20160607T030000
+RDATE:20170527T030000
+RDATE:20180516T030000
+RDATE:20190506T030000
+RDATE:20200424T030000
+RDATE:20210413T030000
+RDATE:20220403T030000
+TZNAME:WET
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0000
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19780601T000000
+RDATE:19780601T000000
+RDATE:20080601T000000
+RDATE:20090601T000000
+RDATE:20100502T000000
+RDATE:20110403T000000
+RDATE:20120820T020000
+RDATE:20130810T020000
+RDATE:20140729T020000
+RDATE:20150718T020000
+RDATE:20160707T020000
+RDATE:20170626T020000
+RDATE:20180615T020000
+RDATE:20190605T020000
+RDATE:20200524T020000
+RDATE:20210513T020000
+RDATE:20220503T020000
+TZNAME:WEST
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+END:DAYLIGHT
+BEGIN:DAYLIGHT
+DTSTART:20120429T020000
+RRULE:FREQ=YEARLY;UNTIL=20130428T020000Z;BYDAY=-1SU;BYMONTH=4
+TZNAME:WEST
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20131027T030000
+RRULE:FREQ=YEARLY;UNTIL=20221030T020000Z;BYDAY=-1SU;BYMONTH=10
+TZNAME:WET
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0000
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20140330T020000
+RRULE:FREQ=YEARLY;UNTIL=20220327T020000Z;BYDAY=-1SU;BYMONTH=3
+TZNAME:WEST
+TZOFFSETFROM:+0000
+TZOFFSETTO:+0100
+END:DAYLIGHT
</ins><span class="cx"> END:VTIMEZONE
</span><span class="cx"> END:VCALENDAR
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAfricaTripoliics"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/Tripoli.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/Tripoli.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Africa/Tripoli.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -20,6 +20,7 @@
</span><span class="cx"> RDATE:19850406T000000
</span><span class="cx"> RDATE:19860404T000000
</span><span class="cx"> RDATE:19970404T000000
</span><ins>+RDATE:20130329T010000
</ins><span class="cx"> TZNAME:CEST
</span><span class="cx"> TZOFFSETFROM:+0100
</span><span class="cx"> TZOFFSETTO:+0200
</span><span class="lines">@@ -82,23 +83,10 @@
</span><span class="cx"> BEGIN:STANDARD
</span><span class="cx"> DTSTART:19971004T000000
</span><span class="cx"> RDATE:19971004T000000
</span><ins>+RDATE:20131025T020000
</ins><span class="cx"> TZNAME:EET
</span><span class="cx"> TZOFFSETFROM:+0200
</span><span class="cx"> TZOFFSETTO:+0200
</span><span class="cx"> END:STANDARD
</span><del>-BEGIN:DAYLIGHT
-DTSTART:20130329T010000
-RRULE:FREQ=YEARLY;BYDAY=-1FR;BYMONTH=3
-TZNAME:CEST
-TZOFFSETFROM:+0100
-TZOFFSETTO:+0200
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:20131025T020000
-RRULE:FREQ=YEARLY;BYDAY=-1FR;BYMONTH=10
-TZNAME:CET
-TZOFFSETFROM:+0200
-TZOFFSETTO:+0100
-END:STANDARD
</del><span class="cx"> END:VTIMEZONE
</span><span class="cx"> END:VCALENDAR
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAmericaEirunepeics"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Eirunepe.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Eirunepe.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Eirunepe.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -51,6 +51,7 @@
</span><span class="cx"> RDATE:19870214T000000
</span><span class="cx"> RDATE:19880207T000000
</span><span class="cx"> RDATE:19940220T000000
</span><ins>+RDATE:20131110T000000
</ins><span class="cx"> TZNAME:ACT
</span><span class="cx"> TZOFFSETFROM:-0400
</span><span class="cx"> TZOFFSETTO:-0500
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAmericaPorto_Acreics"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Porto_Acre.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Porto_Acre.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Porto_Acre.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -49,6 +49,7 @@
</span><span class="cx"> RDATE:19860315T000000
</span><span class="cx"> RDATE:19870214T000000
</span><span class="cx"> RDATE:19880207T000000
</span><ins>+RDATE:20131110T000000
</ins><span class="cx"> TZNAME:ACT
</span><span class="cx"> TZOFFSETFROM:-0400
</span><span class="cx"> TZOFFSETTO:-0500
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoAmericaRio_Brancoics"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Rio_Branco.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Rio_Branco.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/America/Rio_Branco.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -49,6 +49,7 @@
</span><span class="cx"> RDATE:19860315T000000
</span><span class="cx"> RDATE:19870214T000000
</span><span class="cx"> RDATE:19880207T000000
</span><ins>+RDATE:20131110T000000
</ins><span class="cx"> TZNAME:ACT
</span><span class="cx"> TZOFFSETFROM:-0400
</span><span class="cx"> TZOFFSETTO:-0500
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoBrazilAcreics"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Brazil/Acre.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Brazil/Acre.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Brazil/Acre.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -49,6 +49,7 @@
</span><span class="cx"> RDATE:19860315T000000
</span><span class="cx"> RDATE:19870214T000000
</span><span class="cx"> RDATE:19880207T000000
</span><ins>+RDATE:20131110T000000
</ins><span class="cx"> TZNAME:ACT
</span><span class="cx"> TZOFFSETFROM:-0400
</span><span class="cx"> TZOFFSETTO:-0500
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoLibyaics"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Libya.ics (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Libya.ics        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/Libya.ics        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -20,6 +20,7 @@
</span><span class="cx"> RDATE:19850406T000000
</span><span class="cx"> RDATE:19860404T000000
</span><span class="cx"> RDATE:19970404T000000
</span><ins>+RDATE:20130329T010000
</ins><span class="cx"> TZNAME:CEST
</span><span class="cx"> TZOFFSETFROM:+0100
</span><span class="cx"> TZOFFSETTO:+0200
</span><span class="lines">@@ -82,23 +83,10 @@
</span><span class="cx"> BEGIN:STANDARD
</span><span class="cx"> DTSTART:19971004T000000
</span><span class="cx"> RDATE:19971004T000000
</span><ins>+RDATE:20131025T020000
</ins><span class="cx"> TZNAME:EET
</span><span class="cx"> TZOFFSETFROM:+0200
</span><span class="cx"> TZOFFSETTO:+0200
</span><span class="cx"> END:STANDARD
</span><del>-BEGIN:DAYLIGHT
-DTSTART:20130329T010000
-RRULE:FREQ=YEARLY;BYDAY=-1FR;BYMONTH=3
-TZNAME:CEST
-TZOFFSETFROM:+0100
-TZOFFSETTO:+0200
-END:DAYLIGHT
-BEGIN:STANDARD
-DTSTART:20131025T020000
-RRULE:FREQ=YEARLY;BYDAY=-1FR;BYMONTH=10
-TZNAME:CET
-TZOFFSETFROM:+0200
-TZOFFSETTO:+0100
-END:STANDARD
</del><span class="cx"> END:VTIMEZONE
</span><span class="cx"> END:VCALENDAR
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfotimezonesxml"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/timezones.xml (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/timezones.xml        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/timezones.xml        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -2,7 +2,7 @@
</span><span class="cx"> &lt;!DOCTYPE timezones SYSTEM &quot;timezones.dtd&quot;&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;timezones&gt;
</span><del>-  &lt;dtstamp&gt;2013-10-01T01:19:11Z&lt;/dtstamp&gt;
</del><ins>+  &lt;dtstamp&gt;2013-11-15T16:10:31Z&lt;/dtstamp&gt;
</ins><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;Africa/Abidjan&lt;/tzid&gt;
</span><span class="cx">     &lt;dtstamp&gt;2011-10-05T11:50:21Z&lt;/dtstamp&gt;
</span><span class="lines">@@ -78,8 +78,8 @@
</span><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;Africa/Casablanca&lt;/tzid&gt;
</span><del>-    &lt;dtstamp&gt;2013-07-11T02:11:45Z&lt;/dtstamp&gt;
-    &lt;md5&gt;b4e345b053c4699911078dcd16854bab&lt;/md5&gt;
</del><ins>+    &lt;dtstamp&gt;2013-11-15T16:10:31Z&lt;/dtstamp&gt;
+    &lt;md5&gt;4f58dbcb4f7e6dfa7af3d710aeff97b4&lt;/md5&gt;
</ins><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;Africa/Ceuta&lt;/tzid&gt;
</span><span class="lines">@@ -113,8 +113,8 @@
</span><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;Africa/El_Aaiun&lt;/tzid&gt;
</span><del>-    &lt;dtstamp&gt;2011-10-05T11:50:21Z&lt;/dtstamp&gt;
-    &lt;md5&gt;494500808e8542fd83e4706654c43545&lt;/md5&gt;
</del><ins>+    &lt;dtstamp&gt;2013-11-15T16:10:31Z&lt;/dtstamp&gt;
+    &lt;md5&gt;7933d45461e9f988ebfc9d062ce894e4&lt;/md5&gt;
</ins><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;Africa/Freetown&lt;/tzid&gt;
</span><span class="lines">@@ -264,9 +264,9 @@
</span><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;Africa/Tripoli&lt;/tzid&gt;
</span><del>-    &lt;dtstamp&gt;2013-01-14T15:32:16Z&lt;/dtstamp&gt;
</del><ins>+    &lt;dtstamp&gt;2013-11-15T16:10:31Z&lt;/dtstamp&gt;
</ins><span class="cx">     &lt;alias&gt;Libya&lt;/alias&gt;
</span><del>-    &lt;md5&gt;f59e5f16eec995c112b8b27580922fdd&lt;/md5&gt;
</del><ins>+    &lt;md5&gt;6e8040bfd898654905bfd0a49c64e365&lt;/md5&gt;
</ins><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;Africa/Tunis&lt;/tzid&gt;
</span><span class="lines">@@ -570,8 +570,8 @@
</span><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;America/Eirunepe&lt;/tzid&gt;
</span><del>-    &lt;dtstamp&gt;2011-10-05T11:50:21Z&lt;/dtstamp&gt;
-    &lt;md5&gt;d3c4df84162ebac445e1c2dcdb81f3b2&lt;/md5&gt;
</del><ins>+    &lt;dtstamp&gt;2013-11-15T16:10:31Z&lt;/dtstamp&gt;
+    &lt;md5&gt;cc34b66260adda629311a54df088470b&lt;/md5&gt;
</ins><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;America/El_Salvador&lt;/tzid&gt;
</span><span class="lines">@@ -964,8 +964,8 @@
</span><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;America/Porto_Acre&lt;/tzid&gt;
</span><del>-    &lt;dtstamp&gt;2011-10-05T11:50:21Z&lt;/dtstamp&gt;
-    &lt;md5&gt;ce88b8461b7217e1d9ec8f4dfac34670&lt;/md5&gt;
</del><ins>+    &lt;dtstamp&gt;2013-11-15T16:10:31Z&lt;/dtstamp&gt;
+    &lt;md5&gt;b2b04e3c9c1dab12a3764b99dd8536fc&lt;/md5&gt;
</ins><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;America/Porto_Velho&lt;/tzid&gt;
</span><span class="lines">@@ -1006,10 +1006,10 @@
</span><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;America/Rio_Branco&lt;/tzid&gt;
</span><del>-    &lt;dtstamp&gt;2011-10-05T11:50:21Z&lt;/dtstamp&gt;
</del><ins>+    &lt;dtstamp&gt;2013-11-15T16:10:31Z&lt;/dtstamp&gt;
</ins><span class="cx">     &lt;alias&gt;America/Porto_Acre&lt;/alias&gt;
</span><span class="cx">     &lt;alias&gt;Brazil/Acre&lt;/alias&gt;
</span><del>-    &lt;md5&gt;c41ff8b67906037ce014d42019e5831f&lt;/md5&gt;
</del><ins>+    &lt;md5&gt;51273c4521cd00a8ecdcff336f0c9503&lt;/md5&gt;
</ins><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;America/Rosario&lt;/tzid&gt;
</span><span class="lines">@@ -1885,8 +1885,8 @@
</span><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;Brazil/Acre&lt;/tzid&gt;
</span><del>-    &lt;dtstamp&gt;2011-10-05T11:50:21Z&lt;/dtstamp&gt;
-    &lt;md5&gt;b034140cdfc442b0f989f6a6dd6ec620&lt;/md5&gt;
</del><ins>+    &lt;dtstamp&gt;2013-11-15T16:10:31Z&lt;/dtstamp&gt;
+    &lt;md5&gt;ad33124888f5c5dd9bed9317ef0bb953&lt;/md5&gt;
</ins><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;Brazil/DeNoronha&lt;/tzid&gt;
</span><span class="lines">@@ -2641,8 +2641,8 @@
</span><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;Libya&lt;/tzid&gt;
</span><del>-    &lt;dtstamp&gt;2013-01-14T15:32:16Z&lt;/dtstamp&gt;
-    &lt;md5&gt;f514b497bd861c14aa21612f9101c50c&lt;/md5&gt;
</del><ins>+    &lt;dtstamp&gt;2013-11-15T16:10:31Z&lt;/dtstamp&gt;
+    &lt;md5&gt;e6ac54ea0ab33dd6fd125a71fc34cf46&lt;/md5&gt;
</ins><span class="cx">   &lt;/timezone&gt;
</span><span class="cx">   &lt;timezone&gt;
</span><span class="cx">     &lt;tzid&gt;MET&lt;/tzid&gt;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestwistedcaldavzoneinfoversiontxt"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/version.txt (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/version.txt        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/twistedcaldav/zoneinfo/version.txt        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1 +1 @@
</span><del>-IANA Timezone Registry: 2013f
</del><span class="cx">\ No newline at end of file
</span><ins>+IANA Timezone Registry: 2013h
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavbasepropertystorebasepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/base/propertystore/base.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/base/propertystore/base.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/base/propertystore/base.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -214,7 +214,13 @@
</span><span class="cx"> 
</span><span class="cx">     def __delitem__(self, key):
</span><span class="cx">         # Handle per-user behavior
</span><del>-        if self.isGlobalProperty(key):
</del><ins>+        if self.isShadowableProperty(key):
+            try:
+                self._delitem_uid(key, self._perUser)
+            except KeyError:
+                # It is OK for shadowable delete to fail
+                pass
+        elif self.isGlobalProperty(key):
</ins><span class="cx">             self._delitem_uid(key, self._defaultUser)
</span><span class="cx">         else:
</span><span class="cx">             self._delitem_uid(key, self._perUser)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavbasepropertystoretestbasepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/base/propertystore/test/base.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/base/propertystore/test/base.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/base/propertystore/test/base.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -206,6 +206,41 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><ins>+    def test_peruserShadow_delete(self):
+        &quot;&quot;&quot;
+        Delete a shadowable property that has not been overridden by the sharee.
+        &quot;&quot;&quot;
+
+        name = propertyName(&quot;shadow&quot;)
+
+        self.propertyStore1.setSpecialProperties((name,), ())
+        self.propertyStore2.setSpecialProperties((name,), ())
+
+        value1 = propertyValue(&quot;Hello, World1!&quot;)
+
+        self.propertyStore1[name] = value1
+        yield self._changed(self.propertyStore1)
+        self.assertEquals(self.propertyStore1.get(name, None), value1)
+        self.assertEquals(self.propertyStore2.get(name, None), value1)
+        self.failUnless(name in self.propertyStore1)
+        self.failUnless(name in self.propertyStore2)
+
+        del self.propertyStore2[name]
+        yield self._changed(self.propertyStore2)
+        self.assertEquals(self.propertyStore1.get(name, None), value1)
+        self.assertEquals(self.propertyStore2.get(name, None), value1)
+        self.failUnless(name in self.propertyStore1)
+        self.failUnless(name in self.propertyStore2)
+
+        del self.propertyStore1[name]
+        yield self._changed(self.propertyStore1)
+        self.assertEquals(self.propertyStore1.get(name, None), None)
+        self.assertEquals(self.propertyStore2.get(name, None), None)
+        self.failIf(name in self.propertyStore1)
+        self.failIf(name in self.propertyStore2)
+
+
+    @inlineCallbacks
</ins><span class="cx">     def test_peruser_global(self):
</span><span class="cx"> 
</span><span class="cx">         name = propertyName(&quot;global&quot;)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastorefilepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/file.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/file.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/file.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -41,8 +41,8 @@
</span><span class="cx"> from twext.web2.dav.resource import TwistedGETContentMD5
</span><span class="cx"> from twext.web2.http_headers import generateContentType, MimeType
</span><span class="cx"> 
</span><del>-from twistedcaldav import caldavxml, customxml
-from twistedcaldav.caldavxml import ScheduleCalendarTransp, Opaque
</del><ins>+from twistedcaldav import caldavxml, customxml, ical
+from twistedcaldav.caldavxml import ScheduleCalendarTransp, Opaque, Transparent
</ins><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.ical import InvalidICalendarDataError
</span><span class="cx"> 
</span><span class="lines">@@ -84,6 +84,14 @@
</span><span class="cx">     _topPath = &quot;calendars&quot;
</span><span class="cx">     _notifierPrefix = &quot;CalDAV&quot;
</span><span class="cx"> 
</span><ins>+    _componentCalendarName = {
+        &quot;VEVENT&quot;: &quot;calendar&quot;,
+        &quot;VTODO&quot;: &quot;tasks&quot;,
+        &quot;VJOURNAL&quot;: &quot;journals&quot;,
+        &quot;VAVAILABILITY&quot;: &quot;available&quot;,
+        &quot;VPOLL&quot;: &quot;polls&quot;,
+    }
+
</ins><span class="cx">     def __init__(self, uid, path, calendarStore, transaction):
</span><span class="cx">         super(CalendarHome, self).__init__(uid, path, calendarStore, transaction)
</span><span class="cx"> 
</span><span class="lines">@@ -177,20 +185,19 @@
</span><span class="cx"> 
</span><span class="cx">     def createdHome(self):
</span><span class="cx"> 
</span><del>-        # Default calendar
-        defaultCal = self.createCalendarWithName(&quot;calendar&quot;)
-        props = defaultCal.properties()
-        props[PropertyName(*ScheduleCalendarTransp.qname())] = ScheduleCalendarTransp(Opaque())
-
</del><span class="cx">         # Check whether components type must be separate
</span><span class="cx">         if config.RestrictCalendarsToOneComponentType:
</span><del>-            defaultCal.setSupportedComponents(&quot;VEVENT&quot;)
</del><ins>+            for name in ical.allowedStoreComponents:
+                cal = self.createCalendarWithName(self._componentCalendarName[name])
+                cal.setSupportedComponents(name)
+                props = cal.properties()
+                if name not in (&quot;VEVENT&quot;, &quot;VAVAILABILITY&quot;,):
+                    props[PropertyName(*ScheduleCalendarTransp.qname())] = ScheduleCalendarTransp(Transparent())
+                else:
+                    props[PropertyName(*ScheduleCalendarTransp.qname())] = ScheduleCalendarTransp(Opaque())
+        else:
+            cal = self.createCalendarWithName(&quot;calendar&quot;)
</ins><span class="cx"> 
</span><del>-            # Default tasks
-            defaultTasks = self.createCalendarWithName(&quot;tasks&quot;)
-            props = defaultTasks.properties()
-            defaultTasks.setSupportedComponents(&quot;VTODO&quot;)
-
</del><span class="cx">         self.createCalendarWithName(&quot;inbox&quot;)
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreindex_filepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/index_file.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/index_file.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/index_file.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -55,9 +55,9 @@
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.memcachepool import CachePoolUserMixIn
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -341,7 +341,7 @@
</span><span class="cx">                     maxDate = maxDate.duplicate()
</span><span class="cx">                     maxDate.setDateOnly(True)
</span><span class="cx">                     if isStartDate:
</span><del>-                        maxDate += PyCalendarDuration(days=365)
</del><ins>+                        maxDate += Duration(days=365)
</ins><span class="cx">                     self.testAndUpdateIndex(maxDate)
</span><span class="cx">             else:
</span><span class="cx">                 # We cannot handle this filter in an indexed search
</span><span class="lines">@@ -671,7 +671,7 @@
</span><span class="cx">         if master is None or not calendar.isRecurring():
</span><span class="cx">             # When there is no master we have a set of overridden components - index them all.
</span><span class="cx">             # When there is one instance - index it.
</span><del>-            expand = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+            expand = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">             doInstanceIndexing = True
</span><span class="cx">         else:
</span><span class="cx">             # If migrating or re-creating or config option for delayed indexing is off, always index
</span><span class="lines">@@ -682,8 +682,8 @@
</span><span class="cx">             # by default.  This is a caching parameter which affects the size of the index;
</span><span class="cx">             # it does not affect search results beyond this period, but it may affect
</span><span class="cx">             # performance of such a search.
</span><del>-            expand = (PyCalendarDateTime.getToday() +
-                      PyCalendarDuration(days=config.FreeBusyIndexExpandAheadDays))
</del><ins>+            expand = (DateTime.getToday() +
+                      Duration(days=config.FreeBusyIndexExpandAheadDays))
</ins><span class="cx"> 
</span><span class="cx">             if expand_until and expand_until &gt; expand:
</span><span class="cx">                 expand = expand_until
</span><span class="lines">@@ -700,8 +700,8 @@
</span><span class="cx">             # occurrences into some obscenely far-in-the-future date, so we cap the caching
</span><span class="cx">             # period.  Searches beyond this period will always be relatively expensive for
</span><span class="cx">             # resources with occurrences beyond this period.
</span><del>-            if expand &gt; (PyCalendarDateTime.getToday() +
-                         PyCalendarDuration(days=config.FreeBusyIndexExpandMaxDays)):
</del><ins>+            if expand &gt; (DateTime.getToday() +
+                         Duration(days=config.FreeBusyIndexExpandMaxDays)):
</ins><span class="cx">                 raise IndexedSearchException()
</span><span class="cx"> 
</span><span class="cx">         # Always do recurrence expansion even if we do not intend to index - we need this to double-check the
</span><span class="lines">@@ -716,7 +716,7 @@
</span><span class="cx">         # Now coerce indexing to off if needed
</span><span class="cx">         if not doInstanceIndexing:
</span><span class="cx">             instances = None
</span><del>-            recurrenceLimit = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+            recurrenceLimit = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx"> 
</span><span class="cx">         self._delete_from_db(name, uid, False)
</span><span class="cx"> 
</span><span class="lines">@@ -782,8 +782,8 @@
</span><span class="cx">             # Special - for unbounded recurrence we insert a value for &quot;infinity&quot;
</span><span class="cx">             # that will allow an open-ended time-range to always match it.
</span><span class="cx">             if calendar.isRecurringUnbounded():
</span><del>-                start = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
-                end = PyCalendarDateTime(2100, 1, 1, 1, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+                start = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
+                end = DateTime(2100, 1, 1, 1, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">                 float = 'N'
</span><span class="cx">                 self._db_execute(
</span><span class="cx">                     &quot;&quot;&quot;
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingaddressmappingpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/addressmapping.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/addressmapping.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/addressmapping.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -53,7 +53,7 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def getCalendarUser(self, cuaddr, principal):
</span><span class="cx"> 
</span><del>-        # If we have a principal always treat the user as local or partitioned
</del><ins>+        # If we have a principal always treat the user as local
</ins><span class="cx">         if principal:
</span><span class="cx">             returnValue(calendarUserFromPrincipal(cuaddr, principal))
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingcaldavdeliverypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/delivery.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/delivery.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/delivery.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -26,8 +26,7 @@
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> 
</span><span class="cx"> from txdav.base.propertystore.base import PropertyName
</span><del>-from txdav.caldav.datastore.scheduling.cuaddress import LocalCalendarUser, RemoteCalendarUser, \
-    PartitionedCalendarUser, OtherServerCalendarUser
</del><ins>+from txdav.caldav.datastore.scheduling.cuaddress import LocalCalendarUser, RemoteCalendarUser, OtherServerCalendarUser
</ins><span class="cx"> from txdav.caldav.datastore.scheduling.delivery import DeliveryService
</span><span class="cx"> from txdav.caldav.datastore.scheduling.freebusy import processAvailabilityFreeBusy, \
</span><span class="cx">     generateFreeBusyInfo, buildFreeBusyResult
</span><span class="lines">@@ -99,7 +98,7 @@
</span><span class="cx">         uid = self.scheduler.calendar.resourceUID()
</span><span class="cx"> 
</span><span class="cx">         organizerPrincipal = None
</span><del>-        if type(self.scheduler.organizer) in (LocalCalendarUser, PartitionedCalendarUser, OtherServerCalendarUser,):
</del><ins>+        if type(self.scheduler.organizer) in (LocalCalendarUser, OtherServerCalendarUser,):
</ins><span class="cx">             organizerPrincipal = self.scheduler.organizer.principal.uid
</span><span class="cx"> 
</span><span class="cx">         for recipient in self.recipients:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingcaldavschedulerpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/scheduler.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/scheduler.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/scheduler.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -101,6 +101,14 @@
</span><span class="cx">                 &quot;No principal for originator&quot;,
</span><span class="cx">             ))
</span><span class="cx">         else:
</span><ins>+            if not (originatorPrincipal.calendarsEnabled() and originatorPrincipal.thisServer()):
+                log.error(&quot;Originator not enabled or hosted on this server: %s&quot; % (self.originator,))
+                raise HTTPError(self.errorResponse(
+                    responsecode.FORBIDDEN,
+                    self.errorElements[&quot;originator-denied&quot;],
+                    &quot;Originator cannot be scheduled&quot;,
+                ))
+
</ins><span class="cx">             self.originator = LocalCalendarUser(self.originator, originatorPrincipal)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -127,8 +135,8 @@
</span><span class="cx">             else:
</span><span class="cx">                 # Map recipient to their inbox
</span><span class="cx">                 inbox = None
</span><del>-                if principal.calendarsEnabled() and principal.thisServer():
-                    if principal.locallyHosted():
</del><ins>+                if principal.calendarsEnabled():
+                    if principal.thisServer():
</ins><span class="cx">                         recipient_home = yield self.txn.calendarHomeWithUID(principal.uid, create=True)
</span><span class="cx">                         if recipient_home:
</span><span class="cx">                             inbox = (yield recipient_home.calendarWithName(&quot;inbox&quot;))
</span><span class="lines">@@ -138,7 +146,7 @@
</span><span class="cx">                 if inbox:
</span><span class="cx">                     results.append(calendarUserFromPrincipal(recipient, principal, inbox))
</span><span class="cx">                 else:
</span><del>-                    log.error(&quot;No schedule inbox for principal: %s&quot; % (principal,))
</del><ins>+                    log.error(&quot;Recipient not enabled for calendaring: %s&quot; % (principal,))
</ins><span class="cx">                     results.append(InvalidCalendarUser(recipient))
</span><span class="cx"> 
</span><span class="cx">         self.recipients = results
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingcaldavtesttest_schedulerpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/test/test_scheduler.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/test/test_scheduler.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/caldav/test/test_scheduler.py        2013-12-14 06:28:16 UTC (rev 12110)
</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.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from twext.python.clsprop import classproperty
</span><span class="cx"> 
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx">         self._sqlCalendarStore = yield buildCalendarStore(self, self.notifierFactory)
</span><span class="cx">         yield self.populate()
</span><span class="cx"> 
</span><del>-        self.now = PyCalendarDateTime.getNowUTC()
</del><ins>+        self.now = DateTime.getNowUTC()
</ins><span class="cx">         self.now.setHHMMSS(0, 0, 0)
</span><span class="cx"> 
</span><span class="cx">         self.now_12H = self.now.duplicate()
</span><span class="lines">@@ -170,9 +170,9 @@
</span><span class="cx">         scheduler = CalDAVScheduler(self.transactionUnderTest(), &quot;user01&quot;)
</span><span class="cx">         result = (yield scheduler.doSchedulingViaPOST(&quot;mailto:user01@example.com&quot;, [&quot;mailto:user01@example.com&quot;, ], Component.fromString(data_request)))
</span><span class="cx">         self.assertEqual(len(result.responses), 1)
</span><del>-        self.assertEqual(str(result.responses[0].children[0].children[0]), &quot;mailto:user01@example.com&quot;)
-        self.assertTrue(str(result.responses[0].children[1]).startswith(&quot;2&quot;))
-        self.assertEqual(normalizeiCalendarText(str(result.responses[0].children[2].children[0])), data_reply.replace(&quot;\n&quot;, &quot;\r\n&quot;))
</del><ins>+        self.assertEqual(str(result.responses[0].recipient.children[0]), &quot;mailto:user01@example.com&quot;)
+        self.assertTrue(str(result.responses[0].reqstatus).startswith(&quot;2&quot;))
+        self.assertEqual(normalizeiCalendarText(str(result.responses[0].calendar)), data_reply.replace(&quot;\n&quot;, &quot;\r\n&quot;))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -227,9 +227,9 @@
</span><span class="cx">         scheduler = CalDAVScheduler(self.transactionUnderTest(), &quot;user01&quot;)
</span><span class="cx">         result = (yield scheduler.doSchedulingViaPOST(&quot;mailto:user01@example.com&quot;, [&quot;mailto:user01@example.com&quot;, ], Component.fromString(data_request)))
</span><span class="cx">         self.assertEqual(len(result.responses), 1)
</span><del>-        self.assertEqual(str(result.responses[0].children[0].children[0]), &quot;mailto:user01@example.com&quot;)
-        self.assertTrue(str(result.responses[0].children[1]).startswith(&quot;2&quot;))
-        self.assertEqual(normalizeiCalendarText(str(result.responses[0].children[2].children[0])), data_reply.replace(&quot;\n&quot;, &quot;\r\n&quot;))
</del><ins>+        self.assertEqual(str(result.responses[0].recipient.children[0]), &quot;mailto:user01@example.com&quot;)
+        self.assertTrue(str(result.responses[0].reqstatus).startswith(&quot;2&quot;))
+        self.assertEqual(normalizeiCalendarText(str(result.responses[0].calendar)), data_reply.replace(&quot;\n&quot;, &quot;\r\n&quot;))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -294,6 +294,6 @@
</span><span class="cx">         scheduler = CalDAVScheduler(self.transactionUnderTest(), &quot;user01&quot;)
</span><span class="cx">         result = (yield scheduler.doSchedulingViaPOST(&quot;mailto:user01@example.com&quot;, [&quot;mailto:user01@example.com&quot;, ], Component.fromString(data_request)))
</span><span class="cx">         self.assertEqual(len(result.responses), 1)
</span><del>-        self.assertEqual(str(result.responses[0].children[0].children[0]), &quot;mailto:user01@example.com&quot;)
-        self.assertTrue(str(result.responses[0].children[1]).startswith(&quot;2&quot;))
-        self.assertEqual(normalizeiCalendarText(str(result.responses[0].children[2].children[0])), data_reply.replace(&quot;\n&quot;, &quot;\r\n&quot;))
</del><ins>+        self.assertEqual(str(result.responses[0].recipient.children[0]), &quot;mailto:user01@example.com&quot;)
+        self.assertTrue(str(result.responses[0].reqstatus).startswith(&quot;2&quot;))
+        self.assertEqual(normalizeiCalendarText(str(result.responses[0].calendar)), data_reply.replace(&quot;\n&quot;, &quot;\r\n&quot;))
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingcuaddresspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/cuaddress.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/cuaddress.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/cuaddress.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -21,7 +21,6 @@
</span><span class="cx"> 
</span><span class="cx"> __all__ = [
</span><span class="cx">     &quot;LocalCalendarUser&quot;,
</span><del>-    &quot;PartitionedCalendarUser&quot;,
</del><span class="cx">     &quot;OtherServerCalendarUser&quot;,
</span><span class="cx">     &quot;RemoteCalendarUser&quot;,
</span><span class="cx">     &quot;EmailCalendarUser&quot;,
</span><span class="lines">@@ -53,19 +52,6 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class PartitionedCalendarUser(CalendarUser):
-
-    def __init__(self, cuaddr, principal):
-        self.cuaddr = cuaddr
-        self.principal = principal
-        self.serviceType = DeliveryService.serviceType_ischedule
-
-
-    def __str__(self):
-        return &quot;Partitioned calendar user: %s&quot; % (self.cuaddr,)
-
-
-
</del><span class="cx"> class OtherServerCalendarUser(CalendarUser):
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, cuaddr, principal):
</span><span class="lines">@@ -145,9 +131,7 @@
</span><span class="cx">     Get the appropriate calendar user address class for the provided principal.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    if principal.locallyHosted():
</del><ins>+    if principal.thisServer():
</ins><span class="cx">         return LocalCalendarUser(recipient, principal, inbox)
</span><del>-    elif principal.thisServer():
-        return PartitionedCalendarUser(recipient, principal)
</del><span class="cx">     else:
</span><span class="cx">         return OtherServerCalendarUser(recipient, principal)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingfreebusypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/freebusy.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/freebusy.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/freebusy.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -14,10 +14,10 @@
</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.duration import PyCalendarDuration
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
+from pycalendar.period import Period
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx"> 
</span><span class="lines">@@ -68,8 +68,8 @@
</span><span class="cx">         if entry:
</span><span class="cx"> 
</span><span class="cx">             # Offset one day at either end to account for floating
</span><del>-            cached_start = entry.timerange.start + PyCalendarDuration(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
-            cached_end = entry.timerange.end - PyCalendarDuration(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
</del><ins>+            cached_start = entry.timerange.start + Duration(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
+            cached_end = entry.timerange.end - Duration(days=FBCacheEntry.CACHE_DAYS_FLOATING_ADJUST)
</ins><span class="cx"> 
</span><span class="cx">             # Verify that the requested time range lies within the cache time range
</span><span class="cx">             if compareDateTime(timerange.end, cached_end) &lt;= 0 and compareDateTime(timerange.start, cached_start) &gt;= 0:
</span><span class="lines">@@ -187,8 +187,8 @@
</span><span class="cx">                 logItems[&quot;fb-uncached&quot;] = logItems.get(&quot;fb-uncached&quot;, 0) + 1
</span><span class="cx"> 
</span><span class="cx">             # We want to cache a large range of time based on the current date
</span><del>-            cache_start = normalizeToUTC(PyCalendarDateTime.getToday() + PyCalendarDuration(days=0 - config.FreeBusyCacheDaysBack))
-            cache_end = normalizeToUTC(PyCalendarDateTime.getToday() + PyCalendarDuration(days=config.FreeBusyCacheDaysForward))
</del><ins>+            cache_start = normalizeToUTC(DateTime.getToday() + Duration(days=0 - config.FreeBusyCacheDaysBack))
+            cache_end = normalizeToUTC(DateTime.getToday() + Duration(days=config.FreeBusyCacheDaysForward))
</ins><span class="cx"> 
</span><span class="cx">             # If the requested time range would fit in our allowed cache range, trigger the cache creation
</span><span class="cx">             if compareDateTime(timerange.start, cache_start) &gt;= 0 and compareDateTime(timerange.end, cache_end) &lt;= 0:
</span><span class="lines">@@ -227,7 +227,7 @@
</span><span class="cx">             logItems[&quot;fb-cached&quot;] = logItems.get(&quot;fb-cached&quot;, 0) + 1
</span><span class="cx"> 
</span><span class="cx">         # Determine appropriate timezone (UTC is the default)
</span><del>-        tzinfo = tz.gettimezone() if tz is not None else PyCalendarTimezone(utc=True)
</del><ins>+        tzinfo = tz.gettimezone() if tz is not None else Timezone(utc=True)
</ins><span class="cx"> 
</span><span class="cx">     # We care about separate instances for VEVENTs only
</span><span class="cx">     aggregated_resources = {}
</span><span class="lines">@@ -270,15 +270,15 @@
</span><span class="cx">                 if float == 'Y':
</span><span class="cx">                     fbstart.setTimezone(tzinfo)
</span><span class="cx">                 else:
</span><del>-                    fbstart.setTimezone(PyCalendarTimezone(utc=True))
</del><ins>+                    fbstart.setTimezone(Timezone(utc=True))
</ins><span class="cx">                 fbend = parseSQLTimestampToPyCalendar(end)
</span><span class="cx">                 if float == 'Y':
</span><span class="cx">                     fbend.setTimezone(tzinfo)
</span><span class="cx">                 else:
</span><del>-                    fbend.setTimezone(PyCalendarTimezone(utc=True))
</del><ins>+                    fbend.setTimezone(Timezone(utc=True))
</ins><span class="cx"> 
</span><span class="cx">                 # Clip instance to time range
</span><del>-                clipped = clipPeriod(PyCalendarPeriod(fbstart, duration=fbend - fbstart), PyCalendarPeriod(timerange.start, timerange.end))
</del><ins>+                clipped = clipPeriod(Period(fbstart, duration=fbend - fbstart), Period(timerange.start, timerange.end))
</ins><span class="cx"> 
</span><span class="cx">                 # Double check for overlap
</span><span class="cx">                 if clipped:
</span><span class="lines">@@ -364,7 +364,7 @@
</span><span class="cx">     @param timerange: the time-range in which to expand
</span><span class="cx">     @type timerange: L{TimeRange}
</span><span class="cx">     @param tzinfo: timezone for floating time calculations
</span><del>-    @type tzinfo: L{PyCalendarTimezone}
</del><ins>+    @type tzinfo: L{Timezone}
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     # First expand the component
</span><span class="lines">@@ -404,7 +404,7 @@
</span><span class="cx">     @param calendar: the L{Component} that is the VCALENDAR containing the VEVENT's.
</span><span class="cx">     @param fbinfo: the tuple used to store the three types of fb data.
</span><span class="cx">     @param timerange: the time range to restrict free busy data to.
</span><del>-    @param tzinfo: the L{PyCalendarTimezone} for the timezone to use for floating/all-day events.
</del><ins>+    @param tzinfo: the L{Timezone} for the timezone to use for floating/all-day events.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     # Expand out the set of instances for the event with in the required range
</span><span class="lines">@@ -449,10 +449,10 @@
</span><span class="cx">         # Clip period for this instance - use duration for period end if that
</span><span class="cx">         # is what original component used
</span><span class="cx">         if instance.component.hasProperty(&quot;DURATION&quot;):
</span><del>-            period = PyCalendarPeriod(fbstart, duration=fbend - fbstart)
</del><ins>+            period = Period(fbstart, duration=fbend - fbstart)
</ins><span class="cx">         else:
</span><del>-            period = PyCalendarPeriod(fbstart, fbend)
-        clipped = clipPeriod(period, PyCalendarPeriod(timerange.start, timerange.end))
</del><ins>+            period = Period(fbstart, fbend)
+        clipped = clipPeriod(period, Period(timerange.start, timerange.end))
</ins><span class="cx"> 
</span><span class="cx">         # Double check for overlap
</span><span class="cx">         if clipped:
</span><span class="lines">@@ -490,7 +490,7 @@
</span><span class="cx">             assert isinstance(fb.value(), list), &quot;FREEBUSY property does not contain a list of values: %r&quot; % (fb,)
</span><span class="cx">             for period in fb.value():
</span><span class="cx">                 # Clip period for this instance
</span><del>-                clipped = clipPeriod(period.getValue(), PyCalendarPeriod(timerange.start, timerange.end))
</del><ins>+                clipped = clipPeriod(period.getValue(), Period(timerange.start, timerange.end))
</ins><span class="cx">                 if clipped:
</span><span class="cx">                     fbinfo[fbtype_mapper.get(fbtype, 0)].append(clipped)
</span><span class="cx"> 
</span><span class="lines">@@ -509,12 +509,12 @@
</span><span class="cx">         # Get overall start/end
</span><span class="cx">         start = vav.getStartDateUTC()
</span><span class="cx">         if start is None:
</span><del>-            start = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+            start = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         end = vav.getEndDateUTC()
</span><span class="cx">         if end is None:
</span><del>-            end = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
-        period = PyCalendarPeriod(start, end)
-        overall = clipPeriod(period, PyCalendarPeriod(timerange.start, timerange.end))
</del><ins>+            end = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
+        period = Period(start, end)
+        overall = clipPeriod(period, Period(timerange.start, timerange.end))
</ins><span class="cx">         if overall is None:
</span><span class="cx">             continue
</span><span class="cx"> 
</span><span class="lines">@@ -526,10 +526,10 @@
</span><span class="cx">         last_end = timerange.start
</span><span class="cx">         for period in periods:
</span><span class="cx">             if last_end &lt; period.getStart():
</span><del>-                busyperiods.append(PyCalendarPeriod(last_end, period.getStart()))
</del><ins>+                busyperiods.append(Period(last_end, period.getStart()))
</ins><span class="cx">             last_end = period.getEnd()
</span><span class="cx">         if last_end &lt; timerange.end:
</span><del>-            busyperiods.append(PyCalendarPeriod(last_end, timerange.end))
</del><ins>+            busyperiods.append(Period(last_end, timerange.end))
</ins><span class="cx"> 
</span><span class="cx">         # Add to actual results mapped by busy type
</span><span class="cx">         fbtype = vav.propertyValue(&quot;BUSYTYPE&quot;)
</span><span class="lines">@@ -576,10 +576,10 @@
</span><span class="cx">             # Clip period for this instance - use duration for period end if that
</span><span class="cx">             # is what original component used
</span><span class="cx">             if instance.component.hasProperty(&quot;DURATION&quot;):
</span><del>-                period = PyCalendarPeriod(start, duration=end - start)
</del><ins>+                period = Period(start, duration=end - start)
</ins><span class="cx">             else:
</span><del>-                period = PyCalendarPeriod(start, end)
-            clipped = clipPeriod(period, PyCalendarPeriod(timerange.start, timerange.end))
</del><ins>+                period = Period(start, end)
+            clipped = clipPeriod(period, Period(timerange.start, timerange.end))
</ins><span class="cx">             if clipped:
</span><span class="cx">                 periods.append(clipped)
</span><span class="cx"> 
</span><span class="lines">@@ -622,7 +622,7 @@
</span><span class="cx">         fb.addProperty(attendee)
</span><span class="cx">     fb.addProperty(Property(&quot;DTSTART&quot;, timerange.start))
</span><span class="cx">     fb.addProperty(Property(&quot;DTEND&quot;, timerange.end))
</span><del>-    fb.addProperty(Property(&quot;DTSTAMP&quot;, PyCalendarDateTime.getNowUTC()))
</del><ins>+    fb.addProperty(Property(&quot;DTSTAMP&quot;, DateTime.getNowUTC()))
</ins><span class="cx">     if len(fbinfo[0]) != 0:
</span><span class="cx">         fb.addProperty(Property(&quot;FREEBUSY&quot;, fbinfo[0], {&quot;FBTYPE&quot;: &quot;BUSY&quot;}))
</span><span class="cx">     if len(fbinfo[1]) != 0:
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingicaldiffpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/icaldiff.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/icaldiff.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/icaldiff.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,8 +16,8 @@
</span><span class="cx"> 
</span><span class="cx"> from difflib import unified_diff
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.period import PyCalendarPeriod
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.period import Period
</ins><span class="cx"> 
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx"> 
</span><span class="lines">@@ -484,7 +484,7 @@
</span><span class="cx"> 
</span><span class="cx">             # If PARTSTAT was changed by the attendee, add a timestamp if needed
</span><span class="cx">             if config.Scheduling.Options.TimestampAttendeePartStatChanges:
</span><del>-                serverAttendee.setParameter(&quot;X-CALENDARSERVER-DTSTAMP&quot;, PyCalendarDateTime.getNowUTC().getText())
</del><ins>+                serverAttendee.setParameter(&quot;X-CALENDARSERVER-DTSTAMP&quot;, DateTime.getNowUTC().getText())
</ins><span class="cx"> 
</span><span class="cx">             replyNeeded = True
</span><span class="cx"> 
</span><span class="lines">@@ -516,6 +516,10 @@
</span><span class="cx">             if comp.name() == &quot;VALARM&quot;:
</span><span class="cx">                 serverComponent.addComponent(comp)
</span><span class="cx"> 
</span><ins>+        # VPOLL
+        if serverComponent.name() == &quot;VPOLL&quot;:
+            replyNeeded = self._transferVPOLLData(serverComponent, clientComponent)
+
</ins><span class="cx">         return True, replyNeeded
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -556,6 +560,44 @@
</span><span class="cx">             return True
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def _transferVPOLLData(self, serverComponent, clientComponent):
+
+        changed = False
+
+        # Get the VOTER properties in sub-components of the VPOLL as set by the attendee
+        poll_items = {}
+        for component in clientComponent.subcomponents():
+            poll_id = component.propertyValue(&quot;POLL-ITEM-ID&quot;)
+            if poll_id is not None:
+                poll_items[poll_id] = component.getVoterProperty((self.attendee,))
+
+        # Transfer attendee data with the master set
+        for component in serverComponent.subcomponents():
+            poll_id = component.propertyValue(&quot;POLL-ITEM-ID&quot;)
+            if poll_id is not None:
+                voter = component.getVoterProperty((self.attendee,))
+                attendee_voter = poll_items.get(poll_id)
+                if attendee_voter is None:
+                    if voter is not None:
+                        component.removeProperty(voter)
+                        changed = True
+                elif voter is None:
+                    component.addProperty(attendee_voter)
+                    changed = True
+                else:
+                    for paramname in (&quot;RESPONSE&quot;,):
+                        paramvalue = attendee_voter.parameterValue(paramname)
+                        if paramvalue is None:
+                            voter.removeParameter(paramname)
+                            changed = True
+                        else:
+                            if paramvalue != voter.parameterValue(paramname):
+                                voter.setParameter(paramname, paramvalue)
+                                changed = True
+
+        return changed
+
+
</ins><span class="cx">     def _checkInvalidChanges(self, serverComponent, clientComponent, declines):
</span><span class="cx"> 
</span><span class="cx">         # Properties we care about: DTSTART, DTEND, DURATION, RRULE, RDATE, EXDATE
</span><span class="lines">@@ -585,12 +627,12 @@
</span><span class="cx">     def _getNormalizedDateTimeProperties(self, component):
</span><span class="cx"> 
</span><span class="cx">         # Basic time properties
</span><del>-        if component.name() in (&quot;VEVENT&quot;, &quot;VJOURNAL&quot;,):
</del><ins>+        if component.name() in (&quot;VEVENT&quot;, &quot;VJOURNAL&quot;, &quot;VPOLL&quot;):
</ins><span class="cx">             dtstart = component.getProperty(&quot;DTSTART&quot;)
</span><span class="cx">             dtend = component.getProperty(&quot;DTEND&quot;)
</span><span class="cx">             duration = component.getProperty(&quot;DURATION&quot;)
</span><span class="cx"> 
</span><del>-            timeRange = PyCalendarPeriod(
</del><ins>+            timeRange = Period(
</ins><span class="cx">                 start=dtstart.value()  if dtstart  is not None else None,
</span><span class="cx">                 end=dtend.value()    if dtend    is not None else None,
</span><span class="cx">                 duration=duration.value() if duration is not None else None,
</span><span class="lines">@@ -602,16 +644,19 @@
</span><span class="cx">             duration = component.getProperty(&quot;DURATION&quot;)
</span><span class="cx"> 
</span><span class="cx">             if dtstart or duration:
</span><del>-                timeRange = PyCalendarPeriod(
</del><ins>+                timeRange = Period(
</ins><span class="cx">                     start=dtstart.value()  if dtstart  is not None else None,
</span><span class="cx">                     duration=duration.value() if duration is not None else None,
</span><span class="cx">                 )
</span><span class="cx">             else:
</span><del>-                timeRange = PyCalendarPeriod()
</del><ins>+                timeRange = Period()
</ins><span class="cx"> 
</span><span class="cx">             newdue = component.getProperty(&quot;DUE&quot;)
</span><span class="cx">             if newdue is not None:
</span><span class="cx">                 newdue = newdue.value().duplicate().adjustToUTC()
</span><ins>+        else:
+            timeRange = Period()
+            newdue = None
</ins><span class="cx"> 
</span><span class="cx">         # Recurrence rules - we need to normalize the order of the value parts
</span><span class="cx">         newrrules = set()
</span><span class="lines">@@ -627,7 +672,7 @@
</span><span class="cx">         rdates = component.properties(&quot;RDATE&quot;)
</span><span class="cx">         for rdate in rdates:
</span><span class="cx">             for value in rdate.value():
</span><del>-                if isinstance(value, PyCalendarDateTime):
</del><ins>+                if isinstance(value, DateTime):
</ins><span class="cx">                     value = value.duplicate().adjustToUTC()
</span><span class="cx">                 newrdates.add(value)
</span><span class="cx"> 
</span><span class="lines">@@ -734,6 +779,7 @@
</span><span class="cx">         comp.normalizePropertyValueLists(&quot;EXDATE&quot;)
</span><span class="cx">         comp.removePropertyParameters(&quot;ORGANIZER&quot;, (&quot;SCHEDULE-STATUS&quot;,))
</span><span class="cx">         comp.removePropertyParameters(&quot;ATTENDEE&quot;, (&quot;SCHEDULE-STATUS&quot;, &quot;SCHEDULE-FORCE-SEND&quot;,))
</span><ins>+        comp.removePropertyParameters(&quot;VOTER&quot;, (&quot;SCHEDULE-STATUS&quot;, &quot;SCHEDULE-FORCE-SEND&quot;,))
</ins><span class="cx">         comp.removeAlarms()
</span><span class="cx">         comp.normalizeAll()
</span><span class="cx">         comp.normalizeAttachments()
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingicalsplitterpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/icalsplitter.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/icalsplitter.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/icalsplitter.py        2013-12-14 06:28:16 UTC (rev 12110)
</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.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from twistedcaldav.ical import Property
</span><span class="cx"> 
</span><span class="lines">@@ -34,10 +34,10 @@
</span><span class="cx"> 
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         self.threshold = threshold
</span><del>-        self.past = PyCalendarDateTime.getNowUTC()
</del><ins>+        self.past = DateTime.getNowUTC()
</ins><span class="cx">         self.past.setHHMMSS(0, 0, 0)
</span><span class="cx">         self.past.offsetDay(-past)
</span><del>-        self.now = PyCalendarDateTime.getNowUTC()
</del><ins>+        self.now = DateTime.getNowUTC()
</ins><span class="cx">         self.now.setHHMMSS(0, 0, 0)
</span><span class="cx">         self.now.offsetDay(-1)
</span><span class="cx"> 
</span><span class="lines">@@ -91,7 +91,7 @@
</span><span class="cx">         @type ical: L{Component}
</span><span class="cx"> 
</span><span class="cx">         @return: recurrence-id of the split
</span><del>-        @rtype: L{PyCalendarDateTime}
</del><ins>+        @rtype: L{DateTime}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Find the instance RECURRENCE-ID where a split is going to happen
</span><span class="lines">@@ -124,7 +124,7 @@
</span><span class="cx">         @type ical: L{Component}
</span><span class="cx"> 
</span><span class="cx">         @param rid: recurrence-id where the split should occur, or C{None} to determine it here
</span><del>-        @type rid: L{PyCalendarDateTime} or C{None}
</del><ins>+        @type rid: L{DateTime} or C{None}
</ins><span class="cx"> 
</span><span class="cx">         @param olderUID: UID to use for the split off component, or C{None} to generate one here
</span><span class="cx">         @type olderUID: C{str} or C{None}
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingimipoutboundpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/outbound.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/outbound.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/outbound.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -26,8 +26,8 @@
</span><span class="cx"> from email.mime.multipart import MIMEMultipart
</span><span class="cx"> from email.mime.text import MIMEText
</span><span class="cx"> import email.utils
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
</ins><span class="cx"> from twext.enterprise.dal.record import fromTable
</span><span class="cx"> from twext.enterprise.queue import WorkItem
</span><span class="cx"> from twext.python.log import Logger
</span><span class="lines">@@ -320,8 +320,8 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         if onlyAfter is None:
</span><del>-            duration = PyCalendarDuration(days=self.suppressionDays)
-            onlyAfter = PyCalendarDateTime.getNowUTC() - duration
</del><ins>+            duration = Duration(days=self.suppressionDays)
+            onlyAfter = DateTime.getNowUTC() - duration
</ins><span class="cx"> 
</span><span class="cx">         icaluid = calendar.resourceUID()
</span><span class="cx">         method = calendar.propertyValue(&quot;METHOD&quot;)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingimiptesttest_deliverypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_delivery.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_delivery.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_delivery.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -64,7 +64,7 @@
</span><span class="cx">         yield delivery.generateSchedulingResponses()
</span><span class="cx"> 
</span><span class="cx">         self.assertEqual(len(responses.responses), 1)
</span><del>-        self.assertEqual(str(responses.responses[0].children[1]), iTIPRequestStatus.SERVICE_UNAVAILABLE)
</del><ins>+        self.assertEqual(str(responses.responses[0].reqstatus), iTIPRequestStatus.SERVICE_UNAVAILABLE)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingimiptesttest_inboundpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_inbound.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_inbound.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_inbound.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -300,7 +300,7 @@
</span><span class="cx">         yield txn.commit()
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             &quot;1.2;Scheduling message has been delivered&quot;,
</span><del>-            result.responses[0].children[1].toString()
</del><ins>+            result.responses[0].reqstatus.toString()
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -333,7 +333,7 @@
</span><span class="cx">         yield txn.commit()
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             &quot;3.7;Invalid Calendar User&quot;,
</span><del>-            result.responses[0].children[1].toString()
</del><ins>+            result.responses[0].reqstatus.toString()
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingimiptesttest_outboundpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_outbound.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_outbound.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/imip/test/test_outbound.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -17,7 +17,7 @@
</span><span class="cx"> 
</span><span class="cx"> from cStringIO import StringIO
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, succeed
</span><span class="cx"> from twisted.trial import unittest
</span><span class="lines">@@ -275,7 +275,7 @@
</span><span class="cx">                 inputOriginator,
</span><span class="cx">                 inputRecipient,
</span><span class="cx">                 Component.fromString(inputCalendar.replace(&quot;\n&quot;, &quot;\r\n&quot;)),
</span><del>-                onlyAfter=PyCalendarDateTime(2010, 1, 1, 0, 0, 0)
</del><ins>+                onlyAfter=DateTime(2010, 1, 1, 0, 0, 0)
</ins><span class="cx">             )
</span><span class="cx">             yield txn.commit()
</span><span class="cx"> 
</span><span class="lines">@@ -319,7 +319,7 @@
</span><span class="cx">                 inputOriginator,
</span><span class="cx">                 inputRecipient,
</span><span class="cx">                 Component.fromString(inputCalendar.replace(&quot;\n&quot;, &quot;\r\n&quot;)),
</span><del>-                onlyAfter=PyCalendarDateTime(2021, 1, 1, 0, 0, 0)
</del><ins>+                onlyAfter=DateTime(2021, 1, 1, 0, 0, 0)
</ins><span class="cx">             )
</span><span class="cx">             yield txn.commit()
</span><span class="cx">             self.assertFalse(self.sender.smtpSender.sendMessageCalled)
</span><span class="lines">@@ -381,7 +381,7 @@
</span><span class="cx">         txn = self.store.newTransaction()
</span><span class="cx">         yield self.sender.outbound(txn, inputOriginator, inputRecipient,
</span><span class="cx">             Component.fromString(inputCalendar.replace(&quot;\n&quot;, &quot;\r\n&quot;)),
</span><del>-            onlyAfter=PyCalendarDateTime(2010, 1, 1, 0, 0, 0))
</del><ins>+            onlyAfter=DateTime(2010, 1, 1, 0, 0, 0))
</ins><span class="cx"> 
</span><span class="cx">         # Verify we didn't create a new token...
</span><span class="cx">         txn = self.store.newTransaction()
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingimplicitpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/implicit.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/implicit.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/implicit.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -21,7 +21,6 @@
</span><span class="cx"> from twext.web2 import responsecode
</span><span class="cx"> from twext.web2.http import HTTPError
</span><span class="cx"> 
</span><del>-from twistedcaldav import caldavxml
</del><span class="cx"> from twistedcaldav.caldavxml import caldav_namespace
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.ical import Property
</span><span class="lines">@@ -29,7 +28,7 @@
</span><span class="cx"> from txdav.caldav.datastore.scheduling import addressmapping
</span><span class="cx"> from txdav.caldav.datastore.scheduling.caldav.scheduler import CalDAVScheduler
</span><span class="cx"> from txdav.caldav.datastore.scheduling.cuaddress import InvalidCalendarUser, \
</span><del>-    LocalCalendarUser, PartitionedCalendarUser, OtherServerCalendarUser, \
</del><ins>+    LocalCalendarUser, OtherServerCalendarUser, \
</ins><span class="cx">     normalizeCUAddr
</span><span class="cx"> from txdav.caldav.datastore.scheduling.icaldiff import iCalDiff
</span><span class="cx"> from txdav.caldav.datastore.scheduling.itip import iTipGenerator, iTIPRequestStatus
</span><span class="lines">@@ -251,7 +250,7 @@
</span><span class="cx">         # to create new scheduling resources.
</span><span class="cx">         if self.action == &quot;create&quot;:
</span><span class="cx">             if self.organizerPrincipal and not self.organizerPrincipal.enabledAsOrganizer():
</span><del>-                log.error(&quot;ORGANIZER not allowed to be an Organizer: %s&quot; % (self.organizer,))
</del><ins>+                log.error(&quot;ORGANIZER not allowed to be an Organizer: {organizer}&quot;, organizer=self.organizer)
</ins><span class="cx">                 raise HTTPError(ErrorResponse(
</span><span class="cx">                     responsecode.FORBIDDEN,
</span><span class="cx">                     (caldav_namespace, &quot;organizer-allowed&quot;),
</span><span class="lines">@@ -427,7 +426,7 @@
</span><span class="cx">             self.organizer = self.calendar.validOrganizerForScheduling()
</span><span class="cx">         except ValueError:
</span><span class="cx">             # We have different ORGANIZERs in the same iCalendar object - this is an error
</span><del>-            log.error(&quot;Only one ORGANIZER is allowed in an iCalendar object:\n%s&quot; % (self.calendar,))
</del><ins>+            log.error(&quot;Only one ORGANIZER is allowed in an iCalendar object:\n{calendar}&quot;, calendar=self.calendar)
</ins><span class="cx">             raise HTTPError(ErrorResponse(
</span><span class="cx">                 responsecode.FORBIDDEN,
</span><span class="cx">                 (caldav_namespace, &quot;single-organizer&quot;),
</span><span class="lines">@@ -462,7 +461,7 @@
</span><span class="cx">         # Check for matching resource somewhere else in the home
</span><span class="cx">         foundElsewhere = (yield self.calendar_home.hasCalendarResourceUIDSomewhereElse(self.uid, check_resource, mode))
</span><span class="cx">         if foundElsewhere is not None:
</span><del>-            log.debug(&quot;Implicit - found component with same UID in a different collection: %s&quot; % (check_resource,))
</del><ins>+            log.debug(&quot;Implicit - found component with same UID in a different collection: {resource}&quot;, resource=check_resource)
</ins><span class="cx">             raise HTTPError(ErrorResponse(
</span><span class="cx">                 responsecode.FORBIDDEN,
</span><span class="cx">                 (caldav_namespace, &quot;unique-scheduling-object-resource&quot;),
</span><span class="lines">@@ -531,7 +530,7 @@
</span><span class="cx">         # Check for a delete
</span><span class="cx">         if self.action == &quot;remove&quot;:
</span><span class="cx"> 
</span><del>-            log.debug(&quot;Implicit - organizer '%s' is removing UID: '%s'&quot; % (self.organizer, self.uid))
</del><ins>+            log.debug(&quot;Implicit - organizer '{organizer}' is removing UID: '{uid}'&quot;, organizer=self.organizer, uid=self.uid)
</ins><span class="cx">             self.oldcalendar = self.calendar
</span><span class="cx"> 
</span><span class="cx">             # Cancel all attendees
</span><span class="lines">@@ -557,16 +556,16 @@
</span><span class="cx">             no_change, self.changed_rids, self.needs_action_rids, reinvites, recurrence_reschedule = self.isOrganizerChangeInsignificant()
</span><span class="cx">             if no_change:
</span><span class="cx">                 if reinvites:
</span><del>-                    log.debug(&quot;Implicit - organizer '%s' is re-inviting UID: '%s', attendees: %s&quot; % (self.organizer, self.uid, &quot;, &quot;.join(reinvites)))
</del><ins>+                    log.debug(&quot;Implicit - organizer '{organizer}' is re-inviting UID: '{uid}', attendees: {attendees}&quot;, organizer=self.organizer, uid=self.uid, attendees=&quot;, &quot;.join(reinvites))
</ins><span class="cx">                     self.reinvites = reinvites
</span><span class="cx">                 else:
</span><span class="cx">                     # Nothing to do
</span><del>-                    log.debug(&quot;Implicit - organizer '%s' is modifying UID: '%s' but change is not significant&quot; % (self.organizer, self.uid))
</del><ins>+                    log.debug(&quot;Implicit - organizer '{organizer}' is modifying UID: '{uid}' but change is not significant&quot;, organizer=self.organizer, uid=self.uid)
</ins><span class="cx">                     returnValue(None)
</span><span class="cx">             else:
</span><span class="cx">                 # Do not change PARTSTATs for a split operation
</span><span class="cx">                 if self.split_details is None:
</span><del>-                    log.debug(&quot;Implicit - organizer '%s' is modifying UID: '%s'&quot; % (self.organizer, self.uid))
</del><ins>+                    log.debug(&quot;Implicit - organizer '{organizer}' is modifying UID: '{uid}'&quot;, organizer=self.organizer, uid=self.uid)
</ins><span class="cx"> 
</span><span class="cx">                     for rid in self.needs_action_rids:
</span><span class="cx">                         comp = self.calendar.overriddenComponent(rid)
</span><span class="lines">@@ -587,7 +586,7 @@
</span><span class="cx"> 
</span><span class="cx">                                 attendee.setParameter(&quot;PARTSTAT&quot;, &quot;NEEDS-ACTION&quot;)
</span><span class="cx">                 else:
</span><del>-                    log.debug(&quot;Implicit - organizer '%s' is splitting UID: '%s'&quot; % (self.organizer, self.uid))
</del><ins>+                    log.debug(&quot;Implicit - organizer '{organizer}' is splitting UID: '{uid}'&quot;, organizer=self.organizer, uid=self.uid)
</ins><span class="cx"> 
</span><span class="cx">                 # Check for removed attendees
</span><span class="cx">                 if not recurrence_reschedule:
</span><span class="lines">@@ -601,10 +600,10 @@
</span><span class="cx"> 
</span><span class="cx">         elif self.action == &quot;create&quot;:
</span><span class="cx">             if self.split_details is None:
</span><del>-                log.debug(&quot;Implicit - organizer '%s' is creating UID: '%s'&quot; % (self.organizer, self.uid))
</del><ins>+                log.debug(&quot;Implicit - organizer '{organizer}' is creating UID: '{uid}'&quot;, organizer=self.organizer, uid=self.uid)
</ins><span class="cx">                 self.coerceAttendeesPartstatOnCreate()
</span><span class="cx">             else:
</span><del>-                log.debug(&quot;Implicit - organizer '%s' is creating a split UID: '%s'&quot; % (self.organizer, self.uid))
</del><ins>+                log.debug(&quot;Implicit - organizer '{organizer}' is creating a split UID: '{uid}'&quot;, organizer=self.organizer, uid=self.uid)
</ins><span class="cx">                 self.needs_sequence_change = False
</span><span class="cx"> 
</span><span class="cx">         # Always set RSVP=TRUE for any NEEDS-ACTION
</span><span class="lines">@@ -698,7 +697,7 @@
</span><span class="cx">                 oldOrganizer = self.oldcalendar.getOrganizer()
</span><span class="cx">                 newOrganizer = self.calendar.getOrganizer()
</span><span class="cx">                 if oldOrganizer != newOrganizer:
</span><del>-                    log.error(&quot;Cannot change ORGANIZER: UID:%s&quot; % (self.uid,))
</del><ins>+                    log.error(&quot;Cannot change ORGANIZER: UID:{uid}&quot;, uid=self.uid)
</ins><span class="cx">                     raise HTTPError(ErrorResponse(
</span><span class="cx">                         responsecode.FORBIDDEN,
</span><span class="cx">                         (caldav_namespace, &quot;valid-organizer-change&quot;),
</span><span class="lines">@@ -906,7 +905,7 @@
</span><span class="cx">                 if cuaddr not in coerced:
</span><span class="cx">                     attendeePrincipal = self.calendar_home.directoryService().recordWithCalendarUserAddress(cuaddr)
</span><span class="cx">                     attendeeAddress = (yield addressmapping.mapper.getCalendarUser(cuaddr, attendeePrincipal))
</span><del>-                    local_attendee = type(attendeeAddress) in (LocalCalendarUser, PartitionedCalendarUser, OtherServerCalendarUser,)
</del><ins>+                    local_attendee = type(attendeeAddress) in (LocalCalendarUser, OtherServerCalendarUser,)
</ins><span class="cx">                     coerced[cuaddr] = local_attendee
</span><span class="cx">                 if coerced[cuaddr]:
</span><span class="cx">                     attendee.removeParameter(&quot;SCHEDULE-AGENT&quot;)
</span><span class="lines">@@ -977,7 +976,7 @@
</span><span class="cx">                 scheduler = self.makeScheduler()
</span><span class="cx"> 
</span><span class="cx">                 # Do the PUT processing
</span><del>-                log.info(&quot;Implicit CANCEL - organizer: '%s' to attendee: '%s', UID: '%s', RIDs: '%s'&quot; % (self.organizer, attendee, self.uid, rids))
</del><ins>+                log.info(&quot;Implicit CANCEL - organizer: '{organizer}' to attendee: '{attendee}', UID: '{uid}', RIDs: '{rids}'&quot;, organizer=self.organizer, attendee=attendee, uid=self.uid, rids=rids)
</ins><span class="cx">                 response = (yield scheduler.doSchedulingViaPUT(self.originator, (attendee,), itipmsg, internal_request=True, suppress_refresh=self.suppress_refresh))
</span><span class="cx">                 self.handleSchedulingResponse(response, True)
</span><span class="cx"> 
</span><span class="lines">@@ -1034,7 +1033,7 @@
</span><span class="cx">                 scheduler = self.makeScheduler()
</span><span class="cx"> 
</span><span class="cx">                 # Do the PUT processing
</span><del>-                log.info(&quot;Implicit REQUEST - organizer: '%s' to attendee: '%s', UID: '%s'&quot; % (self.organizer, attendee, self.uid,))
</del><ins>+                log.info(&quot;Implicit REQUEST - organizer: '{organizer}' to attendee: '{attendee}', UID: '{uid}'&quot;, organizer=self.organizer, attendee=attendee, uid=self.uid)
</ins><span class="cx">                 response = (yield scheduler.doSchedulingViaPUT(self.originator, (attendee,), itipmsg, internal_request=True, suppress_refresh=self.suppress_refresh))
</span><span class="cx">                 self.handleSchedulingResponse(response, True)
</span><span class="cx"> 
</span><span class="lines">@@ -1047,17 +1046,17 @@
</span><span class="cx"> 
</span><span class="cx">         # Map each recipient in the response to a status code
</span><span class="cx">         responses = {}
</span><ins>+        propname = self.calendar.mainComponent().recipientPropertyName() if is_organizer else &quot;ORGANIZER&quot;
</ins><span class="cx">         for item in response.responses:
</span><del>-            assert isinstance(item, caldavxml.Response), &quot;Wrong element in response&quot;
-            recipient = str(item.children[0].children[0])
-            status = str(item.children[1])
</del><ins>+            recipient = str(item.recipient.children[0])
+            status = str(item.reqstatus)
</ins><span class="cx">             responses[recipient] = status
</span><span class="cx"> 
</span><span class="cx">             # Now apply to each ATTENDEE/ORGANIZER in the original data
</span><span class="cx">             self.calendar.setParameterToValueForPropertyWithValue(
</span><span class="cx">                 &quot;SCHEDULE-STATUS&quot;,
</span><span class="cx">                 status.split(&quot;;&quot;)[0],
</span><del>-                &quot;ATTENDEE&quot; if is_organizer else &quot;ORGANIZER&quot;,
</del><ins>+                propname,
</ins><span class="cx">                 recipient)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1069,19 +1068,19 @@
</span><span class="cx"> 
</span><span class="cx">         if self.action == &quot;remove&quot;:
</span><span class="cx">             if self.calendar.hasPropertyValueInAllComponents(Property(&quot;STATUS&quot;, &quot;CANCELLED&quot;)):
</span><del>-                log.debug(&quot;Implicit - attendee '%s' is removing cancelled UID: '%s'&quot; % (self.attendee, self.uid))
</del><ins>+                log.debug(&quot;Implicit - attendee '{attendee}' is removing cancelled UID: '{uid}'&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                 # Nothing else to do
</span><span class="cx">             elif doScheduling:
</span><span class="cx">                 # If attendee is already marked as declined in all components - nothing to do
</span><span class="cx">                 attendees = self.calendar.getAttendeeProperties((self.attendee,))
</span><span class="cx">                 if all([attendee.parameterValue(&quot;PARTSTAT&quot;, &quot;NEEDS-ACTION&quot;) == &quot;DECLINED&quot; for attendee in attendees]):
</span><del>-                    log.debug(&quot;Implicit - attendee '%s' is removing fully declined UID: '%s'&quot; % (self.attendee, self.uid))
</del><ins>+                    log.debug(&quot;Implicit - attendee '{attendee}' is removing fully declined UID: '{uid}'&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                     # Nothing else to do
</span><span class="cx">                 else:
</span><del>-                    log.debug(&quot;Implicit - attendee '%s' is cancelling UID: '%s'&quot; % (self.attendee, self.uid))
</del><ins>+                    log.debug(&quot;Implicit - attendee '{attendee}' is cancelling UID: '{uid}'&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                     yield self.scheduleCancelWithOrganizer()
</span><span class="cx">             else:
</span><del>-                log.debug(&quot;Implicit - attendee '%s' is removing UID without server scheduling: '%s'&quot; % (self.attendee, self.uid))
</del><ins>+                log.debug(&quot;Implicit - attendee '{attendee}' is removing UID without server scheduling: '{uid}'&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                 # Nothing else to do
</span><span class="cx">             returnValue(None)
</span><span class="cx"> 
</span><span class="lines">@@ -1092,7 +1091,7 @@
</span><span class="cx">                 oldOrganizer = self.oldcalendar.getOrganizer()
</span><span class="cx">                 newOrganizer = self.calendar.getOrganizer()
</span><span class="cx">                 if oldOrganizer != newOrganizer:
</span><del>-                    log.error(&quot;Cannot change ORGANIZER: UID:%s&quot; % (self.uid,))
</del><ins>+                    log.error(&quot;Cannot change ORGANIZER: UID:{uid}&quot;, uid=self.uid)
</ins><span class="cx">                     raise HTTPError(ErrorResponse(
</span><span class="cx">                         responsecode.FORBIDDEN,
</span><span class="cx">                         (caldav_namespace, &quot;valid-attendee-change&quot;),
</span><span class="lines">@@ -1107,7 +1106,7 @@
</span><span class="cx"> 
</span><span class="cx">                 # If Organizer copy exists we cannot allow SCHEDULE-AGENT=CLIENT or NONE
</span><span class="cx">                 if not doScheduling:
</span><del>-                    log.error(&quot;Attendee '%s' is not allowed to change SCHEDULE-AGENT on organizer: UID:%s&quot; % (self.attendeePrincipal, self.uid,))
</del><ins>+                    log.error(&quot;Attendee '{attendee}' is not allowed to change SCHEDULE-AGENT on organizer: UID:{uid}&quot;, attendee=self.attendeePrincipal, uid=self.uid)
</ins><span class="cx">                     raise HTTPError(ErrorResponse(
</span><span class="cx">                         responsecode.FORBIDDEN,
</span><span class="cx">                         (caldav_namespace, &quot;valid-attendee-change&quot;),
</span><span class="lines">@@ -1121,11 +1120,11 @@
</span><span class="cx"> 
</span><span class="cx">                 if not changeAllowed:
</span><span class="cx">                     if self.calendar.hasPropertyValueInAllComponents(Property(&quot;STATUS&quot;, &quot;CANCELLED&quot;)):
</span><del>-                        log.debug(&quot;Attendee '%s' is creating CANCELLED event for mismatched UID: '%s' - removing entire event&quot; % (self.attendee, self.uid,))
</del><ins>+                        log.debug(&quot;Attendee '{attendee}' is creating CANCELLED event for mismatched UID: '{uid}' - removing entire event&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                         self.return_status = ImplicitScheduler.STATUS_ORPHANED_EVENT
</span><span class="cx">                         returnValue(None)
</span><span class="cx">                     else:
</span><del>-                        log.error(&quot;Attendee '%s' is not allowed to make an unauthorized change to an organized event: UID:%s&quot; % (self.attendeePrincipal, self.uid,))
</del><ins>+                        log.error(&quot;Attendee '{attendee}' is not allowed to make an unauthorized change to an organized event: UID:{uid}&quot;, attendee=self.attendeePrincipal, uid=self.uid)
</ins><span class="cx">                         raise HTTPError(ErrorResponse(
</span><span class="cx">                             responsecode.FORBIDDEN,
</span><span class="cx">                             (caldav_namespace, &quot;valid-attendee-change&quot;),
</span><span class="lines">@@ -1135,21 +1134,21 @@
</span><span class="cx">                 # Check that the return calendar actually has any components left - this can happen if a cancelled
</span><span class="cx">                 # component is removed and replaced by another cancelled or invalid one
</span><span class="cx">                 if self.calendar.mainType() is None:
</span><del>-                    log.debug(&quot;Attendee '%s' is replacing CANCELLED event: '%s' - removing entire event&quot; % (self.attendee, self.uid,))
</del><ins>+                    log.debug(&quot;Attendee '{attendee}' is replacing CANCELLED event: '{uid}' - removing entire event&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                     self.return_status = ImplicitScheduler.STATUS_ORPHANED_EVENT
</span><span class="cx">                     returnValue(None)
</span><span class="cx"> 
</span><span class="cx">                 if not doITipReply:
</span><del>-                    log.debug(&quot;Implicit - attendee '%s' is updating UID: '%s' but change is not significant&quot; % (self.attendee, self.uid))
</del><ins>+                    log.debug(&quot;Implicit - attendee '{attendee}' is updating UID: '{uid}' but change is not significant&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                     returnValue(self.return_calendar)
</span><del>-                log.debug(&quot;Attendee '%s' is allowed to update UID: '%s' with local organizer '%s'&quot; % (self.attendee, self.uid, self.organizer))
</del><ins>+                log.debug(&quot;Attendee '{attendee}' is allowed to update UID: '{uid}' with local organizer '{organizer}'&quot;, attendee=self.attendee, uid=self.uid, organizer=self.organizer)
</ins><span class="cx"> 
</span><span class="cx">             elif isinstance(self.organizerAddress, LocalCalendarUser):
</span><span class="cx">                 # If Organizer copy does not exists we cannot allow SCHEDULE-AGENT=SERVER
</span><span class="cx">                 if doScheduling:
</span><span class="cx">                     # Check to see whether all instances are CANCELLED
</span><span class="cx">                     if self.calendar.hasPropertyValueInAllComponents(Property(&quot;STATUS&quot;, &quot;CANCELLED&quot;)):
</span><del>-                        log.debug(&quot;Attendee '%s' is creating CANCELLED event for missing UID: '%s' - removing entire event&quot; % (self.attendee, self.uid,))
</del><ins>+                        log.debug(&quot;Attendee '{attendee}' is creating CANCELLED event for missing UID: '{uid}' - removing entire event&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                         self.return_status = ImplicitScheduler.STATUS_ORPHANED_CANCELLED_EVENT
</span><span class="cx">                         returnValue(None)
</span><span class="cx">                     else:
</span><span class="lines">@@ -1157,25 +1156,25 @@
</span><span class="cx">                         if self.oldcalendar:
</span><span class="cx">                             oldScheduling = self.oldcalendar.getOrganizerScheduleAgent()
</span><span class="cx">                             if not oldScheduling:
</span><del>-                                log.error(&quot;Attendee '%s' is not allowed to set SCHEDULE-AGENT=SERVER on organizer: UID:%s&quot; % (self.attendeePrincipal, self.uid,))
</del><ins>+                                log.error(&quot;Attendee '{attendee}' is not allowed to set SCHEDULE-AGENT=SERVER on organizer: UID:{uid}&quot;, attendee=self.attendeePrincipal, uid=self.uid)
</ins><span class="cx">                                 raise HTTPError(ErrorResponse(
</span><span class="cx">                                     responsecode.FORBIDDEN,
</span><span class="cx">                                     (caldav_namespace, &quot;valid-attendee-change&quot;),
</span><span class="cx">                                     &quot;Attendee cannot change organizer state&quot;,
</span><span class="cx">                                 ))
</span><span class="cx"> 
</span><del>-                        log.debug(&quot;Attendee '%s' is not allowed to update UID: '%s' - missing organizer copy - removing entire event&quot; % (self.attendee, self.uid,))
</del><ins>+                        log.debug(&quot;Attendee '{attendee}' is not allowed to update UID: '{uid}' - missing organizer copy - removing entire event&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                         self.return_status = ImplicitScheduler.STATUS_ORPHANED_EVENT
</span><span class="cx">                         returnValue(None)
</span><span class="cx">                 else:
</span><del>-                    log.debug(&quot;Implicit - attendee '%s' is modifying UID without server scheduling: '%s'&quot; % (self.attendee, self.uid))
</del><ins>+                    log.debug(&quot;Implicit - attendee '{attendee}' is modifying UID without server scheduling: '{uid}'&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                     # Nothing else to do
</span><span class="cx">                     returnValue(None)
</span><span class="cx"> 
</span><span class="cx">             elif isinstance(self.organizerAddress, InvalidCalendarUser):
</span><span class="cx">                 # We will allow the attendee to do anything in this case, but we will mark the organizer
</span><span class="cx">                 # with an schedule-status error
</span><del>-                log.debug(&quot;Attendee '%s' is allowed to update UID: '%s' with invalid organizer '%s'&quot; % (self.attendee, self.uid, self.organizer))
</del><ins>+                log.debug(&quot;Attendee '{attendee}' is allowed to update UID: '{uid}' with invalid organizer '{organizer}'&quot;, attendee=self.attendee, uid=self.uid, organizer=self.organizer)
</ins><span class="cx">                 if doScheduling:
</span><span class="cx">                     self.calendar.setParameterToValueForPropertyWithValue(
</span><span class="cx">                         &quot;SCHEDULE-STATUS&quot;,
</span><span class="lines">@@ -1189,14 +1188,14 @@
</span><span class="cx">                 # to make any change they like as we cannot verify what is reasonable. In reality
</span><span class="cx">                 # we ought to be comparing the Attendee changes against the attendee's own copy
</span><span class="cx">                 # and restrict changes based on that when the organizer's copy is not available.
</span><del>-                log.debug(&quot;Attendee '%s' is allowed to update UID: '%s' with remote organizer '%s'&quot; % (self.attendee, self.uid, self.organizer))
</del><ins>+                log.debug(&quot;Attendee '{attendee}' is allowed to update UID: '{uid}' with remote organizer '{organizer}'&quot;, attendee=self.attendee, uid=self.uid, organizer=self.organizer)
</ins><span class="cx">                 changedRids = None
</span><span class="cx"> 
</span><span class="cx">             if doScheduling:
</span><del>-                log.debug(&quot;Implicit - attendee '%s' is updating UID: '%s'&quot; % (self.attendee, self.uid))
</del><ins>+                log.debug(&quot;Implicit - attendee '{attendee}' is updating UID: '{uid}'&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                 yield self.scheduleWithOrganizer(changedRids)
</span><span class="cx">             else:
</span><del>-                log.debug(&quot;Implicit - attendee '%s' is updating UID without server scheduling: '%s'&quot; % (self.attendee, self.uid))
</del><ins>+                log.debug(&quot;Implicit - attendee '{attendee}' is updating UID without server scheduling: '{uid}'&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                 # Nothing else to do
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1205,7 +1204,7 @@
</span><span class="cx"> 
</span><span class="cx">         if self.action == &quot;remove&quot;:
</span><span class="cx">             # Nothing else to do
</span><del>-            log.debug(&quot;Implicit - missing attendee is removing UID without server scheduling: '%s'&quot; % (self.uid,))
</del><ins>+            log.debug(&quot;Implicit - missing attendee is removing UID without server scheduling: '{uid}'&quot;, uid=self.uid)
</ins><span class="cx"> 
</span><span class="cx">         else:
</span><span class="cx">             # Make sure ORGANIZER is not changed if originally SCHEDULE-AGENT=SERVER
</span><span class="lines">@@ -1214,7 +1213,7 @@
</span><span class="cx">                 oldOrganizer = self.oldcalendar.getOrganizer()
</span><span class="cx">                 newOrganizer = self.calendar.getOrganizer()
</span><span class="cx">                 if oldOrganizer != newOrganizer and self.oldcalendar.getOrganizerScheduleAgent():
</span><del>-                    log.error(&quot;Cannot change ORGANIZER: UID:%s&quot; % (self.uid,))
</del><ins>+                    log.error(&quot;Cannot change ORGANIZER: UID:{uid}&quot;, uid=self.uid)
</ins><span class="cx">                     raise HTTPError(ErrorResponse(
</span><span class="cx">                         responsecode.FORBIDDEN,
</span><span class="cx">                         (caldav_namespace, &quot;valid-attendee-change&quot;),
</span><span class="lines">@@ -1223,7 +1222,7 @@
</span><span class="cx"> 
</span><span class="cx">             # Never allow a missing attendee with a locally hosted organizer
</span><span class="cx">             if isinstance(self.organizerAddress, LocalCalendarUser):
</span><del>-                log.error(&quot;Cannot remove ATTENDEE: UID:%s&quot; % (self.uid,))
</del><ins>+                log.error(&quot;Cannot remove ATTENDEE: UID:{uid}&quot;, uid=self.uid)
</ins><span class="cx">                 raise HTTPError(ErrorResponse(
</span><span class="cx">                     responsecode.FORBIDDEN,
</span><span class="cx">                     (caldav_namespace, &quot;valid-attendee-change&quot;),
</span><span class="lines">@@ -1232,7 +1231,7 @@
</span><span class="cx"> 
</span><span class="cx">             # We will allow the attendee to do anything in this case, but we will mark the organizer
</span><span class="cx">             # with an schedule-status error and schedule-agent none
</span><del>-            log.debug(&quot;Missing attendee is allowed to update UID: '%s' with invalid organizer '%s'&quot; % (self.uid, self.organizer))
</del><ins>+            log.debug(&quot;Missing attendee is allowed to update UID: '{uid}' with invalid organizer '{organizer}'&quot;, uid=self.uid, organizer=self.organizer)
</ins><span class="cx"> 
</span><span class="cx">             # Check SCHEDULE-AGENT and coerce SERVER to NONE
</span><span class="cx">             if self.calendar.getOrganizerScheduleAgent():
</span><span class="lines">@@ -1243,14 +1242,14 @@
</span><span class="cx">     def checkOrganizerScheduleAgent(self):
</span><span class="cx"> 
</span><span class="cx">         is_server = self.calendar.getOrganizerScheduleAgent()
</span><del>-        local_organizer = type(self.organizerAddress) in (LocalCalendarUser, PartitionedCalendarUser, OtherServerCalendarUser,)
</del><ins>+        local_organizer = type(self.organizerAddress) in (LocalCalendarUser, OtherServerCalendarUser,)
</ins><span class="cx"> 
</span><span class="cx">         if config.Scheduling.iMIP.Enabled and self.organizerAddress.cuaddr.lower().startswith(&quot;mailto:&quot;):
</span><span class="cx">             return is_server
</span><span class="cx"> 
</span><span class="cx">         if not config.Scheduling.iSchedule.Enabled and not local_organizer and is_server:
</span><span class="cx">             # Coerce ORGANIZER to SCHEDULE-AGENT=NONE
</span><del>-            log.debug(&quot;Attendee '%s' is not allowed to use SCHEDULE-AGENT=SERVER on organizer: UID:%s&quot; % (self.attendeePrincipal, self.uid,))
</del><ins>+            log.debug(&quot;Attendee '{attendee}' is not allowed to use SCHEDULE-AGENT=SERVER on organizer: UID:{uid}&quot;, attendee=self.attendeePrincipal, uid=self.uid)
</ins><span class="cx">             self.calendar.setParameterToValueForPropertyWithValue(&quot;SCHEDULE-AGENT&quot;, &quot;NONE&quot;, &quot;ORGANIZER&quot;, None)
</span><span class="cx">             self.calendar.setParameterToValueForPropertyWithValue(&quot;SCHEDULE-STATUS&quot;, iTIPRequestStatus.NO_USER_SUPPORT_CODE, &quot;ORGANIZER&quot;, None)
</span><span class="cx">             is_server = False
</span><span class="lines">@@ -1272,8 +1271,8 @@
</span><span class="cx">         calendar_resource = (yield getCalendarObjectForRecord(self.calendar_home.transaction(), self.organizerPrincipal, self.uid))
</span><span class="cx">         if calendar_resource is not None:
</span><span class="cx">             self.organizer_calendar = (yield calendar_resource.componentForUser())
</span><del>-        elif type(self.organizerAddress) in (PartitionedCalendarUser, OtherServerCalendarUser,):
-            # For partitioning where the organizer is on a different node, we will assume that the attendee's copy
</del><ins>+        elif type(self.organizerAddress) in (OtherServerCalendarUser,):
+            # For podding where the organizer is on a different node, we will assume that the attendee's copy
</ins><span class="cx">             # of the event is up to date and &quot;authoritative&quot;. So we pretend that is the organizer copy
</span><span class="cx">             self.organizer_calendar = self.oldcalendar
</span><span class="cx"> 
</span><span class="lines">@@ -1290,7 +1289,7 @@
</span><span class="cx">             oldcalendar = self.organizer_calendar
</span><span class="cx">             oldcalendar.attendeesView((self.attendee,), onlyScheduleAgentServer=True)
</span><span class="cx">             if oldcalendar.mainType() is None:
</span><del>-                log.debug(&quot;Implicit - attendee '%s' cannot use an event they are not an attendee of, UID: '%s'&quot; % (self.attendee, self.uid))
</del><ins>+                log.debug(&quot;Implicit - attendee '{attendee}' cannot use an event they are not an attendee of, UID: '{uid}'&quot;, attendee=self.attendee, uid=self.uid)
</ins><span class="cx">                 raise HTTPError(ErrorResponse(
</span><span class="cx">                     responsecode.FORBIDDEN,
</span><span class="cx">                     (caldav_namespace, &quot;valid-attendee-change&quot;),
</span><span class="lines">@@ -1339,7 +1338,7 @@
</span><span class="cx">         def _gotResponse(response):
</span><span class="cx">             self.handleSchedulingResponse(response, False)
</span><span class="cx"> 
</span><del>-        log.info(&quot;Implicit %s - attendee: '%s' to organizer: '%s', UID: '%s'&quot; % (action, self.attendee, self.organizer, self.uid,))
</del><ins>+        log.info(&quot;Implicit {action} - attendee: '{attendee}' to organizer: '{organizer}', UID: '{uid}'&quot;, action=action, attendee=self.attendee, organizer=self.organizer, uid=self.uid)
</ins><span class="cx">         d = scheduler.doSchedulingViaPUT(self.originator, (self.organizer,), itipmsg, internal_request=True)
</span><span class="cx">         d.addCallback(_gotResponse)
</span><span class="cx">         return d
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduledeliverypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/delivery.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/delivery.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/delivery.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -40,8 +40,7 @@
</span><span class="cx"> from twistedcaldav.ical import normalizeCUAddress, Component
</span><span class="cx"> from twistedcaldav.util import utf8String
</span><span class="cx"> 
</span><del>-from txdav.caldav.datastore.scheduling.cuaddress import PartitionedCalendarUser, RemoteCalendarUser, \
-    OtherServerCalendarUser
</del><ins>+from txdav.caldav.datastore.scheduling.cuaddress import RemoteCalendarUser, OtherServerCalendarUser
</ins><span class="cx"> from txdav.caldav.datastore.scheduling.delivery import DeliveryService
</span><span class="cx"> from txdav.caldav.datastore.scheduling.ischedule.dkim import DKIMRequest, DKIMUtils
</span><span class="cx"> from txdav.caldav.datastore.scheduling.ischedule.remoteservers import IScheduleServerRecord
</span><span class="lines">@@ -58,7 +57,7 @@
</span><span class="cx"> 
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> Handles the sending of iSchedule scheduling messages. Used for both cross-domain scheduling,
</span><del>-as well as internal partitioning or podding.
</del><ins>+as well as internal podding.
</ins><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> __all__ = [
</span><span class="lines">@@ -72,6 +71,7 @@
</span><span class="cx"> class ScheduleViaISchedule(DeliveryService):
</span><span class="cx"> 
</span><span class="cx">     domainServerMap = {}
</span><ins>+    servermgr = None
</ins><span class="cx"> 
</span><span class="cx">     @classmethod
</span><span class="cx">     def serviceType(cls):
</span><span class="lines">@@ -82,9 +82,7 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def matchCalendarUserAddress(cls, cuaddr):
</span><span class="cx"> 
</span><del>-        # TODO: here is where we would attempt service discovery based on the cuaddr.
-
-        # Only handle mailtos:
</del><ins>+        # Handle mailtos:
</ins><span class="cx">         if cuaddr.lower().startswith(&quot;mailto:&quot;):
</span><span class="cx">             domain = extractEmailDomain(cuaddr)
</span><span class="cx">             server = (yield cls.serverForDomain(domain))
</span><span class="lines">@@ -100,25 +98,30 @@
</span><span class="cx">     def serverForDomain(cls, domain):
</span><span class="cx">         if domain not in cls.domainServerMap:
</span><span class="cx"> 
</span><del>-            # First check built-in list of remote servers
-            servermgr = IScheduleServers()
-            server = servermgr.mapDomain(domain)
-            if server is not None:
-                cls.domainServerMap[domain] = server
-            else:
-                # Lookup domain
-                result = (yield lookupServerViaSRV(domain))
-                if result is None:
</del><ins>+            if config.Scheduling.iSchedule.Enabled:
+
+                # First check built-in list of remote servers
+                if cls.servermgr is None:
+                    cls.servermgr = IScheduleServers()
+                server = cls.servermgr.mapDomain(domain)
+                if server is not None:
+                    cls.domainServerMap[domain] = server
+                else:
</ins><span class="cx">                     # Lookup domain
</span><del>-                    result = (yield lookupServerViaSRV(domain, service=&quot;_ischedule&quot;))
</del><ins>+                    result = (yield lookupServerViaSRV(domain))
</ins><span class="cx">                     if result is None:
</span><del>-                        cls.domainServerMap[domain] = None
</del><ins>+                        # Lookup domain
+                        result = (yield lookupServerViaSRV(domain, service=&quot;_ischedule&quot;))
+                        if result is None:
+                            cls.domainServerMap[domain] = None
+                        else:
+                            # Create the iSchedule server record for this server
+                            cls.domainServerMap[domain] = IScheduleServerRecord(uri=&quot;http://%s:%s/.well-known/ischedule&quot; % result)
</ins><span class="cx">                     else:
</span><span class="cx">                         # Create the iSchedule server record for this server
</span><del>-                        cls.domainServerMap[domain] = IScheduleServerRecord(uri=&quot;http://%s:%s/.well-known/ischedule&quot; % result)
-                else:
-                    # Create the iSchedule server record for this server
-                    cls.domainServerMap[domain] = IScheduleServerRecord(uri=&quot;https://%s:%s/.well-known/ischedule&quot; % result)
</del><ins>+                        cls.domainServerMap[domain] = IScheduleServerRecord(uri=&quot;https://%s:%s/.well-known/ischedule&quot; % result)
+            else:
+                cls.domainServerMap[domain] = None
</ins><span class="cx"> 
</span><span class="cx">         returnValue(cls.domainServerMap[domain])
</span><span class="cx"> 
</span><span class="lines">@@ -136,8 +139,6 @@
</span><span class="cx">             if isinstance(recipient, RemoteCalendarUser):
</span><span class="cx">                 # Map the recipient's domain to a server
</span><span class="cx">                 server = (yield self.serverForDomain(recipient.domain))
</span><del>-            elif isinstance(recipient, PartitionedCalendarUser):
-                server = self._getServerForPartitionedUser(recipient)
</del><span class="cx">             elif isinstance(recipient, OtherServerCalendarUser):
</span><span class="cx">                 server = self._getServerForOtherServerUser(recipient)
</span><span class="cx">             else:
</span><span class="lines">@@ -182,20 +183,6 @@
</span><span class="cx">         yield DeferredList(deferreds)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def _getServerForPartitionedUser(self, recipient):
-
-        if not hasattr(self, &quot;partitionedServers&quot;):
-            self.partitionedServers = {}
-
-        partition = recipient.principal.partitionURI()
-        if partition not in self.partitionedServers:
-            self.partitionedServers[partition] = IScheduleServerRecord(uri=joinURL(partition, &quot;/ischedule&quot;))
-            self.partitionedServers[partition].unNormalizeAddresses = False
-            self.partitionedServers[partition].moreHeaders.append(recipient.principal.server().secretHeader())
-
-        return self.partitionedServers[partition]
-
-
</del><span class="cx">     def _getServerForOtherServerUser(self, recipient):
</span><span class="cx"> 
</span><span class="cx">         if not hasattr(self, &quot;otherServers&quot;):
</span><span class="lines">@@ -203,9 +190,12 @@
</span><span class="cx"> 
</span><span class="cx">         serverURI = recipient.principal.serverURI()
</span><span class="cx">         if serverURI not in self.otherServers:
</span><del>-            self.otherServers[serverURI] = IScheduleServerRecord(uri=joinURL(serverURI, &quot;/ischedule&quot;))
-            self.otherServers[serverURI].unNormalizeAddresses = not recipient.principal.server().isImplicit
-            self.otherServers[serverURI].moreHeaders.append(recipient.principal.server().secretHeader())
</del><ins>+            self.otherServers[serverURI] = IScheduleServerRecord(
+                uri=joinURL(serverURI, config.Servers.InboxName),
+                unNormalizeAddresses=not recipient.principal.server().isImplicit,
+                moreHeaders=[recipient.principal.server().secretHeader(), ],
+                podding=True,
+            )
</ins><span class="cx"> 
</span><span class="cx">         return self.otherServers[serverURI]
</span><span class="cx"> 
</span><span class="lines">@@ -222,6 +212,7 @@
</span><span class="cx">         self.refreshOnly = refreshOnly
</span><span class="cx">         self.headers = None
</span><span class="cx">         self.data = None
</span><ins>+        self.original_organizer = None
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -365,7 +356,8 @@
</span><span class="cx"> 
</span><span class="cx">         # The Originator must be the ORGANIZER (for a request) or ATTENDEE (for a reply)
</span><span class="cx">         originator = self.scheduler.organizer.cuaddr if self.scheduler.isiTIPRequest else self.scheduler.attendee
</span><del>-        originator = normalizeCUAddress(originator, normalizationLookup, self.scheduler.txn.directoryService().recordWithCalendarUserAddress, toUUID=False)
</del><ins>+        if self.server.unNormalizeAddresses:
+            originator = normalizeCUAddress(originator, normalizationLookup, self.scheduler.txn.directoryService().recordWithCalendarUserAddress, toUUID=False)
</ins><span class="cx">         self.headers.addRawHeader(&quot;Originator&quot;, utf8String(originator))
</span><span class="cx">         self.sign_headers.append(&quot;Originator&quot;)
</span><span class="cx"> 
</span><span class="lines">@@ -414,15 +406,15 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         if self.data is None:
</span><ins>+
</ins><span class="cx">             # Need to remap cuaddrs from urn:uuid
</span><del>-            if self.server.unNormalizeAddresses and self.scheduler.method == &quot;PUT&quot;:
-                normalizedCalendar = self.scheduler.calendar.duplicate()
</del><ins>+            normalizedCalendar = self.scheduler.calendar.duplicate()
+            self.original_organizer = normalizedCalendar.getOrganizer()
+            if self.server.unNormalizeAddresses:
</ins><span class="cx">                 normalizedCalendar.normalizeCalendarUserAddresses(
</span><span class="cx">                     normalizationLookup,
</span><span class="cx">                     self.scheduler.txn.directoryService().recordWithCalendarUserAddress,
</span><span class="cx">                     toUUID=False)
</span><del>-            else:
-                normalizedCalendar = self.scheduler.calendar
</del><span class="cx"> 
</span><span class="cx">             # For VFREEBUSY we need to strip out ATTENDEEs that do not match the recipient list
</span><span class="cx">             if self.scheduler.isfreebusy:
</span><span class="lines">@@ -445,13 +437,12 @@
</span><span class="cx">         f = Factory()
</span><span class="cx">         f.protocol = HTTPClientProtocol
</span><span class="cx">         if ssl:
</span><del>-            ep = GAIEndpoint(reactor, host, port,
-                             _configuredClientContextFactory())
</del><ins>+            ep = GAIEndpoint(reactor, host, port, _configuredClientContextFactory())
</ins><span class="cx">         else:
</span><span class="cx">             ep = GAIEndpoint(reactor, host, port)
</span><span class="cx">         proto = (yield ep.connect(f))
</span><span class="cx"> 
</span><del>-        if config.Scheduling.iSchedule.DKIM.Enabled:
</del><ins>+        if not self.server.podding() and config.Scheduling.iSchedule.DKIM.Enabled:
</ins><span class="cx">             domain, selector, key_file, algorithm, useDNSKey, useHTTPKey, usePrivateExchangeKey, expire = DKIMUtils.getConfiguration(config)
</span><span class="cx">             request = DKIMRequest(
</span><span class="cx">                 &quot;POST&quot;,
</span><span class="lines">@@ -503,6 +494,14 @@
</span><span class="cx">             calendar_data = response.childOfType(CalendarData)
</span><span class="cx">             if calendar_data:
</span><span class="cx">                 calendar_data = str(calendar_data)
</span><ins>+                if self.server.unNormalizeAddresses and self.original_organizer is not None:
+                    # Need to restore original ORGANIZER value if it got unnormalized
+                    calendar = Component.fromString(calendar_data)
+                    organizers = calendar.getAllPropertiesInAnyComponent(&quot;ORGANIZER&quot;, depth=1)
+                    for organizer in organizers:
+                        organizer.setValue(self.original_organizer)
+                    calendar_data = str(calendar)
+
</ins><span class="cx">             error = response.childOfType(Error)
</span><span class="cx">             if error:
</span><span class="cx">                 error = error.children
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischedulelocalserverspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/localservers.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/localservers.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/localservers.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -31,18 +31,12 @@
</span><span class="cx"> the principals across the whole domain need to be able to directly schedule each other and know of each others
</span><span class="cx"> existence. A common scenario would be a production server and a development/test server.
</span><span class="cx"> 
</span><del>-Each server is identified by an id and url. The id is used when assigning principals to a specific server. Each
-server can also support multiple partitions, and each of those is identified by an id and url, with the id also
-being used to assign principals to a specific partition.
</del><ins>+Each server is identified by an id and url. The id is used when assigning principals to a specific server.
</ins><span class="cx"> 
</span><del>-These servers support the concept of &quot;partitioning&quot; and &quot;podding&quot;.
</del><ins>+These servers support the concept of &quot;podding&quot;.
</ins><span class="cx"> 
</span><del>-A &quot;partitioned&quot; service is one that spreads its
-users out across multiple stores and does reverse proxying of incoming requests to the appropriate partitioned host.
-All servers within the same partition have to be running the same version of the software etc.
-
</del><span class="cx"> A &quot;podded&quot; service is one where different groups of users are hosted on different servers, which may be of
</span><del>-different versions etc. A &quot;pod&quot; may itself be &quot;partitioned&quot;, but the partitioning is &quot;invisible&quot; to the outside world.
</del><ins>+different versions etc.
</ins><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> __all__ = [
</span><span class="lines">@@ -104,13 +98,31 @@
</span><span class="cx">     def getThisServer(self):
</span><span class="cx">         return self._thisServer
</span><span class="cx"> 
</span><ins>+
+    def installReverseProxies(self, maxClients):
+        &quot;&quot;&quot;
+        Install a reverse proxy for each of the other servers in the &quot;pod&quot;.
+
+        @param maxClients: maximum number of clients in the pool.
+        @type maxClients: C{int}
+        &quot;&quot;&quot;
+
+        for server in self._servers.values():
+            if server.thisServer:
+                continue
+            installPool(
+                server.id,
+                server.uri,
+                maxClients,
+            )
+
</ins><span class="cx"> Servers = ServersDB()   # Global server DB
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class Server(object):
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    Represents a server which may itself be partitioned.
</del><ins>+    Represents a server.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     def __init__(self):
</span><span class="lines">@@ -120,8 +132,6 @@
</span><span class="cx">         self.ips = set()
</span><span class="cx">         self.allowed_from_ips = set()
</span><span class="cx">         self.shared_secret = None
</span><del>-        self.partitions = {}
-        self.partitions_ips = set()
</del><span class="cx">         self.isImplicit = True
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -164,25 +174,12 @@
</span><span class="cx">                 actual_ips.add(item)
</span><span class="cx">         self.allowed_from_ips = actual_ips
</span><span class="cx"> 
</span><del>-        for uri in self.partitions.values():
-            parsed_uri = urlparse.urlparse(uri)
-            try:
-                ips = getIPsFromHost(parsed_uri.hostname)
-            except socket.gaierror, e:
-                msg = &quot;Unable to lookup ip-addr for partition '%s': %s&quot; % (parsed_uri.hostname, str(e))
-                log.error(msg)
-                if ignoreIPLookupFailures:
-                    ips = ()
-                else:
-                    raise ValueError(msg)
-            self.partitions_ips.update(ips)
</del><span class="cx"> 
</span><del>-
</del><span class="cx">     def checkThisIP(self, ip):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        Check that the passed in IP address corresponds to this server or one of its partitions.
</del><ins>+        Check that the passed in IP address corresponds to this server.
</ins><span class="cx">         &quot;&quot;&quot;
</span><del>-        return (ip in self.ips) or (ip in self.partitions_ips)
</del><ins>+        return (ip in self.ips)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def hasAllowedFromIP(self):
</span><span class="lines">@@ -218,38 +215,13 @@
</span><span class="cx">         return (SERVER_SECRET_HEADER, self.shared_secret,)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def addPartition(self, id, uri):
-        self.partitions[id] = uri
</del><span class="cx"> 
</span><del>-
-    def getPartitionURIForId(self, id):
-        return self.partitions.get(id)
-
-
-    def isPartitioned(self):
-        return len(self.partitions) != 0
-
-
-    def installReverseProxies(self, ownUID, maxClients):
-
-        for partition, url in self.partitions.iteritems():
-            if partition != ownUID:
-                installPool(
-                    partition,
-                    url,
-                    maxClients,
-                )
-
-
-
</del><span class="cx"> ELEMENT_SERVERS = &quot;servers&quot;
</span><span class="cx"> ELEMENT_SERVER = &quot;server&quot;
</span><span class="cx"> ELEMENT_ID = &quot;id&quot;
</span><span class="cx"> ELEMENT_URI = &quot;uri&quot;
</span><span class="cx"> ELEMENT_ALLOWED_FROM = &quot;allowed-from&quot;
</span><span class="cx"> ELEMENT_SHARED_SECRET = &quot;shared-secret&quot;
</span><del>-ELEMENT_PARTITIONS = &quot;partitions&quot;
-ELEMENT_PARTITION = &quot;partition&quot;
</del><span class="cx"> ATTR_IMPLICIT = &quot;implicit&quot;
</span><span class="cx"> ATTR_VALUE_YES = &quot;yes&quot;
</span><span class="cx"> ATTR_VALUE_NO = &quot;no&quot;
</span><span class="lines">@@ -286,39 +258,13 @@
</span><span class="cx">                     server.allowed_from_ips.add(node.text)
</span><span class="cx">                 elif node.tag == ELEMENT_SHARED_SECRET:
</span><span class="cx">                     server.shared_secret = node.text
</span><del>-                elif node.tag == ELEMENT_PARTITIONS:
-                    ServersParser._parsePartition(xmlFile, node, server)
</del><span class="cx">                 else:
</span><span class="cx">                     raise RuntimeError(&quot;Invalid element '%s' in servers file: '%s'&quot; % (node.tag, xmlFile,))
</span><span class="cx"> 
</span><span class="cx">             if server.id is None or server.uri is None:
</span><del>-                raise RuntimeError(&quot;Invalid partition '%s' in servers file: '%s'&quot; % (child.tag, xmlFile,))
</del><ins>+                raise RuntimeError(&quot;Invalid server '%s' in servers file: '%s'&quot; % (child.tag, xmlFile,))
</ins><span class="cx"> 
</span><span class="cx">             server.check(ignoreIPLookupFailures=ignoreIPLookupFailures)
</span><span class="cx">             results[server.id] = server
</span><span class="cx"> 
</span><span class="cx">         return results
</span><del>-
-
-    @staticmethod
-    def _parsePartition(xmlFile, partitions, server):
-
-        for child in partitions:
-
-            if child.tag != ELEMENT_PARTITION:
-                raise RuntimeError(&quot;Unknown partition type: '%s' in servers file: '%s'&quot; % (child.tag, xmlFile,))
-
-            id = None
-            uri = None
-            for node in child:
-                if node.tag == ELEMENT_ID:
-                    id = node.text
-                elif node.tag == ELEMENT_URI:
-                    uri = node.text
-                else:
-                    raise RuntimeError(&quot;Invalid element '%s' in augment file: '%s'&quot; % (node.tag, xmlFile,))
-
-            if id is None or uri is None:
-                raise RuntimeError(&quot;Invalid partition '%s' in servers file: '%s'&quot; % (child.tag, xmlFile,))
-
-            server.addPartition(id, uri)
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduleremoteserverspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/remoteservers.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/remoteservers.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/remoteservers.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -23,7 +23,7 @@
</span><span class="cx"> 
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> XML based iSchedule configuration file handling. This is for handling of remote servers. The localservers.py module
</span><del>-handles servers that are local (partitioned or podded).
</del><ins>+handles servers that are local (podded).
</ins><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx"> __all__ = [
</span><span class="lines">@@ -138,7 +138,7 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Contains server-to-server details.
</span><span class="cx">     &quot;&quot;&quot;
</span><del>-    def __init__(self, uri=None):
</del><ins>+    def __init__(self, uri=None, unNormalizeAddresses=True, moreHeaders=[], podding=False):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param recordType: record type for directory entry.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -148,8 +148,9 @@
</span><span class="cx">         self.allow_to = True
</span><span class="cx">         self.domains = []
</span><span class="cx">         self.client_hosts = []
</span><del>-        self.unNormalizeAddresses = True
-        self.moreHeaders = []
</del><ins>+        self.unNormalizeAddresses = unNormalizeAddresses
+        self.moreHeaders = moreHeaders
+        self._podding = podding
</ins><span class="cx"> 
</span><span class="cx">         if uri:
</span><span class="cx">             self.uri = uri
</span><span class="lines">@@ -160,6 +161,10 @@
</span><span class="cx">         return (self.ssl, self.host, self.port, self.path,)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def podding(self):
+        return self._podding
+
+
</ins><span class="cx">     def redirect(self, location):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Permanent redirect for the lifetime of this record.
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduleresourcepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/resource.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/resource.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/resource.py        2013-12-14 06:28:16 UTC (rev 12110)
</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.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twext.web2 import responsecode
</span><span class="cx"> from twext.web2.dav.http import ErrorResponse
</span><span class="lines">@@ -52,7 +52,7 @@
</span><span class="cx">     Extends L{DAVResource} to provide iSchedule inbox functionality.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def __init__(self, parent, store):
</del><ins>+    def __init__(self, parent, store, podding=False):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param parent: the parent resource of this one.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -62,6 +62,7 @@
</span><span class="cx"> 
</span><span class="cx">         self.parent = parent
</span><span class="cx">         self._newStore = store
</span><ins>+        self._podding = podding
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def deadProperties(self):
</span><span class="lines">@@ -109,12 +110,12 @@
</span><span class="cx">     def render(self, request):
</span><span class="cx">         output = &quot;&quot;&quot;&lt;html&gt;
</span><span class="cx"> &lt;head&gt;
</span><del>-&lt;title&gt;Server To Server Inbox Resource&lt;/title&gt;
</del><ins>+&lt;title&gt;%(rtype)s Inbox Resource&lt;/title&gt;
</ins><span class="cx"> &lt;/head&gt;
</span><span class="cx"> &lt;body&gt;
</span><del>-&lt;h1&gt;Server To Server Inbox Resource.&lt;/h1&gt;
</del><ins>+&lt;h1&gt;%(rtype)s Inbox Resource.&lt;/h1&gt;
</ins><span class="cx"> &lt;/body
</span><del>-&lt;/html&gt;&quot;&quot;&quot;
</del><ins>+&lt;/html&gt;&quot;&quot;&quot; % {&quot;rtype&quot; : &quot;Podding&quot; if self._podding else &quot;iSchedule&quot;, }
</ins><span class="cx"> 
</span><span class="cx">         response = Response(200, {}, output)
</span><span class="cx">         response.headers.setHeader(&quot;content-type&quot;, MimeType(&quot;text&quot;, &quot;html&quot;))
</span><span class="lines">@@ -126,7 +127,7 @@
</span><span class="cx">         The iSchedule GET method.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        if not request.args:
</del><ins>+        if not request.args or self._podding:
</ins><span class="cx">             # Do normal GET behavior
</span><span class="cx">             return self.render(request)
</span><span class="cx"> 
</span><span class="lines">@@ -157,12 +158,26 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         # Determine min/max date-time for iSchedule
</span><del>-        now = PyCalendarDateTime.getNowUTC()
-        minDateTime = PyCalendarDateTime(now.getYear(), 1, 1, 0, 0, 0, PyCalendarTimezone(utc=True))
</del><ins>+        now = DateTime.getNowUTC()
+        minDateTime = DateTime(now.getYear(), 1, 1, 0, 0, 0, Timezone(utc=True))
</ins><span class="cx">         minDateTime.offsetYear(-1)
</span><del>-        maxDateTime = PyCalendarDateTime(now.getYear(), 1, 1, 0, 0, 0, PyCalendarTimezone(utc=True))
</del><ins>+        maxDateTime = DateTime(now.getYear(), 1, 1, 0, 0, 0, Timezone(utc=True))
</ins><span class="cx">         maxDateTime.offsetYear(10)
</span><span class="cx"> 
</span><ins>+        dataTypes = []
+        dataTypes.append(
+            ischedulexml.CalendarDataType(**{
+                &quot;content-type&quot;: &quot;text/calendar&quot;,
+                &quot;version&quot;: &quot;2.0&quot;,
+            })
+        )
+        if config.EnableJSONData:
+            dataTypes.append(
+                ischedulexml.CalendarDataType(**{
+                    &quot;content-type&quot;: &quot;application/calendar+json&quot;,
+                    &quot;version&quot;: &quot;2.0&quot;,
+                })
+            )
</ins><span class="cx">         result = ischedulexml.QueryResult(
</span><span class="cx"> 
</span><span class="cx">             ischedulexml.Capabilities(
</span><span class="lines">@@ -188,12 +203,7 @@
</span><span class="cx">                         name=&quot;VFREEBUSY&quot;
</span><span class="cx">                     ),
</span><span class="cx">                 ),
</span><del>-                ischedulexml.CalendarDataTypes(
-                    ischedulexml.CalendarDataType(**{
-                            &quot;content-type&quot;: &quot;text/calendar&quot;,
-                            &quot;version&quot;: &quot;2.0&quot;,
-                    }),
-                ),
</del><ins>+                ischedulexml.CalendarDataTypes(*dataTypes),
</ins><span class="cx">                 ischedulexml.Attachments(
</span><span class="cx">                     ischedulexml.External(),
</span><span class="cx">                 ),
</span><span class="lines">@@ -220,26 +230,51 @@
</span><span class="cx">         txn = transactionFromRequest(request, self._newStore)
</span><span class="cx"> 
</span><span class="cx">         # This is a server-to-server scheduling operation.
</span><del>-        scheduler = IScheduleScheduler(txn, None)
</del><ins>+        scheduler = IScheduleScheduler(txn, None, podding=self._podding)
</ins><span class="cx"> 
</span><ins>+        # Check content first
+        contentType = request.headers.getHeader(&quot;content-type&quot;)
+        format = self.determineType(contentType)
+
+        if format is None:
+            msg = &quot;MIME type %s not allowed in iSchedule request&quot; % (contentType,)
+            self.log.error(msg)
+            raise HTTPError(scheduler.errorResponse(
+                responsecode.FORBIDDEN,
+                (ischedule_namespace, &quot;invalid-calendar-data-type&quot;),
+                msg,
+            ))
+
</ins><span class="cx">         originator = self.loadOriginatorFromRequestHeaders(request)
</span><span class="cx">         recipients = self.loadRecipientsFromRequestHeaders(request)
</span><span class="cx">         body = (yield allDataFromStream(request.stream))
</span><ins>+        calendar = Component.fromString(body, format=format)
</ins><span class="cx"> 
</span><span class="cx">         # Do the POST processing treating this as a non-local schedule
</span><span class="cx">         try:
</span><del>-            result = (yield scheduler.doSchedulingViaPOST(request.remoteAddr, request.headers, body, originator, recipients))
</del><ins>+            result = (yield scheduler.doSchedulingViaPOST(request.remoteAddr, request.headers, body, calendar, originator, recipients))
</ins><span class="cx">         except Exception:
</span><span class="cx">             ex = Failure()
</span><span class="cx">             yield txn.abort()
</span><span class="cx">             ex.raiseException()
</span><span class="cx">         else:
</span><span class="cx">             yield txn.commit()
</span><del>-        response = result.response()
-        response.headers.addRawHeader(ISCHEDULE_CAPABILITIES, str(config.Scheduling.iSchedule.SerialNumber))
</del><ins>+        response = result.response(format=format)
+        if not self._podding:
+            response.headers.addRawHeader(ISCHEDULE_CAPABILITIES, str(config.Scheduling.iSchedule.SerialNumber))
</ins><span class="cx">         returnValue(response)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def determineType(self, content_type):
+        &quot;&quot;&quot;
+        Determine if the supplied content-type is valid for storing and return the matching PyCalendar type.
+        &quot;&quot;&quot;
+        format = None
+        if content_type is not None:
+            format = &quot;%s/%s&quot; % (content_type.mediaType, content_type.mediaSubtype,)
+        return format if format in Component.allowedTypes() else None
+
+
</ins><span class="cx">     def loadOriginatorFromRequestHeaders(self, request):
</span><span class="cx">         # Must have Originator header
</span><span class="cx">         originator = request.headers.getRawHeaders(&quot;originator&quot;)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduleschedulerpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/scheduler.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/scheduler.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/scheduler.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -23,7 +23,7 @@
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, returnValue
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav.config import config
</span><del>-from twistedcaldav.ical import normalizeCUAddress, Component
</del><ins>+from twistedcaldav.ical import normalizeCUAddress
</ins><span class="cx"> 
</span><span class="cx"> from txdav.caldav.datastore.scheduling import addressmapping
</span><span class="cx"> from txdav.caldav.datastore.scheduling.cuaddress import RemoteCalendarUser
</span><span class="lines">@@ -119,6 +119,9 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class IScheduleScheduler(RemoteScheduler):
</span><ins>+    &quot;&quot;&quot;
+    Handles iSchedule and podding requests.
+    &quot;&quot;&quot;
</ins><span class="cx"> 
</span><span class="cx">     scheduleResponse = IScheduleResponseQueue
</span><span class="cx"> 
</span><span class="lines">@@ -138,8 +141,13 @@
</span><span class="cx">         &quot;max-recipients&quot;: (ischedule_namespace, &quot;max-recipients&quot;),
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    def __init__(self, txn, originator_uid, logItems=None, noAttendeeRefresh=False, podding=False):
+        super(IScheduleScheduler, self).__init__(txn, originator_uid, logItems=logItems, noAttendeeRefresh=noAttendeeRefresh)
+        self._podding = podding
+
+
</ins><span class="cx">     @inlineCallbacks
</span><del>-    def doSchedulingViaPOST(self, remoteAddr, headers, body, originator, recipients):
</del><ins>+    def doSchedulingViaPOST(self, remoteAddr, headers, body, calendar, originator, recipients):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Carry out iSchedule specific processing.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -148,7 +156,7 @@
</span><span class="cx">         self.headers = headers
</span><span class="cx">         self.verified = False
</span><span class="cx"> 
</span><del>-        if config.Scheduling.iSchedule.DKIM.Enabled:
</del><ins>+        if not self._podding and config.Scheduling.iSchedule.DKIM.Enabled:
</ins><span class="cx">             verifier = DKIMVerifier(self.headers, body, protocol_debug=config.Scheduling.iSchedule.DKIM.ProtocolDebug)
</span><span class="cx">             try:
</span><span class="cx">                 yield verifier.verify()
</span><span class="lines">@@ -172,13 +180,16 @@
</span><span class="cx">                     msg,
</span><span class="cx">                 ))
</span><span class="cx"> 
</span><del>-        calendar = Component.fromString(body)
-
-        if self.headers.getRawHeaders('x-calendarserver-itip-refreshonly', (&quot;F&quot;))[0] == &quot;T&quot;:
</del><ins>+        if self._podding and self.headers.getRawHeaders('x-calendarserver-itip-refreshonly', (&quot;F&quot;))[0] == &quot;T&quot;:
</ins><span class="cx">             self.txn.doing_attendee_refresh = 1
</span><span class="cx"> 
</span><span class="cx">         # Normalize recipient addresses
</span><del>-        recipients = [normalizeCUAddress(recipient, normalizationLookup, self.txn.directoryService().recordWithCalendarUserAddress) for recipient in recipients]
</del><ins>+        results = []
+        for recipient in recipients:
+            normalized = normalizeCUAddress(recipient, normalizationLookup, self.txn.directoryService().recordWithCalendarUserAddress)
+            self.recipientsNormalizationMap[normalized] = recipient
+            results.append(normalized)
+        recipients = results
</ins><span class="cx"> 
</span><span class="cx">         result = (yield super(IScheduleScheduler, self).doSchedulingViaPOST(originator, recipients, calendar))
</span><span class="cx">         returnValue(result)
</span><span class="lines">@@ -218,7 +229,7 @@
</span><span class="cx">         originatorPrincipal = self.txn.directoryService().recordWithCalendarUserAddress(self.originator)
</span><span class="cx">         localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(self.originator))
</span><span class="cx">         if originatorPrincipal or localUser:
</span><del>-            if originatorPrincipal.locallyHosted():
</del><ins>+            if originatorPrincipal.thisServer():
</ins><span class="cx">                 log.error(&quot;Cannot use originator that is on this server: %s&quot; % (self.originator,))
</span><span class="cx">                 raise HTTPError(self.errorResponse(
</span><span class="cx">                     responsecode.FORBIDDEN,
</span><span class="lines">@@ -296,23 +307,17 @@
</span><span class="cx"> 
</span><span class="cx">     def _validAlternateServer(self, principal):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        Check the validity of the partitioned host.
</del><ins>+        Check the validity of the podded host.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        # Extract expected host/port. This will be the partitionURI, or if no partitions,
-        # the serverURI
-        expected_uri = principal.partitionURI()
-        if expected_uri is None:
-            expected_uri = principal.serverURI()
</del><ins>+        # Extract expected host/port. This will be the serverURI.
+        expected_uri = principal.serverURI()
</ins><span class="cx">         expected_uri = urlparse.urlparse(expected_uri)
</span><span class="cx"> 
</span><span class="cx">         # Get the request IP and map to hostname.
</span><span class="cx">         clientip = self.remoteAddr.host
</span><span class="cx"> 
</span><del>-        # Check against this server (or any of its partitions). We need this because an external iTIP message
-        # may be addressed to users on different partitions, and the node receiving the iTIP message will need to
-        # forward it to the partition nodes, thus the client ip seen by the partitions will in fact be the initial
-        # receiving node.
</del><ins>+        # Check against this server.
</ins><span class="cx">         matched = False
</span><span class="cx">         if Servers.getThisServer().checkThisIP(clientip):
</span><span class="cx">             matched = True
</span><span class="lines">@@ -364,7 +369,7 @@
</span><span class="cx">         if organizer:
</span><span class="cx">             organizerPrincipal = self.txn.directoryService().recordWithCalendarUserAddress(organizer)
</span><span class="cx">             if organizerPrincipal:
</span><del>-                if organizerPrincipal.locallyHosted():
</del><ins>+                if organizerPrincipal.thisServer():
</ins><span class="cx">                     log.error(&quot;Invalid ORGANIZER in calendar data: %s&quot; % (self.calendar,))
</span><span class="cx">                     raise HTTPError(self.errorResponse(
</span><span class="cx">                         responsecode.FORBIDDEN,
</span><span class="lines">@@ -372,7 +377,7 @@
</span><span class="cx">                         &quot;Organizer is not local to server&quot;,
</span><span class="cx">                     ))
</span><span class="cx">                 else:
</span><del>-                    # Check that the origin server is the correct partition
</del><ins>+                    # Check that the origin server is the correct pod
</ins><span class="cx">                     self.organizer = calendarUserFromPrincipal(organizer, organizerPrincipal)
</span><span class="cx">                     self._validAlternateServer(self.organizer.principal)
</span><span class="cx">             else:
</span><span class="lines">@@ -405,7 +410,7 @@
</span><span class="cx">         # Attendee cannot be local.
</span><span class="cx">         attendeePrincipal = self.txn.directoryService().recordWithCalendarUserAddress(self.attendee)
</span><span class="cx">         if attendeePrincipal:
</span><del>-            if attendeePrincipal.locallyHosted():
</del><ins>+            if attendeePrincipal.thisServer():
</ins><span class="cx">                 log.error(&quot;Invalid ATTENDEE in calendar data: %s&quot; % (self.calendar,))
</span><span class="cx">                 raise HTTPError(self.errorResponse(
</span><span class="cx">                     responsecode.FORBIDDEN,
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduletesttest_deliverypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_delivery.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_delivery.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_delivery.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx">         Make sure we do an exact comparison on EmailDomain
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><ins>+        self.patch(config.Scheduling.iSchedule, &quot;Enabled&quot;, True)
</ins><span class="cx">         self.patch(config.Scheduling.iSchedule, &quot;RemoteServers&quot;, &quot;&quot;)
</span><span class="cx"> 
</span><span class="cx">         # Only mailtos:
</span><span class="lines">@@ -64,3 +65,9 @@
</span><span class="cx">         self.assertFalse(result)
</span><span class="cx">         result = yield ScheduleViaISchedule.matchCalendarUserAddress(&quot;mailto:user&quot;)
</span><span class="cx">         self.assertFalse(result)
</span><ins>+
+        # Test when not enabled
+        ScheduleViaISchedule.domainServerMap = {}
+        self.patch(config.Scheduling.iSchedule, &quot;Enabled&quot;, False)
+        result = yield ScheduleViaISchedule.matchCalendarUserAddress(&quot;mailto:user@example.com&quot;)
+        self.assertFalse(result)
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduletesttest_localserverspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_localservers.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_localservers.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_localservers.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -37,16 +37,6 @@
</span><span class="cx">   &lt;server&gt;
</span><span class="cx">     &lt;id&gt;00002&lt;/id&gt;
</span><span class="cx">     &lt;uri&gt;https://caldav2.example.com:8843&lt;/uri&gt;
</span><del>-    &lt;partitions&gt;
-        &lt;partition&gt;
-            &lt;id&gt;A&lt;/id&gt;
-            &lt;uri&gt;https://machine1.example.com:8443&lt;/uri&gt;
-        &lt;/partition&gt;
-        &lt;partition&gt;
-            &lt;id&gt;B&lt;/id&gt;
-            &lt;uri&gt;https://machine2.example.com:8443&lt;/uri&gt;
-        &lt;/partition&gt;
-    &lt;/partitions&gt;
</del><span class="cx">   &lt;/server&gt;
</span><span class="cx"> &lt;/servers&gt;
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="lines">@@ -62,16 +52,6 @@
</span><span class="cx">   &lt;server&gt;
</span><span class="cx">     &lt;id&gt;00002&lt;/id&gt;
</span><span class="cx">     &lt;uri&gt;https://caldav2.example.com:8843&lt;/uri&gt;
</span><del>-    &lt;partitions&gt;
-        &lt;partition&gt;
-            &lt;id&gt;A&lt;/id&gt;
-            &lt;uri&gt;https://machine1.example.com:8443&lt;/uri&gt;
-        &lt;/partition&gt;
-        &lt;partition&gt;
-            &lt;id&gt;B&lt;/id&gt;
-            &lt;uri&gt;https://machine2.example.com:8443&lt;/uri&gt;
-        &lt;/partition&gt;
-    &lt;/partitions&gt;
</del><span class="cx">   &lt;/server&gt;
</span><span class="cx"> &lt;/servers&gt;
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="lines">@@ -103,13 +83,7 @@
</span><span class="cx">         self.assertEqual(servers.getServerById(&quot;00001&quot;).shared_secret, &quot;foobar&quot;)
</span><span class="cx">         self.assertEqual(servers.getServerById(&quot;00002&quot;).shared_secret, None)
</span><span class="cx"> 
</span><del>-        self.assertEqual(len(servers.getServerById(&quot;00001&quot;).partitions), 0)
-        self.assertEqual(len(servers.getServerById(&quot;00002&quot;).partitions), 2)
</del><span class="cx"> 
</span><del>-        self.assertEqual(servers.getServerById(&quot;00002&quot;).getPartitionURIForId(&quot;A&quot;), &quot;https://machine1.example.com:8443&quot;)
-        self.assertEqual(servers.getServerById(&quot;00002&quot;).getPartitionURIForId(&quot;B&quot;), &quot;https://machine2.example.com:8443&quot;)
-
-
</del><span class="cx">     def test_this_server(self):
</span><span class="cx"> 
</span><span class="cx">         servers = self._setupServers()
</span><span class="lines">@@ -129,14 +103,6 @@
</span><span class="cx">         self.assertTrue(servers.getServerById(&quot;00002&quot;).thisServer)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def test_check_is_partitioned(self):
-
-        servers = self._setupServers()
-
-        self.assertFalse(servers.getServerById(&quot;00001&quot;).isPartitioned())
-        self.assertTrue(servers.getServerById(&quot;00002&quot;).isPartitioned())
-
-
</del><span class="cx">     def test_check_this_ip(self):
</span><span class="cx"> 
</span><span class="cx">         servers = self._setupServers()
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingischeduletesttest_resourcepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_resource.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_resource.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/ischedule/test/test_resource.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -94,6 +94,7 @@
</span><span class="cx">             headers=http_headers.Headers(rawHeaders={
</span><span class="cx">                 &quot;Originator&quot;: (&quot;mailto:wsanchez@example.com&quot;,),
</span><span class="cx">                 &quot;Recipient&quot;: (&quot;mailto:cdaboo@example.com&quot;,),
</span><ins>+                &quot;Content-Type&quot;: &quot;text/calendar&quot;,
</ins><span class="cx">             }),
</span><span class="cx">             content=&quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> CALSCALE:GREGORIAN
</span><span class="lines">@@ -144,6 +145,7 @@
</span><span class="cx">             headers=http_headers.Headers(rawHeaders={
</span><span class="cx">                 &quot;Originator&quot;: (&quot;mailto:user01@example.org&quot;,),
</span><span class="cx">                 &quot;Recipient&quot;: (&quot;mailto:user02@example.com&quot;,),
</span><ins>+                &quot;Content-Type&quot;: (&quot;text/calendar&quot;,)
</ins><span class="cx">             }),
</span><span class="cx">             content=&quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> CALSCALE:GREGORIAN
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingitippy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/itip.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/itip.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/itip.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> from twistedcaldav.ical import Property, iCalendarProductID, Component, \
</span><span class="cx">     ignoredComponents
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -402,9 +402,14 @@
</span><span class="cx">     @staticmethod
</span><span class="cx">     def updateAttendeeData(from_component, to_component):
</span><span class="cx">         &quot;&quot;&quot;
</span><ins>+        Called when processing a REPLY only.
+
</ins><span class="cx">         Copy the PARTSTAT of the Attendee in the from_component to the matching ATTENDEE
</span><span class="cx">         in the to_component. Ignore if no match found. Also update the private comments.
</span><span class="cx"> 
</span><ins>+        For VPOLL we need to copy POLL-ITEM-ID response values into the actual matching
+        polled sub-components as VOTER properties.
+
</ins><span class="cx">         @param from_component: component to copy from
</span><span class="cx">         @type from_component: L{Component}
</span><span class="cx">         @param to_component: component to copy to
</span><span class="lines">@@ -423,7 +428,7 @@
</span><span class="cx">             reqstatus = &quot;2.0&quot;
</span><span class="cx"> 
</span><span class="cx">         # Get attendee in from_component - there MUST be only one
</span><del>-        attendees = tuple(from_component.properties(&quot;ATTENDEE&quot;))
</del><ins>+        attendees = tuple(from_component.properties(from_component.recipientPropertyName()))
</ins><span class="cx">         if len(attendees) != 1:
</span><span class="cx">             log.error(&quot;There must be one and only one ATTENDEE property in a REPLY\n%s&quot; % (str(from_component),))
</span><span class="cx">             return None, False, False
</span><span class="lines">@@ -471,16 +476,9 @@
</span><span class="cx">                 pass
</span><span class="cx"> 
</span><span class="cx">             elif attendee_comment is None and private_comment is not None:
</span><del>-                # Remove all property parameters
-                private_comment.removeAllParameters()
</del><ins>+                # We now remove the private comment on the organizer's side if the attendee removed it
+                to_component.removeProperty(private_comment)
</ins><span class="cx"> 
</span><del>-                # Add default parameters
-                private_comment.setParameter(&quot;X-CALENDARSERVER-ATTENDEE-REF&quot;, attendee.value())
-                private_comment.setParameter(&quot;X-CALENDARSERVER-DTSTAMP&quot;, PyCalendarDateTime.getNowUTC().getText())
-
-                # Set value empty
-                private_comment.setValue(&quot;&quot;)
-
</del><span class="cx">                 private_comment_changed = True
</span><span class="cx"> 
</span><span class="cx">             elif attendee_comment is not None and private_comment is None:
</span><span class="lines">@@ -491,7 +489,7 @@
</span><span class="cx">                     attendee_comment.value(),
</span><span class="cx">                     params={
</span><span class="cx">                         &quot;X-CALENDARSERVER-ATTENDEE-REF&quot;: attendee.value(),
</span><del>-                        &quot;X-CALENDARSERVER-DTSTAMP&quot;: PyCalendarDateTime.getNowUTC().getText(),
</del><ins>+                        &quot;X-CALENDARSERVER-DTSTAMP&quot;: DateTime.getNowUTC().getText(),
</ins><span class="cx">                     }
</span><span class="cx">                 )
</span><span class="cx">                 to_component.addProperty(private_comment)
</span><span class="lines">@@ -506,17 +504,60 @@
</span><span class="cx"> 
</span><span class="cx">                     # Add default parameters
</span><span class="cx">                     private_comment.setParameter(&quot;X-CALENDARSERVER-ATTENDEE-REF&quot;, attendee.value())
</span><del>-                    private_comment.setParameter(&quot;X-CALENDARSERVER-DTSTAMP&quot;, PyCalendarDateTime.getNowUTC().getText())
</del><ins>+                    private_comment.setParameter(&quot;X-CALENDARSERVER-DTSTAMP&quot;, DateTime.getNowUTC().getText())
</ins><span class="cx"> 
</span><span class="cx">                     # Set new value
</span><span class="cx">                     private_comment.setValue(attendee_comment.value())
</span><span class="cx"> 
</span><span class="cx">                     private_comment_changed = True
</span><span class="cx"> 
</span><ins>+            # Do VPOLL transfer
+            if from_component.name() == &quot;VPOLL&quot;:
+                # TODO: figure out how to report changes back
+                iTipProcessing.updateVPOLLData(from_component, to_component, attendee)
+
</ins><span class="cx">         return attendee.value(), partstat_changed, private_comment_changed
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><ins>+    def updateVPOLLData(from_component, to_component, attendee):
+        &quot;&quot;&quot;
+        Update VPOLL sub-components with voter's response.
+
+        @param from_component: component to copy from
+        @type from_component: L{Component}
+        @param to_component: component to copy to
+        @type to_component: L{Component}
+        @param attendee: attendee being processed
+        @type attendee: L{Property}
+        &quot;&quot;&quot;
+
+        responses = {}
+        for prop in from_component.properties(&quot;POLL-ITEM-ID&quot;):
+            responses[prop.value()] = prop
+
+        for component in to_component.subcomponents():
+            if component.name() in ignoredComponents:
+                continue
+            poll_item_id = component.propertyValue(&quot;POLL-ITEM-ID&quot;)
+            if poll_item_id is None:
+                continue
+            voter = component.getVoterProperty((attendee.value(),))
+
+            # If no response - remove
+            if poll_item_id not in responses or not responses[poll_item_id].hasParameter(&quot;RESPONSE&quot;):
+                if voter is not None:
+                    component.removeProperty(voter)
+                continue
+
+            # Add or update voter
+            if voter is None:
+                voter = Property(&quot;VOTER&quot;, attendee.value())
+                component.addProperty(voter)
+            voter.setParameter(&quot;RESPONSE&quot;, responses[poll_item_id].parameterValue(&quot;RESPONSE&quot;))
+
+
+    @staticmethod
</ins><span class="cx">     def transferItems(from_calendar, to_component, master_valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient, remove_matched=False):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Transfer properties from a calendar to a component by first trying to match the component in the original calendar and
</span><span class="lines">@@ -854,7 +895,7 @@
</span><span class="cx">         itip.filterComponents(changedRids)
</span><span class="cx"> 
</span><span class="cx">         # Force update to DTSTAMP everywhere so reply sequencing will work
</span><del>-        itip.replacePropertyInAllComponents(Property(&quot;DTSTAMP&quot;, PyCalendarDateTime.getNowUTC()))
</del><ins>+        itip.replacePropertyInAllComponents(Property(&quot;DTSTAMP&quot;, DateTime.getNowUTC()))
</ins><span class="cx"> 
</span><span class="cx">         # Remove all attendees except the one we want
</span><span class="cx">         itip.removeAllButOneAttendee(attendee)
</span><span class="lines">@@ -884,6 +925,7 @@
</span><span class="cx">             &quot;EXDATE&quot;,
</span><span class="cx">             &quot;ORGANIZER&quot;,
</span><span class="cx">             &quot;ATTENDEE&quot;,
</span><ins>+            &quot;VOTER&quot;,
</ins><span class="cx">             &quot;X-CALENDARSERVER-PRIVATE-COMMENT&quot;,
</span><span class="cx">             &quot;SUMMARY&quot;,
</span><span class="cx">             &quot;LOCATION&quot;,
</span><span class="lines">@@ -903,10 +945,38 @@
</span><span class="cx">         # Strip out unwanted bits
</span><span class="cx">         iTipGenerator.prepareSchedulingMessage(itip, reply=True)
</span><span class="cx"> 
</span><ins>+        # Handle VPOLL behavior
+        for component in itip.subcomponents():
+            if component.name() == &quot;VPOLL&quot;:
+                iTipGenerator.generateVPOLLReply(component, attendee)
+
</ins><span class="cx">         return itip
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><ins>+    def generateVPOLLReply(vpoll, attendee):
+        &quot;&quot;&quot;
+        Generate the proper poll response in a reply for each component being voted on.
+
+        @param vpoll: the VPOLL component to process
+        @type vpoll: L{Component}
+        @param attendee: calendar user address of attendee replying
+        @type attendee: C{str}
+        &quot;&quot;&quot;
+
+        for component in tuple(vpoll.subcomponents()):
+            if component.name() in ignoredComponents:
+                continue
+            poll_item_id = component.propertyValue(&quot;POLL-ITEM-ID&quot;)
+            if poll_item_id is None:
+                continue
+            voter = component.getVoterProperty((attendee,))
+            if voter is not None and voter.hasParameter(&quot;RESPONSE&quot;):
+                vpoll.addProperty(Property(&quot;POLL-ITEM-ID&quot;, poll_item_id, {&quot;RESPONSE&quot;: voter.parameterValue(&quot;RESPONSE&quot;)}))
+            vpoll.removeComponent(component)
+
+
+    @staticmethod
</ins><span class="cx">     def prepareSchedulingMessage(itip, reply=False):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Remove properties and parameters that should not be sent in an iTIP message
</span><span class="lines">@@ -932,6 +1002,7 @@
</span><span class="cx"> 
</span><span class="cx">         # Property Parameters
</span><span class="cx">         itip.removePropertyParameters(&quot;ATTENDEE&quot;, (&quot;SCHEDULE-AGENT&quot;, &quot;SCHEDULE-STATUS&quot;, &quot;SCHEDULE-FORCE-SEND&quot;, &quot;X-CALENDARSERVER-DTSTAMP&quot;,))
</span><ins>+        itip.removePropertyParameters(&quot;VOTER&quot;, (&quot;SCHEDULE-AGENT&quot;, &quot;SCHEDULE-STATUS&quot;, &quot;SCHEDULE-FORCE-SEND&quot;, &quot;X-CALENDARSERVER-DTSTAMP&quot;,))
</ins><span class="cx">         itip.removePropertyParameters(&quot;ORGANIZER&quot;, (&quot;SCHEDULE-AGENT&quot;, &quot;SCHEDULE-STATUS&quot;, &quot;SCHEDULE-FORCE-SEND&quot;,))
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingprocessingpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/processing.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/processing.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/processing.py        2013-12-14 06:28:16 UTC (rev 12110)
</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.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx"> from twext.web2.dav.method.report import NumberOfMatchesWithinLimits
</span><span class="lines">@@ -785,13 +785,13 @@
</span><span class="cx">         cuas = self.recipient.principal.calendarUserAddresses
</span><span class="cx"> 
</span><span class="cx">         # First expand current one to get instances (only go 1 year into the future)
</span><del>-        default_future_expansion_duration = PyCalendarDuration(days=config.Scheduling.Options.AutoSchedule.FutureFreeBusyDays)
-        expand_max = PyCalendarDateTime.getToday() + default_future_expansion_duration
</del><ins>+        default_future_expansion_duration = Duration(days=config.Scheduling.Options.AutoSchedule.FutureFreeBusyDays)
+        expand_max = DateTime.getToday() + default_future_expansion_duration
</ins><span class="cx">         instances = calendar.expandTimeRanges(expand_max, ignoreInvalidInstances=True)
</span><span class="cx"> 
</span><span class="cx">         # We are going to ignore auto-accept processing for anything more than a day old (actually use -2 days
</span><span class="cx">         # to add some slop to account for possible timezone offsets)
</span><del>-        min_date = PyCalendarDateTime.getToday()
</del><ins>+        min_date = DateTime.getToday()
</ins><span class="cx">         min_date.offsetDay(-2)
</span><span class="cx">         allOld = True
</span><span class="cx"> 
</span><span class="lines">@@ -824,7 +824,7 @@
</span><span class="cx">             # Get the timezone property from the collection, and store in the query filter
</span><span class="cx">             # for use during the query itself.
</span><span class="cx">             tz = testcal.getTimezone()
</span><del>-            tzinfo = tz.gettimezone() if tz is not None else PyCalendarTimezone(utc=True)
</del><ins>+            tzinfo = tz.gettimezone() if tz is not None else Timezone(utc=True)
</ins><span class="cx"> 
</span><span class="cx">             # Now do search for overlapping time-range and set instance.free based
</span><span class="cx">             # on whether there is an overlap or not
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingschedulerpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/scheduler.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/scheduler.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/scheduler.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -38,11 +38,12 @@
</span><span class="cx"> from txdav.caldav.datastore.scheduling.cuaddress import LocalCalendarUser
</span><span class="cx"> from txdav.caldav.datastore.scheduling.cuaddress import RemoteCalendarUser
</span><span class="cx"> from txdav.caldav.datastore.scheduling.cuaddress import EmailCalendarUser
</span><del>-from txdav.caldav.datastore.scheduling.cuaddress import PartitionedCalendarUser
</del><span class="cx"> from txdav.caldav.datastore.scheduling.imip.delivery import ScheduleViaIMip
</span><span class="cx"> from txdav.caldav.datastore.scheduling.ischedule.delivery import ScheduleViaISchedule
</span><span class="cx"> from txdav.caldav.datastore.scheduling.itip import iTIPRequestStatus
</span><ins>+
</ins><span class="cx"> import hashlib
</span><ins>+from collections import namedtuple
</ins><span class="cx"> 
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> CalDAV/Server-to-Server scheduling behavior.
</span><span class="lines">@@ -50,8 +51,8 @@
</span><span class="cx"> This module handles the delivery of scheduling messages to organizer and attendees. The basic idea is to first
</span><span class="cx"> confirm the integrity of the incoming scheduling message, check authorization. Appropriate L{DeliveryService}s
</span><span class="cx"> are then used to deliver the message to attendees or organizer. Delivery responses are processed and returned.
</span><del>-This takes into account partitioning and podding of users by detecting the appropriate host for a calendar
-user and then dispatching the delivery accordingly.
</del><ins>+This takes into account podding of users by detecting the appropriate host for a calendar user and then
+dispatching the delivery accordingly.
</ins><span class="cx"> 
</span><span class="cx"> The L{Scheduler} class defines the basic behavior for processing deliveries. Sub-classes are defined for the
</span><span class="cx"> different ways a deliver can be triggered.
</span><span class="lines">@@ -142,6 +143,7 @@
</span><span class="cx"> 
</span><span class="cx">         self.originator = None
</span><span class="cx">         self.recipients = None
</span><ins>+        self.recipientsNormalizationMap = {}
</ins><span class="cx">         self.calendar = None
</span><span class="cx">         self.organizer = None
</span><span class="cx">         self.attendee = None
</span><span class="lines">@@ -232,51 +234,6 @@
</span><span class="cx">         returnValue(result)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    @inlineCallbacks
-    def loadFromRequestData(self):
-        self.loadOriginatorFromRequestDetails()
-        self.loadRecipientsFromCalendarData()
-
-
-    def loadOriginatorFromRequestDetails(self):
-        # Get the originator who is the authenticated user
-        originatorPrincipal = self.txn.directoryService().recordWithUID(self.originator_uid)
-
-        # Pick the canonical CUA:
-        originator = originatorPrincipal.canonicalCalendarUserAddress() if originatorPrincipal else &quot;&quot;
-
-        if not originator:
-            log.error(&quot;%s request must have Originator&quot; % (self.method,))
-            raise HTTPError(self.errorResponse(
-                responsecode.FORBIDDEN,
-                self.errorElements[&quot;originator-missing&quot;],
-                &quot;Missing originator&quot;,
-            ))
-        else:
-            self.originator = originator
-
-
-    def loadRecipientsFromCalendarData(self):
-
-        # Get the ATTENDEEs
-        attendees = list()
-        unique_set = set()
-        for attendee, _ignore in self.calendar.getAttendeesByInstance():
-            if attendee not in unique_set:
-                attendees.append(attendee)
-                unique_set.add(attendee)
-
-        if not attendees:
-            log.error(&quot;%s request must have at least one Recipient&quot; % (self.method,))
-            raise HTTPError(self.errorResponse(
-                responsecode.FORBIDDEN,
-                self.errorElements[&quot;recipient-missing&quot;],
-                &quot;Must have recipients&quot;,
-            ))
-        else:
-            self.recipients = list(attendees)
-
-
</del><span class="cx">     def preProcessCalendarData(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         After loading calendar data from the request, do some optional processing of it. This method will be
</span><span class="lines">@@ -474,11 +431,10 @@
</span><span class="cx">         freebusy = self.checkForFreeBusy()
</span><span class="cx"> 
</span><span class="cx">         # Prepare for multiple responses
</span><del>-        responses = self.scheduleResponse(self.method, responsecode.OK)
</del><ins>+        responses = self.scheduleResponse(self.method, responsecode.OK, self.mapRecipientAddress)
</ins><span class="cx"> 
</span><span class="cx">         # Loop over each recipient and aggregate into lists by service types.
</span><span class="cx">         caldav_recipients = []
</span><del>-        partitioned_recipients = []
</del><span class="cx">         otherserver_recipients = []
</span><span class="cx">         remote_recipients = []
</span><span class="cx">         imip_recipients = []
</span><span class="lines">@@ -500,9 +456,6 @@
</span><span class="cx">             elif isinstance(recipient, LocalCalendarUser):
</span><span class="cx">                 caldav_recipients.append(recipient)
</span><span class="cx"> 
</span><del>-            elif isinstance(recipient, PartitionedCalendarUser):
-                partitioned_recipients.append(recipient)
-
</del><span class="cx">             elif isinstance(recipient, OtherServerCalendarUser):
</span><span class="cx">                 otherserver_recipients.append(recipient)
</span><span class="cx"> 
</span><span class="lines">@@ -524,10 +477,6 @@
</span><span class="cx">         if caldav_recipients:
</span><span class="cx">             yield self.generateLocalSchedulingResponses(caldav_recipients, responses, freebusy)
</span><span class="cx"> 
</span><del>-        # Now process partitioned recipients
-        if partitioned_recipients:
-            yield self.generateRemoteSchedulingResponses(partitioned_recipients, responses, freebusy, getattr(self.txn, 'doing_attendee_refresh', False))
-
</del><span class="cx">         # Now process other server recipients
</span><span class="cx">         if otherserver_recipients:
</span><span class="cx">             yield self.generateRemoteSchedulingResponses(otherserver_recipients, responses, freebusy, getattr(self.txn, 'doing_attendee_refresh', False))
</span><span class="lines">@@ -577,7 +526,11 @@
</span><span class="cx">         return requestor.generateSchedulingResponses()
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def mapRecipientAddress(self, cuaddr):
+        return self.recipientsNormalizationMap.get(cuaddr, cuaddr)
</ins><span class="cx"> 
</span><ins>+
+
</ins><span class="cx"> class RemoteScheduler(Scheduler):
</span><span class="cx"> 
</span><span class="cx">     def checkOrganizer(self):
</span><span class="lines">@@ -612,8 +565,8 @@
</span><span class="cx">             else:
</span><span class="cx">                 # Map recipient to their inbox
</span><span class="cx">                 inbox = None
</span><del>-                if principal.calendarsEnabled() and principal.thisServer():
-                    if principal.locallyHosted():
</del><ins>+                if principal.calendarsEnabled():
+                    if principal.thisServer():
</ins><span class="cx">                         recipient_home = yield self.txn.calendarHomeWithUID(principal.uid, create=True)
</span><span class="cx">                         if recipient_home:
</span><span class="cx">                             inbox = (yield recipient_home.calendarWithName(&quot;inbox&quot;))
</span><span class="lines">@@ -703,7 +656,12 @@
</span><span class="cx">     response_description_element = davxml.ResponseDescription
</span><span class="cx">     calendar_data_element = caldavxml.CalendarData
</span><span class="cx"> 
</span><del>-    def __init__(self, method, success_response):
</del><ins>+    ScheduleResonseDetails = namedtuple(
+        &quot;ScheduleResonseDetails&quot;,
+        [&quot;recipient&quot;, &quot;reqstatus&quot;, &quot;calendar&quot;, &quot;error&quot;, &quot;message&quot;, ]
+    )
+
+    def __init__(self, method, success_response, recipient_mapper=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         @param method: the name of the method generating the queue.
</span><span class="cx">         @param success_response: the response to return in lieu of a
</span><span class="lines">@@ -712,6 +670,7 @@
</span><span class="cx">         self.responses = []
</span><span class="cx">         self.method = method
</span><span class="cx">         self.success_response = success_response
</span><ins>+        self.recipient_mapper = recipient_mapper
</ins><span class="cx">         self.location = None
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -745,19 +704,20 @@
</span><span class="cx">         else:
</span><span class="cx">             raise AssertionError(&quot;Unknown data type: %r&quot; % (what,))
</span><span class="cx"> 
</span><ins>+        if self.recipient_mapper is not None:
+            recipient = self.recipient_mapper(recipient)
+
</ins><span class="cx">         if not suppressErrorLog and code &gt; 400: # Error codes only
</span><span class="cx">             self.log.error(&quot;Error during %s for %s: %s&quot; % (self.method, recipient, message))
</span><span class="cx"> 
</span><del>-        children = []
-        children.append(self.recipient_element(davxml.HRef.fromString(recipient)) if self.recipient_uses_href else self.recipient_element.fromString(recipient))
-        children.append(self.request_status_element(reqstatus))
-        if calendar is not None:
-            children.append(self.calendar_data_element.fromCalendar(calendar))
-        if error is not None:
-            children.append(error)
-        if message is not None:
-            children.append(self.response_description_element(message))
-        self.responses.append(self.response_element(*children))
</del><ins>+        details = ScheduleResponseQueue.ScheduleResonseDetails(
+            self.recipient_element(davxml.HRef.fromString(recipient)) if self.recipient_uses_href else self.recipient_element.fromString(recipient),
+            self.request_status_element(reqstatus),
+            calendar,
+            error,
+            self.response_description_element(message) if message is not None else None,
+        )
+        self.responses.append(details)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def errorForFailure(self, failure):
</span><span class="lines">@@ -773,19 +733,17 @@
</span><span class="cx">         @param clone: the response to clone.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        children = []
-        children.append(self.recipient_element(davxml.HRef.fromString(recipient)) if self.recipient_uses_href else self.recipient_element.fromString(recipient))
-        children.append(self.request_status_element.fromString(request_status))
-        if calendar_data is not None:
-            children.append(self.calendar_data_element.fromCalendar(calendar_data))
-        if error is not None:
-            children.append(self.error_element(*error))
-        if desc is not None:
-            children.append(self.response_description_element.fromString(desc))
-        self.responses.append(self.response_element(*children))
</del><ins>+        details = ScheduleResponseQueue.ScheduleResonseDetails(
+            self.recipient_element(davxml.HRef.fromString(recipient)) if self.recipient_uses_href else self.recipient_element.fromString(recipient),
+            self.request_status_element.fromString(request_status),
+            calendar_data,
+            self.error_element(*error) if error is not None else None,
+            self.response_description_element.fromString(desc) if desc is not None else None,
+        )
+        self.responses.append(details)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def response(self):
</del><ins>+    def response(self, format=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Generate a L{ScheduleResponseResponse} with the responses contained in the
</span><span class="cx">         queue or, if no such responses, return the C{success_response} provided
</span><span class="lines">@@ -793,6 +751,20 @@
</span><span class="cx">         @return: the response.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         if self.responses:
</span><del>-            return ScheduleResponseResponse(self.schedule_response_element, self.responses, self.location)
</del><ins>+            # Convert our queue to all XML elements
+            xml_responses = []
+            for response in self.responses:
+                children = []
+                children.append(response.recipient)
+                children.append(response.reqstatus)
+                if response.calendar is not None:
+                    children.append(self.calendar_data_element.fromCalendar(response.calendar, format))
+                if response.error is not None:
+                    children.append(response.error)
+                if response.message is not None:
+                    children.append(response.message)
+                xml_responses.append(self.response_element(*children))
+
+            return ScheduleResponseResponse(self.schedule_response_element, xml_responses, self.location)
</ins><span class="cx">         else:
</span><span class="cx">             return self.success_response
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingtesttest_freebusypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_freebusy.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_freebusy.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_freebusy.py        2013-12-14 06:28:16 UTC (rev 12110)
</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.datetime import PyCalendarDateTime
-from pycalendar.period import PyCalendarPeriod
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.period import Period
</ins><span class="cx"> 
</span><span class="cx"> from twext.python.clsprop import classproperty
</span><span class="cx"> 
</span><span class="lines">@@ -94,7 +94,7 @@
</span><span class="cx">             (
</span><span class="cx">                 &quot;#1.3 With single busy time&quot;,
</span><span class="cx">                 [
</span><del>-                    [PyCalendarPeriod.parseText(&quot;20080601T120000Z/20080601T130000Z&quot;), ],
</del><ins>+                    [Period.parseText(&quot;20080601T120000Z/20080601T130000Z&quot;), ],
</ins><span class="cx">                     [],
</span><span class="cx">                     [],
</span><span class="cx">                 ],
</span><span class="lines">@@ -120,8 +120,8 @@
</span><span class="cx">                 &quot;#1.4 With multiple busy time&quot;,
</span><span class="cx">                 [
</span><span class="cx">                     [
</span><del>-                        PyCalendarPeriod.parseText(&quot;20080601T120000Z/20080601T130000Z&quot;),
-                        PyCalendarPeriod.parseText(&quot;20080601T140000Z/20080601T150000Z&quot;),
</del><ins>+                        Period.parseText(&quot;20080601T120000Z/20080601T130000Z&quot;),
+                        Period.parseText(&quot;20080601T140000Z/20080601T150000Z&quot;),
</ins><span class="cx">                     ],
</span><span class="cx">                     [],
</span><span class="cx">                     [],
</span><span class="lines">@@ -148,10 +148,10 @@
</span><span class="cx">                 &quot;#1.5 With multiple busy time, some overlap&quot;,
</span><span class="cx">                 [
</span><span class="cx">                     [
</span><del>-                        PyCalendarPeriod.parseText(&quot;20080601T120000Z/20080601T130000Z&quot;),
-                        PyCalendarPeriod.parseText(&quot;20080601T123000Z/20080601T133000Z&quot;),
-                        PyCalendarPeriod.parseText(&quot;20080601T140000Z/20080601T150000Z&quot;),
-                        PyCalendarPeriod.parseText(&quot;20080601T150000Z/20080601T160000Z&quot;),
</del><ins>+                        Period.parseText(&quot;20080601T120000Z/20080601T130000Z&quot;),
+                        Period.parseText(&quot;20080601T123000Z/20080601T133000Z&quot;),
+                        Period.parseText(&quot;20080601T140000Z/20080601T150000Z&quot;),
+                        Period.parseText(&quot;20080601T150000Z/20080601T160000Z&quot;),
</ins><span class="cx">                     ],
</span><span class="cx">                     [],
</span><span class="cx">                     [],
</span><span class="lines">@@ -178,14 +178,14 @@
</span><span class="cx">                 &quot;#1.6 With all busy time types&quot;,
</span><span class="cx">                 [
</span><span class="cx">                     [
</span><del>-                        PyCalendarPeriod.parseText(&quot;20080601T120000Z/20080601T130000Z&quot;),
-                        PyCalendarPeriod.parseText(&quot;20080601T140000Z/20080601T150000Z&quot;),
</del><ins>+                        Period.parseText(&quot;20080601T120000Z/20080601T130000Z&quot;),
+                        Period.parseText(&quot;20080601T140000Z/20080601T150000Z&quot;),
</ins><span class="cx">                     ],
</span><span class="cx">                     [
</span><del>-                        PyCalendarPeriod.parseText(&quot;20080601T140000Z/20080601T150000Z&quot;),
</del><ins>+                        Period.parseText(&quot;20080601T140000Z/20080601T150000Z&quot;),
</ins><span class="cx">                     ],
</span><span class="cx">                     [
</span><del>-                        PyCalendarPeriod.parseText(&quot;20080601T160000Z/20080601T170000Z&quot;),
</del><ins>+                        Period.parseText(&quot;20080601T160000Z/20080601T170000Z&quot;),
</ins><span class="cx">                     ],
</span><span class="cx">                 ],
</span><span class="cx">                 &quot;20080601T000000Z&quot;,
</span><span class="lines">@@ -211,7 +211,7 @@
</span><span class="cx">             (
</span><span class="cx">                 &quot;#1.7 With single busy time and event details&quot;,
</span><span class="cx">                 [
</span><del>-                    [PyCalendarPeriod.parseText(&quot;20080601T120000Z/20080601T130000Z&quot;), ],
</del><ins>+                    [Period.parseText(&quot;20080601T120000Z/20080601T130000Z&quot;), ],
</ins><span class="cx">                     [],
</span><span class="cx">                     [],
</span><span class="cx">                 ],
</span><span class="lines">@@ -269,7 +269,7 @@
</span><span class="cx">         self._sqlCalendarStore = yield buildCalendarStore(self, self.notifierFactory)
</span><span class="cx">         yield self.populate()
</span><span class="cx"> 
</span><del>-        self.now = PyCalendarDateTime.getNowUTC()
</del><ins>+        self.now = DateTime.getNowUTC()
</ins><span class="cx">         self.now.setHHMMSS(0, 0, 0)
</span><span class="cx"> 
</span><span class="cx">         self.now_12H = self.now.duplicate()
</span><span class="lines">@@ -368,7 +368,7 @@
</span><span class="cx">         timerange = caldavxml.TimeRange(start=self.now.getText(), end=self.now_1D.getText())
</span><span class="cx">         result = (yield generateFreeBusyInfo(calendar, fbinfo, timerange, matchtotal))
</span><span class="cx">         self.assertEqual(result, 1)
</span><del>-        self.assertEqual(fbinfo[0], [PyCalendarPeriod.parseText(&quot;%s/%s&quot; % (self.now_12H.getText(), self.now_13H.getText(),)), ])
</del><ins>+        self.assertEqual(fbinfo[0], [Period.parseText(&quot;%s/%s&quot; % (self.now_12H.getText(), self.now_13H.getText(),)), ])
</ins><span class="cx">         self.assertEqual(len(fbinfo[1]), 0)
</span><span class="cx">         self.assertEqual(len(fbinfo[2]), 0)
</span><span class="cx"> 
</span><span class="lines">@@ -406,7 +406,7 @@
</span><span class="cx">             event_details=event_details
</span><span class="cx">         ))
</span><span class="cx">         self.assertEqual(result, 1)
</span><del>-        self.assertEqual(fbinfo[0], [PyCalendarPeriod.parseText(&quot;%s/%s&quot; % (self.now_12H.getText(), self.now_13H.getText(),)), ])
</del><ins>+        self.assertEqual(fbinfo[0], [Period.parseText(&quot;%s/%s&quot; % (self.now_12H.getText(), self.now_13H.getText(),)), ])
</ins><span class="cx">         self.assertEqual(len(fbinfo[1]), 0)
</span><span class="cx">         self.assertEqual(len(fbinfo[2]), 0)
</span><span class="cx">         self.assertEqual(len(event_details), 1)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingtesttest_icalsplitterpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_icalsplitter.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_icalsplitter.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_icalsplitter.py        2013-12-14 06:28:16 UTC (rev 12110)
</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.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> from twisted.trial import unittest
</span><span class="cx"> from twistedcaldav.stdconfig import config
</span><span class="cx"> from twistedcaldav.ical import Component
</span><span class="lines">@@ -31,7 +31,7 @@
</span><span class="cx"> 
</span><span class="cx">         self.subs = {}
</span><span class="cx"> 
</span><del>-        self.now = PyCalendarDateTime.getNowUTC()
</del><ins>+        self.now = DateTime.getNowUTC()
</ins><span class="cx">         self.now.setHHMMSS(0, 0, 0)
</span><span class="cx"> 
</span><span class="cx">         self.subs[&quot;now&quot;] = self.now
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingtesttest_implicitpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_implicit.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_implicit.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_implicit.py        2013-12-14 06:28:16 UTC (rev 12110)
</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.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twext.python.clsprop import classproperty
</span><span class="cx"> from twext.web2 import responsecode
</span><span class="lines">@@ -248,9 +248,9 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    (&quot;mailto:user1@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user2@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+                    (&quot;mailto:user1@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user2@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user3@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">                 ),
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -287,12 +287,12 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    (&quot;mailto:user1@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user2@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user1@example.com&quot;, PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user2@example.com&quot;, PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+                    (&quot;mailto:user1@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user2@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user3@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user1@example.com&quot;, DateTime(2008, 9, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user2@example.com&quot;, DateTime(2008, 9, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user3@example.com&quot;, DateTime(2008, 9, 1, 12, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">                 ),
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -330,15 +330,15 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    (&quot;mailto:user1@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user2@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user1@example.com&quot;, PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user2@example.com&quot;, PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2008, 9, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user1@example.com&quot;, PyCalendarDateTime(2008, 12, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user2@example.com&quot;, PyCalendarDateTime(2008, 12, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2008, 12, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+                    (&quot;mailto:user1@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user2@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user3@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user1@example.com&quot;, DateTime(2008, 9, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user2@example.com&quot;, DateTime(2008, 9, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user3@example.com&quot;, DateTime(2008, 9, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user1@example.com&quot;, DateTime(2008, 12, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user2@example.com&quot;, DateTime(2008, 12, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user3@example.com&quot;, DateTime(2008, 12, 1, 12, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">                 ),
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -447,7 +447,7 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (&quot;mailto:user3@example.com&quot;, None),
</span><del>-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+                    (&quot;mailto:user3@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">                 ),
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -502,7 +502,7 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+                    (&quot;mailto:user3@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">                 ),
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -648,9 +648,9 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    (&quot;mailto:user1@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user2@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user3@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+                    (&quot;mailto:user1@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user2@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user3@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">                 ),
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -705,7 +705,7 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><span class="cx">                     (&quot;mailto:user3@example.com&quot;, None),
</span><del>-                    (&quot;mailto:user4@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+                    (&quot;mailto:user4@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">                 ),
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -751,7 +751,7 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    (&quot;mailto:user4@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+                    (&quot;mailto:user4@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">                 ),
</span><span class="cx">             ),
</span><span class="cx">             (
</span><span class="lines">@@ -798,9 +798,9 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (
</span><del>-                    (&quot;mailto:user1@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user2@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
-                    (&quot;mailto:user4@example.com&quot;, PyCalendarDateTime(2008, 8, 1, 12, 0, 0, tzid=PyCalendarTimezone(utc=True))),
</del><ins>+                    (&quot;mailto:user1@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user2@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
+                    (&quot;mailto:user4@example.com&quot;, DateTime(2008, 8, 1, 12, 0, 0, tzid=Timezone(utc=True))),
</ins><span class="cx">                 ),
</span><span class="cx">             ),
</span><span class="cx">         )
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingtesttest_itippy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_itip.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_itip.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_itip.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -15,8 +15,8 @@
</span><span class="cx"> ##
</span><span class="cx"> from __future__ import print_function
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twisted.trial import unittest
</span><span class="cx"> 
</span><span class="lines">@@ -2025,7 +2025,7 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (&quot;mailto:user2@example.com&quot;,),
</span><del>-                (PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),),
</del><ins>+                (DateTime(2008, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),),
</ins><span class="cx">             ),
</span><span class="cx"> 
</span><span class="cx">             # Recurring component with one instance, each with one attendee - cancel instance
</span><span class="lines">@@ -2066,7 +2066,7 @@
</span><span class="cx"> END:VCALENDAR
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 (&quot;mailto:user2@example.com&quot;,),
</span><del>-                (PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),),
</del><ins>+                (DateTime(2008, 11, 14, 0, 0, 0, tzid=Timezone(utc=True)),),
</ins><span class="cx">             ),
</span><span class="cx"> 
</span><span class="cx">             # Recurring component with one instance, each with one attendee - cancel master
</span><span class="lines">@@ -2127,7 +2127,7 @@
</span><span class="cx"> &quot;&quot;&quot;,
</span><span class="cx">                 &quot;&quot;,
</span><span class="cx">                 (&quot;mailto:user2@example.com&quot;,),
</span><del>-                (PyCalendarDateTime(2008, 12, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),),
</del><ins>+                (DateTime(2008, 12, 14, 0, 0, 0, tzid=Timezone(utc=True)),),
</ins><span class="cx">             ),
</span><span class="cx"> 
</span><span class="cx">         )
</span><span class="lines">@@ -2229,7 +2229,8 @@
</span><span class="cx"> DTSTART;TZID=America/Los_Angeles:20101007T113000
</span><span class="cx"> DTEND;TZID=America/Los_Angeles:20101007T120000
</span><span class="cx"> ATTENDEE;CN=Missing Attendee;CUTYPE=INDIVIDUAL;EMAIL=missing@example.com;P
</span><del>- ARTSTAT=DECLINED;ROLE=OPT-PARTICIPANT;RSVP=TRUE:mailto:missing@example.com
</del><ins>+ ARTSTAT=DECLINED;ROLE=OPT-PARTICIPANT;RSVP=TRUE:mailto:missing@example.co
+ m
</ins><span class="cx"> ORGANIZER;CN=The Organizer:mailto:organizer@example.com
</span><span class="cx"> REQUEST-STATUS:2.0;Success
</span><span class="cx"> SEQUENCE:24
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingtesttest_utilspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_utils.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_utils.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/test/test_utils.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> Tests for calendarserver.tools.purge
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks
</span><span class="cx"> from twisted.trial import unittest
</span><span class="lines">@@ -30,7 +30,7 @@
</span><span class="cx"> from txdav.common.datastore.test.util import populateCalendarsFrom, CommonCommonTests
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-now = PyCalendarDateTime.getToday().getYear()
</del><ins>+now = DateTime.getToday().getYear()
</ins><span class="cx"> 
</span><span class="cx"> ORGANIZER_ICS = &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreschedulingutilspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/utils.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/utils.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/scheduling/utils.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -29,7 +29,7 @@
</span><span class="cx">     one of them to avoid scheduling problems.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    if record and record.locallyHosted():
</del><ins>+    if record and record.thisServer():
</ins><span class="cx">         # Get record's calendar-home
</span><span class="cx">         calendar_home = yield txn.calendarHomeWithUID(record.uid)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/sql.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/sql.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/sql.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -47,7 +47,7 @@
</span><span class="cx"> from twisted.internet.defer import inlineCallbacks, returnValue, succeed
</span><span class="cx"> from twisted.python import hashlib
</span><span class="cx"> 
</span><del>-from twistedcaldav import caldavxml, customxml
</del><ins>+from twistedcaldav import caldavxml, customxml, ical
</ins><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
</span><span class="cx"> from twistedcaldav.dateops import normalizeForIndex, datetimeMktime, \
</span><span class="lines">@@ -89,11 +89,13 @@
</span><span class="cx">     InvalidUIDError, UIDExistsError, UIDExistsElsewhereError, \
</span><span class="cx">     InvalidResourceMove, InvalidComponentForStoreError
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
-from pycalendar.timezone import PyCalendarTimezone
-from pycalendar.value import PyCalendarValue
</del><ins>+from txdav.idav import ChangeCategory
</ins><span class="cx"> 
</span><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
+from pycalendar.timezone import Timezone
+from pycalendar.value import Value
+
</ins><span class="cx"> from zope.interface.declarations import implements
</span><span class="cx"> 
</span><span class="cx"> from urlparse import urlparse, urlunparse
</span><span class="lines">@@ -406,6 +408,26 @@
</span><span class="cx"> 
</span><span class="cx">     _cacher = Memcacher(&quot;SQL.calhome&quot;, pickle=True, key_normalization=False)
</span><span class="cx"> 
</span><ins>+    _componentCalendarName = {
+        &quot;VEVENT&quot;: &quot;calendar&quot;,
+        &quot;VTODO&quot;: &quot;tasks&quot;,
+        &quot;VJOURNAL&quot;: &quot;journals&quot;,
+        &quot;VAVAILABILITY&quot;: &quot;available&quot;,
+        &quot;VPOLL&quot;: &quot;polls&quot;,
+    }
+
+    _componentDefaultColumn = {
+        &quot;VEVENT&quot;: schema.CALENDAR_HOME_METADATA.DEFAULT_EVENTS,
+        &quot;VTODO&quot;: schema.CALENDAR_HOME_METADATA.DEFAULT_TASKS,
+        &quot;VPOLL&quot;: schema.CALENDAR_HOME_METADATA.DEFAULT_POLLS,
+    }
+
+    _componentDefaultAttribute = {
+        &quot;VEVENT&quot;: &quot;_default_events&quot;,
+        &quot;VTODO&quot;: &quot;_default_tasks&quot;,
+        &quot;VPOLL&quot;: &quot;_default_polls&quot;,
+    }
+
</ins><span class="cx">     def __init__(self, transaction, ownerUID):
</span><span class="cx"> 
</span><span class="cx">         self._childClass = Calendar
</span><span class="lines">@@ -422,9 +444,8 @@
</span><span class="cx"> 
</span><span class="cx">         # Common behavior is to have created and modified
</span><span class="cx"> 
</span><del>-        return (
-            cls._homeMetaDataSchema.DEFAULT_EVENTS,
-            cls._homeMetaDataSchema.DEFAULT_TASKS,
</del><ins>+        default_collections = tuple([cls._componentDefaultColumn[name] for name in sorted(cls._componentDefaultColumn.keys())])
+        return default_collections + (
</ins><span class="cx">             cls._homeMetaDataSchema.ALARM_VEVENT_TIMED,
</span><span class="cx">             cls._homeMetaDataSchema.ALARM_VEVENT_ALLDAY,
</span><span class="cx">             cls._homeMetaDataSchema.ALARM_VTODO_TIMED,
</span><span class="lines">@@ -445,9 +466,8 @@
</span><span class="cx"> 
</span><span class="cx">         # Common behavior is to have created and modified
</span><span class="cx"> 
</span><del>-        return (
-            &quot;_default_events&quot;,
-            &quot;_default_tasks&quot;,
</del><ins>+        default_attributes = tuple([cls._componentDefaultAttribute[name] for name in sorted(cls._componentDefaultAttribute.keys())])
+        return default_attributes + (
</ins><span class="cx">             &quot;_alarm_vevent_timed&quot;,
</span><span class="cx">             &quot;_alarm_vevent_allday&quot;,
</span><span class="cx">             &quot;_alarm_vtodo_timed&quot;,
</span><span class="lines">@@ -624,22 +644,18 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def createdHome(self):
</span><span class="cx"> 
</span><del>-        # Default calendar
-        defaultCal = yield self.createCalendarWithName(&quot;calendar&quot;)
-
</del><span class="cx">         # Check whether components type must be separate
</span><span class="cx">         if config.RestrictCalendarsToOneComponentType:
</span><del>-            yield defaultCal.setSupportedComponents(&quot;VEVENT&quot;)
-            yield self.setDefaultCalendar(defaultCal, False)
-
-            # Default tasks
-            defaultTasks = yield self.createCalendarWithName(&quot;tasks&quot;)
-            yield defaultTasks.setSupportedComponents(&quot;VTODO&quot;)
-            yield defaultTasks.setUsedForFreeBusy(False)
-            yield self.setDefaultCalendar(defaultTasks, True)
</del><ins>+            for name in ical.allowedStoreComponents:
+                cal = yield self.createCalendarWithName(self._componentCalendarName[name])
+                yield cal.setSupportedComponents(name)
+                if name not in (&quot;VEVENT&quot;, &quot;VAVAILABILITY&quot;,):
+                    yield cal.setUsedForFreeBusy(False)
+                yield self.setDefaultCalendar(cal, name)
</ins><span class="cx">         else:
</span><del>-            yield self.setDefaultCalendar(defaultCal, False)
-            yield self.setDefaultCalendar(defaultCal, True)
</del><ins>+            cal = yield self.createCalendarWithName(&quot;calendar&quot;)
+            for name in ical.allowedStoreComponents:
+                yield self.setDefaultCalendar(cal, name)
</ins><span class="cx"> 
</span><span class="cx">         inbox = yield self.createCalendarWithName(&quot;inbox&quot;)
</span><span class="cx">         yield inbox.setUsedForFreeBusy(False)
</span><span class="lines">@@ -693,55 +709,13 @@
</span><span class="cx">                     newcal = yield self.createCalendarWithName(newname)
</span><span class="cx">                     yield newcal.setSupportedComponents(support_component)
</span><span class="cx"> 
</span><del>-            yield _requireCalendarWithType(&quot;VEVENT&quot;, &quot;calendar&quot;)
-            yield _requireCalendarWithType(&quot;VTODO&quot;, &quot;tasks&quot;)
</del><ins>+            for name in ical.allowedStoreComponents:
+                yield _requireCalendarWithType(name, self._componentCalendarName[name])
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def pickNewDefaultCalendar(self, tasks=False):
</del><ins>+    def setDefaultCalendar(self, calendar, componentType):
</ins><span class="cx">         &quot;&quot;&quot;
</span><del>-        First see if default provisioned calendar exists in the calendar home and pick that. Otherwise
-        pick another from the calendar home.
-        &quot;&quot;&quot;
-
-        componentType = &quot;VTODO&quot; if tasks else &quot;VEVENT&quot;
-        test_name = &quot;tasks&quot; if tasks else &quot;calendar&quot;
-
-        defaultCalendar = (yield self.calendarWithName(test_name))
-        if defaultCalendar is None or not defaultCalendar.owned():
-
-            @inlineCallbacks
-            def _findDefault():
-                for calendarName in (yield self.listCalendars()):
-                    calendar = (yield self.calendarWithName(calendarName))
-                    if calendar.isInbox():
-                        continue
-                    if not calendar.owned():
-                        continue
-                    if not calendar.isSupportedComponent(componentType):
-                        continue
-                    break
-                else:
-                    calendar = None
-                returnValue(calendar)
-
-            defaultCalendar = yield _findDefault()
-            if defaultCalendar is None:
-                # Create a default and try and get its name again
-                yield self.ensureDefaultCalendarsExist()
-                defaultCalendar = yield _findDefault()
-                if defaultCalendar is None:
-                    # Failed to even create a default - bad news...
-                    raise RuntimeError(&quot;No valid calendars to use as a default %s calendar.&quot; % (componentType,))
-
-        yield self.setDefaultCalendar(defaultCalendar, tasks)
-
-        returnValue(defaultCalendar)
-
-
-    @inlineCallbacks
-    def setDefaultCalendar(self, calendar, tasks=False):
-        &quot;&quot;&quot;
</del><span class="cx">         Set the default calendar for a particular type of component.
</span><span class="cx"> 
</span><span class="cx">         @param calendar: the calendar being set as the default
</span><span class="lines">@@ -749,10 +723,15 @@
</span><span class="cx">         @param tasks: C{True} for VTODO, C{False} for VEVENT
</span><span class="cx">         @type componentType: C{bool}
</span><span class="cx">         &quot;&quot;&quot;
</span><ins>+
+        # We only support VEVENT and VTOTO right now
+        componentType = componentType.upper()
+        if componentType not in self._componentDefaultAttribute:
+            returnValue(None)
+
</ins><span class="cx">         chm = self._homeMetaDataSchema
</span><del>-        componentType = &quot;VTODO&quot; if tasks else &quot;VEVENT&quot;
-        attribute_to_test = &quot;_default_tasks&quot; if tasks else &quot;_default_events&quot;
-        column_to_set = chm.DEFAULT_TASKS if tasks else chm.DEFAULT_EVENTS
</del><ins>+        attribute_to_test = self._componentDefaultAttribute[componentType]
+        column_to_set = self._componentDefaultColumn[componentType]
</ins><span class="cx"> 
</span><span class="cx">         # Check validity of the default
</span><span class="cx">         if calendar.isInbox():
</span><span class="lines">@@ -794,8 +773,13 @@
</span><span class="cx">         @rtype: L{Calendar} or C{None}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><ins>+        # We only support VEVENT and VTOTO right now
+        componentType = componentType.upper()
+        if componentType not in self._componentDefaultAttribute:
+            returnValue(None)
+
</ins><span class="cx">         # Check any default calendar property first - this will create if none exists
</span><del>-        attribute_to_test = &quot;_default_tasks&quot; if componentType == &quot;VTODO&quot; else &quot;_default_events&quot;
</del><ins>+        attribute_to_test = self._componentDefaultAttribute[componentType]
</ins><span class="cx">         defaultID = getattr(self, attribute_to_test)
</span><span class="cx">         if defaultID:
</span><span class="cx">             default = (yield self.childWithID(defaultID))
</span><span class="lines">@@ -816,7 +800,8 @@
</span><span class="cx"> 
</span><span class="cx">             # Try to find a calendar supporting the required component type. If there are multiple, pick
</span><span class="cx">             # the one with the oldest created timestamp as that will likely be the initial provision.
</span><del>-            for calendarName in (yield self.listCalendars()):
</del><ins>+            existing_names = (yield self.listCalendars())
+            for calendarName in existing_names:
</ins><span class="cx">                 calendar = (yield self.calendarWithName(calendarName))
</span><span class="cx">                 if calendar.isInbox():
</span><span class="cx">                     continue
</span><span class="lines">@@ -832,12 +817,15 @@
</span><span class="cx">                 if not create:
</span><span class="cx">                     returnValue(None)
</span><span class="cx">                 else:
</span><del>-                    new_name = &quot;%ss&quot; % (componentType.lower()[1:],)
</del><ins>+                    # Try a default name mapping first, else use a UUID
+                    new_name = self._componentCalendarName[componentType]
+                    if new_name in existing_names:
+                        new_name = str(uuid.uuid4())
</ins><span class="cx">                     default = yield self.createCalendarWithName(new_name)
</span><del>-                    yield default.setSupportedComponents(componentType.upper())
</del><ins>+                    yield default.setSupportedComponents(componentType)
</ins><span class="cx"> 
</span><span class="cx">             # Update the metadata
</span><del>-            yield self.setDefaultCalendar(default, componentType == &quot;VTODO&quot;)
</del><ins>+            yield self.setDefaultCalendar(default, componentType)
</ins><span class="cx"> 
</span><span class="cx">         returnValue(default)
</span><span class="cx"> 
</span><span class="lines">@@ -847,7 +835,10 @@
</span><span class="cx">         Is the supplied calendar one of the possible default calendars.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         # Not allowed to delete the default calendar
</span><del>-        return calendar._resourceID in (self._default_events, self._default_tasks)
</del><ins>+        for attr in self._componentDefaultAttribute.values():
+            if calendar._resourceID == getattr(self, attr):
+                return True
+        return False
</ins><span class="cx"> 
</span><span class="cx">     ALARM_DETAILS = {
</span><span class="cx">         (True, True): (_homeMetaDataSchema.ALARM_VEVENT_TIMED, &quot;_alarm_vevent_timed&quot;),
</span><span class="lines">@@ -1736,20 +1727,23 @@
</span><span class="cx"> 
</span><span class="cx">         NB Do this before implicit scheduling as we don't want old clients to trigger scheduling when
</span><span class="cx">         the X- property is missing.
</span><ins>+
+        We now only preserve the &quot;X-CALENDARSERVER-ATTENDEE-COMMENT&quot; property. We will now allow clients
+        to delete the &quot;X-CALENDARSERVER-PRIVATE-COMMENT&quot; and treat that as a removal of the attendee
+        comment (which will trigger scheduling with the organizer to remove the comment on the organizer's
+        side).
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         if config.Scheduling.CalDAV.get(&quot;EnablePrivateComments&quot;, True):
</span><span class="cx">             old_has_private_comments = not inserting and self.hasPrivateComment
</span><span class="cx">             new_has_private_comments = component.hasPropertyInAnyComponent((
</span><del>-                &quot;X-CALENDARSERVER-PRIVATE-COMMENT&quot;,
</del><span class="cx">                 &quot;X-CALENDARSERVER-ATTENDEE-COMMENT&quot;,
</span><span class="cx">             ))
</span><span class="cx"> 
</span><span class="cx">             if old_has_private_comments and not new_has_private_comments:
</span><span class="cx">                 # Transfer old comments to new calendar
</span><del>-                log.debug(&quot;Private Comments properties were entirely removed by the client. Restoring existing properties.&quot;)
</del><ins>+                log.debug(&quot;Organizer private comment properties were entirely removed by the client. Restoring existing properties.&quot;)
</ins><span class="cx">                 old_calendar = (yield self.componentForUser())
</span><span class="cx">                 component.transferProperties(old_calendar, (
</span><del>-                    &quot;X-CALENDARSERVER-PRIVATE-COMMENT&quot;,
</del><span class="cx">                     &quot;X-CALENDARSERVER-ATTENDEE-COMMENT&quot;,
</span><span class="cx">                 ))
</span><span class="cx"> 
</span><span class="lines">@@ -2200,8 +2194,18 @@
</span><span class="cx">         else:
</span><span class="cx">             yield self._calendar._updateRevision(self._name)
</span><span class="cx"> 
</span><del>-        yield self._calendar.notifyChanged()
</del><ins>+        # Determine change category
+        category = ChangeCategory.default
+        if internal_state == ComponentUpdateState.INBOX:
+            category = ChangeCategory.inbox
+        elif internal_state == ComponentUpdateState.ORGANIZER_ITIP_UPDATE:
+            category = ChangeCategory.organizerITIPUpdate
+        elif (internal_state == ComponentUpdateState.ATTENDEE_ITIP_UPDATE and
+            hasattr(self._txn, &quot;doing_attende_refresh&quot;)):
+            category = ChangeCategory.attendeeITIPUpdate
</ins><span class="cx"> 
</span><ins>+        yield self._calendar.notifyChanged(category=category)
+
</ins><span class="cx">         # Finally check if a split is needed
</span><span class="cx">         if internal_state not in (ComponentUpdateState.SPLIT_OWNER, ComponentUpdateState.SPLIT_ATTENDEE,) and schedule_state == &quot;organizer&quot;:
</span><span class="cx">             yield self.checkSplit()
</span><span class="lines">@@ -2248,7 +2252,7 @@
</span><span class="cx">                 # When there is no master we have a set of overridden components -
</span><span class="cx">                 #   index them all.
</span><span class="cx">                 # When there is one instance - index it.
</span><del>-                expand = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+                expand = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">                 doInstanceIndexing = True
</span><span class="cx">             else:
</span><span class="cx"> 
</span><span class="lines">@@ -2260,8 +2264,8 @@
</span><span class="cx">                 # by default.  This is a caching parameter which affects the size of the index;
</span><span class="cx">                 # it does not affect search results beyond this period, but it may affect
</span><span class="cx">                 # performance of such a search.
</span><del>-                expand = (PyCalendarDateTime.getToday() +
-                          PyCalendarDuration(days=config.FreeBusyIndexExpandAheadDays))
</del><ins>+                expand = (DateTime.getToday() +
+                          Duration(days=config.FreeBusyIndexExpandAheadDays))
</ins><span class="cx"> 
</span><span class="cx">                 if expand_until and expand_until &gt; expand:
</span><span class="cx">                     expand = expand_until
</span><span class="lines">@@ -2278,12 +2282,12 @@
</span><span class="cx">                 # occurrences into some obscenely far-in-the-future date, so we cap the caching
</span><span class="cx">                 # period.  Searches beyond this period will always be relatively expensive for
</span><span class="cx">                 # resources with occurrences beyond this period.
</span><del>-                if expand &gt; (PyCalendarDateTime.getToday() +
-                             PyCalendarDuration(days=config.FreeBusyIndexExpandMaxDays)):
</del><ins>+                if expand &gt; (DateTime.getToday() +
+                             Duration(days=config.FreeBusyIndexExpandMaxDays)):
</ins><span class="cx">                     raise IndexedSearchException
</span><span class="cx"> 
</span><span class="cx">             if config.FreeBusyIndexLowerLimitDays:
</span><del>-                truncateLowerLimit = PyCalendarDateTime.getToday()
</del><ins>+                truncateLowerLimit = DateTime.getToday()
</ins><span class="cx">                 truncateLowerLimit.offsetDay(-config.FreeBusyIndexLowerLimitDays)
</span><span class="cx">             else:
</span><span class="cx">                 truncateLowerLimit = None
</span><span class="lines">@@ -2310,7 +2314,7 @@
</span><span class="cx">             if not doInstanceIndexing:
</span><span class="cx">                 instances = None
</span><span class="cx">                 recurrenceLowerLimit = None
</span><del>-                recurrenceLimit = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+                recurrenceLimit = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx"> 
</span><span class="cx">         co = schema.CALENDAR_OBJECT
</span><span class="cx">         tr = schema.TIME_RANGE
</span><span class="lines">@@ -2429,7 +2433,7 @@
</span><span class="cx">         @param instances: the set of instances to add
</span><span class="cx">         @type instances: L{InstanceList}
</span><span class="cx">         @param truncateLowerLimit: the lower limit for instances
</span><del>-        @type truncateLowerLimit: L{PyCalendarDateTime}
</del><ins>+        @type truncateLowerLimit: L{DateTime}
</ins><span class="cx">         @param isInboxItem: indicates if an inbox item
</span><span class="cx">         @type isInboxItem: C{bool}
</span><span class="cx">         @param txn: transaction to use
</span><span class="lines">@@ -2458,8 +2462,8 @@
</span><span class="cx">         # For truncated items we insert a tomb stone lower bound so that a time-range
</span><span class="cx">         # query with just an end bound will match
</span><span class="cx">         if lowerLimitApplied or instances.lowerLimit and len(instances.instances) == 0:
</span><del>-            start = PyCalendarDateTime(1901, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
-            end = PyCalendarDateTime(1901, 1, 1, 1, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+            start = DateTime(1901, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
+            end = DateTime(1901, 1, 1, 1, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">             yield self._addInstanceDetails(component, None, start, end, False, True, &quot;UNKNOWN&quot;, isInboxItem, txn)
</span><span class="cx"> 
</span><span class="cx">         # Special - for unbounded recurrence we insert a value for &quot;infinity&quot;
</span><span class="lines">@@ -2467,8 +2471,8 @@
</span><span class="cx">         # We also need to add the &quot;infinity&quot; value if the event was bounded but
</span><span class="cx">         # starts after the future expansion cut-off limit.
</span><span class="cx">         if component.isRecurringUnbounded() or instances.limit and len(instances.instances) == 0:
</span><del>-            start = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
-            end = PyCalendarDateTime(2100, 1, 1, 1, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+            start = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
+            end = DateTime(2100, 1, 1, 1, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">             yield self._addInstanceDetails(component, None, start, end, False, True, &quot;UNKNOWN&quot;, isInboxItem, txn)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -2655,7 +2659,7 @@
</span><span class="cx">         Get the RECURRANCE_MIN, RECURRANCE_MAX value from the database. Occasionally we might need to do an
</span><span class="cx">         update to time-range data via a separate transaction, so we allow that to be passed in.
</span><span class="cx"> 
</span><del>-        @return: L{PyCalendarDateTime} result
</del><ins>+        @return: L{DateTime} result
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         # Setup appropriate txn
</span><span class="cx">         txn = txn if txn is not None else self._txn
</span><span class="lines">@@ -4277,7 +4281,7 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Return an iCalendar ATTACH property for this attachment.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        attach = Property(&quot;ATTACH&quot;, &quot;&quot;, valuetype=PyCalendarValue.VALUETYPE_URI)
</del><ins>+        attach = Property(&quot;ATTACH&quot;, &quot;&quot;, valuetype=Value.VALUETYPE_URI)
</ins><span class="cx">         location = (yield self.updateProperty(attach))
</span><span class="cx">         returnValue((attach, location,))
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretestcommonpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/common.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/common.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/common.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -53,7 +53,9 @@
</span><span class="cx"> from txdav.common.icommondatastore import ConcurrentModification
</span><span class="cx"> from twistedcaldav.ical import Component
</span><span class="cx"> from twistedcaldav.config import config
</span><ins>+from calendarserver.push.util import PushPriority
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx"> storePath = FilePath(__file__).parent().child(&quot;calendar_store&quot;)
</span><span class="cx"> 
</span><span class="cx"> homeRoot = storePath.child(&quot;ho&quot;).child(&quot;me&quot;).child(&quot;home1&quot;)
</span><span class="lines">@@ -456,8 +458,8 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CalDAV/example.com/home1/&quot;,
-                &quot;/CalDAV/example.com/home1/notification/&quot;,
</del><ins>+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/notification/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx">         yield self.commit()
</span><span class="lines">@@ -474,8 +476,8 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CalDAV/example.com/home1/&quot;,
-                &quot;/CalDAV/example.com/home1/notification/&quot;,
</del><ins>+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/notification/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx">         yield self.commit()
</span><span class="lines">@@ -698,7 +700,7 @@
</span><span class="cx">         calendarProperties = (yield home.calendarWithName(name)).properties()
</span><span class="cx">         self.assertEqual(len(calendarProperties), 0)
</span><span class="cx">         # notify is called prior to commit
</span><del>-        self.assertTrue(&quot;/CalDAV/example.com/home1/&quot; in self.notifierFactory.history)
</del><ins>+        self.assertTrue((&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high) in self.notifierFactory.history)
</ins><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx">         # Make sure it's available in a new transaction; i.e. test the commit.
</span><span class="lines">@@ -741,10 +743,10 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CalDAV/example.com/home1/&quot;,
-                &quot;/CalDAV/example.com/home1/calendar_1/&quot;,
-                &quot;/CalDAV/example.com/home1/calendar_2/&quot;,
-                &quot;/CalDAV/example.com/home1/calendar_empty/&quot;,
</del><ins>+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/calendar_1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/calendar_2/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/calendar_empty/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -918,8 +920,8 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CalDAV/example.com/home1/&quot;,
-                &quot;/CalDAV/example.com/home1/calendar_1/&quot;,
</del><ins>+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/calendar_1/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx">         yield self.commit()
</span><span class="lines">@@ -1337,7 +1339,7 @@
</span><span class="cx">     @inlineCallbacks
</span><span class="cx">     def test_iCalendarText(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        L{ICalendarObject.iCalendarText} returns a C{str} describing the same
</del><ins>+        L{ICalendarObject._text} returns a C{str} describing the same
</ins><span class="cx">         data provided by L{ICalendarObject.component}.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         text = yield (yield self.calendarObjectUnderTest())._text()
</span><span class="lines">@@ -1474,8 +1476,8 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CalDAV/example.com/home1/&quot;,
-                &quot;/CalDAV/example.com/home1/calendar_1/&quot;,
</del><ins>+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/calendar_1/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx">         yield self.commit()
</span><span class="lines">@@ -1593,8 +1595,8 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CalDAV/example.com/home1/&quot;,
-                &quot;/CalDAV/example.com/home1/calendar_1/&quot;,
</del><ins>+                (&quot;/CalDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CalDAV/example.com/home1/calendar_1/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx">         yield self.commit()
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_attachmentspy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_attachments.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_attachments.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_attachments.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -16,8 +16,8 @@
</span><span class="cx"> 
</span><span class="cx"> from calendarserver.tap.util import directoryFromConfig
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.value import PyCalendarValue
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.value import Value
</ins><span class="cx"> 
</span><span class="cx"> from twext.enterprise.dal.syntax import Delete
</span><span class="cx"> from twext.python.clsprop import classproperty
</span><span class="lines">@@ -1249,7 +1249,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-now = PyCalendarDateTime.getToday().getYear()
</del><ins>+now = DateTime.getToday().getYear()
</ins><span class="cx"> 
</span><span class="cx"> PLAIN_ICS = &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="cx"> VERSION:2.0
</span><span class="lines">@@ -1454,7 +1454,7 @@
</span><span class="cx">         cal.mainComponent().addProperty(Property(
</span><span class="cx">             &quot;ATTACH&quot;,
</span><span class="cx">             &quot;http://localhost/calendars/users/%s/dropbox/%s.dropbox/%s&quot; % (home.name(), dropboxid, name,),
</span><del>-            valuetype=PyCalendarValue.VALUETYPE_URI
</del><ins>+            valuetype=Value.VALUETYPE_URI
</ins><span class="cx">         ))
</span><span class="cx">         yield event.setComponent(cal)
</span><span class="cx">         yield txn.commit()
</span><span class="lines">@@ -1477,7 +1477,7 @@
</span><span class="cx">         cal.mainComponent().addProperty(Property(
</span><span class="cx">             &quot;ATTACH&quot;,
</span><span class="cx">             &quot;http://localhost/calendars/users/%s/dropbox/%s.dropbox/%s&quot; % (owner_home, dropboxid, name,),
</span><del>-            valuetype=PyCalendarValue.VALUETYPE_URI
</del><ins>+            valuetype=Value.VALUETYPE_URI
</ins><span class="cx">         ))
</span><span class="cx">         yield event.setComponent(cal)
</span><span class="cx">         yield txn.commit()
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_filepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_file.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_file.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_file.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -42,7 +42,7 @@
</span><span class="cx"> from txdav.caldav.datastore.test.common import (
</span><span class="cx">     CommonTests, test_event_text, event1modified_text)
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> storePath = FilePath(__file__).parent().child(&quot;calendar_store&quot;)
</span><span class="cx"> 
</span><span class="lines">@@ -68,7 +68,7 @@
</span><span class="cx">     storePath.copyTo(calendarPath)
</span><span class="cx"> 
</span><span class="cx">     # Set year values to current year
</span><del>-    nowYear = PyCalendarDateTime.getToday().getYear()
</del><ins>+    nowYear = DateTime.getToday().getYear()
</ins><span class="cx">     for home in calendarPath.child(&quot;ho&quot;).child(&quot;me&quot;).children():
</span><span class="cx">         if not home.basename().startswith(&quot;.&quot;):
</span><span class="cx">             for calendar in home.children():
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_implicitpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_implicit.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_implicit.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_implicit.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -478,9 +478,9 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def test_validation_preservePrivateComments(self):
</del><ins>+    def test_validation_noPreservePrivateComments(self):
</ins><span class="cx">         &quot;&quot;&quot;
</span><del>-        Test that resource private comments are restored.
</del><ins>+        Test that attendee private comments are no longer restored.
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         data1 = &quot;&quot;&quot;BEGIN:VCALENDAR
</span><span class="lines">@@ -524,12 +524,65 @@
</span><span class="cx">         calendar_resource = (yield self.calendarObjectUnderTest(name=&quot;test.ics&quot;, home=&quot;user01&quot;,))
</span><span class="cx">         calendar1 = (yield calendar_resource.component())
</span><span class="cx">         calendar1 = str(calendar1).replace(&quot;\r\n &quot;, &quot;&quot;)
</span><del>-        self.assertTrue(&quot;X-CALENDARSERVER-PRIVATE-COMMENT:My Comment&quot; in calendar1)
</del><ins>+        self.assertFalse(&quot;X-CALENDARSERVER-PRIVATE-COMMENT:My Comment&quot; in calendar1)
</ins><span class="cx">         self.assertTrue(&quot;SUMMARY:Changed&quot; in calendar1)
</span><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><ins>+    def test_validation_preserveOrganizerPrivateComments(self):
+        &quot;&quot;&quot;
+        Test that organizer private comments are restored.
+        &quot;&quot;&quot;
+
+        data1 = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-organizer
+DTSTAMP:20080601T120000Z
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF=&quot;urn:uuid:user01&quot;;
+ X-CALENDARSERVER-DTSTAMP=20131101T100000Z:Someone else's comment
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        calendar_collection = (yield self.calendarUnderTest(home=&quot;user01&quot;))
+        calendar = Component.fromString(data1)
+        yield calendar_collection.createCalendarObjectWithName(&quot;test.ics&quot;, calendar)
+        yield self.commit()
+
+        data2 = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-organizer
+DTSTAMP:20080601T120000Z
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+SUMMARY:Changed
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        calendar_resource = (yield self.calendarObjectUnderTest(name=&quot;test.ics&quot;, home=&quot;user01&quot;,))
+        calendar = Component.fromString(data2)
+        txn = self.transactionUnderTest()
+        txn._authz_uid = &quot;user01&quot;
+        yield calendar_resource.setComponent(calendar)
+        yield self.commit()
+
+        calendar_resource = (yield self.calendarObjectUnderTest(name=&quot;test.ics&quot;, home=&quot;user01&quot;,))
+        calendar1 = (yield calendar_resource.component())
+        calendar1 = str(calendar1).replace(&quot;\r\n &quot;, &quot;&quot;)
+        self.assertTrue(&quot;X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF=\&quot;urn:uuid:user01\&quot;;X-CALENDARSERVER-DTSTAMP=20131101T100000Z:Someone else's comment&quot; in calendar1)
+        self.assertTrue(&quot;SUMMARY:Changed&quot; in calendar1)
+        yield self.commit()
+
+
+    @inlineCallbacks
</ins><span class="cx">     def test_validation_replaceMissingToDoProperties_OrganizerAttendee(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Test that missing scheduling properties in VTODOs are recovered.
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_index_filepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_index_file.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_index_file.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_index_file.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -30,7 +30,7 @@
</span><span class="cx"> from twistedcaldav.test.util import InMemoryMemcacheProtocol
</span><span class="cx"> import twistedcaldav.test.util
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> import os
</span><span class="cx"> 
</span><span class="lines">@@ -311,7 +311,7 @@
</span><span class="cx">             else:
</span><span class="cx">                 self.assertFalse(self.db.resourceExists(name), msg=description)
</span><span class="cx"> 
</span><del>-        self.db.testAndUpdateIndex(PyCalendarDateTime(2020, 1, 1))
</del><ins>+        self.db.testAndUpdateIndex(DateTime(2020, 1, 1))
</ins><span class="cx">         for description, name, calendar_txt, reCreate, ok in data:
</span><span class="cx">             if ok:
</span><span class="cx">                 self.assertTrue(self.db.resourceExists(name), msg=description)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_sqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_sql.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_sql.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_sql.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -27,8 +27,8 @@
</span><span class="cx"> L{txdav.caldav.datastore.test.common}.
</span><span class="cx"> &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.timezone import PyCalendarTimezone
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.timezone import Timezone
</ins><span class="cx"> 
</span><span class="cx"> from twext.enterprise.dal.syntax import Select, Parameter, Insert, Delete, \
</span><span class="cx">     Update
</span><span class="lines">@@ -42,7 +42,7 @@
</span><span class="cx"> from twisted.internet.task import deferLater
</span><span class="cx"> from twisted.trial import unittest
</span><span class="cx"> 
</span><del>-from twistedcaldav import caldavxml
</del><ins>+from twistedcaldav import caldavxml, ical
</ins><span class="cx"> from twistedcaldav.caldavxml import CalendarDescription
</span><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.dateops import datetimeMktime
</span><span class="lines">@@ -78,7 +78,7 @@
</span><span class="cx">         self._sqlCalendarStore = yield buildCalendarStore(self, self.notifierFactory)
</span><span class="cx">         yield self.populate()
</span><span class="cx"> 
</span><del>-        self.nowYear = {&quot;now&quot;: PyCalendarDateTime.getToday().getYear()}
</del><ins>+        self.nowYear = {&quot;now&quot;: DateTime.getToday().getYear()}
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -474,14 +474,14 @@
</span><span class="cx">             )
</span><span class="cx"> 
</span><span class="cx">         supported_components = set()
</span><del>-        self.assertEqual(len(toCalendars), 4)
</del><ins>+        self.assertEqual(len(toCalendars), 2 + len(ical.allowedStoreComponents))
</ins><span class="cx">         for calendar in toCalendars:
</span><span class="cx">             if calendar.name() == &quot;inbox&quot;:
</span><span class="cx">                 continue
</span><span class="cx">             result = yield calendar.getSupportedComponents()
</span><span class="cx">             supported_components.add(result)
</span><span class="cx"> 
</span><del>-        self.assertEqual(supported_components, set((&quot;VEVENT&quot;, &quot;VTODO&quot;,)))
</del><ins>+        self.assertEqual(supported_components, set(ical.allowedStoreComponents))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -509,7 +509,7 @@
</span><span class="cx">             result = yield calendar.getSupportedComponents()
</span><span class="cx">             supported_components.add(result)
</span><span class="cx"> 
</span><del>-        self.assertEqual(supported_components, set((&quot;VEVENT&quot;, &quot;VTODO&quot;,)))
</del><ins>+        self.assertEqual(supported_components, set(ical.allowedStoreComponents))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def test_calendarHomeVersion(self):
</span><span class="lines">@@ -1124,7 +1124,7 @@
</span><span class="cx">             result = yield calendar.getSupportedComponents()
</span><span class="cx">             supported_components.add(result)
</span><span class="cx"> 
</span><del>-        self.assertEqual(supported_components, set((&quot;VEVENT&quot;, &quot;VTODO&quot;,)))
</del><ins>+        self.assertEqual(supported_components, set(ical.allowedStoreComponents))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -1190,7 +1190,7 @@
</span><span class="cx">         self.assertEqual(home._default_events, None)
</span><span class="cx">         self.assertEqual(home._default_tasks, None)
</span><span class="cx">         calendar1 = yield home.calendarWithName(&quot;calendar_1&quot;)
</span><del>-        yield home.setDefaultCalendar(calendar1, False)
</del><ins>+        yield home.setDefaultCalendar(calendar1, &quot;VEVENT&quot;)
</ins><span class="cx">         self.assertEqual(home._default_events, calendar1._resourceID)
</span><span class="cx">         self.assertEqual(home._default_tasks, None)
</span><span class="cx">         yield self.commit()
</span><span class="lines">@@ -1198,7 +1198,7 @@
</span><span class="cx">         home = yield self.homeUnderTest(name=&quot;home_defaults&quot;)
</span><span class="cx">         calendar1 = yield home.calendarWithName(&quot;calendar_1&quot;)
</span><span class="cx">         calendar2 = yield home.calendarWithName(&quot;calendar_1-vtodo&quot;)
</span><del>-        yield self.failUnlessFailure(home.setDefaultCalendar(calendar2, False), InvalidDefaultCalendar)
</del><ins>+        yield self.failUnlessFailure(home.setDefaultCalendar(calendar2, &quot;VEVENT&quot;), InvalidDefaultCalendar)
</ins><span class="cx">         self.assertEqual(home._default_events, calendar1._resourceID)
</span><span class="cx">         self.assertEqual(home._default_tasks, None)
</span><span class="cx">         yield self.commit()
</span><span class="lines">@@ -1206,20 +1206,20 @@
</span><span class="cx">         home = yield self.homeUnderTest(name=&quot;home_defaults&quot;)
</span><span class="cx">         calendar1 = yield home.calendarWithName(&quot;calendar_1&quot;)
</span><span class="cx">         calendar2 = yield home.calendarWithName(&quot;calendar_1-vtodo&quot;)
</span><del>-        yield home.setDefaultCalendar(calendar2, True)
</del><ins>+        yield home.setDefaultCalendar(calendar2, &quot;VTODO&quot;)
</ins><span class="cx">         self.assertEqual(home._default_events, calendar1._resourceID)
</span><span class="cx">         self.assertEqual(home._default_tasks, calendar2._resourceID)
</span><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx">         home = yield self.homeUnderTest(name=&quot;home_defaults&quot;)
</span><span class="cx">         calendar1 = yield home.calendarWithName(&quot;inbox&quot;)
</span><del>-        yield self.failUnlessFailure(home.setDefaultCalendar(calendar1, False), InvalidDefaultCalendar)
</del><ins>+        yield self.failUnlessFailure(home.setDefaultCalendar(calendar1, &quot;VEVENT&quot;), InvalidDefaultCalendar)
</ins><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx">         home = yield self.homeUnderTest(name=&quot;home_defaults&quot;)
</span><span class="cx">         home_other = yield self.homeUnderTest(name=&quot;home_splits&quot;)
</span><span class="cx">         calendar1 = yield home_other.calendarWithName(&quot;calendar_1&quot;)
</span><del>-        yield self.failUnlessFailure(home.setDefaultCalendar(calendar1, False), InvalidDefaultCalendar)
</del><ins>+        yield self.failUnlessFailure(home.setDefaultCalendar(calendar1, &quot;VEVENT&quot;), InvalidDefaultCalendar)
</ins><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1377,38 +1377,38 @@
</span><span class="cx">         self.assertEqual(rmax.getYear(), nowYear + 1)
</span><span class="cx"> 
</span><span class="cx">         # Fully within range
</span><del>-        testMin = PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
-        testMax = PyCalendarDateTime(nowYear + 1, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        testMin = DateTime(nowYear, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
+        testMax = DateTime(nowYear + 1, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         result = yield index.notExpandedWithin(testMin, testMax)
</span><span class="cx">         self.assertEqual(result, [])
</span><span class="cx"> 
</span><span class="cx">         # Upper bound exceeded
</span><del>-        testMin = PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
-        testMax = PyCalendarDateTime(nowYear + 5, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        testMin = DateTime(nowYear, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
+        testMax = DateTime(nowYear + 5, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         result = yield index.notExpandedWithin(testMin, testMax)
</span><span class="cx">         self.assertEqual(result, [&quot;indexing.ics&quot;])
</span><span class="cx"> 
</span><span class="cx">         # Lower bound exceeded
</span><del>-        testMin = PyCalendarDateTime(nowYear - 5, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
-        testMax = PyCalendarDateTime(nowYear + 1, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        testMin = DateTime(nowYear - 5, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
+        testMax = DateTime(nowYear + 1, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         result = yield index.notExpandedWithin(testMin, testMax)
</span><span class="cx">         self.assertEqual(result, [&quot;indexing.ics&quot;])
</span><span class="cx"> 
</span><span class="cx">         # Lower and upper bounds exceeded
</span><del>-        testMin = PyCalendarDateTime(nowYear - 5, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
-        testMax = PyCalendarDateTime(nowYear + 5, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        testMin = DateTime(nowYear - 5, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
+        testMax = DateTime(nowYear + 5, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         result = yield index.notExpandedWithin(testMin, testMax)
</span><span class="cx">         self.assertEqual(result, [&quot;indexing.ics&quot;])
</span><span class="cx"> 
</span><span class="cx">         # Lower none within range
</span><span class="cx">         testMin = None
</span><del>-        testMax = PyCalendarDateTime(nowYear + 1, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        testMax = DateTime(nowYear + 1, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         result = yield index.notExpandedWithin(testMin, testMax)
</span><span class="cx">         self.assertEqual(result, [])
</span><span class="cx"> 
</span><span class="cx">         # Lower none and upper bounds exceeded
</span><span class="cx">         testMin = None
</span><del>-        testMax = PyCalendarDateTime(nowYear + 5, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
</del><ins>+        testMax = DateTime(nowYear + 5, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))
</ins><span class="cx">         result = yield index.notExpandedWithin(testMin, testMax)
</span><span class="cx">         self.assertEqual(result, [&quot;indexing.ics&quot;])
</span><span class="cx"> 
</span><span class="lines">@@ -2154,7 +2154,7 @@
</span><span class="cx"> 
</span><span class="cx">         self.subs = {}
</span><span class="cx"> 
</span><del>-        self.now = PyCalendarDateTime.getNowUTC()
</del><ins>+        self.now = DateTime.getNowUTC()
</ins><span class="cx">         self.now.setHHMMSS(0, 0, 0)
</span><span class="cx"> 
</span><span class="cx">         self.subs[&quot;now&quot;] = self.now
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretesttest_utilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_util.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_util.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/test_util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -349,7 +349,8 @@
</span><span class="cx">                 &quot;inbox&quot;: {},
</span><span class="cx">                 # XXX: implementation is configuration-sensitive regarding the
</span><span class="cx">                 # 'tasks' calendar and it shouldn't be.
</span><del>-                &quot;tasks&quot;: {}
</del><ins>+                &quot;tasks&quot;: {},
+                &quot;polls&quot;: {},
</ins><span class="cx">             }
</span><span class="cx">         }, self.storeUnderTest())
</span><span class="cx">         txn = self.transactionUnderTest()
</span><span class="lines">@@ -412,7 +413,7 @@
</span><span class="cx">             c1 = {&quot;1.ics&quot;: self.sampleEvent(&quot;uid1&quot;)}
</span><span class="cx">         if c2 is None:
</span><span class="cx">             c2 = {&quot;2.ics&quot;: self.sampleEvent(&quot;uid2&quot;)}
</span><del>-        defaults = {&quot;calendar&quot;: {}, &quot;inbox&quot;: {}, &quot;tasks&quot;: {}}
</del><ins>+        defaults = {&quot;calendar&quot;: {}, &quot;inbox&quot;: {}, &quot;tasks&quot;: {}, &quot;polls&quot;: {}}
</ins><span class="cx">         def conflicted(caldata):
</span><span class="cx">             d = defaults.copy()
</span><span class="cx">             d.update(conflicted=caldata)
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoretestutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/util.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/util.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/test/util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -61,7 +61,6 @@
</span><span class="cx">         fullName,
</span><span class="cx">         calendarUserAddresses,
</span><span class="cx">         cutype=&quot;INDIVIDUAL&quot;,
</span><del>-        locallyHosted=True,
</del><span class="cx">         thisServer=True,
</span><span class="cx">     ):
</span><span class="cx"> 
</span><span class="lines">@@ -72,7 +71,6 @@
</span><span class="cx">         self.displayName = self.fullName if self.fullName else self.shortNames[0]
</span><span class="cx">         self.calendarUserAddresses = calendarUserAddresses
</span><span class="cx">         self.cutype = cutype
</span><del>-        self._locallyHosted = locallyHosted
</del><span class="cx">         self._thisServer = thisServer
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -92,10 +90,6 @@
</span><span class="cx">         return cua
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def locallyHosted(self):
-        return self._locallyHosted
-
-
</del><span class="cx">     def thisServer(self):
</span><span class="cx">         return self._thisServer
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavdatastoreutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/util.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/util.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/datastore/util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> from twext.python.vcomponent import InvalidICalendarDataError
</span><span class="cx"> from twext.python.vcomponent import VComponent
</span><span class="cx"> 
</span><ins>+from twistedcaldav import ical
</ins><span class="cx"> from twistedcaldav.datafilters.hiddeninstance import HiddenInstanceFilter
</span><span class="cx"> from twistedcaldav.datafilters.privateevents import PrivateEventFilter
</span><span class="cx"> from twistedcaldav.ical import PERUSER_UID
</span><span class="lines">@@ -380,9 +381,11 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     from twistedcaldav.config import config
</span><span class="cx">     if not merge:
</span><del>-        yield outHome.removeCalendarWithName(&quot;calendar&quot;)
</del><span class="cx">         if config.RestrictCalendarsToOneComponentType:
</span><del>-            yield outHome.removeCalendarWithName(&quot;tasks&quot;)
</del><ins>+            for name in ical.allowedStoreComponents:
+                yield outHome.removeCalendarWithName(outHome._componentCalendarName[name])
+        else:
+            yield outHome.removeCalendarWithName(&quot;calendar&quot;)
</ins><span class="cx">         yield outHome.removeCalendarWithName(&quot;inbox&quot;)
</span><span class="cx"> 
</span><span class="cx">     outHome.properties().update(inHome.properties())
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavicalendardirectoryservicepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/icalendardirectoryservice.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/icalendardirectoryservice.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/icalendardirectoryservice.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -60,18 +60,9 @@
</span><span class="cx">         @rtype: C{str}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def locallyHosted(): #@NoSelf
-        &quot;&quot;&quot;
-        Indicates whether the record is host on this specific server &quot;pod&quot;.
-
-        @return: C{True} if locally hosted.
-        @rtype: C{bool}
-        &quot;&quot;&quot;
-
</del><span class="cx">     def thisServer(): #@NoSelf
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        Indicates whether the record is hosted on this server or another &quot;pod&quot;
-        that hosts the same directory service.
</del><ins>+        Indicates whether the record is hosted on this server &quot;pod&quot;.
</ins><span class="cx"> 
</span><span class="cx">         @return: C{True} if hosted by this service.
</span><span class="cx">         @rtype: C{bool}
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcaldavicalendarstorepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/icalendarstore.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/icalendarstore.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/caldav/icalendarstore.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -363,9 +363,9 @@
</span><span class="cx">         instances that occur within the time range that begins at
</span><span class="cx">         C{start} and ends at C{end}.
</span><span class="cx"> 
</span><del>-        @param start: a L{PyCalendarDateTime}.
-        @param end: a L{PyCalendarDateTime}.
-        @param timeZone: a L{PyCalendarTimezone}.
</del><ins>+        @param start: a L{DateTime}.
+        @param end: a L{DateTime}.
+        @param timeZone: a L{Timezone}.
</ins><span class="cx">         @return: an iterable of L{ICalendarObject}s.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcarddavdatastoretestcommonpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/carddav/datastore/test/common.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/carddav/datastore/test/common.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/carddav/datastore/test/common.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -39,7 +39,9 @@
</span><span class="cx"> from txdav.common.icommondatastore import ObjectResourceNameAlreadyExistsError
</span><span class="cx"> from txdav.idav import IPropertyStore, IDataStore
</span><span class="cx"> from txdav.xml.element import WebDAVUnknownElement
</span><ins>+from calendarserver.push.util import PushPriority
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx"> storePath = FilePath(__file__).parent().child(&quot;addressbook_store&quot;)
</span><span class="cx"> 
</span><span class="cx"> home1Root = storePath.child(&quot;ho&quot;).child(&quot;me&quot;).child(&quot;home1&quot;)
</span><span class="lines">@@ -372,7 +374,7 @@
</span><span class="cx">         yield home.removeAddressBookWithName(name)
</span><span class="cx">         self.assertNotIdentical((yield home.addressbookWithName(name)), None)
</span><span class="cx">         # notify is called prior to commit
</span><del>-        self.assertTrue(&quot;/CardDAV/example.com/home1/&quot; in self.notifierFactory.history)
</del><ins>+        self.assertTrue((&quot;/CardDAV/example.com/home1/&quot;, PushPriority.high) in self.notifierFactory.history)
</ins><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx">         # Make sure it's available in a new transaction; i.e. test the commit.
</span><span class="lines">@@ -399,8 +401,8 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CardDAV/example.com/home1/&quot;,
-                &quot;/CardDAV/example.com/home1/addressbook/&quot;,
</del><ins>+                (&quot;/CardDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CardDAV/example.com/home1/addressbook/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -532,8 +534,8 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CardDAV/example.com/home1/&quot;,
-                &quot;/CardDAV/example.com/home1/addressbook/&quot;,
</del><ins>+                (&quot;/CardDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CardDAV/example.com/home1/addressbook/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -693,8 +695,8 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CardDAV/example.com/home1/&quot;,
-                &quot;/CardDAV/example.com/home1/addressbook/&quot;,
</del><ins>+                (&quot;/CardDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CardDAV/example.com/home1/addressbook/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -809,8 +811,8 @@
</span><span class="cx">         self.assertEquals(
</span><span class="cx">             set(self.notifierFactory.history),
</span><span class="cx">             set([
</span><del>-                &quot;/CardDAV/example.com/home1/&quot;,
-                &quot;/CardDAV/example.com/home1/addressbook/&quot;,
</del><ins>+                (&quot;/CardDAV/example.com/home1/&quot;, PushPriority.high),
+                (&quot;/CardDAV/example.com/home1/addressbook/&quot;, PushPriority.high),
</ins><span class="cx">             ])
</span><span class="cx">         )
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -27,7 +27,7 @@
</span><span class="cx"> 
</span><span class="cx"> from cStringIO import StringIO
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from twext.enterprise.dal.syntax import (
</span><span class="cx">     Delete, utcNowSQL, Union, Insert, Len, Max, Parameter, SavepointAction,
</span><span class="lines">@@ -74,6 +74,7 @@
</span><span class="cx"> from txdav.common.inotifications import INotificationCollection, \
</span><span class="cx">     INotificationObject
</span><span class="cx"> from txdav.xml.parser import WebDAVDocument
</span><ins>+from txdav.idav import ChangeCategory
</ins><span class="cx"> 
</span><span class="cx"> from uuid import uuid4, UUID
</span><span class="cx"> 
</span><span class="lines">@@ -1107,7 +1108,7 @@
</span><span class="cx">     def eventsOlderThan(self, cutoff, batchSize=None):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Return up to the oldest batchSize events which exist completely earlier
</span><del>-        than &quot;cutoff&quot; (PyCalendarDateTime)
</del><ins>+        than &quot;cutoff&quot; (DateTime)
</ins><span class="cx"> 
</span><span class="cx">         Returns a deferred to a list of (uid, calendarName, eventName, maxDate)
</span><span class="cx">         tuples.
</span><span class="lines">@@ -1115,7 +1116,7 @@
</span><span class="cx"> 
</span><span class="cx">         # Make sure cut off is after any lower limit truncation in the DB
</span><span class="cx">         if config.FreeBusyIndexLowerLimitDays:
</span><del>-            truncateLowerLimit = PyCalendarDateTime.getToday()
</del><ins>+            truncateLowerLimit = DateTime.getToday()
</ins><span class="cx">             truncateLowerLimit.offsetDay(-config.FreeBusyIndexLowerLimitDays)
</span><span class="cx">             if cutoff &lt; truncateLowerLimit:
</span><span class="cx">                 raise ValueError(&quot;Cannot query events older than %s&quot; % (truncateLowerLimit.getText(),))
</span><span class="lines">@@ -1133,7 +1134,7 @@
</span><span class="cx"> 
</span><span class="cx">         # Make sure cut off is after any lower limit truncation in the DB
</span><span class="cx">         if config.FreeBusyIndexLowerLimitDays:
</span><del>-            truncateLowerLimit = PyCalendarDateTime.getToday()
</del><ins>+            truncateLowerLimit = DateTime.getToday()
</ins><span class="cx">             truncateLowerLimit.offsetDay(-config.FreeBusyIndexLowerLimitDays)
</span><span class="cx">             if cutoff &lt; truncateLowerLimit:
</span><span class="cx">                 raise ValueError(&quot;Cannot query events older than %s&quot; % (truncateLowerLimit.getText(),))
</span><span class="lines">@@ -2203,7 +2204,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def notifyChanged(self):
</del><ins>+    def notifyChanged(self, category=ChangeCategory.default):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Send notifications, change sync token and bump last modified because
</span><span class="cx">         the resource has changed.  We ensure we only do this once per object
</span><span class="lines">@@ -2227,7 +2228,7 @@
</span><span class="cx">             # push notifiers add their work items immediately
</span><span class="cx">             notifier = self._notifiers.get(&quot;push&quot;, None)
</span><span class="cx">             if notifier:
</span><del>-                yield notifier.notify(self._txn)
</del><ins>+                yield notifier.notify(self._txn, priority=category.value)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classproperty
</span><span class="lines">@@ -4335,11 +4336,11 @@
</span><span class="cx">         return self.ownerHome().notifierID()
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def notifyChanged(self):
</del><ins>+    def notifyChanged(self, category=ChangeCategory.default):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Send notifications when a child resource is changed.
</span><span class="cx">         &quot;&quot;&quot;
</span><del>-        return self._notifyChanged(property_change=False)
</del><ins>+        return self._notifyChanged(property_change=False, category=category)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def notifyPropertyChanged(self):
</span><span class="lines">@@ -4350,7 +4351,8 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def _notifyChanged(self, property_change=False):
</del><ins>+    def _notifyChanged(self, property_change=False,
+            category=ChangeCategory.default):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Send notifications, change sync token and bump last modified because
</span><span class="cx">         the resource has changed.  We ensure we only do this once per object
</span><span class="lines">@@ -4386,7 +4388,7 @@
</span><span class="cx">             # push notifiers add their work items immediately
</span><span class="cx">             notifier = self._notifiers.get(&quot;push&quot;, None)
</span><span class="cx">             if notifier:
</span><del>-                yield notifier.notify(self._txn)
</del><ins>+                yield notifier.notify(self._txn, priority=category.value)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classproperty
</span><span class="lines">@@ -5200,7 +5202,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def notifyChanged(self):
</del><ins>+    def notifyChanged(self, category=ChangeCategory.default):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Send notifications, change sync token and bump last modified because
</span><span class="cx">         the resource has changed.  We ensure we only do this once per object
</span><span class="lines">@@ -5219,7 +5221,7 @@
</span><span class="cx">             # push notifiers add their work items immediately
</span><span class="cx">             notifier = self._notifiers.get(&quot;push&quot;, None)
</span><span class="cx">             if notifier:
</span><del>-                yield notifier.notify(self._txn)
</del><ins>+                yield notifier.notify(self._txn, priority=category.value)
</ins><span class="cx"> 
</span><span class="cx">         returnValue(None)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_legacypy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_legacy.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_legacy.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_legacy.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -43,8 +43,8 @@
</span><span class="cx"> from twext.python.clsprop import classproperty
</span><span class="cx"> from twext.python.log import Logger
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
-from pycalendar.duration import PyCalendarDuration
</del><ins>+from pycalendar.datetime import DateTime
+from pycalendar.duration import Duration
</ins><span class="cx"> 
</span><span class="cx"> log = Logger()
</span><span class="cx"> 
</span><span class="lines">@@ -566,7 +566,7 @@
</span><span class="cx">             )
</span><span class="cx">             if qualifiers is not None:
</span><span class="cx"> 
</span><del>-                today = PyCalendarDateTime.getToday()
</del><ins>+                today = DateTime.getToday()
</ins><span class="cx"> 
</span><span class="cx">                 # Determine how far we need to extend the current expansion of
</span><span class="cx">                 # events. If we have an open-ended time-range we will expand
</span><span class="lines">@@ -578,11 +578,11 @@
</span><span class="cx">                     maxDate = maxDate.duplicate()
</span><span class="cx">                     maxDate.offsetDay(1)
</span><span class="cx">                     maxDate.setDateOnly(True)
</span><del>-                    upperLimit = today + PyCalendarDuration(days=config.FreeBusyIndexExpandMaxDays)
</del><ins>+                    upperLimit = today + Duration(days=config.FreeBusyIndexExpandMaxDays)
</ins><span class="cx">                     if maxDate &gt; upperLimit:
</span><span class="cx">                         raise TimeRangeUpperLimit(upperLimit)
</span><span class="cx">                     if isStartDate:
</span><del>-                        maxDate += PyCalendarDuration(days=365)
</del><ins>+                        maxDate += Duration(days=365)
</ins><span class="cx"> 
</span><span class="cx">                 # Determine if the start date is too early for the restricted range we
</span><span class="cx">                 # are applying. If it is today or later we don't need to worry about truncation
</span><span class="lines">@@ -591,7 +591,7 @@
</span><span class="cx">                 if minDate &gt;= today:
</span><span class="cx">                     minDate = None
</span><span class="cx">                 if minDate is not None and config.FreeBusyIndexLowerLimitDays:
</span><del>-                    truncateLowerLimit = today - PyCalendarDuration(days=config.FreeBusyIndexLowerLimitDays)
</del><ins>+                    truncateLowerLimit = today - Duration(days=config.FreeBusyIndexLowerLimitDays)
</ins><span class="cx">                     if minDate &lt; truncateLowerLimit:
</span><span class="cx">                         raise TimeRangeLowerLimit(truncateLowerLimit)
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemacurrentoracledialectsql"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/current-oracle-dialect.sql (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/current-oracle-dialect.sql        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/current-oracle-dialect.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx">     &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
</span><span class="cx">     &quot;DEFAULT_EVENTS&quot; integer default null references CALENDAR on delete set null,
</span><span class="cx">     &quot;DEFAULT_TASKS&quot; integer default null references CALENDAR on delete set null,
</span><ins>+    &quot;DEFAULT_POLLS&quot; integer default null references CALENDAR on delete set null,
</ins><span class="cx">     &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
</span><span class="cx">     &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
</span><span class="cx">     &quot;ALARM_VTODO_TIMED&quot; nclob default null,
</span><span class="lines">@@ -349,7 +350,8 @@
</span><span class="cx"> create table PUSH_NOTIFICATION_WORK (
</span><span class="cx">     &quot;WORK_ID&quot; integer primary key not null,
</span><span class="cx">     &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
</span><del>-    &quot;PUSH_ID&quot; nvarchar2(255)
</del><ins>+    &quot;PUSH_ID&quot; nvarchar2(255),
+    &quot;PRIORITY&quot; integer not null
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> create table GROUP_CACHER_POLLING_WORK (
</span><span class="lines">@@ -368,7 +370,7 @@
</span><span class="cx">     &quot;VALUE&quot; nvarchar2(255)
</span><span class="cx"> );
</span><span class="cx"> 
</span><del>-insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '26');
</del><ins>+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '29');
</ins><span class="cx"> insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '5');
</span><span class="cx"> insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
</span><span class="cx"> create index CALENDAR_HOME_METADAT_3cb9049e on CALENDAR_HOME_METADATA (
</span><span class="lines">@@ -379,6 +381,10 @@
</span><span class="cx">     DEFAULT_TASKS
</span><span class="cx"> );
</span><span class="cx"> 
</span><ins>+create index CALENDAR_HOME_METADAT_910264ce on CALENDAR_HOME_METADATA (
+    DEFAULT_POLLS
+);
+
</ins><span class="cx"> create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
</span><span class="cx">     NOTIFICATION_HOME_RESOURCE_ID
</span><span class="cx"> );
</span><span class="lines">@@ -450,9 +456,11 @@
</span><span class="cx">     CALENDAR_RESOURCE_ID
</span><span class="cx"> );
</span><span class="cx"> 
</span><del>-create index CALENDAR_OBJECT_REVIS_2643d556 on CALENDAR_OBJECT_REVISIONS (
</del><ins>+create index CALENDAR_OBJECT_REVIS_6d9d929c on CALENDAR_OBJECT_REVISIONS (
</ins><span class="cx">     CALENDAR_RESOURCE_ID,
</span><del>-    RESOURCE_NAME
</del><ins>+    RESOURCE_NAME,
+    DELETED,
+    REVISION
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
</span><span class="lines">@@ -465,9 +473,11 @@
</span><span class="cx">     OWNER_HOME_RESOURCE_ID
</span><span class="cx"> );
</span><span class="cx"> 
</span><del>-create index ADDRESSBOOK_OBJECT_RE_980b9872 on ADDRESSBOOK_OBJECT_REVISIONS (
</del><ins>+create index ADDRESSBOOK_OBJECT_RE_00fe8288 on ADDRESSBOOK_OBJECT_REVISIONS (
</ins><span class="cx">     OWNER_HOME_RESOURCE_ID,
</span><del>-    RESOURCE_NAME
</del><ins>+    RESOURCE_NAME,
+    DELETED,
+    REVISION
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> create index ADDRESSBOOK_OBJECT_RE_45004780 on ADDRESSBOOK_OBJECT_REVISIONS (
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemacurrentsql"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/current.sql (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/current.sql        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/current.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -74,6 +74,7 @@
</span><span class="cx">   QUOTA_USED_BYTES         integer     default 0 not null,
</span><span class="cx">   DEFAULT_EVENTS           integer     default null references CALENDAR on delete set null,
</span><span class="cx">   DEFAULT_TASKS            integer     default null references CALENDAR on delete set null,
</span><ins>+  DEFAULT_POLLS            integer     default null references CALENDAR on delete set null,
</ins><span class="cx">   ALARM_VEVENT_TIMED       text        default null,
</span><span class="cx">   ALARM_VEVENT_ALLDAY      text        default null,
</span><span class="cx">   ALARM_VTODO_TIMED        text        default null,
</span><span class="lines">@@ -87,6 +88,8 @@
</span><span class="cx">         CALENDAR_HOME_METADATA(DEFAULT_EVENTS);
</span><span class="cx"> create index CALENDAR_HOME_METADATA_DEFAULT_TASKS on
</span><span class="cx">         CALENDAR_HOME_METADATA(DEFAULT_TASKS);
</span><ins>+create index CALENDAR_HOME_METADATA_DEFAULT_POLLS on
+        CALENDAR_HOME_METADATA(DEFAULT_POLLS);
</ins><span class="cx"> 
</span><span class="cx"> -----------------------
</span><span class="cx"> -- Calendar Metadata --
</span><span class="lines">@@ -504,7 +507,7 @@
</span><span class="cx">   MESSAGE                                      text,                  -- FIXME: xml?
</span><span class="cx"> 
</span><span class="cx">   primary key (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_RESOURCE_ID), -- implicit index
</span><del>-  unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_NAME)     -- implicit index
</del><ins>+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_NAME)  -- implicit index
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> create index SHARED_GROUP_BIND_RESOURCE_ID on
</span><span class="lines">@@ -534,8 +537,8 @@
</span><span class="cx"> create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
</span><span class="cx">   on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
</span><span class="cx"> 
</span><del>-create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
-  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME);
</del><ins>+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
</ins><span class="cx"> 
</span><span class="cx"> create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
</span><span class="cx">   on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
</span><span class="lines">@@ -558,8 +561,8 @@
</span><span class="cx"> create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_HOME_RESOURCE_ID
</span><span class="cx">   on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID);
</span><span class="cx"> 
</span><del>-create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME
-  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, RESOURCE_NAME);
</del><ins>+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
</ins><span class="cx"> 
</span><span class="cx"> create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_REVISION
</span><span class="cx">   on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, REVISION);
</span><span class="lines">@@ -669,7 +672,8 @@
</span><span class="cx"> create table PUSH_NOTIFICATION_WORK (
</span><span class="cx">   WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
</span><span class="cx">   NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
</span><del>-  PUSH_ID                       varchar(255) not null
</del><ins>+  PUSH_ID                       varchar(255) not null,
+  PRIORITY                      integer      not null -- 1:low 5:medium 10:high
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> -----------------
</span><span class="lines">@@ -704,6 +708,6 @@
</span><span class="cx">   VALUE                         varchar(255)
</span><span class="cx"> );
</span><span class="cx"> 
</span><del>-insert into CALENDARSERVER values ('VERSION', '26');
</del><ins>+insert into CALENDARSERVER values ('VERSION', '29');
</ins><span class="cx"> insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '5');
</span><span class="cx"> insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldoracledialectv24sql"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v24.sql (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v24.sql        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v24.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,491 +0,0 @@
</span><del>-create sequence RESOURCE_ID_SEQ;
-create sequence INSTANCE_ID_SEQ;
-create sequence ATTACHMENT_ID_SEQ;
-create sequence REVISION_SEQ;
-create sequence WORKITEM_SEQ;
-create table NODE_INFO (
-    &quot;HOSTNAME&quot; nvarchar2(255),
-    &quot;PID&quot; integer not null,
-    &quot;PORT&quot; integer not null,
-    &quot;TIME&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC' not null, 
-    primary key(&quot;HOSTNAME&quot;, &quot;PORT&quot;)
-);
-
-create table NAMED_LOCK (
-    &quot;LOCK_NAME&quot; nvarchar2(255) primary key
-);
-
-create table CALENDAR_HOME (
-    &quot;RESOURCE_ID&quot; integer primary key,
-    &quot;OWNER_UID&quot; nvarchar2(255) unique,
-    &quot;DATAVERSION&quot; integer default 0 not null
-);
-
-create table CALENDAR (
-    &quot;RESOURCE_ID&quot; integer primary key
-);
-
-create table CALENDAR_HOME_METADATA (
-    &quot;RESOURCE_ID&quot; integer primary key references CALENDAR_HOME on delete cascade,
-    &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
-    &quot;DEFAULT_EVENTS&quot; integer default null references CALENDAR on delete set null,
-    &quot;DEFAULT_TASKS&quot; integer default null references CALENDAR on delete set null,
-    &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
-    &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
-    &quot;ALARM_VTODO_TIMED&quot; nclob default null,
-    &quot;ALARM_VTODO_ALLDAY&quot; nclob default null,
-    &quot;AVAILABILITY&quot; nclob default null,
-    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table CALENDAR_METADATA (
-    &quot;RESOURCE_ID&quot; integer primary key references CALENDAR on delete cascade,
-    &quot;SUPPORTED_COMPONENTS&quot; nvarchar2(255) default null,
-    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table NOTIFICATION_HOME (
-    &quot;RESOURCE_ID&quot; integer primary key,
-    &quot;OWNER_UID&quot; nvarchar2(255) unique
-);
-
-create table NOTIFICATION (
-    &quot;RESOURCE_ID&quot; integer primary key,
-    &quot;NOTIFICATION_HOME_RESOURCE_ID&quot; integer not null references NOTIFICATION_HOME,
-    &quot;NOTIFICATION_UID&quot; nvarchar2(255),
-    &quot;XML_TYPE&quot; nvarchar2(255),
-    &quot;XML_DATA&quot; nclob,
-    &quot;MD5&quot; nchar(32),
-    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
-    unique(&quot;NOTIFICATION_UID&quot;, &quot;NOTIFICATION_HOME_RESOURCE_ID&quot;)
-);
-
-create table CALENDAR_BIND (
-    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
-    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
-    &quot;CALENDAR_RESOURCE_NAME&quot; nvarchar2(255),
-    &quot;BIND_MODE&quot; integer not null,
-    &quot;BIND_STATUS&quot; integer not null,
-    &quot;BIND_REVISION&quot; integer default 0 not null,
-    &quot;MESSAGE&quot; nclob,
-    &quot;TRANSP&quot; integer default 0 not null,
-    &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
-    &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
-    &quot;ALARM_VTODO_TIMED&quot; nclob default null,
-    &quot;ALARM_VTODO_ALLDAY&quot; nclob default null,
-    &quot;TIMEZONE&quot; nclob default null, 
-    primary key(&quot;CALENDAR_HOME_RESOURCE_ID&quot;, &quot;CALENDAR_RESOURCE_ID&quot;), 
-    unique(&quot;CALENDAR_HOME_RESOURCE_ID&quot;, &quot;CALENDAR_RESOURCE_NAME&quot;)
-);
-
-create table CALENDAR_BIND_MODE (
-    &quot;ID&quot; integer primary key,
-    &quot;DESCRIPTION&quot; nvarchar2(16) unique
-);
-
-insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
-insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
-insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
-insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
-create table CALENDAR_BIND_STATUS (
-    &quot;ID&quot; integer primary key,
-    &quot;DESCRIPTION&quot; nvarchar2(16) unique
-);
-
-insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
-insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
-insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
-insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
-create table CALENDAR_TRANSP (
-    &quot;ID&quot; integer primary key,
-    &quot;DESCRIPTION&quot; nvarchar2(16) unique
-);
-
-insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('opaque', 0);
-insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('transparent', 1);
-create table CALENDAR_OBJECT (
-    &quot;RESOURCE_ID&quot; integer primary key,
-    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
-    &quot;RESOURCE_NAME&quot; nvarchar2(255),
-    &quot;ICALENDAR_TEXT&quot; nclob,
-    &quot;ICALENDAR_UID&quot; nvarchar2(255),
-    &quot;ICALENDAR_TYPE&quot; nvarchar2(255),
-    &quot;ATTACHMENTS_MODE&quot; integer default 0 not null,
-    &quot;DROPBOX_ID&quot; nvarchar2(255),
-    &quot;ORGANIZER&quot; nvarchar2(255),
-    &quot;RECURRANCE_MIN&quot; date,
-    &quot;RECURRANCE_MAX&quot; date,
-    &quot;ACCESS&quot; integer default 0 not null,
-    &quot;SCHEDULE_OBJECT&quot; integer default 0,
-    &quot;SCHEDULE_TAG&quot; nvarchar2(36) default null,
-    &quot;SCHEDULE_ETAGS&quot; nclob default null,
-    &quot;PRIVATE_COMMENTS&quot; integer default 0 not null,
-    &quot;MD5&quot; nchar(32),
-    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
-    unique(&quot;CALENDAR_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;)
-);
-
-create table CALENDAR_OBJECT_ATTACHMENTS_MO (
-    &quot;ID&quot; integer primary key,
-    &quot;DESCRIPTION&quot; nvarchar2(16) unique
-);
-
-insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('none', 0);
-insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('read', 1);
-insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('write', 2);
-create table CALENDAR_ACCESS_TYPE (
-    &quot;ID&quot; integer primary key,
-    &quot;DESCRIPTION&quot; nvarchar2(32) unique
-);
-
-insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
-insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
-insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
-insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
-insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
-create table TIME_RANGE (
-    &quot;INSTANCE_ID&quot; integer primary key,
-    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
-    &quot;CALENDAR_OBJECT_RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade,
-    &quot;FLOATING&quot; integer not null,
-    &quot;START_DATE&quot; timestamp not null,
-    &quot;END_DATE&quot; timestamp not null,
-    &quot;FBTYPE&quot; integer not null,
-    &quot;TRANSPARENT&quot; integer not null
-);
-
-create table FREE_BUSY_TYPE (
-    &quot;ID&quot; integer primary key,
-    &quot;DESCRIPTION&quot; nvarchar2(16) unique
-);
-
-insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
-insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
-insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
-insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
-insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
-create table TRANSPARENCY (
-    &quot;TIME_RANGE_INSTANCE_ID&quot; integer not null references TIME_RANGE on delete cascade,
-    &quot;USER_ID&quot; nvarchar2(255),
-    &quot;TRANSPARENT&quot; integer not null
-);
-
-create table ATTACHMENT (
-    &quot;ATTACHMENT_ID&quot; integer primary key,
-    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
-    &quot;DROPBOX_ID&quot; nvarchar2(255),
-    &quot;CONTENT_TYPE&quot; nvarchar2(255),
-    &quot;SIZE&quot; integer not null,
-    &quot;MD5&quot; nchar(32),
-    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;PATH&quot; nvarchar2(1024)
-);
-
-create table ATTACHMENT_CALENDAR_OBJECT (
-    &quot;ATTACHMENT_ID&quot; integer not null references ATTACHMENT on delete cascade,
-    &quot;MANAGED_ID&quot; nvarchar2(255),
-    &quot;CALENDAR_OBJECT_RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade, 
-    primary key(&quot;ATTACHMENT_ID&quot;, &quot;CALENDAR_OBJECT_RESOURCE_ID&quot;), 
-    unique(&quot;MANAGED_ID&quot;, &quot;CALENDAR_OBJECT_RESOURCE_ID&quot;)
-);
-
-create table RESOURCE_PROPERTY (
-    &quot;RESOURCE_ID&quot; integer not null,
-    &quot;NAME&quot; nvarchar2(255),
-    &quot;VALUE&quot; nclob,
-    &quot;VIEWER_UID&quot; nvarchar2(255), 
-    primary key(&quot;RESOURCE_ID&quot;, &quot;NAME&quot;, &quot;VIEWER_UID&quot;)
-);
-
-create table ADDRESSBOOK_HOME (
-    &quot;RESOURCE_ID&quot; integer primary key,
-    &quot;ADDRESSBOOK_PROPERTY_STORE_ID&quot; integer not null,
-    &quot;OWNER_UID&quot; nvarchar2(255) unique,
-    &quot;DATAVERSION&quot; integer default 0 not null
-);
-
-create table ADDRESSBOOK_HOME_METADATA (
-    &quot;RESOURCE_ID&quot; integer primary key references ADDRESSBOOK_HOME on delete cascade,
-    &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
-    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table SHARED_ADDRESSBOOK_BIND (
-    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
-    &quot;OWNER_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
-    &quot;ADDRESSBOOK_RESOURCE_NAME&quot; nvarchar2(255),
-    &quot;BIND_MODE&quot; integer not null,
-    &quot;BIND_STATUS&quot; integer not null,
-    &quot;BIND_REVISION&quot; integer default 0 not null,
-    &quot;MESSAGE&quot; nclob, 
-    primary key(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;OWNER_HOME_RESOURCE_ID&quot;), 
-    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;ADDRESSBOOK_RESOURCE_NAME&quot;)
-);
-
-create table ADDRESSBOOK_OBJECT (
-    &quot;RESOURCE_ID&quot; integer primary key,
-    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
-    &quot;RESOURCE_NAME&quot; nvarchar2(255),
-    &quot;VCARD_TEXT&quot; nclob,
-    &quot;VCARD_UID&quot; nvarchar2(255),
-    &quot;KIND&quot; integer not null,
-    &quot;MD5&quot; nchar(32),
-    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
-    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;), 
-    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;VCARD_UID&quot;)
-);
-
-create table ADDRESSBOOK_OBJECT_KIND (
-    &quot;ID&quot; integer primary key,
-    &quot;DESCRIPTION&quot; nvarchar2(16) unique
-);
-
-insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('person', 0);
-insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('group', 1);
-insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('resource', 2);
-insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('location', 3);
-create table ABO_MEMBERS (
-    &quot;GROUP_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
-    &quot;ADDRESSBOOK_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
-    &quot;MEMBER_ID&quot; integer not null references ADDRESSBOOK_OBJECT, 
-    primary key(&quot;GROUP_ID&quot;, &quot;MEMBER_ID&quot;)
-);
-
-create table ABO_FOREIGN_MEMBERS (
-    &quot;GROUP_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
-    &quot;ADDRESSBOOK_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
-    &quot;MEMBER_ADDRESS&quot; nvarchar2(255), 
-    primary key(&quot;GROUP_ID&quot;, &quot;MEMBER_ADDRESS&quot;)
-);
-
-create table SHARED_GROUP_BIND (
-    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
-    &quot;GROUP_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
-    &quot;GROUP_ADDRESSBOOK_NAME&quot; nvarchar2(255),
-    &quot;BIND_MODE&quot; integer not null,
-    &quot;BIND_STATUS&quot; integer not null,
-    &quot;BIND_REVISION&quot; integer default 0 not null,
-    &quot;MESSAGE&quot; nclob, 
-    primary key(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;GROUP_RESOURCE_ID&quot;), 
-    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;GROUP_ADDRESSBOOK_NAME&quot;)
-);
-
-create table CALENDAR_OBJECT_REVISIONS (
-    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
-    &quot;CALENDAR_RESOURCE_ID&quot; integer references CALENDAR,
-    &quot;CALENDAR_NAME&quot; nvarchar2(255) default null,
-    &quot;RESOURCE_NAME&quot; nvarchar2(255),
-    &quot;REVISION&quot; integer not null,
-    &quot;DELETED&quot; integer not null
-);
-
-create table ADDRESSBOOK_OBJECT_REVISIONS (
-    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
-    &quot;OWNER_HOME_RESOURCE_ID&quot; integer references ADDRESSBOOK_HOME,
-    &quot;ADDRESSBOOK_NAME&quot; nvarchar2(255) default null,
-    &quot;RESOURCE_NAME&quot; nvarchar2(255),
-    &quot;REVISION&quot; integer not null,
-    &quot;DELETED&quot; integer not null
-);
-
-create table NOTIFICATION_OBJECT_REVISIONS (
-    &quot;NOTIFICATION_HOME_RESOURCE_ID&quot; integer not null references NOTIFICATION_HOME on delete cascade,
-    &quot;RESOURCE_NAME&quot; nvarchar2(255),
-    &quot;REVISION&quot; integer not null,
-    &quot;DELETED&quot; integer not null, 
-    unique(&quot;NOTIFICATION_HOME_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;)
-);
-
-create table APN_SUBSCRIPTIONS (
-    &quot;TOKEN&quot; nvarchar2(255),
-    &quot;RESOURCE_KEY&quot; nvarchar2(255),
-    &quot;MODIFIED&quot; integer not null,
-    &quot;SUBSCRIBER_GUID&quot; nvarchar2(255),
-    &quot;USER_AGENT&quot; nvarchar2(255) default null,
-    &quot;IP_ADDR&quot; nvarchar2(255) default null, 
-    primary key(&quot;TOKEN&quot;, &quot;RESOURCE_KEY&quot;)
-);
-
-create table IMIP_TOKENS (
-    &quot;TOKEN&quot; nvarchar2(255),
-    &quot;ORGANIZER&quot; nvarchar2(255),
-    &quot;ATTENDEE&quot; nvarchar2(255),
-    &quot;ICALUID&quot; nvarchar2(255),
-    &quot;ACCESSED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
-    primary key(&quot;ORGANIZER&quot;, &quot;ATTENDEE&quot;, &quot;ICALUID&quot;)
-);
-
-create table IMIP_INVITATION_WORK (
-    &quot;WORK_ID&quot; integer primary key not null,
-    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;FROM_ADDR&quot; nvarchar2(255),
-    &quot;TO_ADDR&quot; nvarchar2(255),
-    &quot;ICALENDAR_TEXT&quot; nclob
-);
-
-create table IMIP_POLLING_WORK (
-    &quot;WORK_ID&quot; integer primary key not null,
-    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table IMIP_REPLY_WORK (
-    &quot;WORK_ID&quot; integer primary key not null,
-    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;ORGANIZER&quot; nvarchar2(255),
-    &quot;ATTENDEE&quot; nvarchar2(255),
-    &quot;ICALENDAR_TEXT&quot; nclob
-);
-
-create table PUSH_NOTIFICATION_WORK (
-    &quot;WORK_ID&quot; integer primary key not null,
-    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;PUSH_ID&quot; nvarchar2(255)
-);
-
-create table GROUP_CACHER_POLLING_WORK (
-    &quot;WORK_ID&quot; integer primary key not null,
-    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table CALENDAR_OBJECT_SPLITTER_WORK (
-    &quot;WORK_ID&quot; integer primary key not null,
-    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
-    &quot;RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade
-);
-
-create table CALENDARSERVER (
-    &quot;NAME&quot; nvarchar2(255) primary key,
-    &quot;VALUE&quot; nvarchar2(255)
-);
-
-insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '24');
-insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '5');
-insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
-create index CALENDAR_HOME_METADAT_3cb9049e on CALENDAR_HOME_METADATA (
-    DEFAULT_EVENTS
-);
-
-create index CALENDAR_HOME_METADAT_d55e5548 on CALENDAR_HOME_METADATA (
-    DEFAULT_TASKS
-);
-
-create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
-    NOTIFICATION_HOME_RESOURCE_ID
-);
-
-create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
-    CALENDAR_RESOURCE_ID
-);
-
-create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
-    CALENDAR_RESOURCE_ID,
-    ICALENDAR_UID
-);
-
-create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
-    CALENDAR_RESOURCE_ID,
-    RECURRANCE_MAX
-);
-
-create index CALENDAR_OBJECT_ICALE_82e731d5 on CALENDAR_OBJECT (
-    ICALENDAR_UID
-);
-
-create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
-    DROPBOX_ID
-);
-
-create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
-    CALENDAR_RESOURCE_ID
-);
-
-create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
-    CALENDAR_OBJECT_RESOURCE_ID
-);
-
-create index TRANSPARENCY_TIME_RAN_5f34467f on TRANSPARENCY (
-    TIME_RANGE_INSTANCE_ID
-);
-
-create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
-    CALENDAR_HOME_RESOURCE_ID
-);
-
-create index ATTACHMENT_CALENDAR_O_81508484 on ATTACHMENT_CALENDAR_OBJECT (
-    CALENDAR_OBJECT_RESOURCE_ID
-);
-
-create index SHARED_ADDRESSBOOK_BI_e9a2e6d4 on SHARED_ADDRESSBOOK_BIND (
-    OWNER_HOME_RESOURCE_ID
-);
-
-create index ABO_MEMBERS_ADDRESSBO_4effa879 on ABO_MEMBERS (
-    ADDRESSBOOK_ID
-);
-
-create index ABO_MEMBERS_MEMBER_ID_8d66adcf on ABO_MEMBERS (
-    MEMBER_ID
-);
-
-create index ABO_FOREIGN_MEMBERS_A_1fd2c5e9 on ABO_FOREIGN_MEMBERS (
-    ADDRESSBOOK_ID
-);
-
-create index SHARED_GROUP_BIND_RES_cf52f95d on SHARED_GROUP_BIND (
-    GROUP_RESOURCE_ID
-);
-
-create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
-    CALENDAR_HOME_RESOURCE_ID,
-    CALENDAR_RESOURCE_ID
-);
-
-create index CALENDAR_OBJECT_REVIS_2643d556 on CALENDAR_OBJECT_REVISIONS (
-    CALENDAR_RESOURCE_ID,
-    RESOURCE_NAME
-);
-
-create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
-    CALENDAR_RESOURCE_ID,
-    REVISION
-);
-
-create index ADDRESSBOOK_OBJECT_RE_2bfcf757 on ADDRESSBOOK_OBJECT_REVISIONS (
-    ADDRESSBOOK_HOME_RESOURCE_ID,
-    OWNER_HOME_RESOURCE_ID
-);
-
-create index ADDRESSBOOK_OBJECT_RE_980b9872 on ADDRESSBOOK_OBJECT_REVISIONS (
-    OWNER_HOME_RESOURCE_ID,
-    RESOURCE_NAME
-);
-
-create index ADDRESSBOOK_OBJECT_RE_45004780 on ADDRESSBOOK_OBJECT_REVISIONS (
-    OWNER_HOME_RESOURCE_ID,
-    REVISION
-);
-
-create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
-    NOTIFICATION_HOME_RESOURCE_ID,
-    REVISION
-);
-
-create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
-    RESOURCE_KEY
-);
-
-create index IMIP_TOKENS_TOKEN_e94b918f on IMIP_TOKENS (
-    TOKEN
-);
-
-create index CALENDAR_OBJECT_SPLIT_af71dcda on CALENDAR_OBJECT_SPLITTER_WORK (
-    RESOURCE_ID
-);
-
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldoracledialectv24sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaoldoracledialectv24sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v24.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v24.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v24.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v24.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,491 @@
</span><ins>+create sequence RESOURCE_ID_SEQ;
+create sequence INSTANCE_ID_SEQ;
+create sequence ATTACHMENT_ID_SEQ;
+create sequence REVISION_SEQ;
+create sequence WORKITEM_SEQ;
+create table NODE_INFO (
+    &quot;HOSTNAME&quot; nvarchar2(255),
+    &quot;PID&quot; integer not null,
+    &quot;PORT&quot; integer not null,
+    &quot;TIME&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC' not null, 
+    primary key(&quot;HOSTNAME&quot;, &quot;PORT&quot;)
+);
+
+create table NAMED_LOCK (
+    &quot;LOCK_NAME&quot; nvarchar2(255) primary key
+);
+
+create table CALENDAR_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique,
+    &quot;DATAVERSION&quot; integer default 0 not null
+);
+
+create table CALENDAR (
+    &quot;RESOURCE_ID&quot; integer primary key
+);
+
+create table CALENDAR_HOME_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references CALENDAR_HOME on delete cascade,
+    &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
+    &quot;DEFAULT_EVENTS&quot; integer default null references CALENDAR on delete set null,
+    &quot;DEFAULT_TASKS&quot; integer default null references CALENDAR on delete set null,
+    &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
+    &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
+    &quot;ALARM_VTODO_TIMED&quot; nclob default null,
+    &quot;ALARM_VTODO_ALLDAY&quot; nclob default null,
+    &quot;AVAILABILITY&quot; nclob default null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references CALENDAR on delete cascade,
+    &quot;SUPPORTED_COMPONENTS&quot; nvarchar2(255) default null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table NOTIFICATION_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique
+);
+
+create table NOTIFICATION (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;NOTIFICATION_HOME_RESOURCE_ID&quot; integer not null references NOTIFICATION_HOME,
+    &quot;NOTIFICATION_UID&quot; nvarchar2(255),
+    &quot;XML_TYPE&quot; nvarchar2(255),
+    &quot;XML_DATA&quot; nclob,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;NOTIFICATION_UID&quot;, &quot;NOTIFICATION_HOME_RESOURCE_ID&quot;)
+);
+
+create table CALENDAR_BIND (
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;CALENDAR_RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob,
+    &quot;TRANSP&quot; integer default 0 not null,
+    &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
+    &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
+    &quot;ALARM_VTODO_TIMED&quot; nclob default null,
+    &quot;ALARM_VTODO_ALLDAY&quot; nclob default null,
+    &quot;TIMEZONE&quot; nclob default null, 
+    primary key(&quot;CALENDAR_HOME_RESOURCE_ID&quot;, &quot;CALENDAR_RESOURCE_ID&quot;), 
+    unique(&quot;CALENDAR_HOME_RESOURCE_ID&quot;, &quot;CALENDAR_RESOURCE_NAME&quot;)
+);
+
+create table CALENDAR_BIND_MODE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
+create table CALENDAR_BIND_STATUS (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
+create table CALENDAR_TRANSP (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('opaque', 0);
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('transparent', 1);
+create table CALENDAR_OBJECT (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob,
+    &quot;ICALENDAR_UID&quot; nvarchar2(255),
+    &quot;ICALENDAR_TYPE&quot; nvarchar2(255),
+    &quot;ATTACHMENTS_MODE&quot; integer default 0 not null,
+    &quot;DROPBOX_ID&quot; nvarchar2(255),
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;RECURRANCE_MIN&quot; date,
+    &quot;RECURRANCE_MAX&quot; date,
+    &quot;ACCESS&quot; integer default 0 not null,
+    &quot;SCHEDULE_OBJECT&quot; integer default 0,
+    &quot;SCHEDULE_TAG&quot; nvarchar2(36) default null,
+    &quot;SCHEDULE_ETAGS&quot; nclob default null,
+    &quot;PRIVATE_COMMENTS&quot; integer default 0 not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;CALENDAR_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;)
+);
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MO (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('none', 0);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('write', 2);
+create table CALENDAR_ACCESS_TYPE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(32) unique
+);
+
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
+create table TIME_RANGE (
+    &quot;INSTANCE_ID&quot; integer primary key,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;CALENDAR_OBJECT_RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade,
+    &quot;FLOATING&quot; integer not null,
+    &quot;START_DATE&quot; timestamp not null,
+    &quot;END_DATE&quot; timestamp not null,
+    &quot;FBTYPE&quot; integer not null,
+    &quot;TRANSPARENT&quot; integer not null
+);
+
+create table FREE_BUSY_TYPE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
+create table TRANSPARENCY (
+    &quot;TIME_RANGE_INSTANCE_ID&quot; integer not null references TIME_RANGE on delete cascade,
+    &quot;USER_ID&quot; nvarchar2(255),
+    &quot;TRANSPARENT&quot; integer not null
+);
+
+create table ATTACHMENT (
+    &quot;ATTACHMENT_ID&quot; integer primary key,
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;DROPBOX_ID&quot; nvarchar2(255),
+    &quot;CONTENT_TYPE&quot; nvarchar2(255),
+    &quot;SIZE&quot; integer not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;PATH&quot; nvarchar2(1024)
+);
+
+create table ATTACHMENT_CALENDAR_OBJECT (
+    &quot;ATTACHMENT_ID&quot; integer not null references ATTACHMENT on delete cascade,
+    &quot;MANAGED_ID&quot; nvarchar2(255),
+    &quot;CALENDAR_OBJECT_RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade, 
+    primary key(&quot;ATTACHMENT_ID&quot;, &quot;CALENDAR_OBJECT_RESOURCE_ID&quot;), 
+    unique(&quot;MANAGED_ID&quot;, &quot;CALENDAR_OBJECT_RESOURCE_ID&quot;)
+);
+
+create table RESOURCE_PROPERTY (
+    &quot;RESOURCE_ID&quot; integer not null,
+    &quot;NAME&quot; nvarchar2(255),
+    &quot;VALUE&quot; nclob,
+    &quot;VIEWER_UID&quot; nvarchar2(255), 
+    primary key(&quot;RESOURCE_ID&quot;, &quot;NAME&quot;, &quot;VIEWER_UID&quot;)
+);
+
+create table ADDRESSBOOK_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;ADDRESSBOOK_PROPERTY_STORE_ID&quot; integer not null,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique,
+    &quot;DATAVERSION&quot; integer default 0 not null
+);
+
+create table ADDRESSBOOK_HOME_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references ADDRESSBOOK_HOME on delete cascade,
+    &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table SHARED_ADDRESSBOOK_BIND (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;OWNER_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;ADDRESSBOOK_RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob, 
+    primary key(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;OWNER_HOME_RESOURCE_ID&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;ADDRESSBOOK_RESOURCE_NAME&quot;)
+);
+
+create table ADDRESSBOOK_OBJECT (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;VCARD_TEXT&quot; nclob,
+    &quot;VCARD_UID&quot; nvarchar2(255),
+    &quot;KIND&quot; integer not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;VCARD_UID&quot;)
+);
+
+create table ADDRESSBOOK_OBJECT_KIND (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('person', 0);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('group', 1);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('resource', 2);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('location', 3);
+create table ABO_MEMBERS (
+    &quot;GROUP_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;ADDRESSBOOK_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;MEMBER_ID&quot; integer not null references ADDRESSBOOK_OBJECT, 
+    primary key(&quot;GROUP_ID&quot;, &quot;MEMBER_ID&quot;)
+);
+
+create table ABO_FOREIGN_MEMBERS (
+    &quot;GROUP_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;ADDRESSBOOK_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;MEMBER_ADDRESS&quot; nvarchar2(255), 
+    primary key(&quot;GROUP_ID&quot;, &quot;MEMBER_ADDRESS&quot;)
+);
+
+create table SHARED_GROUP_BIND (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;GROUP_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;GROUP_ADDRESSBOOK_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob, 
+    primary key(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;GROUP_RESOURCE_ID&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;GROUP_ADDRESSBOOK_NAME&quot;)
+);
+
+create table CALENDAR_OBJECT_REVISIONS (
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer references CALENDAR,
+    &quot;CALENDAR_NAME&quot; nvarchar2(255) default null,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null
+);
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;OWNER_HOME_RESOURCE_ID&quot; integer references ADDRESSBOOK_HOME,
+    &quot;ADDRESSBOOK_NAME&quot; nvarchar2(255) default null,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null
+);
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+    &quot;NOTIFICATION_HOME_RESOURCE_ID&quot; integer not null references NOTIFICATION_HOME on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null, 
+    unique(&quot;NOTIFICATION_HOME_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;)
+);
+
+create table APN_SUBSCRIPTIONS (
+    &quot;TOKEN&quot; nvarchar2(255),
+    &quot;RESOURCE_KEY&quot; nvarchar2(255),
+    &quot;MODIFIED&quot; integer not null,
+    &quot;SUBSCRIBER_GUID&quot; nvarchar2(255),
+    &quot;USER_AGENT&quot; nvarchar2(255) default null,
+    &quot;IP_ADDR&quot; nvarchar2(255) default null, 
+    primary key(&quot;TOKEN&quot;, &quot;RESOURCE_KEY&quot;)
+);
+
+create table IMIP_TOKENS (
+    &quot;TOKEN&quot; nvarchar2(255),
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;ATTENDEE&quot; nvarchar2(255),
+    &quot;ICALUID&quot; nvarchar2(255),
+    &quot;ACCESSED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    primary key(&quot;ORGANIZER&quot;, &quot;ATTENDEE&quot;, &quot;ICALUID&quot;)
+);
+
+create table IMIP_INVITATION_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;FROM_ADDR&quot; nvarchar2(255),
+    &quot;TO_ADDR&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob
+);
+
+create table IMIP_POLLING_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table IMIP_REPLY_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;ATTENDEE&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob
+);
+
+create table PUSH_NOTIFICATION_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;PUSH_ID&quot; nvarchar2(255)
+);
+
+create table GROUP_CACHER_POLLING_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade
+);
+
+create table CALENDARSERVER (
+    &quot;NAME&quot; nvarchar2(255) primary key,
+    &quot;VALUE&quot; nvarchar2(255)
+);
+
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '24');
+insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '5');
+insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
+create index CALENDAR_HOME_METADAT_3cb9049e on CALENDAR_HOME_METADATA (
+    DEFAULT_EVENTS
+);
+
+create index CALENDAR_HOME_METADAT_d55e5548 on CALENDAR_HOME_METADATA (
+    DEFAULT_TASKS
+);
+
+create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
+    NOTIFICATION_HOME_RESOURCE_ID
+);
+
+create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
+    CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
+    CALENDAR_RESOURCE_ID,
+    ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
+    CALENDAR_RESOURCE_ID,
+    RECURRANCE_MAX
+);
+
+create index CALENDAR_OBJECT_ICALE_82e731d5 on CALENDAR_OBJECT (
+    ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
+    DROPBOX_ID
+);
+
+create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
+    CALENDAR_RESOURCE_ID
+);
+
+create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
+    CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index TRANSPARENCY_TIME_RAN_5f34467f on TRANSPARENCY (
+    TIME_RANGE_INSTANCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
+    CALENDAR_HOME_RESOURCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_O_81508484 on ATTACHMENT_CALENDAR_OBJECT (
+    CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index SHARED_ADDRESSBOOK_BI_e9a2e6d4 on SHARED_ADDRESSBOOK_BIND (
+    OWNER_HOME_RESOURCE_ID
+);
+
+create index ABO_MEMBERS_ADDRESSBO_4effa879 on ABO_MEMBERS (
+    ADDRESSBOOK_ID
+);
+
+create index ABO_MEMBERS_MEMBER_ID_8d66adcf on ABO_MEMBERS (
+    MEMBER_ID
+);
+
+create index ABO_FOREIGN_MEMBERS_A_1fd2c5e9 on ABO_FOREIGN_MEMBERS (
+    ADDRESSBOOK_ID
+);
+
+create index SHARED_GROUP_BIND_RES_cf52f95d on SHARED_GROUP_BIND (
+    GROUP_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_HOME_RESOURCE_ID,
+    CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_2643d556 on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_RESOURCE_ID,
+    RESOURCE_NAME
+);
+
+create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_RESOURCE_ID,
+    REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_2bfcf757 on ADDRESSBOOK_OBJECT_REVISIONS (
+    ADDRESSBOOK_HOME_RESOURCE_ID,
+    OWNER_HOME_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_OBJECT_RE_980b9872 on ADDRESSBOOK_OBJECT_REVISIONS (
+    OWNER_HOME_RESOURCE_ID,
+    RESOURCE_NAME
+);
+
+create index ADDRESSBOOK_OBJECT_RE_45004780 on ADDRESSBOOK_OBJECT_REVISIONS (
+    OWNER_HOME_RESOURCE_ID,
+    REVISION
+);
+
+create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
+    NOTIFICATION_HOME_RESOURCE_ID,
+    REVISION
+);
+
+create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
+    RESOURCE_KEY
+);
+
+create index IMIP_TOKENS_TOKEN_e94b918f on IMIP_TOKENS (
+    TOKEN
+);
+
+create index CALENDAR_OBJECT_SPLIT_af71dcda on CALENDAR_OBJECT_SPLITTER_WORK (
+    RESOURCE_ID
+);
+
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldoracledialectv26sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaoldoracledialectv26sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v26.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v26.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v26.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v26.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,495 @@
</span><ins>+create sequence RESOURCE_ID_SEQ;
+create sequence INSTANCE_ID_SEQ;
+create sequence ATTACHMENT_ID_SEQ;
+create sequence REVISION_SEQ;
+create sequence WORKITEM_SEQ;
+create table NODE_INFO (
+    &quot;HOSTNAME&quot; nvarchar2(255),
+    &quot;PID&quot; integer not null,
+    &quot;PORT&quot; integer not null,
+    &quot;TIME&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC' not null, 
+    primary key(&quot;HOSTNAME&quot;, &quot;PORT&quot;)
+);
+
+create table NAMED_LOCK (
+    &quot;LOCK_NAME&quot; nvarchar2(255) primary key
+);
+
+create table CALENDAR_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique,
+    &quot;DATAVERSION&quot; integer default 0 not null
+);
+
+create table CALENDAR (
+    &quot;RESOURCE_ID&quot; integer primary key
+);
+
+create table CALENDAR_HOME_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references CALENDAR_HOME on delete cascade,
+    &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
+    &quot;DEFAULT_EVENTS&quot; integer default null references CALENDAR on delete set null,
+    &quot;DEFAULT_TASKS&quot; integer default null references CALENDAR on delete set null,
+    &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
+    &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
+    &quot;ALARM_VTODO_TIMED&quot; nclob default null,
+    &quot;ALARM_VTODO_ALLDAY&quot; nclob default null,
+    &quot;AVAILABILITY&quot; nclob default null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references CALENDAR on delete cascade,
+    &quot;SUPPORTED_COMPONENTS&quot; nvarchar2(255) default null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table NOTIFICATION_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique
+);
+
+create table NOTIFICATION (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;NOTIFICATION_HOME_RESOURCE_ID&quot; integer not null references NOTIFICATION_HOME,
+    &quot;NOTIFICATION_UID&quot; nvarchar2(255),
+    &quot;XML_TYPE&quot; nvarchar2(255),
+    &quot;XML_DATA&quot; nclob,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;NOTIFICATION_UID&quot;, &quot;NOTIFICATION_HOME_RESOURCE_ID&quot;)
+);
+
+create table CALENDAR_BIND (
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;CALENDAR_RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob,
+    &quot;TRANSP&quot; integer default 0 not null,
+    &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
+    &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
+    &quot;ALARM_VTODO_TIMED&quot; nclob default null,
+    &quot;ALARM_VTODO_ALLDAY&quot; nclob default null,
+    &quot;TIMEZONE&quot; nclob default null, 
+    primary key(&quot;CALENDAR_HOME_RESOURCE_ID&quot;, &quot;CALENDAR_RESOURCE_ID&quot;), 
+    unique(&quot;CALENDAR_HOME_RESOURCE_ID&quot;, &quot;CALENDAR_RESOURCE_NAME&quot;)
+);
+
+create table CALENDAR_BIND_MODE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
+create table CALENDAR_BIND_STATUS (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
+create table CALENDAR_TRANSP (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('opaque', 0);
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('transparent', 1);
+create table CALENDAR_OBJECT (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob,
+    &quot;ICALENDAR_UID&quot; nvarchar2(255),
+    &quot;ICALENDAR_TYPE&quot; nvarchar2(255),
+    &quot;ATTACHMENTS_MODE&quot; integer default 0 not null,
+    &quot;DROPBOX_ID&quot; nvarchar2(255),
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;RECURRANCE_MIN&quot; date,
+    &quot;RECURRANCE_MAX&quot; date,
+    &quot;ACCESS&quot; integer default 0 not null,
+    &quot;SCHEDULE_OBJECT&quot; integer default 0,
+    &quot;SCHEDULE_TAG&quot; nvarchar2(36) default null,
+    &quot;SCHEDULE_ETAGS&quot; nclob default null,
+    &quot;PRIVATE_COMMENTS&quot; integer default 0 not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;CALENDAR_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;)
+);
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MO (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('none', 0);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('write', 2);
+create table CALENDAR_ACCESS_TYPE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(32) unique
+);
+
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
+create table TIME_RANGE (
+    &quot;INSTANCE_ID&quot; integer primary key,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;CALENDAR_OBJECT_RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade,
+    &quot;FLOATING&quot; integer not null,
+    &quot;START_DATE&quot; timestamp not null,
+    &quot;END_DATE&quot; timestamp not null,
+    &quot;FBTYPE&quot; integer not null,
+    &quot;TRANSPARENT&quot; integer not null
+);
+
+create table FREE_BUSY_TYPE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
+create table TRANSPARENCY (
+    &quot;TIME_RANGE_INSTANCE_ID&quot; integer not null references TIME_RANGE on delete cascade,
+    &quot;USER_ID&quot; nvarchar2(255),
+    &quot;TRANSPARENT&quot; integer not null
+);
+
+create table ATTACHMENT (
+    &quot;ATTACHMENT_ID&quot; integer primary key,
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;DROPBOX_ID&quot; nvarchar2(255),
+    &quot;CONTENT_TYPE&quot; nvarchar2(255),
+    &quot;SIZE&quot; integer not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;PATH&quot; nvarchar2(1024)
+);
+
+create table ATTACHMENT_CALENDAR_OBJECT (
+    &quot;ATTACHMENT_ID&quot; integer not null references ATTACHMENT on delete cascade,
+    &quot;MANAGED_ID&quot; nvarchar2(255),
+    &quot;CALENDAR_OBJECT_RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade, 
+    primary key(&quot;ATTACHMENT_ID&quot;, &quot;CALENDAR_OBJECT_RESOURCE_ID&quot;), 
+    unique(&quot;MANAGED_ID&quot;, &quot;CALENDAR_OBJECT_RESOURCE_ID&quot;)
+);
+
+create table RESOURCE_PROPERTY (
+    &quot;RESOURCE_ID&quot; integer not null,
+    &quot;NAME&quot; nvarchar2(255),
+    &quot;VALUE&quot; nclob,
+    &quot;VIEWER_UID&quot; nvarchar2(255), 
+    primary key(&quot;RESOURCE_ID&quot;, &quot;NAME&quot;, &quot;VIEWER_UID&quot;)
+);
+
+create table ADDRESSBOOK_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;ADDRESSBOOK_PROPERTY_STORE_ID&quot; integer not null,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique,
+    &quot;DATAVERSION&quot; integer default 0 not null
+);
+
+create table ADDRESSBOOK_HOME_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references ADDRESSBOOK_HOME on delete cascade,
+    &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table SHARED_ADDRESSBOOK_BIND (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;OWNER_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;ADDRESSBOOK_RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob, 
+    primary key(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;OWNER_HOME_RESOURCE_ID&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;ADDRESSBOOK_RESOURCE_NAME&quot;)
+);
+
+create table ADDRESSBOOK_OBJECT (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;VCARD_TEXT&quot; nclob,
+    &quot;VCARD_UID&quot; nvarchar2(255),
+    &quot;KIND&quot; integer not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;VCARD_UID&quot;)
+);
+
+create table ADDRESSBOOK_OBJECT_KIND (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('person', 0);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('group', 1);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('resource', 2);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('location', 3);
+create table ABO_MEMBERS (
+    &quot;GROUP_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;ADDRESSBOOK_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;MEMBER_ID&quot; integer not null references ADDRESSBOOK_OBJECT, 
+    primary key(&quot;GROUP_ID&quot;, &quot;MEMBER_ID&quot;)
+);
+
+create table ABO_FOREIGN_MEMBERS (
+    &quot;GROUP_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;ADDRESSBOOK_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;MEMBER_ADDRESS&quot; nvarchar2(255), 
+    primary key(&quot;GROUP_ID&quot;, &quot;MEMBER_ADDRESS&quot;)
+);
+
+create table SHARED_GROUP_BIND (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;GROUP_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;GROUP_ADDRESSBOOK_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob, 
+    primary key(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;GROUP_RESOURCE_ID&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;GROUP_ADDRESSBOOK_NAME&quot;)
+);
+
+create table CALENDAR_OBJECT_REVISIONS (
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer references CALENDAR,
+    &quot;CALENDAR_NAME&quot; nvarchar2(255) default null,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null
+);
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;OWNER_HOME_RESOURCE_ID&quot; integer references ADDRESSBOOK_HOME,
+    &quot;ADDRESSBOOK_NAME&quot; nvarchar2(255) default null,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null
+);
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+    &quot;NOTIFICATION_HOME_RESOURCE_ID&quot; integer not null references NOTIFICATION_HOME on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null, 
+    unique(&quot;NOTIFICATION_HOME_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;)
+);
+
+create table APN_SUBSCRIPTIONS (
+    &quot;TOKEN&quot; nvarchar2(255),
+    &quot;RESOURCE_KEY&quot; nvarchar2(255),
+    &quot;MODIFIED&quot; integer not null,
+    &quot;SUBSCRIBER_GUID&quot; nvarchar2(255),
+    &quot;USER_AGENT&quot; nvarchar2(255) default null,
+    &quot;IP_ADDR&quot; nvarchar2(255) default null, 
+    primary key(&quot;TOKEN&quot;, &quot;RESOURCE_KEY&quot;)
+);
+
+create table IMIP_TOKENS (
+    &quot;TOKEN&quot; nvarchar2(255),
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;ATTENDEE&quot; nvarchar2(255),
+    &quot;ICALUID&quot; nvarchar2(255),
+    &quot;ACCESSED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    primary key(&quot;ORGANIZER&quot;, &quot;ATTENDEE&quot;, &quot;ICALUID&quot;)
+);
+
+create table IMIP_INVITATION_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;FROM_ADDR&quot; nvarchar2(255),
+    &quot;TO_ADDR&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob
+);
+
+create table IMIP_POLLING_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table IMIP_REPLY_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;ATTENDEE&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob
+);
+
+create table PUSH_NOTIFICATION_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;PUSH_ID&quot; nvarchar2(255)
+);
+
+create table GROUP_CACHER_POLLING_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade
+);
+
+create table CALENDARSERVER (
+    &quot;NAME&quot; nvarchar2(255) primary key,
+    &quot;VALUE&quot; nvarchar2(255)
+);
+
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '26');
+insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '5');
+insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
+create index CALENDAR_HOME_METADAT_3cb9049e on CALENDAR_HOME_METADATA (
+    DEFAULT_EVENTS
+);
+
+create index CALENDAR_HOME_METADAT_d55e5548 on CALENDAR_HOME_METADATA (
+    DEFAULT_TASKS
+);
+
+create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
+    NOTIFICATION_HOME_RESOURCE_ID
+);
+
+create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
+    CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
+    CALENDAR_RESOURCE_ID,
+    ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
+    CALENDAR_RESOURCE_ID,
+    RECURRANCE_MAX
+);
+
+create index CALENDAR_OBJECT_ICALE_82e731d5 on CALENDAR_OBJECT (
+    ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
+    DROPBOX_ID
+);
+
+create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
+    CALENDAR_RESOURCE_ID
+);
+
+create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
+    CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index TRANSPARENCY_TIME_RAN_5f34467f on TRANSPARENCY (
+    TIME_RANGE_INSTANCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
+    CALENDAR_HOME_RESOURCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_O_81508484 on ATTACHMENT_CALENDAR_OBJECT (
+    CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index SHARED_ADDRESSBOOK_BI_e9a2e6d4 on SHARED_ADDRESSBOOK_BIND (
+    OWNER_HOME_RESOURCE_ID
+);
+
+create index ABO_MEMBERS_ADDRESSBO_4effa879 on ABO_MEMBERS (
+    ADDRESSBOOK_ID
+);
+
+create index ABO_MEMBERS_MEMBER_ID_8d66adcf on ABO_MEMBERS (
+    MEMBER_ID
+);
+
+create index ABO_FOREIGN_MEMBERS_A_1fd2c5e9 on ABO_FOREIGN_MEMBERS (
+    ADDRESSBOOK_ID
+);
+
+create index SHARED_GROUP_BIND_RES_cf52f95d on SHARED_GROUP_BIND (
+    GROUP_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_HOME_RESOURCE_ID,
+    CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_6d9d929c on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_RESOURCE_ID,
+    RESOURCE_NAME,
+    DELETED,
+    REVISION
+);
+
+create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_RESOURCE_ID,
+    REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_2bfcf757 on ADDRESSBOOK_OBJECT_REVISIONS (
+    ADDRESSBOOK_HOME_RESOURCE_ID,
+    OWNER_HOME_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_OBJECT_RE_00fe8288 on ADDRESSBOOK_OBJECT_REVISIONS (
+    OWNER_HOME_RESOURCE_ID,
+    RESOURCE_NAME,
+    DELETED,
+    REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_45004780 on ADDRESSBOOK_OBJECT_REVISIONS (
+    OWNER_HOME_RESOURCE_ID,
+    REVISION
+);
+
+create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
+    NOTIFICATION_HOME_RESOURCE_ID,
+    REVISION
+);
+
+create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
+    RESOURCE_KEY
+);
+
+create index IMIP_TOKENS_TOKEN_e94b918f on IMIP_TOKENS (
+    TOKEN
+);
+
+create index CALENDAR_OBJECT_SPLIT_af71dcda on CALENDAR_OBJECT_SPLITTER_WORK (
+    RESOURCE_ID
+);
+
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldoracledialectv27sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaoldoracledialectv27sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v27.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v27.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v27.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v27.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,500 @@
</span><ins>+create sequence RESOURCE_ID_SEQ;
+create sequence INSTANCE_ID_SEQ;
+create sequence ATTACHMENT_ID_SEQ;
+create sequence REVISION_SEQ;
+create sequence WORKITEM_SEQ;
+create table NODE_INFO (
+    &quot;HOSTNAME&quot; nvarchar2(255),
+    &quot;PID&quot; integer not null,
+    &quot;PORT&quot; integer not null,
+    &quot;TIME&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC' not null, 
+    primary key(&quot;HOSTNAME&quot;, &quot;PORT&quot;)
+);
+
+create table NAMED_LOCK (
+    &quot;LOCK_NAME&quot; nvarchar2(255) primary key
+);
+
+create table CALENDAR_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique,
+    &quot;DATAVERSION&quot; integer default 0 not null
+);
+
+create table CALENDAR (
+    &quot;RESOURCE_ID&quot; integer primary key
+);
+
+create table CALENDAR_HOME_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references CALENDAR_HOME on delete cascade,
+    &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
+    &quot;DEFAULT_EVENTS&quot; integer default null references CALENDAR on delete set null,
+    &quot;DEFAULT_TASKS&quot; integer default null references CALENDAR on delete set null,
+    &quot;DEFAULT_POLLS&quot; integer default null references CALENDAR on delete set null,
+    &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
+    &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
+    &quot;ALARM_VTODO_TIMED&quot; nclob default null,
+    &quot;ALARM_VTODO_ALLDAY&quot; nclob default null,
+    &quot;AVAILABILITY&quot; nclob default null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references CALENDAR on delete cascade,
+    &quot;SUPPORTED_COMPONENTS&quot; nvarchar2(255) default null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table NOTIFICATION_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique
+);
+
+create table NOTIFICATION (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;NOTIFICATION_HOME_RESOURCE_ID&quot; integer not null references NOTIFICATION_HOME,
+    &quot;NOTIFICATION_UID&quot; nvarchar2(255),
+    &quot;XML_TYPE&quot; nvarchar2(255),
+    &quot;XML_DATA&quot; nclob,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;NOTIFICATION_UID&quot;, &quot;NOTIFICATION_HOME_RESOURCE_ID&quot;)
+);
+
+create table CALENDAR_BIND (
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;CALENDAR_RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob,
+    &quot;TRANSP&quot; integer default 0 not null,
+    &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
+    &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
+    &quot;ALARM_VTODO_TIMED&quot; nclob default null,
+    &quot;ALARM_VTODO_ALLDAY&quot; nclob default null,
+    &quot;TIMEZONE&quot; nclob default null, 
+    primary key(&quot;CALENDAR_HOME_RESOURCE_ID&quot;, &quot;CALENDAR_RESOURCE_ID&quot;), 
+    unique(&quot;CALENDAR_HOME_RESOURCE_ID&quot;, &quot;CALENDAR_RESOURCE_NAME&quot;)
+);
+
+create table CALENDAR_BIND_MODE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
+create table CALENDAR_BIND_STATUS (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
+create table CALENDAR_TRANSP (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('opaque', 0);
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('transparent', 1);
+create table CALENDAR_OBJECT (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob,
+    &quot;ICALENDAR_UID&quot; nvarchar2(255),
+    &quot;ICALENDAR_TYPE&quot; nvarchar2(255),
+    &quot;ATTACHMENTS_MODE&quot; integer default 0 not null,
+    &quot;DROPBOX_ID&quot; nvarchar2(255),
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;RECURRANCE_MIN&quot; date,
+    &quot;RECURRANCE_MAX&quot; date,
+    &quot;ACCESS&quot; integer default 0 not null,
+    &quot;SCHEDULE_OBJECT&quot; integer default 0,
+    &quot;SCHEDULE_TAG&quot; nvarchar2(36) default null,
+    &quot;SCHEDULE_ETAGS&quot; nclob default null,
+    &quot;PRIVATE_COMMENTS&quot; integer default 0 not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;CALENDAR_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;)
+);
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MO (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('none', 0);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('write', 2);
+create table CALENDAR_ACCESS_TYPE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(32) unique
+);
+
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
+create table TIME_RANGE (
+    &quot;INSTANCE_ID&quot; integer primary key,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;CALENDAR_OBJECT_RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade,
+    &quot;FLOATING&quot; integer not null,
+    &quot;START_DATE&quot; timestamp not null,
+    &quot;END_DATE&quot; timestamp not null,
+    &quot;FBTYPE&quot; integer not null,
+    &quot;TRANSPARENT&quot; integer not null
+);
+
+create table FREE_BUSY_TYPE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
+create table TRANSPARENCY (
+    &quot;TIME_RANGE_INSTANCE_ID&quot; integer not null references TIME_RANGE on delete cascade,
+    &quot;USER_ID&quot; nvarchar2(255),
+    &quot;TRANSPARENT&quot; integer not null
+);
+
+create table ATTACHMENT (
+    &quot;ATTACHMENT_ID&quot; integer primary key,
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;DROPBOX_ID&quot; nvarchar2(255),
+    &quot;CONTENT_TYPE&quot; nvarchar2(255),
+    &quot;SIZE&quot; integer not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;PATH&quot; nvarchar2(1024)
+);
+
+create table ATTACHMENT_CALENDAR_OBJECT (
+    &quot;ATTACHMENT_ID&quot; integer not null references ATTACHMENT on delete cascade,
+    &quot;MANAGED_ID&quot; nvarchar2(255),
+    &quot;CALENDAR_OBJECT_RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade, 
+    primary key(&quot;ATTACHMENT_ID&quot;, &quot;CALENDAR_OBJECT_RESOURCE_ID&quot;), 
+    unique(&quot;MANAGED_ID&quot;, &quot;CALENDAR_OBJECT_RESOURCE_ID&quot;)
+);
+
+create table RESOURCE_PROPERTY (
+    &quot;RESOURCE_ID&quot; integer not null,
+    &quot;NAME&quot; nvarchar2(255),
+    &quot;VALUE&quot; nclob,
+    &quot;VIEWER_UID&quot; nvarchar2(255), 
+    primary key(&quot;RESOURCE_ID&quot;, &quot;NAME&quot;, &quot;VIEWER_UID&quot;)
+);
+
+create table ADDRESSBOOK_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;ADDRESSBOOK_PROPERTY_STORE_ID&quot; integer not null,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique,
+    &quot;DATAVERSION&quot; integer default 0 not null
+);
+
+create table ADDRESSBOOK_HOME_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references ADDRESSBOOK_HOME on delete cascade,
+    &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table SHARED_ADDRESSBOOK_BIND (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;OWNER_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;ADDRESSBOOK_RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob, 
+    primary key(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;OWNER_HOME_RESOURCE_ID&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;ADDRESSBOOK_RESOURCE_NAME&quot;)
+);
+
+create table ADDRESSBOOK_OBJECT (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;VCARD_TEXT&quot; nclob,
+    &quot;VCARD_UID&quot; nvarchar2(255),
+    &quot;KIND&quot; integer not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;VCARD_UID&quot;)
+);
+
+create table ADDRESSBOOK_OBJECT_KIND (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('person', 0);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('group', 1);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('resource', 2);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('location', 3);
+create table ABO_MEMBERS (
+    &quot;GROUP_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;ADDRESSBOOK_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;MEMBER_ID&quot; integer not null references ADDRESSBOOK_OBJECT, 
+    primary key(&quot;GROUP_ID&quot;, &quot;MEMBER_ID&quot;)
+);
+
+create table ABO_FOREIGN_MEMBERS (
+    &quot;GROUP_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;ADDRESSBOOK_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;MEMBER_ADDRESS&quot; nvarchar2(255), 
+    primary key(&quot;GROUP_ID&quot;, &quot;MEMBER_ADDRESS&quot;)
+);
+
+create table SHARED_GROUP_BIND (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;GROUP_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;GROUP_ADDRESSBOOK_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob, 
+    primary key(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;GROUP_RESOURCE_ID&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;GROUP_ADDRESSBOOK_NAME&quot;)
+);
+
+create table CALENDAR_OBJECT_REVISIONS (
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer references CALENDAR,
+    &quot;CALENDAR_NAME&quot; nvarchar2(255) default null,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null
+);
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;OWNER_HOME_RESOURCE_ID&quot; integer references ADDRESSBOOK_HOME,
+    &quot;ADDRESSBOOK_NAME&quot; nvarchar2(255) default null,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null
+);
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+    &quot;NOTIFICATION_HOME_RESOURCE_ID&quot; integer not null references NOTIFICATION_HOME on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null, 
+    unique(&quot;NOTIFICATION_HOME_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;)
+);
+
+create table APN_SUBSCRIPTIONS (
+    &quot;TOKEN&quot; nvarchar2(255),
+    &quot;RESOURCE_KEY&quot; nvarchar2(255),
+    &quot;MODIFIED&quot; integer not null,
+    &quot;SUBSCRIBER_GUID&quot; nvarchar2(255),
+    &quot;USER_AGENT&quot; nvarchar2(255) default null,
+    &quot;IP_ADDR&quot; nvarchar2(255) default null, 
+    primary key(&quot;TOKEN&quot;, &quot;RESOURCE_KEY&quot;)
+);
+
+create table IMIP_TOKENS (
+    &quot;TOKEN&quot; nvarchar2(255),
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;ATTENDEE&quot; nvarchar2(255),
+    &quot;ICALUID&quot; nvarchar2(255),
+    &quot;ACCESSED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    primary key(&quot;ORGANIZER&quot;, &quot;ATTENDEE&quot;, &quot;ICALUID&quot;)
+);
+
+create table IMIP_INVITATION_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;FROM_ADDR&quot; nvarchar2(255),
+    &quot;TO_ADDR&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob
+);
+
+create table IMIP_POLLING_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table IMIP_REPLY_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;ATTENDEE&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob
+);
+
+create table PUSH_NOTIFICATION_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;PUSH_ID&quot; nvarchar2(255)
+);
+
+create table GROUP_CACHER_POLLING_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade
+);
+
+create table CALENDARSERVER (
+    &quot;NAME&quot; nvarchar2(255) primary key,
+    &quot;VALUE&quot; nvarchar2(255)
+);
+
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '27');
+insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '5');
+insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
+create index CALENDAR_HOME_METADAT_3cb9049e on CALENDAR_HOME_METADATA (
+    DEFAULT_EVENTS
+);
+
+create index CALENDAR_HOME_METADAT_d55e5548 on CALENDAR_HOME_METADATA (
+    DEFAULT_TASKS
+);
+
+create index CALENDAR_HOME_METADAT_910264ce on CALENDAR_HOME_METADATA (
+    DEFAULT_POLLS
+);
+
+create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
+    NOTIFICATION_HOME_RESOURCE_ID
+);
+
+create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
+    CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
+    CALENDAR_RESOURCE_ID,
+    ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
+    CALENDAR_RESOURCE_ID,
+    RECURRANCE_MAX
+);
+
+create index CALENDAR_OBJECT_ICALE_82e731d5 on CALENDAR_OBJECT (
+    ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
+    DROPBOX_ID
+);
+
+create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
+    CALENDAR_RESOURCE_ID
+);
+
+create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
+    CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index TRANSPARENCY_TIME_RAN_5f34467f on TRANSPARENCY (
+    TIME_RANGE_INSTANCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
+    CALENDAR_HOME_RESOURCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_O_81508484 on ATTACHMENT_CALENDAR_OBJECT (
+    CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index SHARED_ADDRESSBOOK_BI_e9a2e6d4 on SHARED_ADDRESSBOOK_BIND (
+    OWNER_HOME_RESOURCE_ID
+);
+
+create index ABO_MEMBERS_ADDRESSBO_4effa879 on ABO_MEMBERS (
+    ADDRESSBOOK_ID
+);
+
+create index ABO_MEMBERS_MEMBER_ID_8d66adcf on ABO_MEMBERS (
+    MEMBER_ID
+);
+
+create index ABO_FOREIGN_MEMBERS_A_1fd2c5e9 on ABO_FOREIGN_MEMBERS (
+    ADDRESSBOOK_ID
+);
+
+create index SHARED_GROUP_BIND_RES_cf52f95d on SHARED_GROUP_BIND (
+    GROUP_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_HOME_RESOURCE_ID,
+    CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_6d9d929c on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_RESOURCE_ID,
+    RESOURCE_NAME,
+    DELETED,
+    REVISION
+);
+
+create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_RESOURCE_ID,
+    REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_2bfcf757 on ADDRESSBOOK_OBJECT_REVISIONS (
+    ADDRESSBOOK_HOME_RESOURCE_ID,
+    OWNER_HOME_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_OBJECT_RE_00fe8288 on ADDRESSBOOK_OBJECT_REVISIONS (
+    OWNER_HOME_RESOURCE_ID,
+    RESOURCE_NAME,
+    DELETED,
+    REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_45004780 on ADDRESSBOOK_OBJECT_REVISIONS (
+    OWNER_HOME_RESOURCE_ID,
+    REVISION
+);
+
+create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
+    NOTIFICATION_HOME_RESOURCE_ID,
+    REVISION
+);
+
+create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
+    RESOURCE_KEY
+);
+
+create index IMIP_TOKENS_TOKEN_e94b918f on IMIP_TOKENS (
+    TOKEN
+);
+
+create index CALENDAR_OBJECT_SPLIT_af71dcda on CALENDAR_OBJECT_SPLITTER_WORK (
+    RESOURCE_ID
+);
+
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldoracledialectv28sql"></a>
<div class="addfile"><h4>Added: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v28.sql (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v28.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/oracle-dialect/v28.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,501 @@
</span><ins>+create sequence RESOURCE_ID_SEQ;
+create sequence INSTANCE_ID_SEQ;
+create sequence ATTACHMENT_ID_SEQ;
+create sequence REVISION_SEQ;
+create sequence WORKITEM_SEQ;
+create table NODE_INFO (
+    &quot;HOSTNAME&quot; nvarchar2(255),
+    &quot;PID&quot; integer not null,
+    &quot;PORT&quot; integer not null,
+    &quot;TIME&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC' not null, 
+    primary key(&quot;HOSTNAME&quot;, &quot;PORT&quot;)
+);
+
+create table NAMED_LOCK (
+    &quot;LOCK_NAME&quot; nvarchar2(255) primary key
+);
+
+create table CALENDAR_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique,
+    &quot;DATAVERSION&quot; integer default 0 not null
+);
+
+create table CALENDAR (
+    &quot;RESOURCE_ID&quot; integer primary key
+);
+
+create table CALENDAR_HOME_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references CALENDAR_HOME on delete cascade,
+    &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
+    &quot;DEFAULT_EVENTS&quot; integer default null references CALENDAR on delete set null,
+    &quot;DEFAULT_TASKS&quot; integer default null references CALENDAR on delete set null,
+    &quot;DEFAULT_POLLS&quot; integer default null references CALENDAR on delete set null,
+    &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
+    &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
+    &quot;ALARM_VTODO_TIMED&quot; nclob default null,
+    &quot;ALARM_VTODO_ALLDAY&quot; nclob default null,
+    &quot;AVAILABILITY&quot; nclob default null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references CALENDAR on delete cascade,
+    &quot;SUPPORTED_COMPONENTS&quot; nvarchar2(255) default null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table NOTIFICATION_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique
+);
+
+create table NOTIFICATION (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;NOTIFICATION_HOME_RESOURCE_ID&quot; integer not null references NOTIFICATION_HOME,
+    &quot;NOTIFICATION_UID&quot; nvarchar2(255),
+    &quot;XML_TYPE&quot; nvarchar2(255),
+    &quot;XML_DATA&quot; nclob,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;NOTIFICATION_UID&quot;, &quot;NOTIFICATION_HOME_RESOURCE_ID&quot;)
+);
+
+create table CALENDAR_BIND (
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;CALENDAR_RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob,
+    &quot;TRANSP&quot; integer default 0 not null,
+    &quot;ALARM_VEVENT_TIMED&quot; nclob default null,
+    &quot;ALARM_VEVENT_ALLDAY&quot; nclob default null,
+    &quot;ALARM_VTODO_TIMED&quot; nclob default null,
+    &quot;ALARM_VTODO_ALLDAY&quot; nclob default null,
+    &quot;TIMEZONE&quot; nclob default null, 
+    primary key(&quot;CALENDAR_HOME_RESOURCE_ID&quot;, &quot;CALENDAR_RESOURCE_ID&quot;), 
+    unique(&quot;CALENDAR_HOME_RESOURCE_ID&quot;, &quot;CALENDAR_RESOURCE_NAME&quot;)
+);
+
+create table CALENDAR_BIND_MODE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
+create table CALENDAR_BIND_STATUS (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
+create table CALENDAR_TRANSP (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('opaque', 0);
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('transparent', 1);
+create table CALENDAR_OBJECT (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob,
+    &quot;ICALENDAR_UID&quot; nvarchar2(255),
+    &quot;ICALENDAR_TYPE&quot; nvarchar2(255),
+    &quot;ATTACHMENTS_MODE&quot; integer default 0 not null,
+    &quot;DROPBOX_ID&quot; nvarchar2(255),
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;RECURRANCE_MIN&quot; date,
+    &quot;RECURRANCE_MAX&quot; date,
+    &quot;ACCESS&quot; integer default 0 not null,
+    &quot;SCHEDULE_OBJECT&quot; integer default 0,
+    &quot;SCHEDULE_TAG&quot; nvarchar2(36) default null,
+    &quot;SCHEDULE_ETAGS&quot; nclob default null,
+    &quot;PRIVATE_COMMENTS&quot; integer default 0 not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;CALENDAR_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;)
+);
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MO (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('none', 0);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('write', 2);
+create table CALENDAR_ACCESS_TYPE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(32) unique
+);
+
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
+create table TIME_RANGE (
+    &quot;INSTANCE_ID&quot; integer primary key,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer not null references CALENDAR on delete cascade,
+    &quot;CALENDAR_OBJECT_RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade,
+    &quot;FLOATING&quot; integer not null,
+    &quot;START_DATE&quot; timestamp not null,
+    &quot;END_DATE&quot; timestamp not null,
+    &quot;FBTYPE&quot; integer not null,
+    &quot;TRANSPARENT&quot; integer not null
+);
+
+create table FREE_BUSY_TYPE (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
+create table TRANSPARENCY (
+    &quot;TIME_RANGE_INSTANCE_ID&quot; integer not null references TIME_RANGE on delete cascade,
+    &quot;USER_ID&quot; nvarchar2(255),
+    &quot;TRANSPARENT&quot; integer not null
+);
+
+create table ATTACHMENT (
+    &quot;ATTACHMENT_ID&quot; integer primary key,
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;DROPBOX_ID&quot; nvarchar2(255),
+    &quot;CONTENT_TYPE&quot; nvarchar2(255),
+    &quot;SIZE&quot; integer not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;PATH&quot; nvarchar2(1024)
+);
+
+create table ATTACHMENT_CALENDAR_OBJECT (
+    &quot;ATTACHMENT_ID&quot; integer not null references ATTACHMENT on delete cascade,
+    &quot;MANAGED_ID&quot; nvarchar2(255),
+    &quot;CALENDAR_OBJECT_RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade, 
+    primary key(&quot;ATTACHMENT_ID&quot;, &quot;CALENDAR_OBJECT_RESOURCE_ID&quot;), 
+    unique(&quot;MANAGED_ID&quot;, &quot;CALENDAR_OBJECT_RESOURCE_ID&quot;)
+);
+
+create table RESOURCE_PROPERTY (
+    &quot;RESOURCE_ID&quot; integer not null,
+    &quot;NAME&quot; nvarchar2(255),
+    &quot;VALUE&quot; nclob,
+    &quot;VIEWER_UID&quot; nvarchar2(255), 
+    primary key(&quot;RESOURCE_ID&quot;, &quot;NAME&quot;, &quot;VIEWER_UID&quot;)
+);
+
+create table ADDRESSBOOK_HOME (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;ADDRESSBOOK_PROPERTY_STORE_ID&quot; integer not null,
+    &quot;OWNER_UID&quot; nvarchar2(255) unique,
+    &quot;DATAVERSION&quot; integer default 0 not null
+);
+
+create table ADDRESSBOOK_HOME_METADATA (
+    &quot;RESOURCE_ID&quot; integer primary key references ADDRESSBOOK_HOME on delete cascade,
+    &quot;QUOTA_USED_BYTES&quot; integer default 0 not null,
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table SHARED_ADDRESSBOOK_BIND (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;OWNER_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;ADDRESSBOOK_RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob, 
+    primary key(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;OWNER_HOME_RESOURCE_ID&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;ADDRESSBOOK_RESOURCE_NAME&quot;)
+);
+
+create table ADDRESSBOOK_OBJECT (
+    &quot;RESOURCE_ID&quot; integer primary key,
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;VCARD_TEXT&quot; nclob,
+    &quot;VCARD_UID&quot; nvarchar2(255),
+    &quot;KIND&quot; integer not null,
+    &quot;MD5&quot; nchar(32),
+    &quot;CREATED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;MODIFIED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;VCARD_UID&quot;)
+);
+
+create table ADDRESSBOOK_OBJECT_KIND (
+    &quot;ID&quot; integer primary key,
+    &quot;DESCRIPTION&quot; nvarchar2(16) unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('person', 0);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('group', 1);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('resource', 2);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('location', 3);
+create table ABO_MEMBERS (
+    &quot;GROUP_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;ADDRESSBOOK_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;MEMBER_ID&quot; integer not null references ADDRESSBOOK_OBJECT, 
+    primary key(&quot;GROUP_ID&quot;, &quot;MEMBER_ID&quot;)
+);
+
+create table ABO_FOREIGN_MEMBERS (
+    &quot;GROUP_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;ADDRESSBOOK_ID&quot; integer not null references ADDRESSBOOK_HOME on delete cascade,
+    &quot;MEMBER_ADDRESS&quot; nvarchar2(255), 
+    primary key(&quot;GROUP_ID&quot;, &quot;MEMBER_ADDRESS&quot;)
+);
+
+create table SHARED_GROUP_BIND (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;GROUP_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+    &quot;GROUP_ADDRESSBOOK_NAME&quot; nvarchar2(255),
+    &quot;BIND_MODE&quot; integer not null,
+    &quot;BIND_STATUS&quot; integer not null,
+    &quot;BIND_REVISION&quot; integer default 0 not null,
+    &quot;MESSAGE&quot; nclob, 
+    primary key(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;GROUP_RESOURCE_ID&quot;), 
+    unique(&quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot;, &quot;GROUP_ADDRESSBOOK_NAME&quot;)
+);
+
+create table CALENDAR_OBJECT_REVISIONS (
+    &quot;CALENDAR_HOME_RESOURCE_ID&quot; integer not null references CALENDAR_HOME,
+    &quot;CALENDAR_RESOURCE_ID&quot; integer references CALENDAR,
+    &quot;CALENDAR_NAME&quot; nvarchar2(255) default null,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null
+);
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+    &quot;ADDRESSBOOK_HOME_RESOURCE_ID&quot; integer not null references ADDRESSBOOK_HOME,
+    &quot;OWNER_HOME_RESOURCE_ID&quot; integer references ADDRESSBOOK_HOME,
+    &quot;ADDRESSBOOK_NAME&quot; nvarchar2(255) default null,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null
+);
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+    &quot;NOTIFICATION_HOME_RESOURCE_ID&quot; integer not null references NOTIFICATION_HOME on delete cascade,
+    &quot;RESOURCE_NAME&quot; nvarchar2(255),
+    &quot;REVISION&quot; integer not null,
+    &quot;DELETED&quot; integer not null, 
+    unique(&quot;NOTIFICATION_HOME_RESOURCE_ID&quot;, &quot;RESOURCE_NAME&quot;)
+);
+
+create table APN_SUBSCRIPTIONS (
+    &quot;TOKEN&quot; nvarchar2(255),
+    &quot;RESOURCE_KEY&quot; nvarchar2(255),
+    &quot;MODIFIED&quot; integer not null,
+    &quot;SUBSCRIBER_GUID&quot; nvarchar2(255),
+    &quot;USER_AGENT&quot; nvarchar2(255) default null,
+    &quot;IP_ADDR&quot; nvarchar2(255) default null, 
+    primary key(&quot;TOKEN&quot;, &quot;RESOURCE_KEY&quot;)
+);
+
+create table IMIP_TOKENS (
+    &quot;TOKEN&quot; nvarchar2(255),
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;ATTENDEE&quot; nvarchar2(255),
+    &quot;ICALUID&quot; nvarchar2(255),
+    &quot;ACCESSED&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC', 
+    primary key(&quot;ORGANIZER&quot;, &quot;ATTENDEE&quot;, &quot;ICALUID&quot;)
+);
+
+create table IMIP_INVITATION_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;FROM_ADDR&quot; nvarchar2(255),
+    &quot;TO_ADDR&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob
+);
+
+create table IMIP_POLLING_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table IMIP_REPLY_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;ORGANIZER&quot; nvarchar2(255),
+    &quot;ATTENDEE&quot; nvarchar2(255),
+    &quot;ICALENDAR_TEXT&quot; nclob
+);
+
+create table PUSH_NOTIFICATION_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;PUSH_ID&quot; nvarchar2(255),
+    &quot;PRIORITY&quot; integer not null
+);
+
+create table GROUP_CACHER_POLLING_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+    &quot;WORK_ID&quot; integer primary key not null,
+    &quot;NOT_BEFORE&quot; timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+    &quot;RESOURCE_ID&quot; integer not null references CALENDAR_OBJECT on delete cascade
+);
+
+create table CALENDARSERVER (
+    &quot;NAME&quot; nvarchar2(255) primary key,
+    &quot;VALUE&quot; nvarchar2(255)
+);
+
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '28');
+insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '5');
+insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
+create index CALENDAR_HOME_METADAT_3cb9049e on CALENDAR_HOME_METADATA (
+    DEFAULT_EVENTS
+);
+
+create index CALENDAR_HOME_METADAT_d55e5548 on CALENDAR_HOME_METADATA (
+    DEFAULT_TASKS
+);
+
+create index CALENDAR_HOME_METADAT_910264ce on CALENDAR_HOME_METADATA (
+    DEFAULT_POLLS
+);
+
+create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
+    NOTIFICATION_HOME_RESOURCE_ID
+);
+
+create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
+    CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
+    CALENDAR_RESOURCE_ID,
+    ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
+    CALENDAR_RESOURCE_ID,
+    RECURRANCE_MAX
+);
+
+create index CALENDAR_OBJECT_ICALE_82e731d5 on CALENDAR_OBJECT (
+    ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
+    DROPBOX_ID
+);
+
+create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
+    CALENDAR_RESOURCE_ID
+);
+
+create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
+    CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index TRANSPARENCY_TIME_RAN_5f34467f on TRANSPARENCY (
+    TIME_RANGE_INSTANCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
+    CALENDAR_HOME_RESOURCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_O_81508484 on ATTACHMENT_CALENDAR_OBJECT (
+    CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index SHARED_ADDRESSBOOK_BI_e9a2e6d4 on SHARED_ADDRESSBOOK_BIND (
+    OWNER_HOME_RESOURCE_ID
+);
+
+create index ABO_MEMBERS_ADDRESSBO_4effa879 on ABO_MEMBERS (
+    ADDRESSBOOK_ID
+);
+
+create index ABO_MEMBERS_MEMBER_ID_8d66adcf on ABO_MEMBERS (
+    MEMBER_ID
+);
+
+create index ABO_FOREIGN_MEMBERS_A_1fd2c5e9 on ABO_FOREIGN_MEMBERS (
+    ADDRESSBOOK_ID
+);
+
+create index SHARED_GROUP_BIND_RES_cf52f95d on SHARED_GROUP_BIND (
+    GROUP_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_HOME_RESOURCE_ID,
+    CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_6d9d929c on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_RESOURCE_ID,
+    RESOURCE_NAME,
+    DELETED,
+    REVISION
+);
+
+create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_RESOURCE_ID,
+    REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_2bfcf757 on ADDRESSBOOK_OBJECT_REVISIONS (
+    ADDRESSBOOK_HOME_RESOURCE_ID,
+    OWNER_HOME_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_OBJECT_RE_00fe8288 on ADDRESSBOOK_OBJECT_REVISIONS (
+    OWNER_HOME_RESOURCE_ID,
+    RESOURCE_NAME,
+    DELETED,
+    REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_45004780 on ADDRESSBOOK_OBJECT_REVISIONS (
+    OWNER_HOME_RESOURCE_ID,
+    REVISION
+);
+
+create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
+    NOTIFICATION_HOME_RESOURCE_ID,
+    REVISION
+);
+
+create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
+    RESOURCE_KEY
+);
+
+create index IMIP_TOKENS_TOKEN_e94b918f on IMIP_TOKENS (
+    TOKEN
+);
+
+create index CALENDAR_OBJECT_SPLIT_af71dcda on CALENDAR_OBJECT_SPLITTER_WORK (
+    RESOURCE_ID
+);
+
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldpostgresdialectv24sql"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v24.sql (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v24.sql        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v24.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,700 +0,0 @@
</span><del>--- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
-
-----
--- Copyright (c) 2010-2013 Apple Inc. 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.
-----
-
-
------------------
--- Resource ID --
------------------
-
-create sequence RESOURCE_ID_SEQ;
-
-
--------------------------
--- Cluster Bookkeeping --
--------------------------
-
--- Information about a process connected to this database.
-
--- Note that this must match the node info schema in twext.enterprise.queue.
-create table NODE_INFO (
-  HOSTNAME  varchar(255) not null,
-  PID       integer      not null,
-  PORT      integer      not null,
-  TIME      timestamp    not null default timezone('UTC', CURRENT_TIMESTAMP),
-
-  primary key (HOSTNAME, PORT)
-);
-
--- Unique named locks.  This table should always be empty, but rows are
--- temporarily created in order to prevent undesirable concurrency.
-create table NAMED_LOCK (
-    LOCK_NAME varchar(255) primary key
-);
-
-
--------------------
--- Calendar Home --
--------------------
-
-create table CALENDAR_HOME (
-  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  OWNER_UID        varchar(255) not null unique,                                 -- implicit index
-  DATAVERSION      integer      default 0 not null
-);
-
---------------
--- Calendar --
---------------
-
-create table CALENDAR (
-  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
-);
-
-----------------------------
--- Calendar Home Metadata --
-----------------------------
-
-create table CALENDAR_HOME_METADATA (
-  RESOURCE_ID              integer     primary key references CALENDAR_HOME on delete cascade, -- implicit index
-  QUOTA_USED_BYTES         integer     default 0 not null,
-  DEFAULT_EVENTS           integer     default null references CALENDAR on delete set null,
-  DEFAULT_TASKS            integer     default null references CALENDAR on delete set null,
-  ALARM_VEVENT_TIMED       text        default null,
-  ALARM_VEVENT_ALLDAY      text        default null,
-  ALARM_VTODO_TIMED        text        default null,
-  ALARM_VTODO_ALLDAY       text        default null,
-  AVAILABILITY             text        default null,
-  CREATED                  timestamp   default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED                 timestamp   default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
-create index CALENDAR_HOME_METADATA_DEFAULT_EVENTS on
-        CALENDAR_HOME_METADATA(DEFAULT_EVENTS);
-create index CALENDAR_HOME_METADATA_DEFAULT_TASKS on
-        CALENDAR_HOME_METADATA(DEFAULT_TASKS);
-
------------------------
--- Calendar Metadata --
------------------------
-
-create table CALENDAR_METADATA (
-  RESOURCE_ID           integer      primary key references CALENDAR on delete cascade, -- implicit index
-  SUPPORTED_COMPONENTS  varchar(255) default null,
-  CREATED               timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
-
----------------------------
--- Sharing Notifications --
----------------------------
-
-create table NOTIFICATION_HOME (
-  RESOURCE_ID integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  OWNER_UID   varchar(255) not null unique                                 -- implicit index
-);
-
-create table NOTIFICATION (
-  RESOURCE_ID                   integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME,
-  NOTIFICATION_UID              varchar(255) not null,
-  XML_TYPE                      varchar(255) not null,
-  XML_DATA                      text         not null,
-  MD5                           char(32)     not null,
-  CREATED                       timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED                      timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-
-  unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
-);
-
-create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
-        NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
-
-
--------------------
--- Calendar Bind --
--------------------
-
--- Joins CALENDAR_HOME and CALENDAR
-
-create table CALENDAR_BIND (
-  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
-  CALENDAR_RESOURCE_ID      integer      not null references CALENDAR on delete cascade,
-  CALENDAR_RESOURCE_NAME    varchar(255) not null,
-  BIND_MODE                 integer      not null, -- enum CALENDAR_BIND_MODE
-  BIND_STATUS               integer      not null, -- enum CALENDAR_BIND_STATUS
-  BIND_REVISION                                integer      default 0 not null,
-  MESSAGE                   text,
-  TRANSP                    integer      default 0 not null, -- enum CALENDAR_TRANSP
-  ALARM_VEVENT_TIMED        text         default null,
-  ALARM_VEVENT_ALLDAY       text         default null,
-  ALARM_VTODO_TIMED         text         default null,
-  ALARM_VTODO_ALLDAY        text         default null,
-  TIMEZONE                  text         default null,
-
-  primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
-  unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME)     -- implicit index
-);
-
-create index CALENDAR_BIND_RESOURCE_ID on
-        CALENDAR_BIND(CALENDAR_RESOURCE_ID);
-
--- Enumeration of calendar bind modes
-
-create table CALENDAR_BIND_MODE (
-  ID          integer     primary key,
-  DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_BIND_MODE values (0, 'own'  );
-insert into CALENDAR_BIND_MODE values (1, 'read' );
-insert into CALENDAR_BIND_MODE values (2, 'write');
-insert into CALENDAR_BIND_MODE values (3, 'direct');
-
--- Enumeration of statuses
-
-create table CALENDAR_BIND_STATUS (
-  ID          integer     primary key,
-  DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_BIND_STATUS values (0, 'invited' );
-insert into CALENDAR_BIND_STATUS values (1, 'accepted');
-insert into CALENDAR_BIND_STATUS values (2, 'declined');
-insert into CALENDAR_BIND_STATUS values (3, 'invalid');
-
-
--- Enumeration of transparency
-
-create table CALENDAR_TRANSP (
-  ID          integer     primary key,
-  DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_TRANSP values (0, 'opaque' );
-insert into CALENDAR_TRANSP values (1, 'transparent');
-
-
----------------------
--- Calendar Object --
----------------------
-
-create table CALENDAR_OBJECT (
-  RESOURCE_ID          integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  CALENDAR_RESOURCE_ID integer      not null references CALENDAR on delete cascade,
-  RESOURCE_NAME        varchar(255) not null,
-  ICALENDAR_TEXT       text         not null,
-  ICALENDAR_UID        varchar(255) not null,
-  ICALENDAR_TYPE       varchar(255) not null,
-  ATTACHMENTS_MODE     integer      default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
-  DROPBOX_ID           varchar(255),
-  ORGANIZER            varchar(255),
-  RECURRANCE_MIN       date,        -- minimum date that recurrences have been expanded to.
-  RECURRANCE_MAX       date,        -- maximum date that recurrences have been expanded to.
-  ACCESS               integer      default 0 not null,
-  SCHEDULE_OBJECT      boolean      default false,
-  SCHEDULE_TAG         varchar(36)  default null,
-  SCHEDULE_ETAGS       text         default null,
-  PRIVATE_COMMENTS     boolean      default false not null,
-  MD5                  char(32)     not null,
-  CREATED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED             timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-
-  unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
-
-  -- since the 'inbox' is a 'calendar resource' for the purpose of storing
-  -- calendar objects, this constraint has to be selectively enforced by the
-  -- application layer.
-
-  -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
-);
-
-create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
-  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
-
-create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
-  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
-
-create index CALENDAR_OBJECT_ICALENDAR_UID on
-  CALENDAR_OBJECT(ICALENDAR_UID);
-
-create index CALENDAR_OBJECT_DROPBOX_ID on
-  CALENDAR_OBJECT(DROPBOX_ID);
-
--- Enumeration of attachment modes
-
-create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
-  ID          integer     primary key,
-  DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
-
-
--- Enumeration of calendar access types
-
-create table CALENDAR_ACCESS_TYPE (
-  ID          integer     primary key,
-  DESCRIPTION varchar(32) not null unique
-);
-
-insert into CALENDAR_ACCESS_TYPE values (0, ''             );
-insert into CALENDAR_ACCESS_TYPE values (1, 'public'       );
-insert into CALENDAR_ACCESS_TYPE values (2, 'private'      );
-insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
-insert into CALENDAR_ACCESS_TYPE values (4, 'restricted'   );
-
-
------------------
--- Instance ID --
------------------
-
-create sequence INSTANCE_ID_SEQ;
-
-
-----------------
--- Time Range --
-----------------
-
-create table TIME_RANGE (
-  INSTANCE_ID                 integer        primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
-  CALENDAR_RESOURCE_ID        integer        not null references CALENDAR on delete cascade,
-  CALENDAR_OBJECT_RESOURCE_ID integer        not null references CALENDAR_OBJECT on delete cascade,
-  FLOATING                    boolean        not null,
-  START_DATE                  timestamp      not null,
-  END_DATE                    timestamp      not null,
-  FBTYPE                      integer        not null,
-  TRANSPARENT                 boolean        not null
-);
-
-create index TIME_RANGE_CALENDAR_RESOURCE_ID on
-  TIME_RANGE(CALENDAR_RESOURCE_ID);
-create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
-  TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
-
-
--- Enumeration of free/busy types
-
-create table FREE_BUSY_TYPE (
-  ID          integer     primary key,
-  DESCRIPTION varchar(16) not null unique
-);
-
-insert into FREE_BUSY_TYPE values (0, 'unknown'         );
-insert into FREE_BUSY_TYPE values (1, 'free'            );
-insert into FREE_BUSY_TYPE values (2, 'busy'            );
-insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
-insert into FREE_BUSY_TYPE values (4, 'busy-tentative'  );
-
-
-------------------
--- Transparency --
-------------------
-
-create table TRANSPARENCY (
-  TIME_RANGE_INSTANCE_ID      integer      not null references TIME_RANGE on delete cascade,
-  USER_ID                     varchar(255) not null,
-  TRANSPARENT                 boolean      not null
-);
-
-create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
-  TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
-
-
-----------------
--- Attachment --
-----------------
-
-create sequence ATTACHMENT_ID_SEQ;
-
-create table ATTACHMENT (
-  ATTACHMENT_ID               integer           primary key default nextval('ATTACHMENT_ID_SEQ'), -- implicit index
-  CALENDAR_HOME_RESOURCE_ID   integer           not null references CALENDAR_HOME,
-  DROPBOX_ID                  varchar(255),
-  CONTENT_TYPE                varchar(255)      not null,
-  SIZE                        integer           not null,
-  MD5                         char(32)          not null,
-  CREATED                     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED                    timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-  PATH                        varchar(1024)     not null
-);
-
-create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
-  ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
-
--- Many-to-many relationship between attachments and calendar objects
-create table ATTACHMENT_CALENDAR_OBJECT (
-  ATTACHMENT_ID                  integer      not null references ATTACHMENT on delete cascade,
-  MANAGED_ID                     varchar(255) not null,
-  CALENDAR_OBJECT_RESOURCE_ID    integer      not null references CALENDAR_OBJECT on delete cascade,
-
-  primary key (ATTACHMENT_ID, CALENDAR_OBJECT_RESOURCE_ID), -- implicit index
-  unique (MANAGED_ID, CALENDAR_OBJECT_RESOURCE_ID) --implicit index
-);
-
-create index ATTACHMENT_CALENDAR_OBJECT_CALENDAR_OBJECT_RESOURCE_ID on
-        ATTACHMENT_CALENDAR_OBJECT(CALENDAR_OBJECT_RESOURCE_ID);
-
------------------------
--- Resource Property --
------------------------
-
-create table RESOURCE_PROPERTY (
-  RESOURCE_ID integer      not null, -- foreign key: *.RESOURCE_ID
-  NAME        varchar(255) not null,
-  VALUE       text         not null, -- FIXME: xml?
-  VIEWER_UID  varchar(255),
-
-  primary key (RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
-);
-
-
-----------------------
--- AddressBook Home --
-----------------------
-
-create table ADDRESSBOOK_HOME (
-  RESOURCE_ID                                      integer                        primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  ADDRESSBOOK_PROPERTY_STORE_ID        integer              default nextval('RESOURCE_ID_SEQ') not null,         -- implicit index
-  OWNER_UID                                        varchar(255)         not null unique,                                -- implicit index
-  DATAVERSION                                      integer              default 0 not null
-);
-
-
--------------------------------
--- AddressBook Home Metadata --
--------------------------------
-
-create table ADDRESSBOOK_HOME_METADATA (
-  RESOURCE_ID      integer      primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
-  QUOTA_USED_BYTES integer      default 0 not null,
-  CREATED          timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED         timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
-
------------------------------
--- Shared AddressBook Bind --
------------------------------
-
--- Joins sharee ADDRESSBOOK_HOME and owner ADDRESSBOOK_HOME
-
-create table SHARED_ADDRESSBOOK_BIND (
-  ADDRESSBOOK_HOME_RESOURCE_ID                        integer                        not null references ADDRESSBOOK_HOME,
-  OWNER_ADDRESSBOOK_HOME_RESOURCE_ID    integer              not null references ADDRESSBOOK_HOME on delete cascade,
-  ADDRESSBOOK_RESOURCE_NAME                            varchar(255)         not null,
-  BIND_MODE                                            integer              not null,        -- enum CALENDAR_BIND_MODE
-  BIND_STATUS                                          integer              not null,        -- enum CALENDAR_BIND_STATUS
-  BIND_REVISION                                                           integer              default 0 not null,
-  MESSAGE                                              text,                                  -- FIXME: xml?
-
-  primary key (ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_ADDRESSBOOK_HOME_RESOURCE_ID), -- implicit index
-  unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
-);
-
-create index SHARED_ADDRESSBOOK_BIND_RESOURCE_ID on
-  SHARED_ADDRESSBOOK_BIND(OWNER_ADDRESSBOOK_HOME_RESOURCE_ID);
-
-
-------------------------
--- AddressBook Object --
-------------------------
-
-create table ADDRESSBOOK_OBJECT (
-  RESOURCE_ID                             integer                   primary key default nextval('RESOURCE_ID_SEQ'),    -- implicit index
-  ADDRESSBOOK_HOME_RESOURCE_ID         integer              not null references ADDRESSBOOK_HOME on delete cascade,
-  RESOURCE_NAME                           varchar(255)         not null,
-  VCARD_TEXT                              text                 not null,
-  VCARD_UID                               varchar(255)         not null,
-  KIND                                                             integer              not null,  -- enum ADDRESSBOOK_OBJECT_KIND
-  MD5                                     char(32)             not null,
-  CREATED                                 timestamp            default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED                                timestamp            default timezone('UTC', CURRENT_TIMESTAMP),
-
-  unique (ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME), -- implicit index
-  unique (ADDRESSBOOK_HOME_RESOURCE_ID, VCARD_UID)      -- implicit index
-);
-
-
------------------------------
--- AddressBook Object kind --
------------------------------
-
-create table ADDRESSBOOK_OBJECT_KIND (
-  ID          integer     primary key,
-  DESCRIPTION varchar(16) not null unique
-);
-
-insert into ADDRESSBOOK_OBJECT_KIND values (0, 'person');
-insert into ADDRESSBOOK_OBJECT_KIND values (1, 'group' );
-insert into ADDRESSBOOK_OBJECT_KIND values (2, 'resource');
-insert into ADDRESSBOOK_OBJECT_KIND values (3, 'location');
-
-
----------------------------------
--- Address Book Object Members --
----------------------------------
-
-create table ABO_MEMBERS (
-    GROUP_ID              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,        -- AddressBook Object's (kind=='group') RESOURCE_ID
-         ADDRESSBOOK_ID                  integer      not null references ADDRESSBOOK_HOME on delete cascade,
-    MEMBER_ID             integer      not null references ADDRESSBOOK_OBJECT,                                                -- member AddressBook Object's RESOURCE_ID
-
-    primary key (GROUP_ID, MEMBER_ID) -- implicit index
-);
-
-create index ABO_MEMBERS_ADDRESSBOOK_ID on
-        ABO_MEMBERS(ADDRESSBOOK_ID);
-create index ABO_MEMBERS_MEMBER_ID on
-        ABO_MEMBERS(MEMBER_ID);
-
-------------------------------------------
--- Address Book Object Foreign Members  --
-------------------------------------------
-
-create table ABO_FOREIGN_MEMBERS (
-    GROUP_ID              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,        -- AddressBook Object's (kind=='group') RESOURCE_ID
-         ADDRESSBOOK_ID                  integer      not null references ADDRESSBOOK_HOME on delete cascade,
-    MEMBER_ADDRESS            varchar(255) not null,                                                                                                         -- member AddressBook Object's 'calendar' address
-
-    primary key (GROUP_ID, MEMBER_ADDRESS) -- implicit index
-);
-
-create index ABO_FOREIGN_MEMBERS_ADDRESSBOOK_ID on
-        ABO_FOREIGN_MEMBERS(ADDRESSBOOK_ID);
-
------------------------
--- Shared Group Bind --
------------------------
-
--- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (kind == group)
-
-create table SHARED_GROUP_BIND (        
-  ADDRESSBOOK_HOME_RESOURCE_ID                 integer      not null references ADDRESSBOOK_HOME,
-  GROUP_RESOURCE_ID                              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,
-  GROUP_ADDRESSBOOK_RESOURCE_NAME        varchar(255) not null,
-  BIND_MODE                                    integer      not null, -- enum CALENDAR_BIND_MODE
-  BIND_STATUS                                  integer      not null, -- enum CALENDAR_BIND_STATUS
-  BIND_REVISION                                                   integer      default 0 not null,
-  MESSAGE                                      text,                  -- FIXME: xml?
-
-  primary key (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_RESOURCE_ID), -- implicit index
-  unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
-);
-
-create index SHARED_GROUP_BIND_RESOURCE_ID on
-  SHARED_GROUP_BIND(GROUP_RESOURCE_ID);
-
-
----------------
--- Revisions --
----------------
-
-create sequence REVISION_SEQ;
-
-
--------------------------------
--- Calendar Object Revisions --
--------------------------------
-
-create table CALENDAR_OBJECT_REVISIONS (
-  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
-  CALENDAR_RESOURCE_ID      integer      references CALENDAR,
-  CALENDAR_NAME             varchar(255) default null,
-  RESOURCE_NAME             varchar(255),
-  REVISION                  integer      default nextval('REVISION_SEQ') not null,
-  DELETED                   boolean      not null
-);
-
-create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
-  on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
-
-create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
-  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME);
-
-create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
-  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
-
-
-----------------------------------
--- AddressBook Object Revisions --
-----------------------------------
-
-create table ADDRESSBOOK_OBJECT_REVISIONS (
-  ADDRESSBOOK_HOME_RESOURCE_ID                         integer                        not null references ADDRESSBOOK_HOME,
-  OWNER_ADDRESSBOOK_HOME_RESOURCE_ID    integer             references ADDRESSBOOK_HOME,
-  ADDRESSBOOK_NAME                                     varchar(255)         default null,
-  RESOURCE_NAME                                        varchar(255),
-  REVISION                                             integer             default nextval('REVISION_SEQ') not null,
-  DELETED                                              boolean              not null
-);
-
-create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_ADDRESSBOOK_HOME_RESOURCE_ID
-  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_ADDRESSBOOK_HOME_RESOURCE_ID);
-
-create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME
-  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME);
-
-create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_REVISION
-  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_ADDRESSBOOK_HOME_RESOURCE_ID, REVISION);
-
-
------------------------------------
--- Notification Object Revisions --
------------------------------------
-
-create table NOTIFICATION_OBJECT_REVISIONS (
-  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME on delete cascade,
-  RESOURCE_NAME                 varchar(255),
-  REVISION                      integer      default nextval('REVISION_SEQ') not null,
-  DELETED                       boolean      not null,
-
-  unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
-);
-
-create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
-  on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
-
-
--------------------------------------------
--- Apple Push Notification Subscriptions --
--------------------------------------------
-
-create table APN_SUBSCRIPTIONS (
-  TOKEN                         varchar(255) not null,
-  RESOURCE_KEY                  varchar(255) not null,
-  MODIFIED                      integer      not null,
-  SUBSCRIBER_GUID               varchar(255) not null,
-  USER_AGENT                    varchar(255) default null,
-  IP_ADDR                       varchar(255) default null,
-
-  primary key (TOKEN, RESOURCE_KEY) -- implicit index
-);
-
-create index APN_SUBSCRIPTIONS_RESOURCE_KEY
-   on APN_SUBSCRIPTIONS(RESOURCE_KEY);
-
-   
------------------
--- IMIP Tokens --
------------------
-
-create table IMIP_TOKENS (
-  TOKEN                         varchar(255) not null,
-  ORGANIZER                     varchar(255) not null,
-  ATTENDEE                      varchar(255) not null,
-  ICALUID                       varchar(255) not null,
-  ACCESSED                      timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-
-  primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
-);
-
-create index IMIP_TOKENS_TOKEN
-   on IMIP_TOKENS(TOKEN);
-
-   
-----------------
--- Work Items --
-----------------
-
-create sequence WORKITEM_SEQ;
-
-
----------------------------
--- IMIP Inivitation Work --
----------------------------
-
-create table IMIP_INVITATION_WORK (
-  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
-  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-  FROM_ADDR                     varchar(255) not null,
-  TO_ADDR                       varchar(255) not null,
-  ICALENDAR_TEXT                text         not null
-);
-
-
------------------------
--- IMIP Polling Work --
------------------------
-
-create table IMIP_POLLING_WORK (
-  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
-  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
-
----------------------
--- IMIP Reply Work --
----------------------
-
-create table IMIP_REPLY_WORK (
-  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
-  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-  ORGANIZER                     varchar(255) not null,
-  ATTENDEE                      varchar(255) not null,
-  ICALENDAR_TEXT                text         not null
-);
-
-
-------------------------
--- Push Notifications --
-------------------------
-
-create table PUSH_NOTIFICATION_WORK (
-  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
-  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-  PUSH_ID                       varchar(255) not null
-);
-
------------------
--- GroupCacher --
------------------
-
-create table GROUP_CACHER_POLLING_WORK (
-  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
-  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
-
---------------------------
--- Object Splitter Work --
---------------------------
-
-create table CALENDAR_OBJECT_SPLITTER_WORK (
-  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
-  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-  RESOURCE_ID                   integer      not null references CALENDAR_OBJECT on delete cascade
-);
-
-create index CALENDAR_OBJECT_SPLITTER_WORK_RESOURCE_ID on
-        CALENDAR_OBJECT_SPLITTER_WORK(RESOURCE_ID);
-
---------------------
--- Schema Version --
---------------------
-
-create table CALENDARSERVER (
-  NAME                          varchar(255) primary key, -- implicit index
-  VALUE                         varchar(255)
-);
-
-insert into CALENDARSERVER values ('VERSION', '24');
-insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '5');
-insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldpostgresdialectv24sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaoldpostgresdialectv24sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v24.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v24.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v24.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v24.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,700 @@
</span><ins>+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2013 Apple Inc. 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.
+----
+
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+
+-------------------------
+-- Cluster Bookkeeping --
+-------------------------
+
+-- Information about a process connected to this database.
+
+-- Note that this must match the node info schema in twext.enterprise.queue.
+create table NODE_INFO (
+  HOSTNAME  varchar(255) not null,
+  PID       integer      not null,
+  PORT      integer      not null,
+  TIME      timestamp    not null default timezone('UTC', CURRENT_TIMESTAMP),
+
+  primary key (HOSTNAME, PORT)
+);
+
+-- Unique named locks.  This table should always be empty, but rows are
+-- temporarily created in order to prevent undesirable concurrency.
+create table NAMED_LOCK (
+    LOCK_NAME varchar(255) primary key
+);
+
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID        varchar(255) not null unique,                                 -- implicit index
+  DATAVERSION      integer      default 0 not null
+);
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+create table CALENDAR_HOME_METADATA (
+  RESOURCE_ID              integer     primary key references CALENDAR_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES         integer     default 0 not null,
+  DEFAULT_EVENTS           integer     default null references CALENDAR on delete set null,
+  DEFAULT_TASKS            integer     default null references CALENDAR on delete set null,
+  ALARM_VEVENT_TIMED       text        default null,
+  ALARM_VEVENT_ALLDAY      text        default null,
+  ALARM_VTODO_TIMED        text        default null,
+  ALARM_VTODO_ALLDAY       text        default null,
+  AVAILABILITY             text        default null,
+  CREATED                  timestamp   default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                 timestamp   default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+create index CALENDAR_HOME_METADATA_DEFAULT_EVENTS on
+        CALENDAR_HOME_METADATA(DEFAULT_EVENTS);
+create index CALENDAR_HOME_METADATA_DEFAULT_TASKS on
+        CALENDAR_HOME_METADATA(DEFAULT_TASKS);
+
+-----------------------
+-- Calendar Metadata --
+-----------------------
+
+create table CALENDAR_METADATA (
+  RESOURCE_ID           integer      primary key references CALENDAR on delete cascade, -- implicit index
+  SUPPORTED_COMPONENTS  varchar(255) default null,
+  CREATED               timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+  RESOURCE_ID integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID   varchar(255) not null unique                                 -- implicit index
+);
+
+create table NOTIFICATION (
+  RESOURCE_ID                   integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME,
+  NOTIFICATION_UID              varchar(255) not null,
+  XML_TYPE                      varchar(255) not null,
+  XML_DATA                      text         not null,
+  MD5                           char(32)     not null,
+  CREATED                       timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                      timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+        NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      not null references CALENDAR on delete cascade,
+  CALENDAR_RESOURCE_NAME    varchar(255) not null,
+  BIND_MODE                 integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS               integer      not null, -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                integer      default 0 not null,
+  MESSAGE                   text,
+  TRANSP                    integer      default 0 not null, -- enum CALENDAR_TRANSP
+  ALARM_VEVENT_TIMED        text         default null,
+  ALARM_VEVENT_ALLDAY       text         default null,
+  ALARM_VTODO_TIMED         text         default null,
+  ALARM_VTODO_ALLDAY        text         default null,
+  TIMEZONE                  text         default null,
+
+  primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+  unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME)     -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on
+        CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own'  );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+
+
+-- Enumeration of transparency
+
+create table CALENDAR_TRANSP (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_TRANSP values (0, 'opaque' );
+insert into CALENDAR_TRANSP values (1, 'transparent');
+
+
+---------------------
+-- Calendar Object --
+---------------------
+
+create table CALENDAR_OBJECT (
+  RESOURCE_ID          integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID integer      not null references CALENDAR on delete cascade,
+  RESOURCE_NAME        varchar(255) not null,
+  ICALENDAR_TEXT       text         not null,
+  ICALENDAR_UID        varchar(255) not null,
+  ICALENDAR_TYPE       varchar(255) not null,
+  ATTACHMENTS_MODE     integer      default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+  DROPBOX_ID           varchar(255),
+  ORGANIZER            varchar(255),
+  RECURRANCE_MIN       date,        -- minimum date that recurrences have been expanded to.
+  RECURRANCE_MAX       date,        -- maximum date that recurrences have been expanded to.
+  ACCESS               integer      default 0 not null,
+  SCHEDULE_OBJECT      boolean      default false,
+  SCHEDULE_TAG         varchar(36)  default null,
+  SCHEDULE_ETAGS       text         default null,
+  PRIVATE_COMMENTS     boolean      default false not null,
+  MD5                  char(32)     not null,
+  CREATED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED             timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+  -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+  -- calendar objects, this constraint has to be selectively enforced by the
+  -- application layer.
+
+  -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ICALENDAR_UID on
+  CALENDAR_OBJECT(ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+  CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, ''             );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public'       );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private'      );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted'   );
+
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+  INSTANCE_ID                 integer        primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID        integer        not null references CALENDAR on delete cascade,
+  CALENDAR_OBJECT_RESOURCE_ID integer        not null references CALENDAR_OBJECT on delete cascade,
+  FLOATING                    boolean        not null,
+  START_DATE                  timestamp      not null,
+  END_DATE                    timestamp      not null,
+  FBTYPE                      integer        not null,
+  TRANSPARENT                 boolean        not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown'         );
+insert into FREE_BUSY_TYPE values (1, 'free'            );
+insert into FREE_BUSY_TYPE values (2, 'busy'            );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative'  );
+
+
+------------------
+-- Transparency --
+------------------
+
+create table TRANSPARENCY (
+  TIME_RANGE_INSTANCE_ID      integer      not null references TIME_RANGE on delete cascade,
+  USER_ID                     varchar(255) not null,
+  TRANSPARENT                 boolean      not null
+);
+
+create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
+  TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
+
+
+----------------
+-- Attachment --
+----------------
+
+create sequence ATTACHMENT_ID_SEQ;
+
+create table ATTACHMENT (
+  ATTACHMENT_ID               integer           primary key default nextval('ATTACHMENT_ID_SEQ'), -- implicit index
+  CALENDAR_HOME_RESOURCE_ID   integer           not null references CALENDAR_HOME,
+  DROPBOX_ID                  varchar(255),
+  CONTENT_TYPE                varchar(255)      not null,
+  SIZE                        integer           not null,
+  MD5                         char(32)          not null,
+  CREATED                     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                    timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  PATH                        varchar(1024)     not null
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+  ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+-- Many-to-many relationship between attachments and calendar objects
+create table ATTACHMENT_CALENDAR_OBJECT (
+  ATTACHMENT_ID                  integer      not null references ATTACHMENT on delete cascade,
+  MANAGED_ID                     varchar(255) not null,
+  CALENDAR_OBJECT_RESOURCE_ID    integer      not null references CALENDAR_OBJECT on delete cascade,
+
+  primary key (ATTACHMENT_ID, CALENDAR_OBJECT_RESOURCE_ID), -- implicit index
+  unique (MANAGED_ID, CALENDAR_OBJECT_RESOURCE_ID) --implicit index
+);
+
+create index ATTACHMENT_CALENDAR_OBJECT_CALENDAR_OBJECT_RESOURCE_ID on
+        ATTACHMENT_CALENDAR_OBJECT(CALENDAR_OBJECT_RESOURCE_ID);
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+  RESOURCE_ID integer      not null, -- foreign key: *.RESOURCE_ID
+  NAME        varchar(255) not null,
+  VALUE       text         not null, -- FIXME: xml?
+  VIEWER_UID  varchar(255),
+
+  primary key (RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+  RESOURCE_ID                                      integer                        primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  ADDRESSBOOK_PROPERTY_STORE_ID        integer              default nextval('RESOURCE_ID_SEQ') not null,         -- implicit index
+  OWNER_UID                                        varchar(255)         not null unique,                                -- implicit index
+  DATAVERSION                                      integer              default 0 not null
+);
+
+
+-------------------------------
+-- AddressBook Home Metadata --
+-------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+  RESOURCE_ID      integer      primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES integer      default 0 not null,
+  CREATED          timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED         timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+-----------------------------
+-- Shared AddressBook Bind --
+-----------------------------
+
+-- Joins sharee ADDRESSBOOK_HOME and owner ADDRESSBOOK_HOME
+
+create table SHARED_ADDRESSBOOK_BIND (
+  ADDRESSBOOK_HOME_RESOURCE_ID                        integer                        not null references ADDRESSBOOK_HOME,
+  OWNER_ADDRESSBOOK_HOME_RESOURCE_ID    integer              not null references ADDRESSBOOK_HOME on delete cascade,
+  ADDRESSBOOK_RESOURCE_NAME                            varchar(255)         not null,
+  BIND_MODE                                            integer              not null,        -- enum CALENDAR_BIND_MODE
+  BIND_STATUS                                          integer              not null,        -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                                           integer              default 0 not null,
+  MESSAGE                                              text,                                  -- FIXME: xml?
+
+  primary key (ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_ADDRESSBOOK_HOME_RESOURCE_ID), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
+);
+
+create index SHARED_ADDRESSBOOK_BIND_RESOURCE_ID on
+  SHARED_ADDRESSBOOK_BIND(OWNER_ADDRESSBOOK_HOME_RESOURCE_ID);
+
+
+------------------------
+-- AddressBook Object --
+------------------------
+
+create table ADDRESSBOOK_OBJECT (
+  RESOURCE_ID                             integer                   primary key default nextval('RESOURCE_ID_SEQ'),    -- implicit index
+  ADDRESSBOOK_HOME_RESOURCE_ID         integer              not null references ADDRESSBOOK_HOME on delete cascade,
+  RESOURCE_NAME                           varchar(255)         not null,
+  VCARD_TEXT                              text                 not null,
+  VCARD_UID                               varchar(255)         not null,
+  KIND                                                             integer              not null,  -- enum ADDRESSBOOK_OBJECT_KIND
+  MD5                                     char(32)             not null,
+  CREATED                                 timestamp            default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                                timestamp            default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, VCARD_UID)      -- implicit index
+);
+
+
+-----------------------------
+-- AddressBook Object kind --
+-----------------------------
+
+create table ADDRESSBOOK_OBJECT_KIND (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND values (0, 'person');
+insert into ADDRESSBOOK_OBJECT_KIND values (1, 'group' );
+insert into ADDRESSBOOK_OBJECT_KIND values (2, 'resource');
+insert into ADDRESSBOOK_OBJECT_KIND values (3, 'location');
+
+
+---------------------------------
+-- Address Book Object Members --
+---------------------------------
+
+create table ABO_MEMBERS (
+    GROUP_ID              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,        -- AddressBook Object's (kind=='group') RESOURCE_ID
+         ADDRESSBOOK_ID                  integer      not null references ADDRESSBOOK_HOME on delete cascade,
+    MEMBER_ID             integer      not null references ADDRESSBOOK_OBJECT,                                                -- member AddressBook Object's RESOURCE_ID
+
+    primary key (GROUP_ID, MEMBER_ID) -- implicit index
+);
+
+create index ABO_MEMBERS_ADDRESSBOOK_ID on
+        ABO_MEMBERS(ADDRESSBOOK_ID);
+create index ABO_MEMBERS_MEMBER_ID on
+        ABO_MEMBERS(MEMBER_ID);
+
+------------------------------------------
+-- Address Book Object Foreign Members  --
+------------------------------------------
+
+create table ABO_FOREIGN_MEMBERS (
+    GROUP_ID              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,        -- AddressBook Object's (kind=='group') RESOURCE_ID
+         ADDRESSBOOK_ID                  integer      not null references ADDRESSBOOK_HOME on delete cascade,
+    MEMBER_ADDRESS            varchar(255) not null,                                                                                                         -- member AddressBook Object's 'calendar' address
+
+    primary key (GROUP_ID, MEMBER_ADDRESS) -- implicit index
+);
+
+create index ABO_FOREIGN_MEMBERS_ADDRESSBOOK_ID on
+        ABO_FOREIGN_MEMBERS(ADDRESSBOOK_ID);
+
+-----------------------
+-- Shared Group Bind --
+-----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (kind == group)
+
+create table SHARED_GROUP_BIND (        
+  ADDRESSBOOK_HOME_RESOURCE_ID                 integer      not null references ADDRESSBOOK_HOME,
+  GROUP_RESOURCE_ID                              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,
+  GROUP_ADDRESSBOOK_RESOURCE_NAME        varchar(255) not null,
+  BIND_MODE                                    integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS                                  integer      not null, -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                                   integer      default 0 not null,
+  MESSAGE                                      text,                  -- FIXME: xml?
+
+  primary key (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_RESOURCE_ID), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
+);
+
+create index SHARED_GROUP_BIND_RESOURCE_ID on
+  SHARED_GROUP_BIND(GROUP_RESOURCE_ID);
+
+
+---------------
+-- Revisions --
+---------------
+
+create sequence REVISION_SEQ;
+
+
+-------------------------------
+-- Calendar Object Revisions --
+-------------------------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      references CALENDAR,
+  CALENDAR_NAME             varchar(255) default null,
+  RESOURCE_NAME             varchar(255),
+  REVISION                  integer      default nextval('REVISION_SEQ') not null,
+  DELETED                   boolean      not null
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
+
+
+----------------------------------
+-- AddressBook Object Revisions --
+----------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+  ADDRESSBOOK_HOME_RESOURCE_ID                         integer                        not null references ADDRESSBOOK_HOME,
+  OWNER_ADDRESSBOOK_HOME_RESOURCE_ID    integer             references ADDRESSBOOK_HOME,
+  ADDRESSBOOK_NAME                                     varchar(255)         default null,
+  RESOURCE_NAME                                        varchar(255),
+  REVISION                                             integer             default nextval('REVISION_SEQ') not null,
+  DELETED                                              boolean              not null
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_ADDRESSBOOK_HOME_RESOURCE_ID
+  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_ADDRESSBOOK_HOME_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME
+  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_REVISION
+  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_ADDRESSBOOK_HOME_RESOURCE_ID, REVISION);
+
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME on delete cascade,
+  RESOURCE_NAME                 varchar(255),
+  REVISION                      integer      default nextval('REVISION_SEQ') not null,
+  DELETED                       boolean      not null,
+
+  unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+  on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
+
+
+-------------------------------------------
+-- Apple Push Notification Subscriptions --
+-------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+  TOKEN                         varchar(255) not null,
+  RESOURCE_KEY                  varchar(255) not null,
+  MODIFIED                      integer      not null,
+  SUBSCRIBER_GUID               varchar(255) not null,
+  USER_AGENT                    varchar(255) default null,
+  IP_ADDR                       varchar(255) default null,
+
+  primary key (TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+   on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+   
+-----------------
+-- IMIP Tokens --
+-----------------
+
+create table IMIP_TOKENS (
+  TOKEN                         varchar(255) not null,
+  ORGANIZER                     varchar(255) not null,
+  ATTENDEE                      varchar(255) not null,
+  ICALUID                       varchar(255) not null,
+  ACCESSED                      timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
+);
+
+create index IMIP_TOKENS_TOKEN
+   on IMIP_TOKENS(TOKEN);
+
+   
+----------------
+-- Work Items --
+----------------
+
+create sequence WORKITEM_SEQ;
+
+
+---------------------------
+-- IMIP Inivitation Work --
+---------------------------
+
+create table IMIP_INVITATION_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  FROM_ADDR                     varchar(255) not null,
+  TO_ADDR                       varchar(255) not null,
+  ICALENDAR_TEXT                text         not null
+);
+
+
+-----------------------
+-- IMIP Polling Work --
+-----------------------
+
+create table IMIP_POLLING_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------
+-- IMIP Reply Work --
+---------------------
+
+create table IMIP_REPLY_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  ORGANIZER                     varchar(255) not null,
+  ATTENDEE                      varchar(255) not null,
+  ICALENDAR_TEXT                text         not null
+);
+
+
+------------------------
+-- Push Notifications --
+------------------------
+
+create table PUSH_NOTIFICATION_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  PUSH_ID                       varchar(255) not null
+);
+
+-----------------
+-- GroupCacher --
+-----------------
+
+create table GROUP_CACHER_POLLING_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+--------------------------
+-- Object Splitter Work --
+--------------------------
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  RESOURCE_ID                   integer      not null references CALENDAR_OBJECT on delete cascade
+);
+
+create index CALENDAR_OBJECT_SPLITTER_WORK_RESOURCE_ID on
+        CALENDAR_OBJECT_SPLITTER_WORK(RESOURCE_ID);
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+  NAME                          varchar(255) primary key, -- implicit index
+  VALUE                         varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '24');
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '5');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldpostgresdialectv26sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaoldpostgresdialectv26sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v26.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v26.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v26.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v26.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,700 @@
</span><ins>+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2013 Apple Inc. 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.
+----
+
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+
+-------------------------
+-- Cluster Bookkeeping --
+-------------------------
+
+-- Information about a process connected to this database.
+
+-- Note that this must match the node info schema in twext.enterprise.queue.
+create table NODE_INFO (
+  HOSTNAME  varchar(255) not null,
+  PID       integer      not null,
+  PORT      integer      not null,
+  TIME      timestamp    not null default timezone('UTC', CURRENT_TIMESTAMP),
+
+  primary key (HOSTNAME, PORT)
+);
+
+-- Unique named locks.  This table should always be empty, but rows are
+-- temporarily created in order to prevent undesirable concurrency.
+create table NAMED_LOCK (
+    LOCK_NAME varchar(255) primary key
+);
+
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID        varchar(255) not null unique,                                 -- implicit index
+  DATAVERSION      integer      default 0 not null
+);
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+create table CALENDAR_HOME_METADATA (
+  RESOURCE_ID              integer     primary key references CALENDAR_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES         integer     default 0 not null,
+  DEFAULT_EVENTS           integer     default null references CALENDAR on delete set null,
+  DEFAULT_TASKS            integer     default null references CALENDAR on delete set null,
+  ALARM_VEVENT_TIMED       text        default null,
+  ALARM_VEVENT_ALLDAY      text        default null,
+  ALARM_VTODO_TIMED        text        default null,
+  ALARM_VTODO_ALLDAY       text        default null,
+  AVAILABILITY             text        default null,
+  CREATED                  timestamp   default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                 timestamp   default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+create index CALENDAR_HOME_METADATA_DEFAULT_EVENTS on
+        CALENDAR_HOME_METADATA(DEFAULT_EVENTS);
+create index CALENDAR_HOME_METADATA_DEFAULT_TASKS on
+        CALENDAR_HOME_METADATA(DEFAULT_TASKS);
+
+-----------------------
+-- Calendar Metadata --
+-----------------------
+
+create table CALENDAR_METADATA (
+  RESOURCE_ID           integer      primary key references CALENDAR on delete cascade, -- implicit index
+  SUPPORTED_COMPONENTS  varchar(255) default null,
+  CREATED               timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+  RESOURCE_ID integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID   varchar(255) not null unique                                 -- implicit index
+);
+
+create table NOTIFICATION (
+  RESOURCE_ID                   integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME,
+  NOTIFICATION_UID              varchar(255) not null,
+  XML_TYPE                      varchar(255) not null,
+  XML_DATA                      text         not null,
+  MD5                           char(32)     not null,
+  CREATED                       timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                      timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+        NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      not null references CALENDAR on delete cascade,
+  CALENDAR_RESOURCE_NAME    varchar(255) not null,
+  BIND_MODE                 integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS               integer      not null, -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                integer      default 0 not null,
+  MESSAGE                   text,
+  TRANSP                    integer      default 0 not null, -- enum CALENDAR_TRANSP
+  ALARM_VEVENT_TIMED        text         default null,
+  ALARM_VEVENT_ALLDAY       text         default null,
+  ALARM_VTODO_TIMED         text         default null,
+  ALARM_VTODO_ALLDAY        text         default null,
+  TIMEZONE                  text         default null,
+
+  primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+  unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME)     -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on
+        CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own'  );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+
+
+-- Enumeration of transparency
+
+create table CALENDAR_TRANSP (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_TRANSP values (0, 'opaque' );
+insert into CALENDAR_TRANSP values (1, 'transparent');
+
+
+---------------------
+-- Calendar Object --
+---------------------
+
+create table CALENDAR_OBJECT (
+  RESOURCE_ID          integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID integer      not null references CALENDAR on delete cascade,
+  RESOURCE_NAME        varchar(255) not null,
+  ICALENDAR_TEXT       text         not null,
+  ICALENDAR_UID        varchar(255) not null,
+  ICALENDAR_TYPE       varchar(255) not null,
+  ATTACHMENTS_MODE     integer      default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+  DROPBOX_ID           varchar(255),
+  ORGANIZER            varchar(255),
+  RECURRANCE_MIN       date,        -- minimum date that recurrences have been expanded to.
+  RECURRANCE_MAX       date,        -- maximum date that recurrences have been expanded to.
+  ACCESS               integer      default 0 not null,
+  SCHEDULE_OBJECT      boolean      default false,
+  SCHEDULE_TAG         varchar(36)  default null,
+  SCHEDULE_ETAGS       text         default null,
+  PRIVATE_COMMENTS     boolean      default false not null,
+  MD5                  char(32)     not null,
+  CREATED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED             timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+  -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+  -- calendar objects, this constraint has to be selectively enforced by the
+  -- application layer.
+
+  -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ICALENDAR_UID on
+  CALENDAR_OBJECT(ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+  CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, ''             );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public'       );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private'      );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted'   );
+
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+  INSTANCE_ID                 integer        primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID        integer        not null references CALENDAR on delete cascade,
+  CALENDAR_OBJECT_RESOURCE_ID integer        not null references CALENDAR_OBJECT on delete cascade,
+  FLOATING                    boolean        not null,
+  START_DATE                  timestamp      not null,
+  END_DATE                    timestamp      not null,
+  FBTYPE                      integer        not null,
+  TRANSPARENT                 boolean        not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown'         );
+insert into FREE_BUSY_TYPE values (1, 'free'            );
+insert into FREE_BUSY_TYPE values (2, 'busy'            );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative'  );
+
+
+------------------
+-- Transparency --
+------------------
+
+create table TRANSPARENCY (
+  TIME_RANGE_INSTANCE_ID      integer      not null references TIME_RANGE on delete cascade,
+  USER_ID                     varchar(255) not null,
+  TRANSPARENT                 boolean      not null
+);
+
+create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
+  TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
+
+
+----------------
+-- Attachment --
+----------------
+
+create sequence ATTACHMENT_ID_SEQ;
+
+create table ATTACHMENT (
+  ATTACHMENT_ID               integer           primary key default nextval('ATTACHMENT_ID_SEQ'), -- implicit index
+  CALENDAR_HOME_RESOURCE_ID   integer           not null references CALENDAR_HOME,
+  DROPBOX_ID                  varchar(255),
+  CONTENT_TYPE                varchar(255)      not null,
+  SIZE                        integer           not null,
+  MD5                         char(32)          not null,
+  CREATED                     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                    timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  PATH                        varchar(1024)     not null
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+  ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+-- Many-to-many relationship between attachments and calendar objects
+create table ATTACHMENT_CALENDAR_OBJECT (
+  ATTACHMENT_ID                  integer      not null references ATTACHMENT on delete cascade,
+  MANAGED_ID                     varchar(255) not null,
+  CALENDAR_OBJECT_RESOURCE_ID    integer      not null references CALENDAR_OBJECT on delete cascade,
+
+  primary key (ATTACHMENT_ID, CALENDAR_OBJECT_RESOURCE_ID), -- implicit index
+  unique (MANAGED_ID, CALENDAR_OBJECT_RESOURCE_ID) --implicit index
+);
+
+create index ATTACHMENT_CALENDAR_OBJECT_CALENDAR_OBJECT_RESOURCE_ID on
+        ATTACHMENT_CALENDAR_OBJECT(CALENDAR_OBJECT_RESOURCE_ID);
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+  RESOURCE_ID integer      not null, -- foreign key: *.RESOURCE_ID
+  NAME        varchar(255) not null,
+  VALUE       text         not null, -- FIXME: xml?
+  VIEWER_UID  varchar(255),
+
+  primary key (RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+  RESOURCE_ID                                      integer                        primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  ADDRESSBOOK_PROPERTY_STORE_ID        integer              default nextval('RESOURCE_ID_SEQ') not null,         -- implicit index
+  OWNER_UID                                        varchar(255)         not null unique,                                -- implicit index
+  DATAVERSION                                      integer              default 0 not null
+);
+
+
+-------------------------------
+-- AddressBook Home Metadata --
+-------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+  RESOURCE_ID      integer      primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES integer      default 0 not null,
+  CREATED          timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED         timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+-----------------------------
+-- Shared AddressBook Bind --
+-----------------------------
+
+-- Joins sharee ADDRESSBOOK_HOME and owner ADDRESSBOOK_HOME
+
+create table SHARED_ADDRESSBOOK_BIND (
+  ADDRESSBOOK_HOME_RESOURCE_ID                        integer                        not null references ADDRESSBOOK_HOME,
+  OWNER_HOME_RESOURCE_ID                            integer              not null references ADDRESSBOOK_HOME on delete cascade,
+  ADDRESSBOOK_RESOURCE_NAME                            varchar(255)         not null,
+  BIND_MODE                                            integer              not null,        -- enum CALENDAR_BIND_MODE
+  BIND_STATUS                                          integer              not null,        -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                                           integer              default 0 not null,
+  MESSAGE                                              text,                                  -- FIXME: xml?
+
+  primary key (ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
+);
+
+create index SHARED_ADDRESSBOOK_BIND_RESOURCE_ID on
+  SHARED_ADDRESSBOOK_BIND(OWNER_HOME_RESOURCE_ID);
+
+
+------------------------
+-- AddressBook Object --
+------------------------
+
+create table ADDRESSBOOK_OBJECT (
+  RESOURCE_ID                             integer                   primary key default nextval('RESOURCE_ID_SEQ'),    -- implicit index
+  ADDRESSBOOK_HOME_RESOURCE_ID         integer              not null references ADDRESSBOOK_HOME on delete cascade,
+  RESOURCE_NAME                           varchar(255)         not null,
+  VCARD_TEXT                              text                 not null,
+  VCARD_UID                               varchar(255)         not null,
+  KIND                                                             integer              not null,  -- enum ADDRESSBOOK_OBJECT_KIND
+  MD5                                     char(32)             not null,
+  CREATED                                 timestamp            default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                                timestamp            default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, VCARD_UID)      -- implicit index
+);
+
+
+-----------------------------
+-- AddressBook Object kind --
+-----------------------------
+
+create table ADDRESSBOOK_OBJECT_KIND (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND values (0, 'person');
+insert into ADDRESSBOOK_OBJECT_KIND values (1, 'group' );
+insert into ADDRESSBOOK_OBJECT_KIND values (2, 'resource');
+insert into ADDRESSBOOK_OBJECT_KIND values (3, 'location');
+
+
+---------------------------------
+-- Address Book Object Members --
+---------------------------------
+
+create table ABO_MEMBERS (
+    GROUP_ID              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,        -- AddressBook Object's (kind=='group') RESOURCE_ID
+         ADDRESSBOOK_ID                  integer      not null references ADDRESSBOOK_HOME on delete cascade,
+    MEMBER_ID             integer      not null references ADDRESSBOOK_OBJECT,                                                -- member AddressBook Object's RESOURCE_ID
+
+    primary key (GROUP_ID, MEMBER_ID) -- implicit index
+);
+
+create index ABO_MEMBERS_ADDRESSBOOK_ID on
+        ABO_MEMBERS(ADDRESSBOOK_ID);
+create index ABO_MEMBERS_MEMBER_ID on
+        ABO_MEMBERS(MEMBER_ID);
+
+------------------------------------------
+-- Address Book Object Foreign Members  --
+------------------------------------------
+
+create table ABO_FOREIGN_MEMBERS (
+    GROUP_ID              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,        -- AddressBook Object's (kind=='group') RESOURCE_ID
+         ADDRESSBOOK_ID                  integer      not null references ADDRESSBOOK_HOME on delete cascade,
+    MEMBER_ADDRESS            varchar(255) not null,                                                                                                         -- member AddressBook Object's 'calendar' address
+
+    primary key (GROUP_ID, MEMBER_ADDRESS) -- implicit index
+);
+
+create index ABO_FOREIGN_MEMBERS_ADDRESSBOOK_ID on
+        ABO_FOREIGN_MEMBERS(ADDRESSBOOK_ID);
+
+-----------------------
+-- Shared Group Bind --
+-----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (kind == group)
+
+create table SHARED_GROUP_BIND (        
+  ADDRESSBOOK_HOME_RESOURCE_ID                 integer      not null references ADDRESSBOOK_HOME,
+  GROUP_RESOURCE_ID                              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,
+  GROUP_ADDRESSBOOK_NAME                        varchar(255) not null,
+  BIND_MODE                                    integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS                                  integer      not null, -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                                   integer      default 0 not null,
+  MESSAGE                                      text,                  -- FIXME: xml?
+
+  primary key (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_RESOURCE_ID), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_NAME)     -- implicit index
+);
+
+create index SHARED_GROUP_BIND_RESOURCE_ID on
+  SHARED_GROUP_BIND(GROUP_RESOURCE_ID);
+
+
+---------------
+-- Revisions --
+---------------
+
+create sequence REVISION_SEQ;
+
+
+-------------------------------
+-- Calendar Object Revisions --
+-------------------------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      references CALENDAR,
+  CALENDAR_NAME             varchar(255) default null,
+  RESOURCE_NAME             varchar(255),
+  REVISION                  integer      default nextval('REVISION_SEQ') not null,
+  DELETED                   boolean      not null
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
+
+
+----------------------------------
+-- AddressBook Object Revisions --
+----------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+  ADDRESSBOOK_HOME_RESOURCE_ID                         integer                        not null references ADDRESSBOOK_HOME,
+  OWNER_HOME_RESOURCE_ID                            integer             references ADDRESSBOOK_HOME,
+  ADDRESSBOOK_NAME                                     varchar(255)         default null,
+  RESOURCE_NAME                                        varchar(255),
+  REVISION                                             integer             default nextval('REVISION_SEQ') not null,
+  DELETED                                              boolean              not null
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_HOME_RESOURCE_ID
+  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_REVISION
+  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, REVISION);
+
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME on delete cascade,
+  RESOURCE_NAME                 varchar(255),
+  REVISION                      integer      default nextval('REVISION_SEQ') not null,
+  DELETED                       boolean      not null,
+
+  unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+  on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
+
+
+-------------------------------------------
+-- Apple Push Notification Subscriptions --
+-------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+  TOKEN                         varchar(255) not null,
+  RESOURCE_KEY                  varchar(255) not null,
+  MODIFIED                      integer      not null,
+  SUBSCRIBER_GUID               varchar(255) not null,
+  USER_AGENT                    varchar(255) default null,
+  IP_ADDR                       varchar(255) default null,
+
+  primary key (TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+   on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+   
+-----------------
+-- IMIP Tokens --
+-----------------
+
+create table IMIP_TOKENS (
+  TOKEN                         varchar(255) not null,
+  ORGANIZER                     varchar(255) not null,
+  ATTENDEE                      varchar(255) not null,
+  ICALUID                       varchar(255) not null,
+  ACCESSED                      timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
+);
+
+create index IMIP_TOKENS_TOKEN
+   on IMIP_TOKENS(TOKEN);
+
+   
+----------------
+-- Work Items --
+----------------
+
+create sequence WORKITEM_SEQ;
+
+
+---------------------------
+-- IMIP Inivitation Work --
+---------------------------
+
+create table IMIP_INVITATION_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  FROM_ADDR                     varchar(255) not null,
+  TO_ADDR                       varchar(255) not null,
+  ICALENDAR_TEXT                text         not null
+);
+
+
+-----------------------
+-- IMIP Polling Work --
+-----------------------
+
+create table IMIP_POLLING_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------
+-- IMIP Reply Work --
+---------------------
+
+create table IMIP_REPLY_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  ORGANIZER                     varchar(255) not null,
+  ATTENDEE                      varchar(255) not null,
+  ICALENDAR_TEXT                text         not null
+);
+
+
+------------------------
+-- Push Notifications --
+------------------------
+
+create table PUSH_NOTIFICATION_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  PUSH_ID                       varchar(255) not null
+);
+
+-----------------
+-- GroupCacher --
+-----------------
+
+create table GROUP_CACHER_POLLING_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+--------------------------
+-- Object Splitter Work --
+--------------------------
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  RESOURCE_ID                   integer      not null references CALENDAR_OBJECT on delete cascade
+);
+
+create index CALENDAR_OBJECT_SPLITTER_WORK_RESOURCE_ID on
+        CALENDAR_OBJECT_SPLITTER_WORK(RESOURCE_ID);
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+  NAME                          varchar(255) primary key, -- implicit index
+  VALUE                         varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '26');
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '5');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldpostgresdialectv27sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaoldpostgresdialectv27sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v27.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v27.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v27.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v27.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,703 @@
</span><ins>+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2013 Apple Inc. 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.
+----
+
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+
+-------------------------
+-- Cluster Bookkeeping --
+-------------------------
+
+-- Information about a process connected to this database.
+
+-- Note that this must match the node info schema in twext.enterprise.queue.
+create table NODE_INFO (
+  HOSTNAME  varchar(255) not null,
+  PID       integer      not null,
+  PORT      integer      not null,
+  TIME      timestamp    not null default timezone('UTC', CURRENT_TIMESTAMP),
+
+  primary key (HOSTNAME, PORT)
+);
+
+-- Unique named locks.  This table should always be empty, but rows are
+-- temporarily created in order to prevent undesirable concurrency.
+create table NAMED_LOCK (
+    LOCK_NAME varchar(255) primary key
+);
+
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID        varchar(255) not null unique,                                 -- implicit index
+  DATAVERSION      integer      default 0 not null
+);
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+create table CALENDAR_HOME_METADATA (
+  RESOURCE_ID              integer     primary key references CALENDAR_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES         integer     default 0 not null,
+  DEFAULT_EVENTS           integer     default null references CALENDAR on delete set null,
+  DEFAULT_TASKS            integer     default null references CALENDAR on delete set null,
+  DEFAULT_POLLS            integer     default null references CALENDAR on delete set null,
+  ALARM_VEVENT_TIMED       text        default null,
+  ALARM_VEVENT_ALLDAY      text        default null,
+  ALARM_VTODO_TIMED        text        default null,
+  ALARM_VTODO_ALLDAY       text        default null,
+  AVAILABILITY             text        default null,
+  CREATED                  timestamp   default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                 timestamp   default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+create index CALENDAR_HOME_METADATA_DEFAULT_EVENTS on
+        CALENDAR_HOME_METADATA(DEFAULT_EVENTS);
+create index CALENDAR_HOME_METADATA_DEFAULT_TASKS on
+        CALENDAR_HOME_METADATA(DEFAULT_TASKS);
+create index CALENDAR_HOME_METADATA_DEFAULT_POLLS on
+        CALENDAR_HOME_METADATA(DEFAULT_POLLS);
+
+-----------------------
+-- Calendar Metadata --
+-----------------------
+
+create table CALENDAR_METADATA (
+  RESOURCE_ID           integer      primary key references CALENDAR on delete cascade, -- implicit index
+  SUPPORTED_COMPONENTS  varchar(255) default null,
+  CREATED               timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+  RESOURCE_ID integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID   varchar(255) not null unique                                 -- implicit index
+);
+
+create table NOTIFICATION (
+  RESOURCE_ID                   integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME,
+  NOTIFICATION_UID              varchar(255) not null,
+  XML_TYPE                      varchar(255) not null,
+  XML_DATA                      text         not null,
+  MD5                           char(32)     not null,
+  CREATED                       timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                      timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+        NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      not null references CALENDAR on delete cascade,
+  CALENDAR_RESOURCE_NAME    varchar(255) not null,
+  BIND_MODE                 integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS               integer      not null, -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                integer      default 0 not null,
+  MESSAGE                   text,
+  TRANSP                    integer      default 0 not null, -- enum CALENDAR_TRANSP
+  ALARM_VEVENT_TIMED        text         default null,
+  ALARM_VEVENT_ALLDAY       text         default null,
+  ALARM_VTODO_TIMED         text         default null,
+  ALARM_VTODO_ALLDAY        text         default null,
+  TIMEZONE                  text         default null,
+
+  primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+  unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME)     -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on
+        CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own'  );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+
+
+-- Enumeration of transparency
+
+create table CALENDAR_TRANSP (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_TRANSP values (0, 'opaque' );
+insert into CALENDAR_TRANSP values (1, 'transparent');
+
+
+---------------------
+-- Calendar Object --
+---------------------
+
+create table CALENDAR_OBJECT (
+  RESOURCE_ID          integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID integer      not null references CALENDAR on delete cascade,
+  RESOURCE_NAME        varchar(255) not null,
+  ICALENDAR_TEXT       text         not null,
+  ICALENDAR_UID        varchar(255) not null,
+  ICALENDAR_TYPE       varchar(255) not null,
+  ATTACHMENTS_MODE     integer      default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+  DROPBOX_ID           varchar(255),
+  ORGANIZER            varchar(255),
+  RECURRANCE_MIN       date,        -- minimum date that recurrences have been expanded to.
+  RECURRANCE_MAX       date,        -- maximum date that recurrences have been expanded to.
+  ACCESS               integer      default 0 not null,
+  SCHEDULE_OBJECT      boolean      default false,
+  SCHEDULE_TAG         varchar(36)  default null,
+  SCHEDULE_ETAGS       text         default null,
+  PRIVATE_COMMENTS     boolean      default false not null,
+  MD5                  char(32)     not null,
+  CREATED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED             timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+  -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+  -- calendar objects, this constraint has to be selectively enforced by the
+  -- application layer.
+
+  -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ICALENDAR_UID on
+  CALENDAR_OBJECT(ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+  CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, ''             );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public'       );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private'      );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted'   );
+
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+  INSTANCE_ID                 integer        primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID        integer        not null references CALENDAR on delete cascade,
+  CALENDAR_OBJECT_RESOURCE_ID integer        not null references CALENDAR_OBJECT on delete cascade,
+  FLOATING                    boolean        not null,
+  START_DATE                  timestamp      not null,
+  END_DATE                    timestamp      not null,
+  FBTYPE                      integer        not null,
+  TRANSPARENT                 boolean        not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown'         );
+insert into FREE_BUSY_TYPE values (1, 'free'            );
+insert into FREE_BUSY_TYPE values (2, 'busy'            );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative'  );
+
+
+------------------
+-- Transparency --
+------------------
+
+create table TRANSPARENCY (
+  TIME_RANGE_INSTANCE_ID      integer      not null references TIME_RANGE on delete cascade,
+  USER_ID                     varchar(255) not null,
+  TRANSPARENT                 boolean      not null
+);
+
+create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
+  TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
+
+
+----------------
+-- Attachment --
+----------------
+
+create sequence ATTACHMENT_ID_SEQ;
+
+create table ATTACHMENT (
+  ATTACHMENT_ID               integer           primary key default nextval('ATTACHMENT_ID_SEQ'), -- implicit index
+  CALENDAR_HOME_RESOURCE_ID   integer           not null references CALENDAR_HOME,
+  DROPBOX_ID                  varchar(255),
+  CONTENT_TYPE                varchar(255)      not null,
+  SIZE                        integer           not null,
+  MD5                         char(32)          not null,
+  CREATED                     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                    timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  PATH                        varchar(1024)     not null
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+  ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+-- Many-to-many relationship between attachments and calendar objects
+create table ATTACHMENT_CALENDAR_OBJECT (
+  ATTACHMENT_ID                  integer      not null references ATTACHMENT on delete cascade,
+  MANAGED_ID                     varchar(255) not null,
+  CALENDAR_OBJECT_RESOURCE_ID    integer      not null references CALENDAR_OBJECT on delete cascade,
+
+  primary key (ATTACHMENT_ID, CALENDAR_OBJECT_RESOURCE_ID), -- implicit index
+  unique (MANAGED_ID, CALENDAR_OBJECT_RESOURCE_ID) --implicit index
+);
+
+create index ATTACHMENT_CALENDAR_OBJECT_CALENDAR_OBJECT_RESOURCE_ID on
+        ATTACHMENT_CALENDAR_OBJECT(CALENDAR_OBJECT_RESOURCE_ID);
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+  RESOURCE_ID integer      not null, -- foreign key: *.RESOURCE_ID
+  NAME        varchar(255) not null,
+  VALUE       text         not null, -- FIXME: xml?
+  VIEWER_UID  varchar(255),
+
+  primary key (RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+  RESOURCE_ID                                      integer                        primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  ADDRESSBOOK_PROPERTY_STORE_ID        integer              default nextval('RESOURCE_ID_SEQ') not null,         -- implicit index
+  OWNER_UID                                        varchar(255)         not null unique,                                -- implicit index
+  DATAVERSION                                      integer              default 0 not null
+);
+
+
+-------------------------------
+-- AddressBook Home Metadata --
+-------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+  RESOURCE_ID      integer      primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES integer      default 0 not null,
+  CREATED          timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED         timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+-----------------------------
+-- Shared AddressBook Bind --
+-----------------------------
+
+-- Joins sharee ADDRESSBOOK_HOME and owner ADDRESSBOOK_HOME
+
+create table SHARED_ADDRESSBOOK_BIND (
+  ADDRESSBOOK_HOME_RESOURCE_ID                        integer                        not null references ADDRESSBOOK_HOME,
+  OWNER_HOME_RESOURCE_ID                            integer              not null references ADDRESSBOOK_HOME on delete cascade,
+  ADDRESSBOOK_RESOURCE_NAME                            varchar(255)         not null,
+  BIND_MODE                                            integer              not null,        -- enum CALENDAR_BIND_MODE
+  BIND_STATUS                                          integer              not null,        -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                                           integer              default 0 not null,
+  MESSAGE                                              text,                                  -- FIXME: xml?
+
+  primary key (ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
+);
+
+create index SHARED_ADDRESSBOOK_BIND_RESOURCE_ID on
+  SHARED_ADDRESSBOOK_BIND(OWNER_HOME_RESOURCE_ID);
+
+
+------------------------
+-- AddressBook Object --
+------------------------
+
+create table ADDRESSBOOK_OBJECT (
+  RESOURCE_ID                             integer                   primary key default nextval('RESOURCE_ID_SEQ'),    -- implicit index
+  ADDRESSBOOK_HOME_RESOURCE_ID         integer              not null references ADDRESSBOOK_HOME on delete cascade,
+  RESOURCE_NAME                           varchar(255)         not null,
+  VCARD_TEXT                              text                 not null,
+  VCARD_UID                               varchar(255)         not null,
+  KIND                                                             integer              not null,  -- enum ADDRESSBOOK_OBJECT_KIND
+  MD5                                     char(32)             not null,
+  CREATED                                 timestamp            default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                                timestamp            default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, VCARD_UID)      -- implicit index
+);
+
+
+-----------------------------
+-- AddressBook Object kind --
+-----------------------------
+
+create table ADDRESSBOOK_OBJECT_KIND (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND values (0, 'person');
+insert into ADDRESSBOOK_OBJECT_KIND values (1, 'group' );
+insert into ADDRESSBOOK_OBJECT_KIND values (2, 'resource');
+insert into ADDRESSBOOK_OBJECT_KIND values (3, 'location');
+
+
+---------------------------------
+-- Address Book Object Members --
+---------------------------------
+
+create table ABO_MEMBERS (
+    GROUP_ID              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,        -- AddressBook Object's (kind=='group') RESOURCE_ID
+         ADDRESSBOOK_ID                  integer      not null references ADDRESSBOOK_HOME on delete cascade,
+    MEMBER_ID             integer      not null references ADDRESSBOOK_OBJECT,                                                -- member AddressBook Object's RESOURCE_ID
+
+    primary key (GROUP_ID, MEMBER_ID) -- implicit index
+);
+
+create index ABO_MEMBERS_ADDRESSBOOK_ID on
+        ABO_MEMBERS(ADDRESSBOOK_ID);
+create index ABO_MEMBERS_MEMBER_ID on
+        ABO_MEMBERS(MEMBER_ID);
+
+------------------------------------------
+-- Address Book Object Foreign Members  --
+------------------------------------------
+
+create table ABO_FOREIGN_MEMBERS (
+    GROUP_ID              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,        -- AddressBook Object's (kind=='group') RESOURCE_ID
+         ADDRESSBOOK_ID                  integer      not null references ADDRESSBOOK_HOME on delete cascade,
+    MEMBER_ADDRESS            varchar(255) not null,                                                                                                         -- member AddressBook Object's 'calendar' address
+
+    primary key (GROUP_ID, MEMBER_ADDRESS) -- implicit index
+);
+
+create index ABO_FOREIGN_MEMBERS_ADDRESSBOOK_ID on
+        ABO_FOREIGN_MEMBERS(ADDRESSBOOK_ID);
+
+-----------------------
+-- Shared Group Bind --
+-----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (kind == group)
+
+create table SHARED_GROUP_BIND (        
+  ADDRESSBOOK_HOME_RESOURCE_ID                 integer      not null references ADDRESSBOOK_HOME,
+  GROUP_RESOURCE_ID                              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,
+  GROUP_ADDRESSBOOK_NAME                        varchar(255) not null,
+  BIND_MODE                                    integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS                                  integer      not null, -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                                   integer      default 0 not null,
+  MESSAGE                                      text,                  -- FIXME: xml?
+
+  primary key (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_RESOURCE_ID), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_NAME)     -- implicit index
+);
+
+create index SHARED_GROUP_BIND_RESOURCE_ID on
+  SHARED_GROUP_BIND(GROUP_RESOURCE_ID);
+
+
+---------------
+-- Revisions --
+---------------
+
+create sequence REVISION_SEQ;
+
+
+-------------------------------
+-- Calendar Object Revisions --
+-------------------------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      references CALENDAR,
+  CALENDAR_NAME             varchar(255) default null,
+  RESOURCE_NAME             varchar(255),
+  REVISION                  integer      default nextval('REVISION_SEQ') not null,
+  DELETED                   boolean      not null
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
+
+
+----------------------------------
+-- AddressBook Object Revisions --
+----------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+  ADDRESSBOOK_HOME_RESOURCE_ID                         integer                        not null references ADDRESSBOOK_HOME,
+  OWNER_HOME_RESOURCE_ID                            integer             references ADDRESSBOOK_HOME,
+  ADDRESSBOOK_NAME                                     varchar(255)         default null,
+  RESOURCE_NAME                                        varchar(255),
+  REVISION                                             integer             default nextval('REVISION_SEQ') not null,
+  DELETED                                              boolean              not null
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_HOME_RESOURCE_ID
+  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_REVISION
+  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, REVISION);
+
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME on delete cascade,
+  RESOURCE_NAME                 varchar(255),
+  REVISION                      integer      default nextval('REVISION_SEQ') not null,
+  DELETED                       boolean      not null,
+
+  unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+  on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
+
+
+-------------------------------------------
+-- Apple Push Notification Subscriptions --
+-------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+  TOKEN                         varchar(255) not null,
+  RESOURCE_KEY                  varchar(255) not null,
+  MODIFIED                      integer      not null,
+  SUBSCRIBER_GUID               varchar(255) not null,
+  USER_AGENT                    varchar(255) default null,
+  IP_ADDR                       varchar(255) default null,
+
+  primary key (TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+   on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+   
+-----------------
+-- IMIP Tokens --
+-----------------
+
+create table IMIP_TOKENS (
+  TOKEN                         varchar(255) not null,
+  ORGANIZER                     varchar(255) not null,
+  ATTENDEE                      varchar(255) not null,
+  ICALUID                       varchar(255) not null,
+  ACCESSED                      timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
+);
+
+create index IMIP_TOKENS_TOKEN
+   on IMIP_TOKENS(TOKEN);
+
+   
+----------------
+-- Work Items --
+----------------
+
+create sequence WORKITEM_SEQ;
+
+
+---------------------------
+-- IMIP Inivitation Work --
+---------------------------
+
+create table IMIP_INVITATION_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  FROM_ADDR                     varchar(255) not null,
+  TO_ADDR                       varchar(255) not null,
+  ICALENDAR_TEXT                text         not null
+);
+
+
+-----------------------
+-- IMIP Polling Work --
+-----------------------
+
+create table IMIP_POLLING_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------
+-- IMIP Reply Work --
+---------------------
+
+create table IMIP_REPLY_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  ORGANIZER                     varchar(255) not null,
+  ATTENDEE                      varchar(255) not null,
+  ICALENDAR_TEXT                text         not null
+);
+
+
+------------------------
+-- Push Notifications --
+------------------------
+
+create table PUSH_NOTIFICATION_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  PUSH_ID                       varchar(255) not null
+);
+
+-----------------
+-- GroupCacher --
+-----------------
+
+create table GROUP_CACHER_POLLING_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+--------------------------
+-- Object Splitter Work --
+--------------------------
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  RESOURCE_ID                   integer      not null references CALENDAR_OBJECT on delete cascade
+);
+
+create index CALENDAR_OBJECT_SPLITTER_WORK_RESOURCE_ID on
+        CALENDAR_OBJECT_SPLITTER_WORK(RESOURCE_ID);
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+  NAME                          varchar(255) primary key, -- implicit index
+  VALUE                         varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '27');
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '5');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaoldpostgresdialectv28sql"></a>
<div class="addfile"><h4>Added: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v28.sql (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v28.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/old/postgres-dialect/v28.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,704 @@
</span><ins>+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2013 Apple Inc. 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.
+----
+
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+
+-------------------------
+-- Cluster Bookkeeping --
+-------------------------
+
+-- Information about a process connected to this database.
+
+-- Note that this must match the node info schema in twext.enterprise.queue.
+create table NODE_INFO (
+  HOSTNAME  varchar(255) not null,
+  PID       integer      not null,
+  PORT      integer      not null,
+  TIME      timestamp    not null default timezone('UTC', CURRENT_TIMESTAMP),
+
+  primary key (HOSTNAME, PORT)
+);
+
+-- Unique named locks.  This table should always be empty, but rows are
+-- temporarily created in order to prevent undesirable concurrency.
+create table NAMED_LOCK (
+    LOCK_NAME varchar(255) primary key
+);
+
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID        varchar(255) not null unique,                                 -- implicit index
+  DATAVERSION      integer      default 0 not null
+);
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+create table CALENDAR_HOME_METADATA (
+  RESOURCE_ID              integer     primary key references CALENDAR_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES         integer     default 0 not null,
+  DEFAULT_EVENTS           integer     default null references CALENDAR on delete set null,
+  DEFAULT_TASKS            integer     default null references CALENDAR on delete set null,
+  DEFAULT_POLLS            integer     default null references CALENDAR on delete set null,
+  ALARM_VEVENT_TIMED       text        default null,
+  ALARM_VEVENT_ALLDAY      text        default null,
+  ALARM_VTODO_TIMED        text        default null,
+  ALARM_VTODO_ALLDAY       text        default null,
+  AVAILABILITY             text        default null,
+  CREATED                  timestamp   default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                 timestamp   default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+create index CALENDAR_HOME_METADATA_DEFAULT_EVENTS on
+        CALENDAR_HOME_METADATA(DEFAULT_EVENTS);
+create index CALENDAR_HOME_METADATA_DEFAULT_TASKS on
+        CALENDAR_HOME_METADATA(DEFAULT_TASKS);
+create index CALENDAR_HOME_METADATA_DEFAULT_POLLS on
+        CALENDAR_HOME_METADATA(DEFAULT_POLLS);
+
+-----------------------
+-- Calendar Metadata --
+-----------------------
+
+create table CALENDAR_METADATA (
+  RESOURCE_ID           integer      primary key references CALENDAR on delete cascade, -- implicit index
+  SUPPORTED_COMPONENTS  varchar(255) default null,
+  CREATED               timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+  RESOURCE_ID integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID   varchar(255) not null unique                                 -- implicit index
+);
+
+create table NOTIFICATION (
+  RESOURCE_ID                   integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME,
+  NOTIFICATION_UID              varchar(255) not null,
+  XML_TYPE                      varchar(255) not null,
+  XML_DATA                      text         not null,
+  MD5                           char(32)     not null,
+  CREATED                       timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                      timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+        NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      not null references CALENDAR on delete cascade,
+  CALENDAR_RESOURCE_NAME    varchar(255) not null,
+  BIND_MODE                 integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS               integer      not null, -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                integer      default 0 not null,
+  MESSAGE                   text,
+  TRANSP                    integer      default 0 not null, -- enum CALENDAR_TRANSP
+  ALARM_VEVENT_TIMED        text         default null,
+  ALARM_VEVENT_ALLDAY       text         default null,
+  ALARM_VTODO_TIMED         text         default null,
+  ALARM_VTODO_ALLDAY        text         default null,
+  TIMEZONE                  text         default null,
+
+  primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+  unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME)     -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on
+        CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own'  );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+
+
+-- Enumeration of transparency
+
+create table CALENDAR_TRANSP (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_TRANSP values (0, 'opaque' );
+insert into CALENDAR_TRANSP values (1, 'transparent');
+
+
+---------------------
+-- Calendar Object --
+---------------------
+
+create table CALENDAR_OBJECT (
+  RESOURCE_ID          integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID integer      not null references CALENDAR on delete cascade,
+  RESOURCE_NAME        varchar(255) not null,
+  ICALENDAR_TEXT       text         not null,
+  ICALENDAR_UID        varchar(255) not null,
+  ICALENDAR_TYPE       varchar(255) not null,
+  ATTACHMENTS_MODE     integer      default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+  DROPBOX_ID           varchar(255),
+  ORGANIZER            varchar(255),
+  RECURRANCE_MIN       date,        -- minimum date that recurrences have been expanded to.
+  RECURRANCE_MAX       date,        -- maximum date that recurrences have been expanded to.
+  ACCESS               integer      default 0 not null,
+  SCHEDULE_OBJECT      boolean      default false,
+  SCHEDULE_TAG         varchar(36)  default null,
+  SCHEDULE_ETAGS       text         default null,
+  PRIVATE_COMMENTS     boolean      default false not null,
+  MD5                  char(32)     not null,
+  CREATED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED             timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+  -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+  -- calendar objects, this constraint has to be selectively enforced by the
+  -- application layer.
+
+  -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ICALENDAR_UID on
+  CALENDAR_OBJECT(ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+  CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, ''             );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public'       );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private'      );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted'   );
+
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+  INSTANCE_ID                 integer        primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID        integer        not null references CALENDAR on delete cascade,
+  CALENDAR_OBJECT_RESOURCE_ID integer        not null references CALENDAR_OBJECT on delete cascade,
+  FLOATING                    boolean        not null,
+  START_DATE                  timestamp      not null,
+  END_DATE                    timestamp      not null,
+  FBTYPE                      integer        not null,
+  TRANSPARENT                 boolean        not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown'         );
+insert into FREE_BUSY_TYPE values (1, 'free'            );
+insert into FREE_BUSY_TYPE values (2, 'busy'            );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative'  );
+
+
+------------------
+-- Transparency --
+------------------
+
+create table TRANSPARENCY (
+  TIME_RANGE_INSTANCE_ID      integer      not null references TIME_RANGE on delete cascade,
+  USER_ID                     varchar(255) not null,
+  TRANSPARENT                 boolean      not null
+);
+
+create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
+  TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
+
+
+----------------
+-- Attachment --
+----------------
+
+create sequence ATTACHMENT_ID_SEQ;
+
+create table ATTACHMENT (
+  ATTACHMENT_ID               integer           primary key default nextval('ATTACHMENT_ID_SEQ'), -- implicit index
+  CALENDAR_HOME_RESOURCE_ID   integer           not null references CALENDAR_HOME,
+  DROPBOX_ID                  varchar(255),
+  CONTENT_TYPE                varchar(255)      not null,
+  SIZE                        integer           not null,
+  MD5                         char(32)          not null,
+  CREATED                     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                    timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  PATH                        varchar(1024)     not null
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+  ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+-- Many-to-many relationship between attachments and calendar objects
+create table ATTACHMENT_CALENDAR_OBJECT (
+  ATTACHMENT_ID                  integer      not null references ATTACHMENT on delete cascade,
+  MANAGED_ID                     varchar(255) not null,
+  CALENDAR_OBJECT_RESOURCE_ID    integer      not null references CALENDAR_OBJECT on delete cascade,
+
+  primary key (ATTACHMENT_ID, CALENDAR_OBJECT_RESOURCE_ID), -- implicit index
+  unique (MANAGED_ID, CALENDAR_OBJECT_RESOURCE_ID) --implicit index
+);
+
+create index ATTACHMENT_CALENDAR_OBJECT_CALENDAR_OBJECT_RESOURCE_ID on
+        ATTACHMENT_CALENDAR_OBJECT(CALENDAR_OBJECT_RESOURCE_ID);
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+  RESOURCE_ID integer      not null, -- foreign key: *.RESOURCE_ID
+  NAME        varchar(255) not null,
+  VALUE       text         not null, -- FIXME: xml?
+  VIEWER_UID  varchar(255),
+
+  primary key (RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+  RESOURCE_ID                                      integer                        primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  ADDRESSBOOK_PROPERTY_STORE_ID        integer              default nextval('RESOURCE_ID_SEQ') not null,         -- implicit index
+  OWNER_UID                                        varchar(255)         not null unique,                                -- implicit index
+  DATAVERSION                                      integer              default 0 not null
+);
+
+
+-------------------------------
+-- AddressBook Home Metadata --
+-------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+  RESOURCE_ID      integer      primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES integer      default 0 not null,
+  CREATED          timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED         timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+-----------------------------
+-- Shared AddressBook Bind --
+-----------------------------
+
+-- Joins sharee ADDRESSBOOK_HOME and owner ADDRESSBOOK_HOME
+
+create table SHARED_ADDRESSBOOK_BIND (
+  ADDRESSBOOK_HOME_RESOURCE_ID                        integer                        not null references ADDRESSBOOK_HOME,
+  OWNER_HOME_RESOURCE_ID                            integer              not null references ADDRESSBOOK_HOME on delete cascade,
+  ADDRESSBOOK_RESOURCE_NAME                            varchar(255)         not null,
+  BIND_MODE                                            integer              not null,        -- enum CALENDAR_BIND_MODE
+  BIND_STATUS                                          integer              not null,        -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                                           integer              default 0 not null,
+  MESSAGE                                              text,                                  -- FIXME: xml?
+
+  primary key (ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
+);
+
+create index SHARED_ADDRESSBOOK_BIND_RESOURCE_ID on
+  SHARED_ADDRESSBOOK_BIND(OWNER_HOME_RESOURCE_ID);
+
+
+------------------------
+-- AddressBook Object --
+------------------------
+
+create table ADDRESSBOOK_OBJECT (
+  RESOURCE_ID                             integer                   primary key default nextval('RESOURCE_ID_SEQ'),    -- implicit index
+  ADDRESSBOOK_HOME_RESOURCE_ID         integer              not null references ADDRESSBOOK_HOME on delete cascade,
+  RESOURCE_NAME                           varchar(255)         not null,
+  VCARD_TEXT                              text                 not null,
+  VCARD_UID                               varchar(255)         not null,
+  KIND                                                             integer              not null,  -- enum ADDRESSBOOK_OBJECT_KIND
+  MD5                                     char(32)             not null,
+  CREATED                                 timestamp            default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                                timestamp            default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, VCARD_UID)      -- implicit index
+);
+
+
+-----------------------------
+-- AddressBook Object kind --
+-----------------------------
+
+create table ADDRESSBOOK_OBJECT_KIND (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND values (0, 'person');
+insert into ADDRESSBOOK_OBJECT_KIND values (1, 'group' );
+insert into ADDRESSBOOK_OBJECT_KIND values (2, 'resource');
+insert into ADDRESSBOOK_OBJECT_KIND values (3, 'location');
+
+
+---------------------------------
+-- Address Book Object Members --
+---------------------------------
+
+create table ABO_MEMBERS (
+    GROUP_ID              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,        -- AddressBook Object's (kind=='group') RESOURCE_ID
+         ADDRESSBOOK_ID                  integer      not null references ADDRESSBOOK_HOME on delete cascade,
+    MEMBER_ID             integer      not null references ADDRESSBOOK_OBJECT,                                                -- member AddressBook Object's RESOURCE_ID
+
+    primary key (GROUP_ID, MEMBER_ID) -- implicit index
+);
+
+create index ABO_MEMBERS_ADDRESSBOOK_ID on
+        ABO_MEMBERS(ADDRESSBOOK_ID);
+create index ABO_MEMBERS_MEMBER_ID on
+        ABO_MEMBERS(MEMBER_ID);
+
+------------------------------------------
+-- Address Book Object Foreign Members  --
+------------------------------------------
+
+create table ABO_FOREIGN_MEMBERS (
+    GROUP_ID              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,        -- AddressBook Object's (kind=='group') RESOURCE_ID
+         ADDRESSBOOK_ID                  integer      not null references ADDRESSBOOK_HOME on delete cascade,
+    MEMBER_ADDRESS            varchar(255) not null,                                                                                                         -- member AddressBook Object's 'calendar' address
+
+    primary key (GROUP_ID, MEMBER_ADDRESS) -- implicit index
+);
+
+create index ABO_FOREIGN_MEMBERS_ADDRESSBOOK_ID on
+        ABO_FOREIGN_MEMBERS(ADDRESSBOOK_ID);
+
+-----------------------
+-- Shared Group Bind --
+-----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (kind == group)
+
+create table SHARED_GROUP_BIND (        
+  ADDRESSBOOK_HOME_RESOURCE_ID                 integer      not null references ADDRESSBOOK_HOME,
+  GROUP_RESOURCE_ID                              integer      not null references ADDRESSBOOK_OBJECT on delete cascade,
+  GROUP_ADDRESSBOOK_NAME                        varchar(255) not null,
+  BIND_MODE                                    integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS                                  integer      not null, -- enum CALENDAR_BIND_STATUS
+  BIND_REVISION                                                   integer      default 0 not null,
+  MESSAGE                                      text,                  -- FIXME: xml?
+
+  primary key (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_RESOURCE_ID), -- implicit index
+  unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_NAME)     -- implicit index
+);
+
+create index SHARED_GROUP_BIND_RESOURCE_ID on
+  SHARED_GROUP_BIND(GROUP_RESOURCE_ID);
+
+
+---------------
+-- Revisions --
+---------------
+
+create sequence REVISION_SEQ;
+
+
+-------------------------------
+-- Calendar Object Revisions --
+-------------------------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      references CALENDAR,
+  CALENDAR_NAME             varchar(255) default null,
+  RESOURCE_NAME             varchar(255),
+  REVISION                  integer      default nextval('REVISION_SEQ') not null,
+  DELETED                   boolean      not null
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
+
+
+----------------------------------
+-- AddressBook Object Revisions --
+----------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+  ADDRESSBOOK_HOME_RESOURCE_ID                         integer                        not null references ADDRESSBOOK_HOME,
+  OWNER_HOME_RESOURCE_ID                            integer             references ADDRESSBOOK_HOME,
+  ADDRESSBOOK_NAME                                     varchar(255)         default null,
+  RESOURCE_NAME                                        varchar(255),
+  REVISION                                             integer             default nextval('REVISION_SEQ') not null,
+  DELETED                                              boolean              not null
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_HOME_RESOURCE_ID
+  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_REVISION
+  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, REVISION);
+
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME on delete cascade,
+  RESOURCE_NAME                 varchar(255),
+  REVISION                      integer      default nextval('REVISION_SEQ') not null,
+  DELETED                       boolean      not null,
+
+  unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+  on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
+
+
+-------------------------------------------
+-- Apple Push Notification Subscriptions --
+-------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+  TOKEN                         varchar(255) not null,
+  RESOURCE_KEY                  varchar(255) not null,
+  MODIFIED                      integer      not null,
+  SUBSCRIBER_GUID               varchar(255) not null,
+  USER_AGENT                    varchar(255) default null,
+  IP_ADDR                       varchar(255) default null,
+
+  primary key (TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+   on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+   
+-----------------
+-- IMIP Tokens --
+-----------------
+
+create table IMIP_TOKENS (
+  TOKEN                         varchar(255) not null,
+  ORGANIZER                     varchar(255) not null,
+  ATTENDEE                      varchar(255) not null,
+  ICALUID                       varchar(255) not null,
+  ACCESSED                      timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
+);
+
+create index IMIP_TOKENS_TOKEN
+   on IMIP_TOKENS(TOKEN);
+
+   
+----------------
+-- Work Items --
+----------------
+
+create sequence WORKITEM_SEQ;
+
+
+---------------------------
+-- IMIP Inivitation Work --
+---------------------------
+
+create table IMIP_INVITATION_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  FROM_ADDR                     varchar(255) not null,
+  TO_ADDR                       varchar(255) not null,
+  ICALENDAR_TEXT                text         not null
+);
+
+
+-----------------------
+-- IMIP Polling Work --
+-----------------------
+
+create table IMIP_POLLING_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------
+-- IMIP Reply Work --
+---------------------
+
+create table IMIP_REPLY_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  ORGANIZER                     varchar(255) not null,
+  ATTENDEE                      varchar(255) not null,
+  ICALENDAR_TEXT                text         not null
+);
+
+
+------------------------
+-- Push Notifications --
+------------------------
+
+create table PUSH_NOTIFICATION_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  PUSH_ID                       varchar(255) not null,
+  PRIORITY                      integer      not null -- 1:low 5:medium 10:high
+);
+
+-----------------
+-- GroupCacher --
+-----------------
+
+create table GROUP_CACHER_POLLING_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+--------------------------
+-- Object Splitter Work --
+--------------------------
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+  WORK_ID                       integer      primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+  NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  RESOURCE_ID                   integer      not null references CALENDAR_OBJECT on delete cascade
+);
+
+create index CALENDAR_OBJECT_SPLITTER_WORK_RESOURCE_ID on
+        CALENDAR_OBJECT_SPLITTER_WORK(RESOURCE_ID);
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+  NAME                          varchar(255) primary key, -- implicit index
+  VALUE                         varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '28');
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '5');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_24_to_25sql"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_24_to_25.sql (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_24_to_25.sql        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_24_to_25.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,26 +0,0 @@
</span><del>-----
--- Copyright (c) 2012-2013 Apple Inc. 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.
-----
-
----------------------------------------------------
--- Upgrade database schema from VERSION 24 to 25 --
----------------------------------------------------
-
--- This is actually a noop for Oracle as we had some invalid names in the v20 schema that
--- were corrected in v20 (but not corrected in postgres which is being updated for v25).
-
--- Now update the version
--- No data upgrades
-update CALENDARSERVER set VALUE = '25' where NAME = 'VERSION';
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_24_to_25sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_24_to_25sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_24_to_25.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_24_to_25.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_24_to_25.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_24_to_25.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+----
+-- Copyright (c) 2012-2013 Apple Inc. 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.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 24 to 25 --
+---------------------------------------------------
+
+-- This is actually a noop for Oracle as we had some invalid names in the v20 schema that
+-- were corrected in v20 (but not corrected in postgres which is being updated for v25).
+
+-- Now update the version
+-- No data upgrades
+update CALENDARSERVER set VALUE = '25' where NAME = 'VERSION';
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_25_to_26sql"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_25_to_26.sql (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_25_to_26.sql        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_25_to_26.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -15,35 +15,29 @@
</span><span class="cx"> ----
</span><span class="cx"> 
</span><span class="cx"> ---------------------------------------------------
</span><del>--- Upgrade database schema from VERSION 24 to 25 --
</del><ins>+-- Upgrade database schema from VERSION 25 to 26 --
</ins><span class="cx"> ---------------------------------------------------
</span><span class="cx"> 
</span><del>-----------------------------------------
--- Change Address Book Object Members --
-----------------------------------------
</del><ins>+-- Replace index
</ins><span class="cx"> 
</span><del>-alter table ABO_MEMBERS
-        drop (&quot;abo_members_member_id_fkey&quot;);
-alter table ABO_MEMBERS
-        drop (&quot;abo_members_group_id_fkey&quot;);
-alter table ABO_MEMBERS
-        add (&quot;REVISION&quot; integer default nextval('REVISION_SEQ') not null);
-alter table ABO_MEMBERS
-        add (&quot;REMOVED&quot; boolean default false not null);
-alter table ABO_MEMBERS
-         drop (&quot;abo_members_pkey&quot;);
-alter table ABO_MEMBERS
-         add (&quot;abo_members_pkey&quot; primary key (&quot;GROUP_ID&quot;, &quot;MEMBER_ID&quot;, &quot;REVISION&quot;));
</del><ins>+drop index CALENDAR_OBJECT_REVIS_2643d556;
+create index CALENDAR_OBJECT_REVIS_6d9d929c on CALENDAR_OBJECT_REVISIONS (
+    CALENDAR_RESOURCE_ID,
+    RESOURCE_NAME,
+    DELETED,
+    REVISION
+);
</ins><span class="cx"> 
</span><del>-------------------------------------------
--- Change Address Book Object Revisions --
-------------------------------------------
-        
-alter table ADDRESSBOOK_OBJECT_REVISIONS
-        add (&quot;OBJECT_RESOURCE_ID&quot; integer default 0);
</del><span class="cx"> 
</span><del>---------------------
--- Update version --
---------------------
</del><ins>+drop index ADDRESSBOOK_OBJECT_RE_980b9872;
+create index ADDRESSBOOK_OBJECT_RE_00fe8288 on ADDRESSBOOK_OBJECT_REVISIONS (
+    OWNER_HOME_RESOURCE_ID,
+    RESOURCE_NAME,
+    DELETED,
+    REVISION
+);
</ins><span class="cx"> 
</span><ins>+
+-- Now update the version
+-- No data upgrades
</ins><span class="cx"> update CALENDARSERVER set VALUE = '26' where NAME = 'VERSION';
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_26_to_27sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_26_to_27sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_26_to_27.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_26_to_27.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_26_to_27.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_26_to_27.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+----
+-- Copyright (c) 2012-2013 Apple Inc. 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.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 26 to 27 --
+---------------------------------------------------
+
+-- Calendar home related updates
+
+alter table CALENDAR_HOME_METADATA
+ add (&quot;DEFAULT_POLLS&quot; integer default null references CALENDAR on delete set null);
+
+create index CALENDAR_HOME_METADAT_910264ce on CALENDAR_HOME_METADATA (
+    DEFAULT_POLLS
+);
+
+
+-- Now update the version
+-- No data upgrades
+update CALENDARSERVER set VALUE = '27' where NAME = 'VERSION';
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_27_to_28sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_27_to_28sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_27_to_28.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_27_to_28.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_27_to_28.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_27_to_28.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+----
+-- Copyright (c) 2012-2013 Apple Inc. 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.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 27 to 28 --
+---------------------------------------------------
+
+-- Push notification work related updates
+
+alter table PUSH_NOTIFICATION_WORK
+ add (&quot;PRIORITY&quot; integer default 10 not null);
+
+update PUSH_NOTIFICATION_WORK set PRIORITY = 10;
+
+-- Now update the version
+update CALENDARSERVER set VALUE = '28' where NAME = 'VERSION';
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradesoracledialectupgrade_from_28_to_29sql"></a>
<div class="addfile"><h4>Added: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_28_to_29.sql (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_28_to_29.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_28_to_29.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+----
+-- Copyright (c) 2012-2013 Apple Inc. 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.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 28 to 29 --
+---------------------------------------------------
+
+----------------------------------------
+-- Change Address Book Object Members --
+----------------------------------------
+
+alter table ABO_MEMBERS
+        drop (&quot;abo_members_member_id_fkey&quot;);
+alter table ABO_MEMBERS
+        drop (&quot;abo_members_group_id_fkey&quot;);
+alter table ABO_MEMBERS
+        add (&quot;REVISION&quot; integer default nextval('REVISION_SEQ') not null);
+alter table ABO_MEMBERS
+        add (&quot;REMOVED&quot; boolean default false not null);
+alter table ABO_MEMBERS
+         drop (&quot;abo_members_pkey&quot;);
+alter table ABO_MEMBERS
+         add (&quot;abo_members_pkey&quot; primary key (&quot;GROUP_ID&quot;, &quot;MEMBER_ID&quot;, &quot;REVISION&quot;));
+
+------------------------------------------
+-- Change Address Book Object Revisions --
+------------------------------------------
+        
+alter table ADDRESSBOOK_OBJECT_REVISIONS
+        add (&quot;OBJECT_RESOURCE_ID&quot; integer default 0);
+
+--------------------
+-- Update version --
+--------------------
+
+update CALENDARSERVER set VALUE = '29' where NAME = 'VERSION';
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_24_to_25sql"></a>
<div class="delfile"><h4>Deleted: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_24_to_25.sql (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_24_to_25.sql        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_24_to_25.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -1,35 +0,0 @@
</span><del>-----
--- Copyright (c) 2012-2013 Apple Inc. 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.
-----
-
----------------------------------------------------
--- Upgrade database schema from VERSION 24 to 25 --
----------------------------------------------------
-
--- Rename columns and indexes
-alter table SHARED_ADDRESSBOOK_BIND
-        rename column OWNER_ADDRESSBOOK_HOME_RESOURCE_ID to OWNER_HOME_RESOURCE_ID;
-
-alter table SHARED_GROUP_BIND
-        rename column GROUP_ADDRESSBOOK_RESOURCE_NAME to GROUP_ADDRESSBOOK_NAME;
-
-alter table ADDRESSBOOK_OBJECT_REVISIONS
-        rename column OWNER_ADDRESSBOOK_HOME_RESOURCE_ID to OWNER_HOME_RESOURCE_ID;
-
-alter index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_ADDRESSBOOK_HOME_RESOURCE_ID rename to ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_HOME_RESOURCE_ID;
-
--- Now update the version
--- No data upgrades
-update CALENDARSERVER set VALUE = '25' where NAME = 'VERSION';
</del></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_24_to_25sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_24_to_25sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_24_to_25.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_24_to_25.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_24_to_25.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_24_to_25.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+----
+-- Copyright (c) 2012-2013 Apple Inc. 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.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 24 to 25 --
+---------------------------------------------------
+
+-- Rename columns and indexes
+alter table SHARED_ADDRESSBOOK_BIND
+        rename column OWNER_ADDRESSBOOK_HOME_RESOURCE_ID to OWNER_HOME_RESOURCE_ID;
+
+alter table SHARED_GROUP_BIND
+        rename column GROUP_ADDRESSBOOK_RESOURCE_NAME to GROUP_ADDRESSBOOK_NAME;
+
+alter table ADDRESSBOOK_OBJECT_REVISIONS
+        rename column OWNER_ADDRESSBOOK_HOME_RESOURCE_ID to OWNER_HOME_RESOURCE_ID;
+
+alter index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_ADDRESSBOOK_HOME_RESOURCE_ID rename to ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_HOME_RESOURCE_ID;
+
+-- Now update the version
+-- No data upgrades
+update CALENDARSERVER set VALUE = '25' where NAME = 'VERSION';
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_25_to_26sql"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_25_to_26.sql (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_25_to_26.sql        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_25_to_26.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -15,30 +15,18 @@
</span><span class="cx"> ----
</span><span class="cx"> 
</span><span class="cx"> ---------------------------------------------------
</span><del>--- Upgrade database schema from VERSION 24 to 25 --
</del><ins>+-- Upgrade database schema from VERSION 25 to 26 --
</ins><span class="cx"> ---------------------------------------------------
</span><span class="cx"> 
</span><del>-----------------------------------------
--- Change Address Book Object Members --
-----------------------------------------
</del><ins>+-- Replace index
+drop index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME;
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
</ins><span class="cx"> 
</span><del>-alter table ABO_MEMBERS
-        drop constraint        abo_members_member_id_fkey,
-        drop constraint        abo_members_group_id_fkey,
-        add column        REVISION                integer      default nextval('REVISION_SEQ') not null,
-        add column        REMOVED         boolean      default false not null,
-        drop constraint abo_members_pkey,
-        add constraint abo_members_pkey primary key(GROUP_ID, MEMBER_ID, REVISION);
</del><ins>+drop index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME;
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+  on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
</ins><span class="cx"> 
</span><del>-------------------------------------------
--- Change Address Book Object Revisions --
-------------------------------------------
-        
-alter table ADDRESSBOOK_OBJECT_REVISIONS
-        add column OBJECT_RESOURCE_ID integer default 0;
-        
---------------------
--- Update version --
---------------------
-
</del><ins>+-- Now update the version
+-- No data upgrades
</ins><span class="cx"> update CALENDARSERVER set VALUE = '26' where NAME = 'VERSION';
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_26_to_27sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_26_to_27sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_26_to_27.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_26_to_27.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_26_to_27.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_26_to_27.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+----
+-- Copyright (c) 2012-2013 Apple Inc. 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.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 26 to 27 --
+---------------------------------------------------
+
+-- Calendar home related updates
+
+alter table CALENDAR_HOME_METADATA
+ add column DEFAULT_POLLS integer default null references CALENDAR on delete set null;
+
+create index CALENDAR_HOME_METADATA_DEFAULT_POLLS on
+        CALENDAR_HOME_METADATA(DEFAULT_POLLS);
+
+-- Now update the version
+-- No data upgrades
+update CALENDARSERVER set VALUE = '27' where NAME = 'VERSION';
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_27_to_28sqlfromrev12016CalendarServertrunktxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_27_to_28sql"></a>
<div class="copfile"><h4>Copied: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_27_to_28.sql (from rev 12016, CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_27_to_28.sql) (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_27_to_28.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_27_to_28.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+----
+-- Copyright (c) 2012-2013 Apple Inc. 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.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 27 to 28 --
+---------------------------------------------------
+
+-- Push notification work related updates
+
+alter table PUSH_NOTIFICATION_WORK
+ add column PRIORITY integer default 10 not null;
+
+update PUSH_NOTIFICATION_WORK set PRIORITY = 10;
+
+-- Now update the version
+update CALENDARSERVER set VALUE = '28' where NAME = 'VERSION';
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoresql_schemaupgradespostgresdialectupgrade_from_28_to_29sql"></a>
<div class="addfile"><h4>Added: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_28_to_29.sql (0 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_28_to_29.sql                                (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_28_to_29.sql        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+----
+-- Copyright (c) 2012-2013 Apple Inc. 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.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 28 to 29 --
+---------------------------------------------------
+
+----------------------------------------
+-- Change Address Book Object Members --
+----------------------------------------
+
+alter table ABO_MEMBERS
+        drop constraint        abo_members_member_id_fkey,
+        drop constraint        abo_members_group_id_fkey,
+        add column        REVISION                integer      default nextval('REVISION_SEQ') not null,
+        add column        REMOVED         boolean      default false not null,
+        drop constraint abo_members_pkey,
+        add constraint abo_members_pkey primary key(GROUP_ID, MEMBER_ID, REVISION);
+
+------------------------------------------
+-- Change Address Book Object Revisions --
+------------------------------------------
+        
+alter table ADDRESSBOOK_OBJECT_REVISIONS
+        add column OBJECT_RESOURCE_ID integer default 0;
+        
+--------------------
+-- Update version --
+--------------------
+
+update CALENDARSERVER set VALUE = '29' where NAME = 'VERSION';
</ins></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoretestutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/test/util.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/test/util.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/test/util.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -32,7 +32,7 @@
</span><span class="cx"> 
</span><span class="cx"> from hashlib import md5
</span><span class="cx"> 
</span><del>-from pycalendar.datetime import PyCalendarDateTime
</del><ins>+from pycalendar.datetime import DateTime
</ins><span class="cx"> 
</span><span class="cx"> from random import Random
</span><span class="cx"> 
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx"> from twisted.internet.task import deferLater
</span><span class="cx"> from twisted.trial.unittest import TestCase
</span><span class="cx"> 
</span><ins>+from twistedcaldav import ical
</ins><span class="cx"> from twistedcaldav.config import config
</span><span class="cx"> from twistedcaldav.stdconfig import DEFAULT_CONFIG
</span><span class="cx"> from twistedcaldav.vcard import Component as ABComponent
</span><span class="lines">@@ -447,12 +448,11 @@
</span><span class="cx">             # We don't want the default calendar or inbox to appear unless it's
</span><span class="cx">             # explicitly listed.
</span><span class="cx">             try:
</span><del>-                yield home.removeCalendarWithName(&quot;calendar&quot;)
-                # FIXME: this should be an argument to the function, not a
-                # global configuration variable.  Related: this needs
-                # independent tests.
</del><span class="cx">                 if config.RestrictCalendarsToOneComponentType:
</span><del>-                    yield home.removeCalendarWithName(&quot;tasks&quot;)
</del><ins>+                    for name in ical.allowedStoreComponents:
+                        yield home.removeCalendarWithName(home._componentCalendarName[name])
+                else:
+                    yield home.removeCalendarWithName(&quot;calendar&quot;)
</ins><span class="cx">                 yield home.removeCalendarWithName(&quot;inbox&quot;)
</span><span class="cx">             except NoSuchHomeChildError:
</span><span class="cx">                 pass
</span><span class="lines">@@ -480,7 +480,7 @@
</span><span class="cx">     Update the supplied iCalendar data so that all dates are updated to the current year.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    nowYear = PyCalendarDateTime.getToday().getYear()
</del><ins>+    nowYear = DateTime.getToday().getYear()
</ins><span class="cx">     return data % {&quot;now&quot;: nowYear}
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -726,8 +726,8 @@
</span><span class="cx">         return &quot;/%s/%s/%s/&quot; % (prefix, self.hostname, id)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    def send(self, prefix, id, txn):
-        self.history.append(self.pushKeyForId(prefix, id))
</del><ins>+    def send(self, prefix, id, txn, priority): 
+        self.history.append((self.pushKeyForId(prefix, id), priority))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def reset(self):
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoreupgradesqlupgradescalendar_upgrade_from_3_to_4py"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_3_to_4.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_3_to_4.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_3_to_4.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -94,27 +94,32 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     inbox = (yield home.calendarWithName(&quot;inbox&quot;))
</span><del>-    prop = inbox.properties().get(PropertyName.fromElement(propname))
-    if prop is not None:
-        defaultCalendar = str(prop.children[0])
-        parts = defaultCalendar.split(&quot;/&quot;)
-        if len(parts) == 5:
</del><ins>+    if inbox is not None:
+        prop = inbox.properties().get(PropertyName.fromElement(propname))
+        if prop is not None:
+            defaultCalendar = str(prop.children[0])
+            parts = defaultCalendar.split(&quot;/&quot;)
+            if len(parts) == 5:
</ins><span class="cx"> 
</span><del>-            calendarName = parts[-1]
-            calendarHomeUID = parts[-2]
-            if calendarHomeUID == home.uid():
</del><ins>+                calendarName = parts[-1]
+                calendarHomeUID = parts[-2]
+                if calendarHomeUID == home.uid():
</ins><span class="cx"> 
</span><del>-                calendar = (yield home.calendarWithName(calendarName))
-                if calendar is not None:
-                    try:
-                        yield home.setDefaultCalendar(
-                            calendar, tasks=(propname == customxml.ScheduleDefaultTasksURL)
-                        )
-                    except InvalidDefaultCalendar:
-                        # Ignore these - the server will recover
-                        pass
</del><ins>+                    calendar = (yield home.calendarWithName(calendarName))
+                    if calendar is not None:
+                        try:
+                            if propname == caldavxml.ScheduleDefaultCalendarURL:
+                                ctype = &quot;VEVENT&quot;
+                            elif propname == customxml.ScheduleDefaultTasksURL:
+                                ctype = &quot;VTODO&quot;
+                            yield home.setDefaultCalendar(
+                                calendar, ctype
+                            )
+                        except InvalidDefaultCalendar:
+                            # Ignore these - the server will recover
+                            pass
</ins><span class="cx"> 
</span><del>-        del inbox.properties()[PropertyName.fromElement(propname)]
</del><ins>+            del inbox.properties()[PropertyName.fromElement(propname)]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -130,15 +135,13 @@
</span><span class="cx">     calendars = (yield home.loadChildren())
</span><span class="cx">     for calendar in calendars:
</span><span class="cx">         if calendar.isInbox():
</span><del>-            continue
</del><ins>+            prop = calendar.properties().get(PropertyName.fromElement(caldavxml.CalendarFreeBusySet))
+            if prop is not None:
+                del calendar.properties()[PropertyName.fromElement(caldavxml.CalendarFreeBusySet)]
</ins><span class="cx">         prop = calendar.properties().get(PropertyName.fromElement(caldavxml.ScheduleCalendarTransp))
</span><span class="cx">         if prop is not None:
</span><span class="cx">             yield calendar.setUsedForFreeBusy(prop == caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()))
</span><span class="cx">             del calendar.properties()[PropertyName.fromElement(caldavxml.ScheduleCalendarTransp)]
</span><del>-    inbox = (yield home.calendarWithName(&quot;inbox&quot;))
-    prop = inbox.properties().get(PropertyName.fromElement(caldavxml.CalendarFreeBusySet))
-    if prop is not None:
-        del inbox.properties()[PropertyName.fromElement(caldavxml.CalendarFreeBusySet)]
</del><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoreupgradesqlupgradescalendar_upgrade_from_4_to_5py"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_4_to_5.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_4_to_5.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_4_to_5.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -102,10 +102,11 @@
</span><span class="cx">     the new value from the XML property.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     inbox = (yield home.calendarWithName(&quot;inbox&quot;))
</span><del>-    prop = inbox.properties().get(PropertyName.fromElement(customxml.CalendarAvailability))
-    if prop is not None:
-        yield home.setAvailability(prop.calendar())
-        del inbox.properties()[customxml.CalendarAvailability]
</del><ins>+    if inbox is not None:
+        prop = inbox.properties().get(PropertyName.fromElement(customxml.CalendarAvailability))
+        if prop is not None:
+            yield home.setAvailability(prop.calendar())
+            del inbox.properties()[PropertyName.fromElement(customxml.CalendarAvailability)]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavcommondatastoreupgradesqlupgradestesttest_upgrade_from_4_to_5py"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_4_to_5.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_4_to_5.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_4_to_5.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -161,7 +161,10 @@
</span><span class="cx">                 self.assertEqual(version, 4)
</span><span class="cx">                 calendar = (yield self.calendarUnderTest(name=calname, home=user))
</span><span class="cx">                 self.assertEqual(calendar.getTimezone(), None)
</span><del>-                self.assertTrue(PropertyName.fromElement(caldavxml.CalendarTimeZone) in calendar.properties())
</del><ins>+                if tz:
+                    self.assertTrue(PropertyName.fromElement(caldavxml.CalendarTimeZone) in calendar.properties())
+                else:
+                    self.assertTrue(PropertyName.fromElement(caldavxml.CalendarTimeZone) not in calendar.properties())
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><span class="lines">@@ -272,7 +275,10 @@
</span><span class="cx">                 self.assertEqual(version, 4)
</span><span class="cx">                 calendar = (yield self.calendarUnderTest(name=&quot;inbox&quot;, home=user))
</span><span class="cx">                 self.assertEqual(home.getAvailability(), None)
</span><del>-                self.assertTrue(PropertyName.fromElement(customxml.CalendarAvailability) in calendar.properties())
</del><ins>+                if av:
+                    self.assertTrue(PropertyName.fromElement(customxml.CalendarAvailability) in calendar.properties())
+                else:
+                    self.assertTrue(PropertyName.fromElement(customxml.CalendarAvailability) not in calendar.properties())
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span></span></pre></div>
<a id="CalendarServerbranchesusersgayasharedgroupfixestxdavidavpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/idav.py (12109 => 12110)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/idav.py        2013-12-14 04:45:59 UTC (rev 12109)
+++ CalendarServer/branches/users/gaya/sharedgroupfixes/txdav/idav.py        2013-12-14 06:28:16 UTC (rev 12110)
</span><span class="lines">@@ -34,6 +34,9 @@
</span><span class="cx"> from zope.interface import Attribute, Interface
</span><span class="cx"> from zope.interface.common.mapping import IMapping
</span><span class="cx"> 
</span><ins>+from twisted.python.constants import Values, ValueConstant
+from calendarserver.push.util import PushPriority
+
</ins><span class="cx"> #
</span><span class="cx"> # Exceptions
</span><span class="cx"> #
</span><span class="lines">@@ -231,6 +234,19 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+class ChangeCategory(Values):
+    &quot;&quot;&quot;
+    Constants to use for notifyChanged's category parameter.  Maps
+    types of changes to the appropriate push priority level.
+    TODO: make these values configurable in plist perhaps.
+    &quot;&quot;&quot;
+    default             = ValueConstant(PushPriority.high)
+    inbox               = ValueConstant(PushPriority.medium)
+    attendeeITIPUpdate  = ValueConstant(PushPriority.medium)
+    organizerITIPUpdate = ValueConstant(PushPriority.medium)
+
+
+
</ins><span class="cx"> class INotifier(Interface):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Interface for an object that can send change notifications. Notifiers are associated with specific notifier factories
</span><span class="lines">@@ -260,9 +276,12 @@
</span><span class="cx">         @rtype: L{IStoreNotifier} or C{None}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def notifyChanged(): #@NoSelf
</del><ins>+    def notifyChanged(category): #@NoSelf
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Send a change notification to any notifiers assigned to the object.
</span><ins>+
+        @param category: the kind of change triggering this notification
+        @type: L{ChangeCategory}
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     def notifierID(): #@NoSelf
</span></span></pre>
</div>
</div>

</body>
</html>