[CalendarServer-changes] [4953] CalendarServer/branches/users/cdaboo/partition-4464
source_changes at macosforge.org
source_changes at macosforge.org
Thu Jan 21 12:33:21 PST 2010
Revision: 4953
http://trac.macosforge.org/projects/calendarserver/changeset/4953
Author: cdaboo at apple.com
Date: 2010-01-21 12:33:21 -0800 (Thu, 21 Jan 2010)
Log Message:
-----------
Merged 4878-4951 from trunk.
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/provision/root.py
CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/sidecar/task.py
CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/sidecar/test/test_task.py
CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/anonymize.py
CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/principals.py
CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/warmup.py
CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/webadmin/resource.py
CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/vobject/vobject.icalendar.patch
CalendarServer/branches/users/cdaboo/partition-4464/pyflakes
CalendarServer/branches/users/cdaboo/partition-4464/support/build.sh
CalendarServer/branches/users/cdaboo/partition-4464/support/submit
CalendarServer/branches/users/cdaboo/partition-4464/twext/internet/tcp.py
CalendarServer/branches/users/cdaboo/partition-4464/twext/web2/dav/__init__.py
CalendarServer/branches/users/cdaboo/partition-4464/twext/web2/dav/davxml.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/appleopendirectory.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/cachingdirectory.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/resourceinfo.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_principal.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlfile.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/dropbox.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/extensions.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/ical.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/index.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/mail.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/memcacher.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/__init__.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/delete_common.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/put_common.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/report_common.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/notify.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/resource.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/implicit.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/processing.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_index.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_mkcalendar.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/util.py
Added Paths:
-----------
CalendarServer/branches/users/cdaboo/partition-4464/doc/Developer/Calendar Store.graffle
CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-daboo-srv-caldav.txt
CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-daboo-webdav-sync.txt
CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-desruisseaux-ischedule.txt
CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-nottingham-site-meta.txt
CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-reschke-webdav-post.txt
CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/Twisted/twisted.web2.dav.element.parser.patch
CalendarServer/branches/users/cdaboo/partition-4464/twext/python/icalendar.py
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/report_sync_collection.py
CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/
CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/__init__.py
CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/icalendarstore.py
CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/
CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/__init__.py
CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/iaddressbookstore.py
CalendarServer/branches/users/cdaboo/partition-4464/txdav/
CalendarServer/branches/users/cdaboo/partition-4464/txdav/__init__.py
CalendarServer/branches/users/cdaboo/partition-4464/txdav/idav.py
Removed Paths:
-------------
CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/vobject/vobject.base.patch
CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/admin/
CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/__init__.py
CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/icalendarstore.py
CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/__init__.py
CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/iaddressbookstore.py
CalendarServer/branches/users/cdaboo/partition-4464/txdav/__init__.py
CalendarServer/branches/users/cdaboo/partition-4464/txdav/idav.py
Property Changed:
----------------
CalendarServer/branches/users/cdaboo/partition-4464/
CalendarServer/branches/users/cdaboo/partition-4464/doc/Extensions/caldav-privatecomments.txt
CalendarServer/branches/users/cdaboo/partition-4464/doc/Extensions/caldav-privatecomments.xml
Property changes on: CalendarServer/branches/users/cdaboo/partition-4464
___________________________________________________________________
Modified: svn:ignore
- .dependencies
*.tgz
data
logs
build
*.pyc
*.pyo
_trial_temp*
+ .dependencies
*.tgz
data
logs
build
*.pyc
*.pyo
_run
Modified: svn:mergeinfo
- /CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
+ /CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4485
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/trunk:4465-4876,4878-4951
Modified: CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/provision/root.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/provision/root.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/provision/root.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -15,7 +15,6 @@
##
__all__ = [
- "RootACLMixIn",
"RootResource",
]
@@ -37,7 +36,7 @@
from twistedcaldav.cache import MemcacheResponseCache, MemcacheChangeNotifier
from twistedcaldav.cache import DisabledCache
from twistedcaldav.static import CalendarHomeFile
-from twistedcaldav.directory.principal import DirectoryPrincipalResource, DirectoryCalendarPrincipalResource
+from twistedcaldav.directory.principal import DirectoryPrincipalResource
log = Logger()
Modified: CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/sidecar/task.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/sidecar/task.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/sidecar/task.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -16,9 +16,10 @@
from __future__ import with_statement
__all__ = [
- "CalDAVService",
- "CalDAVOptions",
- "CalDAVServiceMaker",
+ "CalDAVTaskService",
+ "CalDAVTaskServiceMaker",
+ "CalDAVTaskOptions",
+ "Task",
]
from calendarserver.provision.root import RootResource
@@ -81,6 +82,8 @@
def urlForResource(self, resource):
url = self._urlsByResource.get(resource, None)
if url is None:
+ class NoURLForResourceError(RuntimeError):
+ pass
raise NoURLForResourceError(resource)
return url
@@ -115,8 +118,7 @@
originator = LocalCalendarUser(originator, originatorPrincipal)
recipients = (owner,)
scheduler = DirectScheduler(FakeRequest(rootResource, "PUT"), inboxItemFile)
- result = (yield scheduler.doSchedulingViaPUT(originator, recipients,
- calendar, internal_request=False))
+ yield scheduler.doSchedulingViaPUT(originator, recipients, calendar, internal_request=False)
if os.path.exists(inboxItemFile.fp.path):
os.remove(inboxItemFile.fp.path)
@@ -363,8 +365,6 @@
#
# Setup the Directory
#
- directories = []
-
directoryClass = namedClass(config.DirectoryService.type)
self.log_info("Configuring directory service of type: %s"
Modified: CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/sidecar/test/test_task.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/sidecar/test/test_task.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/sidecar/test/test_task.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -19,14 +19,12 @@
from calendarserver.sidecar.task import CalDAVTaskServiceMaker, CalDAVTaskOptions, Task
from os.path import dirname, abspath
from twext.python.plistlib import writePlist
-from twisted.python.usage import Options, UsageError
-from twistedcaldav.config import config, ConfigDict, _mergeData
-from twistedcaldav.stdconfig import DEFAULT_CONFIG, DEFAULT_CONFIG_FILE
+from twisted.python.usage import Options
+from twistedcaldav.config import config, ConfigDict
+from twistedcaldav.stdconfig import DEFAULT_CONFIG
from twistedcaldav.test.util import TestCase
from twisted.internet.defer import inlineCallbacks
-import memcacheclient
-
# Points to top of source tree.
sourceRoot = dirname(dirname(dirname(dirname(abspath(__file__)))))
Modified: CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/anonymize.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/anonymize.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/anonymize.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -22,13 +22,11 @@
from subprocess import Popen, PIPE, STDOUT
import datetime
import hashlib
-import operator
import os
import plistlib
import random
import shutil
import sys
-import tempfile
import urllib
import uuid
import vobject
Modified: CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/principals.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/principals.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/principals.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -56,6 +56,7 @@
name = os.path.basename(sys.argv[0])
print "usage: %s [options] action_flags principal [principal ...]" % (name,)
+ print " %s [options] --list-principal-types" % (name,)
#print " %s [options] --list-principals type" % (name,)
print ""
print " Performs the given actions against the giving principals."
@@ -71,6 +72,7 @@
print ""
print "actions:"
#print " --search <search-string>: search for matching resources"
+ print " --list-principal-types: list all of the known principal types"
#print " --list-principals=type: list all principals of the given type"
print " --read-property=property: read DAV property (eg.: {DAV:}group-member-set)"
print " --list-read-proxies: list proxies with read-only access"
@@ -100,6 +102,7 @@
"help",
"config=",
#"search=",
+ "list-principal-types",
"list-principals=",
"read-property=",
"list-read-proxies",
@@ -119,6 +122,7 @@
# Get configuration
#
configFileName = None
+ listPrincipalTypes = False
listPrincipals = None
principalActions = []
@@ -129,6 +133,9 @@
elif opt in ("-f", "--config"):
configFileName = arg
+ elif opt in ("", "--list-principal-types"):
+ listPrincipalTypes = True
+
elif opt in ("", "--list-principals"):
listPrincipals = arg
@@ -211,6 +218,15 @@
#
# List principals
#
+ if listPrincipalTypes:
+ if args:
+ usage("Too many arguments")
+
+ for recordType in config.directory.recordTypes():
+ print recordType
+
+ return
+
if listPrincipals:
if args:
usage("Too many arguments")
@@ -473,8 +489,6 @@
print ""
- resource = None
-
for opt, arg in optargs:
if opt in ("-s", "--search",):
Modified: CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/warmup.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/warmup.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/tools/warmup.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -81,7 +81,6 @@
usage(e)
configFileName = None
- outputFileName = None
calendarHomes = set()
records = set()
@@ -168,7 +167,7 @@
child = calendarCollection.getChild(name)
#sys.stdout.write("+")
- childCalendar = child.iCalendarText()
+ child.iCalendarText()
readProperties(child)
@@ -180,7 +179,7 @@
def readProperties(resource):
#sys.stdout.write("-")
for qname in resource.deadProperties().list():
- property = resource.readDeadProperty(qname)
+ resource.readDeadProperty(qname)
#sys.stdout.write(".")
if __name__ == "__main__":
Modified: CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/webadmin/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/webadmin/resource.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/calendarserver/webadmin/resource.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -154,7 +154,7 @@
# Update the auto-schedule value if specified.
if autoSchedule is not None and (autoSchedule == "true" or autoSchedule == "false"):
if principal.record.recordType != "users" and principal.record.recordType != "groups":
- result = principal.setAutoSchedule(autoSchedule == "true")
+ principal.setAutoSchedule(autoSchedule == "true")
# Update the proxies if specified.
for proxyId in removeProxies:
@@ -263,7 +263,7 @@
if davPropertyName:
try:
namespace, name = davPropertyName.split("#")
- except Exception, e:
+ except Exception:
propertyHtml += "<div>Unable to parse property to read: <b>%s</b></div>" % davPropertyName
result = (yield resource.readProperty((namespace, name), None))
Copied: CalendarServer/branches/users/cdaboo/partition-4464/doc/Developer/Calendar Store.graffle (from rev 4951, CalendarServer/trunk/doc/Developer/Calendar Store.graffle)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/doc/Developer/Calendar Store.graffle (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/doc/Developer/Calendar Store.graffle 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,3025 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>ActiveLayerIndex</key>
+ <integer>0</integer>
+ <key>ApplicationVersion</key>
+ <array>
+ <string>com.omnigroup.OmniGrafflePro</string>
+ <string>138.12.0.121252</string>
+ </array>
+ <key>AutoAdjust</key>
+ <true/>
+ <key>BackgroundGraphic</key>
+ <dict>
+ <key>Bounds</key>
+ <string>{{0, 0}, {756, 553}}</string>
+ <key>Class</key>
+ <string>SolidGraphic</string>
+ <key>ID</key>
+ <integer>2</integer>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ </dict>
+ <key>CanvasOrigin</key>
+ <string>{0, 0}</string>
+ <key>ColumnAlign</key>
+ <integer>1</integer>
+ <key>ColumnSpacing</key>
+ <real>36</real>
+ <key>CreationDate</key>
+ <string>2010-01-11 11:21:54 -0800</string>
+ <key>Creator</key>
+ <string>Wilfredo Sanchez</string>
+ <key>DisplayScale</key>
+ <string>1p = 1p</string>
+ <key>GraphDocumentVersion</key>
+ <integer>6</integer>
+ <key>GraphicsList</key>
+ <array>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>106</integer>
+ </dict>
+ <key>ID</key>
+ <integer>107</integer>
+ <key>Points</key>
+ <array>
+ <string>{186, 438.25}</string>
+ <string>{146.07, 438.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>70</integer>
+ <key>Info</key>
+ <integer>8</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{66, 425.05}, {79.5703, 26.4}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>106</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 Attachment}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>98</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ <key>ID</key>
+ <integer>104</integer>
+ <key>Points</key>
+ <array>
+ <string>{408.997, 78.8045}</string>
+ <string>{464.075, 121.102}</string>
+ <string>{448.5, 214.75}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>Ball</string>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>100</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>97</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ <key>ID</key>
+ <integer>103</integer>
+ <key>Points</key>
+ <array>
+ <string>{347.859, 78.8099}</string>
+ <string>{293.5, 121.75}</string>
+ <string>{309.5, 214.75}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>Ball</string>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>100</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{325, 31.5}, {106, 47}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>100</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 IDirectoryRecord (from directory services API)}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>68</integer>
+ <key>Info</key>
+ <integer>8</integer>
+ </dict>
+ <key>ID</key>
+ <integer>98</integer>
+ <key>Points</key>
+ <array>
+ <string>{405.638, 178.64}</string>
+ <string>{448.5, 214.75}</string>
+ <string>{488.5, 248.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>Arrow</string>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>86</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>72</integer>
+ <key>Info</key>
+ <integer>7</integer>
+ </dict>
+ <key>ID</key>
+ <integer>97</integer>
+ <key>Points</key>
+ <array>
+ <string>{347.07, 179.741}</string>
+ <string>{309.5, 214.75}</string>
+ <string>{267.5, 248.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>Arrow</string>
+ <key>LineType</key>
+ <integer>1</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>86</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{326.25, 121.75}, {98.5, 63}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>86</integer>
+ <key>Shape</key>
+ <string>Octagon</string>
+ <key>Style</key>
+ <dict/>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 Home Factory\
+(API entrypoint)}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{537, 286.75}, {6, 18}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>14</real>
+ </dict>
+ <key>ID</key>
+ <integer>84</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Pad</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs30 \cf0 *}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{150.5, 499}, {401, 42}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>Vertical</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>ID</key>
+ <integer>83</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Align</key>
+ <integer>0</integer>
+ <key>Pad</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
+
+\f0\fs24 \cf0 *: calendars will have multiple calendar homes, and addressbooks will have multiple addressbook homes, only in the case of sharing. one home will still be the "primary" home.}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{238, 286.75}, {6, 18}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>14</real>
+ </dict>
+ <key>ID</key>
+ <integer>82</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Pad</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs30 \cf0 *}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>72</integer>
+ </dict>
+ <key>ID</key>
+ <integer>80</integer>
+ <key>Points</key>
+ <array>
+ <string>{191, 171.25}</string>
+ <string>{227, 230.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>78</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{150.5, 135.25}, {81, 36}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>78</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 iTIP Queue}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>69</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ <key>ID</key>
+ <integer>54</integer>
+ <key>Points</key>
+ <array>
+ <string>{488.5, 420.25}</string>
+ <string>{416, 361.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>66</integer>
+ <key>Info</key>
+ <integer>3</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>69</integer>
+ </dict>
+ <key>ID</key>
+ <integer>55</integer>
+ <key>Points</key>
+ <array>
+ <string>{488.5, 343.25}</string>
+ <string>{416, 343.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>67</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>69</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ <key>ID</key>
+ <integer>56</integer>
+ <key>Points</key>
+ <array>
+ <string>{488.5, 266.25}</string>
+ <string>{416, 325.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>68</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>69</integer>
+ <key>Info</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>57</integer>
+ <key>Points</key>
+ <array>
+ <string>{267.5, 420.25}</string>
+ <string>{335, 361.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>70</integer>
+ <key>Info</key>
+ <integer>2</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>69</integer>
+ </dict>
+ <key>ID</key>
+ <integer>58</integer>
+ <key>Points</key>
+ <array>
+ <string>{267.5, 343.25}</string>
+ <string>{335, 343.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>71</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>69</integer>
+ <key>Info</key>
+ <integer>3</integer>
+ </dict>
+ <key>ID</key>
+ <integer>59</integer>
+ <key>Points</key>
+ <array>
+ <string>{267.5, 266.25}</string>
+ <string>{335, 325.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>72</integer>
+ <key>Info</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>66</integer>
+ </dict>
+ <key>ID</key>
+ <integer>60</integer>
+ <key>Points</key>
+ <array>
+ <string>{529, 361.25}</string>
+ <string>{529, 420.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>67</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>67</integer>
+ </dict>
+ <key>ID</key>
+ <integer>61</integer>
+ <key>Points</key>
+ <array>
+ <string>{529, 266.25}</string>
+ <string>{529, 325.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledDoubleArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>68</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>70</integer>
+ </dict>
+ <key>ID</key>
+ <integer>63</integer>
+ <key>Points</key>
+ <array>
+ <string>{227, 361.25}</string>
+ <string>{227, 420.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>71</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>Helvetica</string>
+ <key>Size</key>
+ <real>12</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>71</integer>
+ </dict>
+ <key>ID</key>
+ <integer>64</integer>
+ <key>Points</key>
+ <array>
+ <string>{227, 266.25}</string>
+ <string>{227, 325.25}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>HeadArrow</key>
+ <string>FilledDoubleArrow</string>
+ <key>TailArrow</key>
+ <string>FilledDoubleArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>72</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{488.5, 420.25}, {81, 36}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>66</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 vCard Object}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{488.5, 325.25}, {81, 36}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>67</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 Address Book}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{488.5, 230.25}, {81, 36}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>68</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 Address Book Home}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{335, 325.25}, {81, 36}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>69</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 Dead Property}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{186.5, 420.25}, {81, 36}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>70</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 iCalendar Object}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{186.5, 325.25}, {81, 36}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>71</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 Calendar}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{186.5, 230.25}, {81, 36}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>72</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\fs24 \cf0 Calendar Home}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{52, 8}, {647, 484}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>105</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ </dict>
+ </array>
+ <key>GridInfo</key>
+ <dict/>
+ <key>GuidesLocked</key>
+ <string>NO</string>
+ <key>GuidesVisible</key>
+ <string>YES</string>
+ <key>HPages</key>
+ <integer>1</integer>
+ <key>ImageCounter</key>
+ <integer>1</integer>
+ <key>KeepToScale</key>
+ <false/>
+ <key>Layers</key>
+ <array>
+ <dict>
+ <key>Lock</key>
+ <string>NO</string>
+ <key>Name</key>
+ <string>Layer 1</string>
+ <key>Print</key>
+ <string>YES</string>
+ <key>View</key>
+ <string>YES</string>
+ </dict>
+ </array>
+ <key>LayoutInfo</key>
+ <dict>
+ <key>Animate</key>
+ <string>NO</string>
+ <key>circoMinDist</key>
+ <real>18</real>
+ <key>circoSeparation</key>
+ <real>0.0</real>
+ <key>layoutEngine</key>
+ <string>dot</string>
+ <key>neatoSeparation</key>
+ <real>0.0</real>
+ <key>twopiSeparation</key>
+ <real>0.0</real>
+ </dict>
+ <key>LinksVisible</key>
+ <string>YES</string>
+ <key>MagnetsVisible</key>
+ <string>NO</string>
+ <key>MasterSheets</key>
+ <array/>
+ <key>ModificationDate</key>
+ <string>2010-01-14 13:46:09 -0800</string>
+ <key>Modifier</key>
+ <string>Glyph Lefkowitz</string>
+ <key>NotesVisible</key>
+ <string>NO</string>
+ <key>Orientation</key>
+ <integer>2</integer>
+ <key>OriginVisible</key>
+ <string>NO</string>
+ <key>PageBreaks</key>
+ <string>YES</string>
+ <key>PrintInfo</key>
+ <dict>
+ <key>NSBottomMargin</key>
+ <array>
+ <string>float</string>
+ <string>41</string>
+ </array>
+ <key>NSLeftMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ <key>NSOrientation</key>
+ <array>
+ <string>int</string>
+ <string>1</string>
+ </array>
+ <key>NSPaperSize</key>
+ <array>
+ <string>size</string>
+ <string>{792, 612}</string>
+ </array>
+ <key>NSRightMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ <key>NSTopMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ </dict>
+ <key>PrintOnePage</key>
+ <false/>
+ <key>QuickLookPreview</key>
+ <data>
+ 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
+ iE5xLvIs4jXadChM0DqfkODgpOrb/wMEeayFCmVuZHN0cmVhbQplbmRvYmoKNiAwIG9i
+ ago0Mjg0CmVuZG9iagozIDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQgNCAwIFIg
+ L1Jlc291cmNlcyA3IDAgUiAvQ29udGVudHMgNSAwIFIgL01lZGlhQm94IFswIDAgNzU2
+ IDU1M10KPj4KZW5kb2JqCjcgMCBvYmoKPDwgL1Byb2NTZXQgWyAvUERGIC9UZXh0IC9J
+ bWFnZUIgL0ltYWdlQyAvSW1hZ2VJIF0gL0NvbG9yU3BhY2UgPDwgL0NzMiAxNyAwIFIK
+ L0NzMSA4IDAgUiA+PiAvRm9udCA8PCAvRjEuMCAxOCAwIFIgPj4gL1hPYmplY3QgPDwg
+ L0ltMyAxMyAwIFIgL0ltNCAxNSAwIFIKL0ltMiAxMSAwIFIgL0ltMSA5IDAgUiA+PiA+
+ PgplbmRvYmoKMTMgMCBvYmoKPDwgL0xlbmd0aCAxNCAwIFIgL1R5cGUgL1hPYmplY3Qg
+ L1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNTYgL0hlaWdodCAxMzggL0ludGVycG9sYXRl
+ CnRydWUgL0NvbG9yU3BhY2UgMTkgMCBSIC9JbnRlbnQgL1BlcmNlcHR1YWwgL1NNYXNr
+ IDIwIDAgUiAvQml0c1BlckNvbXBvbmVudAo4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+
+ CnN0cmVhbQp4Ae3QAQ0AAADCoPdPbQ8HESgMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM/AwMng8AAQplbmRzdHJlYW0KZW5kb2Jq
+ CjE0IDAgb2JqCjQ4NQplbmRvYmoKMTUgMCBvYmoKPDwgL0xlbmd0aCAxNiAwIFIgL1R5
+ cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyMDQgL0hlaWdodCA5OCAv
+ SW50ZXJwb2xhdGUKdHJ1ZSAvQ29sb3JTcGFjZSAxOSAwIFIgL0ludGVudCAvUGVyY2Vw
+ dHVhbCAvU01hc2sgMjIgMCBSIC9CaXRzUGVyQ29tcG9uZW50CjggL0ZpbHRlciAvRmxh
+ dGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U9tDB+IQGHAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY+AwM6kgAAQpl
+ bmRzdHJlYW0KZW5kb2JqCjE2IDAgb2JqCjI4NQplbmRvYmoKMTEgMCBvYmoKPDwgL0xl
+ bmd0aCAxMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAy
+ NDIgL0hlaWdodCAxNzAgL0ludGVycG9sYXRlCnRydWUgL0NvbG9yU3BhY2UgMTkgMCBS
+ IC9JbnRlbnQgL1BlcmNlcHR1YWwgL1NNYXNrIDI0IDAgUiAvQml0c1BlckNvbXBvbmVu
+ dAo4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQo/
+ iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwa+AwPiKwABCmVuZHN0cmVhbQplbmRv
+ YmoKMTIgMCBvYmoKNTYyCmVuZG9iago5IDAgb2JqCjw8IC9MZW5ndGggMTAgMCBSIC9U
+ eXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMTE1MCAvSGVpZ2h0IDg3
+ MCAvSW50ZXJwb2xhdGUKdHJ1ZSAvQ29sb3JTcGFjZSAxOSAwIFIgL0ludGVudCAvUGVy
+ Y2VwdHVhbCAvU01hc2sgMjYgMCBSIC9CaXRzUGVyQ29tcG9uZW50CjggL0ZpbHRlciAv
+ RmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dABDQAAAMKg909tDjeIQGHAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMPA6MM8/AAEKZW5kc3RyZWFtCmVuZG9iagoxMCAwIG9i
+ agoxMzExMQplbmRvYmoKMjQgMCBvYmoKPDwgL0xlbmd0aCAyNSAwIFIgL1R5cGUgL1hP
+ YmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyNDIgL0hlaWdodCAxNzAgL0NvbG9y
+ U3BhY2UKL0RldmljZUdyYXkgL0ludGVycG9sYXRlIHRydWUgL0JpdHNQZXJDb21wb25l
+ bnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHtXfk/VP0Xr1SSdTIM
+ szBjGSY01oj0KCp7IntZUsgSCfFYQspSIj1KKSS7LKk81fP0+v5r33M+987ca4ypGTNm
+ esz5oZelO+77nvM573M+99732bfPbOYrYL4C5itgvgJ78grs14/9BtcOgB5gzEJ3Yz7k
+ AHymiSKnwVpYHDx48JB+DD7JwoKANz3UFFwAC1APW1oeoc1KN1Mcbml5GD4PYCNqkwJN
+ 8FoA2sOI1eqoNZgNmK2uhgfjhxy1gs9D2AS0yWBGvBDLBC6AtbG1s7O3d+Ds1Bzs7e3s
+ bAH4UQKaxLdpYMZche49cuQoorXncI45crlOTs7OPN3N2dnJict1PMbh2CNqAI2Oxtg2
+ ehYjDka8VtbWtnYOHEeuE4/n4srnCwRCoUhXEwoFAj7f1YXHc+I6chzsbK2trRAzLGhj
+ uxkDGuIZ8NqAdx25PBe+QChyE4slEg/PnZiHRCIWu4mEAr4LD0Db29kQzLiejelmKqAh
+ ngGvwzGuswtfKBJLPL28pT6+MpnsOJqftkaOgqN9faTeXp4SsUjId3HmHnMAzBjbxgxt
+ EtAHD1nC+kW8PFeBSOzhJfWV+fmfkMsDg8CCdTM8NFAuP+HvJ/OVenmIRQJXHmKG9WxJ
+ 0rZxQpsJaFt7DuAVukk8pTK/AHlQSGhYeHjEqUjKorQz+qhTEeHhYaEhQfIAP5nUU+Im
+ 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
+ j+fiyucLBEKhSFcTCgUCPt/VhcdzArgOdrbWxL/6H/rLANHiK8rN8MgMzAyysQNPc445
+ crlOTs7OPN3N2dnJict1PMYB74J7jx6BxxuoFazFmRnsvxI34212SwRtbWMLsO0dODs1
+ B3sAa2tjjXBhl+OgBQa0MVcw+wIiZny0gIA+YgWwATiYra6GB+OHHLU6QuAS95oOXsRO
+ MANoQA2wwdmUWelmisMtwbcQzMhHJuRfpa8p0AcsADbi1ofBJ2EsmyRcGvd+GjY5SwCv
+ s1EfQP6Fz1ReVdP9As5SH2a6AM1nZr4C5itgvgLmK2DYK/B/uvd6oQplbmRzdHJlYW0K
+ ZW5kb2JqCjI1IDAgb2JqCjU5NzEKZW5kb2JqCjIwIDAgb2JqCjw8IC9MZW5ndGggMjEg
+ MCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMjU2IC9IZWln
+ aHQgMTM4IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9JbnRlcnBvbGF0ZSB0cnVlIC9C
+ aXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB
+ 7V3pU1J9FNZEkR0UQVkCL26ASDcpUipwYCxTKzUNKx0La8Iw0omJyRYcK0amXErHZcrM
+ SRs1Rx1GHaec9197z8Xet0XMzz/veT7x8T7PWX7b4ZyUFAQqgAqgAqgAKvCrAqmHCL/y
+ OvA38D7yE2lE4yePI0DrQOopKbvcgTOHk35owOEAIUaKgyRIsN+lnsHlZu6CRyx+EOBy
+ M8CUIMIBCvxgn56eAdR5fL5AIBAKhSKCAZ8PJPh8XmYmo8HfFWDop4HXA3mgLhSJxRKp
+ VEY4pFKJWCwCFfggwa4C+wRBgj7YnmEvEktksqxsuTwnR6FQEguFIidHLs/OkskkYhGj
+ APgABEFyARjrM8Zn2EuBu0KZm6dSqTUaLbHQaNQqVV6uUgEaSBMKgAswAiRZCBL0IfAF
+ QmAP5IG5VqfX51MGgkHl6/U6LagAEoACQgGTBpILkMrEPpcHxpdlK3JVwJ0yFBYVlxiN
+ JpOZSJhMRmNJcVGhgQINVLmKbBm4AI/LZMG9DgDmB/qZApFEJleqtHqqoMhoKrVYrTRN
+ HycU8OlWq6XUZCwqoPRalVIuk4jAA9I5SSIAzA+pj5+gr9ZRhSVmi5UuP3HSXlEJcBAI
+ 5rsr7CdPlNNWi7mkkNKpEwLwIQkmcYBUMH8mXyiWyXPVOkOxuYy22SscZ5yuKrfb7SES
+ 8OFVLucZR4XdRpeZiw06da5cJhbyM8EB/gyAXfMLgL5SrS8wWmjbKYezylN9vqa2rv4i
+ oaivq605X+2pcjpO2WiLsUDPeIBYkMwBGP7g/VKgryswWsvtp13ucxfqLzU2Nbd4iUVL
+ c1PjpfoL59yu0/Zyq7GACQGpCBxgTwCA+2dkCsRZCpXOYCyzVTo9NXUNV7zX29o7bvl8
+ nUTC57vV0d523Xuloa7G46y0lRkNOpUii3GAPQGQegTWPjB/rpYqtpRXuqprLze3tnX4
+ 7vjvBbrvB4nE/e7APf8dX0dba/Pl2mpXZbmlmNLmggPAGvhnAmDcH6JfodIXmmm7s7qu
+ 0Xvj5m1/INj7MPQoTCgehR72BgP+2zdveBvrqp122lyoVymYDAAB8PsWMMFfkq3UUiVl
+ ttMeoN/u83f3hMJ9T59F+glF5NnTvnCop9vvawcBPKdtZSWUVpktSco/gyeUyvN0BWb6
+ lKvmsre9sysYCj+NDLyMDsYIxWD05UDkaTgU7Ops916ucZ2izQW6PLlUyMvYY39OBk/E
+ uH+RxeZw1zff8HU9CPVFXkRjb4ZH3hKKkeE3seiLSF/oQZfvRnO922GzFDEBIOJBAvzD
+ /zlcvjhLqaFKrPaz5xpab94Nhvr6X8WGRsfGJyeniMTk5PjY6FDsVX9fKHj3ZmvDubN2
+ awmlUWaJ+dwk/AViCH+Dia6ounCl7XYA6Edfj4xNTL+f+ThLJD7OvJ+eGBt5HQUBArfb
+ rlyoqqBNBkgAYkES/pD+5XlHC0vLwf29Hf6e8PNXr0fHpz7Mzn2eXyAS85/nZj9MjY++
+ fvU83OPv8EIAlJcWHs2TwwKwx/6w/EnkTPifOFN96ZovEHoyEBsZn575NP9lcWmZSCwt
+ fpn/NDM9PhIbeBIK+K5dqj5zgkkAcmYB+DP+gb8U+Bdb7c7zjW13guFIdGhsamZuYWl5
+ ZXWNSKyuLC8tzM1MjQ1FI+HgnbbG8067tRj4S5PyF0pzVPmQ/lw1Te3+3scDsdGJD0B/
+ ZW09TijW11ZAgA8To7GBx73+9qYaFyTAfFWOVJjM/kJZjpoyHquoqm3u6Hr45OWbd9Oz
+ 84sra/GNzS0isbkRX1tZnJ+dfvfm5ZOHXR3NtVUVx4yUOke2D3+FhjLSle66lluB0LPo
+ 0Pj7uS9fV+MbW9uEYmsjvvr1y9z78aHos1DgVkudu5I2UhrF/vxh+QP+V33djyKDwxMz
+ nxdX1oH+t+9E4tv21sb6yuLnmYnhwcijbt9Vhr/JcCD/eq/vfrg/Njr5cX5pNb4J9HeI
+ xPdv25vx1aX5j5Ojsf7wfR8sgPvxh+NvplCm0CTsn4T/PwRi5+/8f7sBS01Lh+0/bP/M
+ xx2ei97OINj/7dTswvJafGv7+w6B7OGTd75vb8XXlhdmp96C/YOd3osex3EzbADhAJCe
+ hvx/OQGh/dH/Mf4x/2H+x/UP13/c/+D+D/e/uP/H8w+e//D8i+d/vP8g8gII73/w/gvv
+ //D+E+9/8f4b7//x/QPff/D9C9//8P0T33/x/Rvf/7H+Aesf/lcA6z+w/gPrP7D+A+s/
+ sP4D6z+w/gPrP7D+A+s/sP4D6z+w/gPrP7D+A+s/CFQA61+w/gXrX7D+BetfsP4F61+w
+ /uVv9S8s//97ygH8D3v/g9/4s7j/Bbv7n7C8/w3L+x+xvf8Vu/ufcVje/47DZXn/Q7b3
+ v2R5/9M0lve/Zfo/s7r/Mbv7X7O9/zn2v2f7/ANm/Al751+ksHz+CfBn+/wbds8/YhyA
+ zfOvgD8TAeydf7YrAHvn3yUmn8IAQNbOP9wVgL3zL3/MvmUmgLJz/in8G4zd82+Zv8Ml
+ FDjC1vnHiT8Esnr+dUKB/2QAJQ4HfrLCX6gAKoAKoAKoAKPAv2Ksf5IKZW5kc3RyZWFt
+ CmVuZG9iagoyMSAwIG9iagoxOTMwCmVuZG9iagoyNiAwIG9iago8PCAvTGVuZ3RoIDI3
+ IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDExNTAgL0hl
+ aWdodCA4NzAgL0NvbG9yU3BhY2UKL0RldmljZUdyYXkgL0ludGVycG9sYXRlIHRydWUg
+ L0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K
+ eAHt3eu313Wd93FFhA0bNiAbNm4BUQ6KgISiIGXisTQMO2iUh5wozEOZOBgzFkZjUZij
+ ok4qZnko0ga1cDQPretfu37bZlah9pprdvO6c63H506t9a5Xaz1uPNd3bzRPOMEjQIAA
+ AQIECBAgQIAAAQIECBAgQIAAAQIECBAg8P+fwIkTb4pHgACB/wWB94Ny4n8fyv/Mzkkn
+ nTT1/XeyR4AAgUkK/LkiUwc9mYjYoC4hQe9/8Zw0dfC/NG3a9OnThzwCBAj8fQKDkkyb
+ NmjK1IkC/c3+TLRnIj3ThoZmzJg5PHizPAIECPw9AhMhmTljaGj6oEATAfro/vxne6YP
+ zRieNXtkZM7ceR4BAgT+ToG5c+eMjMweHp4xNH3Qn4/Oz5/jM9Ge2SNz580fHV2wcGxs
+ bJFHgACByQoMGrJwwejoKfPmDgI0Y2jaxOfPR3z9nDjxU9f0QXvmzJu/YGzR+PjiJUuW
+ nu4RIEBg8gJLlyxZPD6+aGx0/ryRWcODz5+J/Hzwd8/vx2fw4TMyd/7CReNLli47c/mK
+ latWneURIEBgsgKrVq1csfyMZUsXj48tOGXu4PNnkJ/BD18fyM+JU97/8hmZNzo2vnTZ
+ 8lVnr16z9tz16z/mESBAYLIC69evW7tm9Vkrly9bMj42Om9kIj8f+vgZfPqcPH1oeBCf
+ RYuXrTjrnHUf27Dxgk2bL9riESBAYLICF23adMHGDevXnXPW8mWnvZ+fwe9+pkw5/ttn
+ 4tPnz/FZcsaqNevPu2Dzxy/eeunll19xxZUeAQIEJiFwxRVXXH7Z1ksu3rL5gg3nnrNq
+ 2eKx0bmzZw596OPnxCmD3zjPmju6aMkZZ607b9OWSy678tPXbPvs9u3XeQQIEJicwPbt
+ 12675lNXXvrJLRduWDuRn/lzZs2YNvUDv/gZ/OA1+PSZP7b4jLPO3bhl65VXX/u5L37p
+ yzfedPMtHgECBCYncPNNN+644QvXbbv6iksuOn+Qn9PGThkZHnz8HP9r5ylTp82YPW/B
+ +LJV6zZ+4vKrt39xx0237tz1zdvvuNMjQIDA5ATuuP22b+z86k07vvDZT1+65fy1K08f
+ H503a2jwx17H/eJnytTpg0+fRUuWr9mw5fJrPrfj5q/tuvPb99y75777vusRIEBgEgL3
+ 3Xffnt3f+dbtu/7hphuuu/rSizasXr5k8PEzc/Cj11/XZ/Brn6HhuaPjy85af+HWqz+3
+ 46u77rx7z9779/1g//4fegQIEJiEwP79+x/4/v177737jq/f8qXtn/rkBetWLTt1dM7w
+ 9JOP+8XPiYNf+8yat3Dx8nPO23LF9i/duutb9+79/v4HDxw8+NDPPAIECExC4KGHDv70
+ wIP7v7d39127brl+2+VbNqw+87SFcwe/+PlgfWbMPmVs6cp1F3zy6i/cvOtbe+7/wY8O
+ PvzoocefeNIjQIDAJASeeOLxQ488/NMHH/jne+/6+o2f/9TFG9euWDI2b/aH6jNt5sjo
+ qYMfvDZfdu2Or9157/37Dzz82JNPPXP42V94BAgQmITAs88efubnTzz6swP7/2n37bfe
+ 8Jmtm85ddfqiU0ZmTDv+22fqRH3Gz1i94eNXfu6mXd/ZO4jP408dfu75F1/yCBAgMDmB
+ F59/7vDPDz384wf2fvvrN26//KKPnb1sfP6gPsf9kfuJU6cNz1lw2vI1Gy/+9BdvvWPP
+ vh89fOip557/9ZGXX/EIECAwOYGXj7z0/C+eOvTQg9/bffstn7/q4+etPmN8dPCHXh+o
+ z/ThuQsXr1h7wdZrbtj57b37Dz721HMvHHnl6Kuvve4RIEBgEgKvvfbq0Vd+88KzP3/k
+ Jz+4765br7/64o1rlp82Omfm9A/XZ2zJynWbLt224xv33P/gw08efv7I7177/bFjb3gE
+ CBCYhMCxY8def/WV3zx/+PGf/cs/3b3zhmsuuWDt8sULBn/k/qH6zBtbsmr9psuvvfG2
+ e/cdePSp5379yqt/+I833/qjR4AAgUkIvPXWm2/8/ugrLz33b4/8+P57vrFj29YL161Y
+ Mvgj94+qz9JV6zdfvv2m2/f84OChZ54/cvT3//HHt9951yNAgMAkBN555+233nj933/z
+ q6ce+8m+3bu+cu2lm85dGepz0RXbb77jvv0PPX74hZdfPfbm2+++5xEgQGByAu++/eYf
+ jh55/plDBx/4x2/e+NnL/t/q88SzL77y2rG33nnvvT95BAgQmITAoFhvv3ns1d++cDjW
+ Z/C3ec2at+j0sz625crrbrnzuz/82ZO/eOmV19/447vv/en/eAQIEJiEwJ/+9N47bx17
+ 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
+ fZasOnfTZdd+Zdfu7x945OfPvfTy0d+/8eabb3kECBCYhMCbbw7ic/S3L/7iyX/90f3f
+ +fqObVsvXLtiyYKP+slr7tiSlesu3PqZHV//zv0P/uyJZ57/9StHX//9H455BAgQmITA
+ H/7w+9ePvvzSL58+dPCHe7+984ZrPrlx7fLFC+Z8xO995i5cvHztxkuuvv5rd333Bz95
+ 5N+eff7Xv/3d0aOvegQIEJiEwNGjR1/57Uu/OvzkIwf27bnz1i98+uLzzznztNE5Mz/4
+ W+dpw3MWnLb8nPMvvurzt9x+7/cefOixnx/+1Yu/OXLktx4BAgQmIXDkyJFfv/DLw08+
+ evCH999z282fu2rLhtVnjI+OzJx2/J95nTRt5sjo+BmrN2y5YvuN37j7u/t+/NBjTz79
+ 7C+f9wgQIDBZgeeeferJRx56cN+eu3Z++drLN68/a9mp80dmfLA+J88YmX/qslXrN23d
+ 9qVbb9+994EfHXzk0JNPPf30Mx4BAgQmI/D00z9/8tC//vTBfXu/881brr9m64XrVi1d
+ dMrsoZOnHPfX+5x08ozZp4wtWbF248Wf+vyNO+/cvXffvxw4+PAjjz52yCNAgMAkBB57
+ 7NFHHj54YP/3v3vPHV/78nVXfeL8NcuXjM2b9cH6TDl5aNa8hYvPXL3hosu3XX/L1++8
+ Z8/9+/Y/eODAT37qESBAYBICP/nJgR8/uH/fP+25+/adN33xM5duXn/2GeODP3D/QH1O
+ GNRneM7o+LJV6y745Ke233Dzzm/edc+evfd/b59HgACByQp875/37vnOXbd97abrr73q
+ 4o1rVy5dNDoyPP3kv/7bvE44YcrU6TNHBj96LV/9sc1bP739+q98dedtd3zr7t27d9/r
+ ESBAYDICu3ffc/ddd+zaecuXv3jtVZdsWn/2mYsXzps9Y9pxf5PpoD4nTRuaNXd0/PSV
+ a87bsvWqbdddv+Omr/7Dzm/s2nWbR4AAgUkI7Nq16xs7/+GrN+744vbPXHnJ5g3nLF96
+ 6ujED14nfeDb56TBj14jpywc/Oy19rxNF1961dXXXvf567+0Y8eXPQIECExOYMeOG67/
+ /PZtV1956Sc2bViz8vTxBfNGZk4/+bi/3OeEE06cMnXajOE588dOW7ZqzfqNmz9xyWVX
+ XnX1Nds8AgQITFrgM9dcfdUVl37y45vOX3/OitPHF54yMjw0+MHrr//AfaI+g4+fmbPn
+ TuRnxeq1Hzv/ws1bPnHxJVu3XuoRIEBgcgJbt15y8Se2bLrgvPVrz15++vjY/DmzJj59
+ PlCfE6YMPn6GhifyM770zJVnr1m3fsN5Gy+48MJNHgECBCYncOGFGzeet2H92nPOXnnG
+ 0vGF8+fOnjl08tQpx//a588fP9Pfz8/CUxeffsbylWetPmfN2rXrPAIECExWYO3aNavP
+ XrVy+bKlpy1acMqc2YOfuz786TP40WvK1JMn8jNn3ujYqeNLli5bduby5StWrFjpESBA
+ YDICg34sX37msmVLF48vWjg6b2TWzEF8Bp8+x//aZ/B/sjr4zc9EfmYOj8ydN7pgbFCg
+ 8dMWL/EIECAweYHFp42Pnzq2cHT+vDkjwzP+RnxOOPH9r59pQ0PDs0YGATpl/ujoggUL
+ PQIECExeYMHo6Oj8U+bNHZk9PHNo+kd/+Ux8/AzyM/j8GfRn5vDwrNkjIyNz5sz1CBAg
+ MHmBOXMGJZk9a3jw3TPRnpM+4seu9//xFhP5mejPydOmDw3NmDFzECGPAAECf4/AzJkz
+ ZwwNTaTn/fZ8+Hc+//XP1vlzf06aOijQoEGDN90jQIDA5AUmMjKRk6kTnz2DD58P/cL5
+ v+Iz8a8nvl+giY8gjwABAv8bAhPdmShPTM9fMjT4D3oECBD43xH4S1r8OwIECBAgQIAA
+ AQIECBAgQIAAAQIECBAg0BH4v12XVLAKZW5kc3RyZWFtCmVuZG9iagoyNyAwIG9iagox
+ MDEyMQplbmRvYmoKMjIgMCBvYmoKPDwgL0xlbmd0aCAyMyAwIFIgL1R5cGUgL1hPYmpl
+ Y3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAyMDQgL0hlaWdodCA5OCAvQ29sb3JTcGFj
+ ZQovRGV2aWNlR3JheSAvSW50ZXJwb2xhdGUgdHJ1ZSAvQml0c1BlckNvbXBvbmVudCA4
+ IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae2c+VeS6xbHLc0BlUEBEURQ
+ FESRQVEUU3HCFMwpjFIJxTScG1DLUsyBxMwhNbXEIYeyTJvsNK37r939vNjqHsXynLXu
+ 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
+ 9x7VERtno1KBVnqNV8ZP47nxxfhlbBjPgH6sdtd7fP/p4xV117Y+PPmNetw5rr2dG1Vh
+ VnFlC93/xzKEj9knOabB06FZWGvYduQPmsxMsAwoxH8FPpf6khNV3NXu7bhFEsxQPixs
+ JbpLVG4p1Oo9g0qsHCvYAHZwksQsWhy4U2u6OXh32CJ6bflNV7Lrhv769nr72vIebcqo
+ KSgTzbNEZpSxW6Pk3Xjb/WaREZ84Or7nvYpayf5JRRA/hTlaKvIUVfRWUNbEb2cOfhu2
+ flw/pef1Qf08CT2tn9Gv6KMRvgx0Sc/Cc1Efo0nwsGkh4hKgioMz1E5UY40D4inx8rRb
+ ZJH9D0AZ/WYKZW5kc3RyZWFtCmVuZG9iagoyOSAwIG9iago3MDQKZW5kb2JqCjE3IDAg
+ b2JqClsgL0lDQ0Jhc2VkIDI4IDAgUiBdCmVuZG9iagozMCAwIG9iago8PCAvTGVuZ3Ro
+ IDMxIDAgUiAvTiAzIC9BbHRlcm5hdGUgL0RldmljZVJHQiAvRmlsdGVyIC9GbGF0ZURl
+ Y29kZSA+PgpzdHJlYW0KeAHtWmdUFU2T7pkbuYHMJeecg+TMJeeckXxJkiSDiAKSVZIi
+ oiQRA6ggKIKiIAgoGBBEzGBCUFCQoBJkB339vt2zZ3/t/lv7nJl+prq6q5m60110PQBI
+ lvtFR4fDAICIyLgYB1OqgJu7hwDuGYDAlpAHEPwCYqMN7OyskKf/oaw8RrSRMiq7NRaf
+ K5NuH9euzsmy9Lv12lJX/odOf8RMMYhBACA7RMAa/BsHbmH/3zhpCyfGRcchOvu3cECI
+ H9IO1SBYJsbJwRDBdwHAk4J/YbonW9j/F2Z6t4X9/GKCAeCcR/QF/PyCEczF+Bv7b2GF
+ LZwQEIyMz4XMAcscGRgaiYgQG1jdQFpsAABiJxGdwMDYgAgAxPEAwNSIiCikXXLrnUgE
+ RMcgfSWRC4hsvTukRkpUNAAaVcjcTvxb5icHQFs9APS3/i0TUweA4QYAPQP/li06/Hqf
+ EOVBbNA2pV/DQSQqAJhXm5uLYgDgSgDYKN7cXDuxublRBwDqBQDd4QHxMQm/dAF6q8IA
+ AmAArIAT8AFhIAFkgRJQA1pAHxgDC2ALnIA78AYBIAREgBiQCFJBOsgGBaAIHAYVoBqc
+ BGfBBdACroBOcBP0gyEwDMbAMzAJ3oOPYB4sgzUIgnAQCWKGOCA+SBSShhQhdUgXMoYs
+ IQfIHfKFgqAIKB5KhTKhfKgEOgrVQmegZqgd6oZuQ8PQE2gSmoEWoFUYhokwK8wDi8Jy
+ sBqsD1vAjrAXHARHw8lwJnwAPgLXwo3wZbgLHoQfwRPwR3gJ3kQRUGwoAZQ0Sg1FRVmj
+ 3FE0VDQqFZWLOoSqQZ1DdaD6UCOoV6hPqO9oNJoJzYeWQWugTdBOaD90FDoVnY8uR59C
+ X0L3oB+iJ9Cf0esYIoYLI4FRw5hiXDA0TBxmH6YUU4dpxfRiRjFvMYtYFJYVK4JVwRpj
+ XbDB2CRsHrYC24i9jr2PncR+xaFwbDhxnAbOCueNi8Zl4spwZ3DXcPdxr3FLeDyeGy+P
+ p+Jd8GH4NHwJ/hT+Kv4+/i3+Gx2JTpBOlc6Szpcuni6frobuMt0Q3STdCoFEECJoEGwJ
+ NEIqoYRwltBNGCd8JmKIvERloiUxgLiLWEpsJPYSnxMXSSSSCEmH5EKKJOWQaklXSaOk
+ OTKWLEDWJDuRI8m55BPkTvI4eYGeRC9OT6XfTp9EX0rfRD9IP8UAM/AxaDK4MMQwHGRo
+ ZLjN8I4RYuRj1GJ0Y0xgLGW8yHifcZaJwCTBZMIUyJTJVMvUzTTB9JOZl1mb2ZM5hbmC
+ uYP5KfMPFk4WDRZ3lhSWCpZrLM9Z1ll5WXVZfVjTWU+w3mJ9z4Zjk2SzZItgK2JrYRtj
+ +0bhouhQfCmZlNOUQcpndmZ2FXZ39t3sJ9j72T9yMHAoc7hz7Oao47jNMcfJwqnO6c25
+ j7OBc5hzhYuXy5ArjKuI6wrXK24styy3E3cqdx33EPciDzePIU84zyGe6zxTvPS8ary+
+ vPm8rbwv+bB8CnwefPv4LvA94Ufxy/K78WfyX+B/KoAWUBDwFMgRaBV4JUgQVBMMECwU
+ 7BScEWITogpFC1UKDQp9FxYVdhROF24SfilCEtEUCRU5ItIvsiwqIuokminaKvpGjFmM
+ KhYjVic2Ko4SVxaniZeJD4h/l5CS8JQ4IHFDYl5SSNJZMkeyQ3JWil/KQSpLql3qkzSf
+ tIN0tvRV6c8yQjIuMvkyXTJLspKy3rKlsrdlN+S2yYXKVck9kifKG8gnyl+Qf6fAreCg
+ kKdwU+G7ooJisGK14rgSg5KZ0l6ldqWFbVLbArYd3zamzKBsppyh3Km8oqKgEqZSrzKh
+ yqXqrFqkOqSGVaOqpal1qC2rK6pHqDeoT2kIa/hqVGo802TXdNIs0XygRday1MrTGtDG
+ ahtpZ2r36EA6+jp7dLp0furq6qbp3tD9qaent0evWx/oG+hn6N8ywBiYGuQaDFJJVBtq
+ MXXUkGLoZnjM8JWRoBHN6IzRrLGCcZxxu/G6ib5JlsmgKb2po+lR01dmwmahZk1my+Za
+ 5unmAxb0Fs4WxyzeWEpZ7rRstwJWZlZFVk+sBaxDrC9ar9pQbfbbjNny2QbbXrRdszO2
+ K7R7ai9iH2nf4YB2sHWocHjvqOiY6njbidXJ1+m80w9nE+cS5wkXGZcUlwFXVld/12bX
+ n25WbhVuM+7q7tnuYx4iHnEevZ4sngGeLV4oL0evOq+l7UbbD2+f8lbzzvN+5iPjk+Yz
+ 7CvkG+c74MfpF+7X5c/sT/PvCCAF+AZcCsQHegVepGFoHrSmIHSQe1BTMDrYI7g5BBvi
+ FdISShfqE9oWRg4LDOvcwbJjx47ecO7w2PChCOGI1IixSLnInMjJKM2o0qi5aNPo2ui1
+ nS47m2OIMUExN2N5YpNiR+Pk4wriPsQbxtfErye4J7QlsiRGJ95Pkk7KS/qQbJxclwKn
+ +KZ07eLbtXvXi1Tt1GOpa7s9d19L405LTXuxR2dP1Z7Nvb57e9KF07PSP2SYZzRm0mdG
+ Z47uU913dN96lm9Wb7Z4dkH2lxynnPZc3tz03Kk8q7yL+ZT81Pw3BWYFF/az7t+1/80B
+ swNNB9kPph18X2hdeLmItyir6HOxS3FXiURJcclqaWDpvUNqh2oPEw/HH54ssyi7fETg
+ SMGRb+X+5fePah49VcFckVbx6ZjrsVvHFY9XV5Iqkys/VDlX9VYrVtfUMNTsrpmt9awd
+ OqF5oqGOqy6/bvVk2Mnn9Vb1nafkTlWfZjydcXrpDO3Mk7MWZzsb5BtONLI15jaunYs6
+ 9/a8y/mhC3oXWpskmiqbmZpzmtcv7rz4oWV7y2ireWvXJdVL5y+LXD7WxtyWdwW6knxl
+ oT20/XWHR8fIVcurt67pXrvSqdDZcF3ketUNzhulXfRded3o7j3dqzcTbi70RPTM9Ab1
+ vrnlc+tFn3vf437H/ocDNgN3b1vcvnPH9E7/oPHgrSHDoZ671Ls37xncu3mfer/ngeGD
+ 3mGj4f6Hpg9vj1iM3B21GR1+5Pjo8Zjb2PPH3o/fjNPGZ55EPFl4Gv909dme56jnuS/o
+ X5S+5HxZ9UrkVcOE4sSVSd3JvtdWr0ffeLx58zbs7dd3Ke/h9wVTLFPHP4h+aJpWn+6Z
+ sZp5/NH348dP8Z82Z/PnKHO1n2U+t38x+jI87zU/sxD/Ff5auMiz2LCkttS37Lj8eiVq
+ 5ee3/d+5vzf80PhxZ9V9dXotaR2/fnRDcuPqT8ufLzYj/8YCf2OBv7HA31jgbyzwNxb4
+ Gwv8jQX+ngv8PRf4ey7w91zg77nA33OBv+cC/3/PBaL9Yvx+xQIo5A4HBQHw9TQAZHcA
+ WIYBIKL+t+2/8yi/ow2AQpJCWzkkJiTb0A2pQKdhSfgMSh31EB2DEcQ8w5bjAvB6dMIE
+ BiKZxEQWpddh8GLMYbrGvMKqxbaLMshB4QzlusnDwRvHNywgK1gqzC1SKyYj3ippLDUi
+ Q5NdlS9SFFPqVd6usqpWrqGhOa6dosuld8PAzxA2ajCxMV02r7SkWt21YbG1tyu0v+dI
+ drJ2PujywI3R3cmjzHN8O5e3p0+17xt/0YCwwPO0hWCVkJTQrh3YcMkIxUjVKK1og50m
+ MRaxNnEO8S4JbonuSR7JHikeu9xSXXc7pdnvsd5rkW6SQc3U2aeWpZAtlSOWK5THl89d
+ wLmf/QDlIHshexFnMU8Jf6nwIfHDsmXbjmiU6x01rjA7Zn7cotKqyrratsa+1uGEY53j
+ Scd6x1MOp+3P2J61brBoND1nfJ56Qa9Jv9nyondLdGvmpbLLZ9o6rgy2v+iYvbrWSbjO
+ eUO8S7mbetOmx7M3+FZc367+2IHg2x53rAd1h+Tv8t0j31u7P/VgeLjjYc1I9mjYI5sx
+ hcfMj5fGx57UP419ZvCc/PzZi5MvI16pvFqf6J7MeG30Bv2m523aO413S+8vTAV94P7Q
+ Nx0+wzLT8dHr4+anqlnt2fG5yM/oz2VfxL60zuvM9y9YLYx89fj6bnHn4sZS1jJ5uWiF
+ ZaX4G/23vO+Y7+nfN3/krnKs9q6Vrlf+ZNjcRPxPAuogD8kV2UBNMDe8F15GBaOm0GHo
+ NUwhVh77EncI70onRrdOmCQ+JD0gP6f/zEhikmf2ZTnK+owiyB7N0c3FwZ3M84kvln9N
+ MFuYWaRKTFL8sqSm1E0ZquwteQOFDiWlbdUqZNVEtWcampqlWh91dHWL9F4ZSFFjDS8a
+ PTOBTCXM7MwTLKosb1nN2NDbbrNztU9xqHS84TThAlwF3PTdfTx2ex73urb9qfcPX6If
+ sz9HAH+gKE0mSClYPUQ7VD/McIdxuFEENVIf+V0o75SNEY7liCPFbcYvJLxMvJlUn5yX
+ ErnLKVVzt2AaIW1xz8u9d9IvZ5zILNq3Oys82zPHKlc7Tyaft4B+P9j/9cD7g08K7xX1
+ FLeXnC+tO1RxuLAs60hKeeRRvwrHY0bHlStFqliqoerFmvnaxRMrdT9OrtVvnNo4vXFm
+ 4+xaw4/Gb+dWzi9d+Nr0tXn+4nzLQuvipW9t8BVyO0eH0FXpa8qdWtepN8y6bLodb7r3
+ ePcG3grr29mfNJB+O+9OyeCBoX13U+/F3494QBv2eug4YjGq/0hlTOIx9zhpfOPJp6dP
+ nvU9b35R/jL1lfeEwaTIa9zrmTdDby+8K3wfNWX7QW6aND0zc+tj1afEWbs56c8Mn398
+ mZofWxj4em2xeen0cvVK+bfi77k/0lZj1mjrzhvUn7Kb7L/8//v7l4H2w2jYD36IMkLd
+ QOuguzHGmEGsK/YTbi+eB99O50GACeeJ3iQK6S45l96CgYFhjLGGKYpZn4WVZZq1m62d
+ MsQ+zYnlEuWm8tB4s/jq+QcEZoRIwooidqJxYmXi7RIvpYC0kIyxbKhcgXyTwojiyjZu
+ ZTUVcVWKGl5tVX1OY1LzkdZt7es6Lbpn9Kr0Dxvsp+4zTDWKM44wCTL1MfMwd7aws7S0
+ 0rYWtSHbLNu+tBuwv+hQ4bjPKdLZ3cXIVc6Nwx3t/sXjmWe/V8v2Ku8CnyRfmp+lv4j/
+ WsBIYCMtM8grWDmEFPI+9HpY2Y7IcOMI3oilyKGouuiUnQ4xkrEg9mFcRbxPgnDCdOL5
+ pLhkTeSEf3BXSarXbrHd82nX9uTsdUwXSJ/LuJqZt881SyxrKbs3pyTXL08hH+QPF9Tu
+ jzlgdJBycKaws6iwOKBErZRU+vrQlcP7y2hHjMpFj+KOzlQMHbtwvKgyrsq1WqtGoBZd
+ O3PiQd3lk8fq00+FnLY9o3NWq8Go0fqc63n/CxFNSc3ZFw+11LW2Xrp1+XHb9JX1Dsar
+ ote0Oh2ux9yo75q4yYOsLpW33vbLDCTfvj3IPRR9t/8+/4Pk4Ucj20aLHn1+bDPe9JTh
+ WeTz9Zd9E0deR7w1fy//QXhG4pPRXOKXga/blq5/o61KbuC3/P87n761J2BVAaivBcAF
+ 2XNsowCoDQFAdAPJh48AYEcGwEkDwMs9APZuB1Dxp3/tHxgkj82L5K/1gAMIRvLUJUhm
+ uhs8AfMQHSQM6UBuUCxUCDVCd6APMAbJIRsjmeMcuAG+By+gKChtVAAqB9WIGkatoHnQ
+ Rugd6FJ0J3oKw4jRxARhSjA3MLNYTqwZNhF7GjuOw+M0ceG4atwoHofXxsfgz+An6Njp
+ 7Ojy6HroNgjqhDhCM2GOKE0MI54lfifZkk6TAdmT3EbPQr+TfphBgaGEYRnJnl5nEmHa
+ z7TM7Ms8xKLOcoqVwprN+p0tnG2S4kK5x27MfoNDnWOIM4QLx3WG25J7nqecl8r7ha+S
+ 3xbJTV4TjBdSFFoQbhVJEtUXI4iNi5+SSJK0lhKVBtIvZa7KVsilyvsoGClKK7EobWyb
+ UR5TuaV6Se2U+lGNg5pZWmnaSTqJurv0MvQLDMqoJw0vGfUbPzdZNKM3l7awtIyyOmzd
+ ZfPJjsveymGv4xWneRcRVwu3ne7HPPo9l7aLeLv5HPTt8wcBuoF7aD3B+BCH0ONhs+E6
+ EUWRU9G6O+tiReJOJcgmtiebprxIjU9j3nMl3T+Tad9A9r5ck3xywbMDjYV7i/eW5h4+
+ cuTc0cFjC1UCNZ4nak/On7Y+e+mcyIWqi/ytL9vOdeR3pnTt7ante3/H8u74cO4jzydc
+ zwcn6t+e+zAzazPftHTx2/xq5Lr5RtvP6V/rBw5QgDQwAj6I748ifIQxsASxQEqQPRQN
+ FSF8gofQV5gFVoFd4RS4Er4JT6GIKAWUCyoFVYXqQU2j6dHKaC/0PvR59DgGwshiPDA5
+ mDbMFJaCeH0Xtgn7HseNc8IdwN3Go5EcfQa+lw6LZOSL6Z4iOfgIwlUinuhGbCChSf6k
+ m2Qh8j7yNL01/SUGXoZchiVGf8YRJiOmK8yyzPUsfMiORWE9zEZhO0rhpdSxS7Nf5tDj
+ GOeM42LmauF25v7BU8NrzrvMd5LfWYAg0COYJqQttCncJ3JQ1EtMVhwSfyZxWbJa6qD0
+ HpkY2SC57fIuCraKlkpm20yVzVQsVG3VXNS9NUI047WytMt0GnS79Mb156lEQwkjE+Ng
+ k3zTJrMnFihLJSua9XGbx3Zs9m4OVY7Tziouia7n3T54CHsGeNVvn/VR9c3wGwkQC0yl
+ PQqWDzkQ+mmHdXhzJGtUSvRkjG5sVdxmQmDivWT1lDOp3LuL9xD2ZmdgM3OyCNlFuex5
+ NQVS+y8fpBY+RHyseOhtWXm5bQXx2GBlQbV9Lc+JuZM3Tx0/s6vB/5zNBd1mlRbVS2Zt
+ nu07r+Z3nr5xp3uul7PPYmDPnet3wX2r4aqRlTHn8eNPR15gXqlOBr4pfNcx9XaG/Elj
+ LvRLzcKLJcGVyO99a6Ibhb/8j0EiSBGEueICEkA5uA7eQwyQFhQClSNf/DqsCAfD1fBT
+ hAvigMpGWB+zaEG0K7oQPYD4WgeTgmnHfMdqIH7uxmEQbsZh3AReCp+I76ej0AXTXSMw
+ IAyL60QKMZr4gGRAaiPLkE/S89FXMHAwlDNyMVYh3/E5ZlXmHhY7lknWGDYsWyVFmXKf
+ PYwDz9HE6YP4dYB7D486zxJvK18cvxr/hkC/YLGQt7CcCBAZEz0nliXuJ6EnKSYlKM0v
+ wy8rJCchr6Sgq2ij5LctSblEpVl1RG1Fg1/TQitZu1FnWc9K/zQVY0gzum0ia3rYbNNi
+ h+Vzayubbjs1+4uOsk7nXGRdL7vregx5eWyf88nw4/RvDbSjfQkuDlUJexGeHakU9Xrn
+ gVjZuOGE+CTe5IFd8buF0x7tzc3Qy/yW1ZITlSef/3V/28HdRduK+0s9Dy2U5ZULHr12
+ zO34YlVRjVztvbqIevKp5jP2Z1caj503uDDdXNQi2nryslBbTTtvR/k1ls6CG6iupO65
+ Hr/e0T7j/rbbEncqhkh30+4tPPAbHhsxH+0aU37c8ETwacVzthfFL8cmwKTwa5M3IW8L
+ 3jW+H5qanoZnuD7KftKZNZ+z+Wz/xXreZEHzq+Qiy+KPpRfLV1cOf4v4rv+D+cfE6rm1
+ uHXt9c2Nnp8ZmwZb/v/NwdraPwDBMCo8KkbAytDo1+P/3S0iPB7hef0qzMidFBlus8Xt
+ oiDXdKCfkSVS8yDXz+jwXzw4RAfiokU6OyKyLSwT6W9j+w/WDYoxcUAw0heyi46jbmEO
+ BAdFx9k5/SNPSwkxtEEwCZEfosUa/xmnJszPAuGgAXpE3hIT7+CMYBEEd8cmOBojmBHB
+ 71JCnFz/0VkKpBn9I4fhoFAT8986MHNonPmWLVbkHzChHVGWW3NAbMGqwBKEAxqIRxhf
+ NBCJ7KlWwBBZWX/fZUEQ8ENaEpC2WLADTCE4AukRhfSJQrDAP3qG/01i8qtfMNLvv44o
+ gPDLohBrf2z+tiOA2PwzZigIRPAfuR9iY6tta3axPqEZ/7b5R2NrvF+zUWhUmFFY/zMn
+ tBhaCa2CpiJxpS5aAwigKWguIIus++poA7QeWgtp0wAm4B0ycvCfOW6NH9ESlFAelazp
+ EoK0bv3t/n9akdVmSzv0X8//bQYg9P7sldk/M0D4k784gcibBljET8cRXh4AfUm7927V
+ /7nE0ZK2uILAMCo6OSY0OCROwABhTdJkBMwjA+RkBJQUFBXAfwBMLNjWCmVuZHN0cmVh
+ bQplbmRvYmoKMzEgMCBvYmoKNjA0NQplbmRvYmoKMTkgMCBvYmoKWyAvSUNDQmFzZWQg
+ MzAgMCBSIF0KZW5kb2JqCjMyIDAgb2JqCjw8IC9MZW5ndGggMzMgMCBSIC9OIDMgL0Fs
+ dGVybmF0ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4
+ AYVUz2sTQRT+Nm6p0CIIWmsOsniQIklZq2hF1Db9EWJrDNsftkWQZDNJ1m426+4mtaWI
+ 5OLRKt5F7aEH/4AeevBkL0qFWkUo3qsoYqEXLfHNbky2perAzn7z3jfvfW923wANctI0
+ 9YAE5A3HUqIRaWx8Qmr8iACOoglBNCVV2+xOJAZBg3P5e+fYeg+BW1bDe/t3snetmtK2
+ mgeE/UDgR5rZKrDvF3EKWRICiDzfoSnHdAjf49jy7I85Tnl4wbUPKz3EWSJ8QDUtzn9N
+ uFPNJdNAg0g4lPVxUj6c14uU1x0HaW5mxsgQvU+QprvM7qtioZxO9g6QvZ30fk6z3j7C
+ IcILGa0/RriNnvWM1T/iYeGk5sSGPRwYNfT4YBW3Gqn4NcIUXxBNJ6JUcdkuDfGYrv1W
+ 8kqCcJA4ymRhgHNaSE/XTG74uocFfSbXE6/id1ZR4XmPE2fe1N3vRdoCrzAOHQwaDJoN
+ SFAQRQRhmLBQQIY8GjE0snI/I6sGG5N7MnUkart0YkSxQXs23D23UaTdPP4oInGUQ7UI
+ kvxB/iqvyU/lefnLXLDYVveUrZuauvLgO8XlmbkaHtfTyONzTV58ldR2k1dHlqx5erya
+ 7Bo/7FeXMeaCNY/Ec7D78S1flcyXKYwUxeNV8+pLhHVaMTffn2x/Oz3iLs8utdZzrYmL
+ N1abl2f9akj77qq8k+ZV+U9e9fH8Z83EY+IpMSZ2iuchiZfFLvGS2EurC+JgbccInZWG
+ KdJtkfok1WBgmrz1L10/W3i9Rn8M9VGUGczSVIn3f8IqZDSduQ5v+o/bx/wX5PeK558o
+ Ai9s4MiZum1Tce8QoWWlbnOuAhe/0X3wtm5ro344/ARYPKsWrVI1nyC8ARx2h3oe6CmY
+ 05aWzTlShyyfk7rpymJSzFDbQ1JS1yXXZUsWs5lVYul22JnTHW4coTlC98SnSmWT+q/x
+ EbD9sFL5+axS2X5OGtaBl/pvwLz9RQplbmRzdHJlYW0KZW5kb2JqCjMzIDAgb2JqCjcz
+ NwplbmRvYmoKOCAwIG9iagpbIC9JQ0NCYXNlZCAzMiAwIFIgXQplbmRvYmoKNCAwIG9i
+ ago8PCAvVHlwZSAvUGFnZXMgL01lZGlhQm94IFswIDAgNjEyIDc5Ml0gL0NvdW50IDEg
+ L0tpZHMgWyAzIDAgUiBdID4+CmVuZG9iagozNCAwIG9iago8PCAvVHlwZSAvQ2F0YWxv
+ ZyAvT3V0bGluZXMgMiAwIFIgL1BhZ2VzIDQgMCBSIC9WZXJzaW9uIC8xLjQgPj4KZW5k
+ b2JqCjIgMCBvYmoKPDwgL0xhc3QgMzUgMCBSIC9GaXJzdCAzNiAwIFIgPj4KZW5kb2Jq
+ CjM2IDAgb2JqCjw8IC9QYXJlbnQgMzcgMCBSIC9Db3VudCAwIC9EZXN0IFsgMyAwIFIg
+ L1hZWiAwIDU1MyAwIF0gL1RpdGxlIChDYW52YXMgMSkKPj4KZW5kb2JqCjM3IDAgb2Jq
+ Cjw8ID4+CmVuZG9iagozNSAwIG9iago8PCAvUGFyZW50IDM3IDAgUiAvQ291bnQgMCAv
+ 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
+ MFyw2Cm71YqNNrvNZkPYipHVpYOU1Wa12S1GiktBWOsyIopVkQJGDIgjVHRgBGZlLpBf
+ wZRcmTU1OHSSUVk+iK6EalJcLEnwYhgrqCaSioLXadJL00shPJ0O248FhFuq289pFP4k
+ H+9LVqbkIY/alYf9HKS8cjEPuzUQ+IRAHqjq0jqXJh/EPprl4wNq7E2ILB2R9rDUOZ4p
+ JMpN4QAvaJDIXm7+bPLPlsb2nzogccLa45u8Batj0xel7mo+edtoYIv/jX0FmyDFdBzM
+ LPzkEq5JMASwyMb7z662aa2rf7y1FVPtEndcAIH3XewNWDNAczgmZVdK8iGAtoR0vGos
+ rmEbcD27gG02rGQF03E43LEiO3aEyr2ix9+oW6pbbqB1LrfBYaRFl8nA+HUpPheSyey8
+ S0H5HXbB4zO6fSY6N2mB3RYU/L6AHOh8Udx680Z5FfSsd0FUlpaWRRMsVJxQCiVtYBbs
+ nOlke8fAQYmtkRbzyD7I8S7sxrAlmo0g/7Mx6OOE3+jqDc8vGzkvZjtD7d27+O3Fc6ZN
+ Z3laocu6KlcySr65+O5YyRnasWTTU8WumJzalTs7umZvvndZ5+tTg1UGUV867dtHc+3R
+ LhAmIqwZkB1guwwL2TDnQjzFCEQZQ9co2scy1zirQBQbotdeBda/OqCPEXEGOBNJqRUL
+ mHMx7ZsxLXui+/u/sGpYiHD9AU2OX5ZOf5LgXK8UfRQanpaD5RqFXekI5NdoFsgWavhi
+ QaeU0fY8PkXm1CidJelUVrDkSAlVkpfm02l4VnAEks2OCO4Kec1ONx9wZikoZ4GilC8t
+ dRj4YNreFNsoe9AxLikw3Dpy1E/xdhjQUbwNJcQ76Cdkn74SPT0ozsr6QNATjidEz+rL
+ 6iNqC8yFJOZSC4uMybC6fLgwSUQWl11EJo8BzItkVESJyOY0izBgCCTuJts0UWpAuOFZ
+ KSayL4/EapyEYW824oRO7U0GJveOwvlkOrUGaASfgHWQDKYVifwFwwqL9Fi9rO72hm1i
+ a97iOblTcO8oo/L+ux8uEeV72e+eP9G+3OxTurRpGf5ZaSZZ0a/u2Xri2Paut2dkjN39
+ mNHBqVWO7Pl4kZBhyZw5ZULalDd21tTsiG53JNP0WiVX7g3VLPzJg1tf0OMrZA20xz9m
+ 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
+ 4LUiFFKyQBsebrLrlEoFC+5Z+IPp6pXBUbU8gh8K6XXgjuA5hiUNOV4mwPE2KVeTA22F
+ EoYtvYqJdrdOs+q0hR04jJYS61ZpTg+WEL/k0qVLQduzU/l2QksFkPP9X114853f9MbO
+ Hb/06+OxXwBJe+kJ14/S1dcu0COvvwYEhbVjjI2V7DFyv+PN0I+6jA9a9lhoos8O19Xo
+ 6nXz+RX0Cn6DYQfcktlh3G7abt6L9po0NWi8sdp8zshUsG+w1Dp2N9qN97B7zWxKKmsx
+ mk2g4xuViiSnoCaKgskOBCU8YTZaupWPmEBfeDfBwcB6tVcsNxEyseyAxHnWbAtousCI
+ xRhIF9IZ4SqKabHObLawGBPmtoATnJCGRALEQIXcnKXSwXw+R1M8JQnFAmJ8FxaNwkVA
+ GZoWz/jvn1P+ZOeT/qArO02Tl61hR6ljbW+BE5fJnh97LPb1y7F5vZzwgooTLcKWFKYO
+ WPE+QivpF2+B/zf4Z78MKKTBz0Tu2qjgbEeLnMQfIt2NCcKtmAw4V8uHWzEFqAhVoEpU
+ Jf2Hw1j4px7yfwy18D8At0j/azEZ/n/iVjQNTUf1qAFuAM2UPkZWAZZSHNzaQdPGz6i6
+ ZUx6Tcui9pa2BXOboCZRS5qA2QP/OYDQuwBXAK5CJQMAd3xwCsAwgAqAqQDNAG0AawC2
+ ALwA0AtwGuBdgCsAV2HwDIABIAVgGEAFwFSAZoA2gDUAWwBeAOgFOA3wLsAVgKtAGAbA
+ AJACMAygAmAqQHO8/wd4osE0Rp4h+eQh+dQh+eCQPLmJdGN/ZHZuzGcNyY8Ykh89JF8+
+ JD9mSB7Gc1P/VUPyNUPyoHjf1P6WIfmJQ/LkpPFG/CcPyQMtb6onHHFj+zlD8nOH5JuH
+ 5CUev2E+5g2pnz8k3zokv2BIfuGQ/B1D8ouG5KX/Gb3h+8Q6vXE8dw7JLxmSXzYkf9eQ
+ fNuQ/PIh+fYh+RVD8h0k/38GpnvKCmVuZHN0cmVhbQplbmRvYmoKMzkgMCBvYmoKMTAx
+ NDMKZW5kb2JqCjQwIDAgb2JqCjw8IC9UeXBlIC9Gb250RGVzY3JpcHRvciAvQXNjZW50
+ IDc3MCAvQ2FwSGVpZ2h0IDczNyAvRGVzY2VudCAtMjMwIC9GbGFncyAzMgovRm9udEJC
+ b3ggWy05NTEgLTQ4MSAxNDQ1IDExMjJdIC9Gb250TmFtZSAvVktaRk9DK0hlbHZldGlj
+ YSAvSXRhbGljQW5nbGUgMAovU3RlbVYgMCAvTWF4V2lkdGggMTUwMCAvWEhlaWdodCA2
+ MzcgL0ZvbnRGaWxlMiAzOCAwIFIgPj4KZW5kb2JqCjQxIDAgb2JqClsgMjc4IDAgMzU1
+ IDAgMCAwIDAgMCAzMzMgMzMzIDM4OSAwIDI3OCAwIDI3OCAwIDAgMCAwIDAgMCAwIDAg
+ MCAwIDAgMjc4IDAKMCAwIDAgMCAwIDY2NyA2NjcgNzIyIDcyMiAwIDYxMSAwIDcyMiAy
+ NzggMCAwIDAgMCAwIDc3OCA2NjcgNzc4IDcyMiAwIDYxMQowIDAgMCAwIDAgMCAwIDAg
+ MCAwIDAgMCA1NTYgNTU2IDUwMCA1NTYgNTU2IDI3OCA1NTYgNTU2IDIyMiAyMjIgNTAw
+ IDIyMiA4MzMKNTU2IDU1NiA1NTYgMCAzMzMgNTAwIDI3OCA1NTYgNTAwIDcyMiAwIDUw
+ MCBdCmVuZG9iagoxOCAwIG9iago8PCAvVHlwZSAvRm9udCAvU3VidHlwZSAvVHJ1ZVR5
+ cGUgL0Jhc2VGb250IC9WS1pGT0MrSGVsdmV0aWNhIC9Gb250RGVzY3JpcHRvcgo0MCAw
+ IFIgL1dpZHRocyA0MSAwIFIgL0ZpcnN0Q2hhciAzMiAvTGFzdENoYXIgMTIxIC9FbmNv
+ ZGluZyAvTWFjUm9tYW5FbmNvZGluZwo+PgplbmRvYmoKNDIgMCBvYmoKKFVudGl0bGVk
+ KQplbmRvYmoKNDMgMCBvYmoKKE1hYyBPUyBYIDEwLjYuMiBRdWFydHogUERGQ29udGV4
+ dCkKZW5kb2JqCjQ0IDAgb2JqCihHbHlwaCBMZWZrb3dpdHopCmVuZG9iago0NSAwIG9i
+ agooT21uaUdyYWZmbGUgUHJvZmVzc2lvbmFsKQplbmRvYmoKNDYgMCBvYmoKKEQ6MjAx
+ MDAxMTQyMTQ2MThaMDAnMDAnKQplbmRvYmoKMSAwIG9iago8PCAvVGl0bGUgNDIgMCBS
+ IC9BdXRob3IgNDQgMCBSIC9Qcm9kdWNlciA0MyAwIFIgL0NyZWF0b3IgNDUgMCBSIC9D
+ cmVhdGlvbkRhdGUKNDYgMCBSIC9Nb2REYXRlIDQ2IDAgUiA+PgplbmRvYmoKeHJlZgow
+ IDQ3CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDA2MTQ4MiAwMDAwMCBuIAowMDAwMDUw
+ MDg2IDAwMDAwIG4gCjAwMDAwMDQ0MDAgMDAwMDAgbiAKMDAwMDA0OTkyMyAwMDAwMCBu
+ IAowMDAwMDAwMDIyIDAwMDAwIG4gCjAwMDAwMDQzODAgMDAwMDAgbiAKMDAwMDAwNDUw
+ NCAwMDAwMCBuIAowMDAwMDQ5ODg3IDAwMDAwIG4gCjAwMDAwMDY3NTUgMDAwMDAgbiAK
+ MDAwMDAyMDA4NyAwMDAwMCBuIAowMDAwMDA1OTUyIDAwMDAwIG4gCjAwMDAwMDY3MzUg
+ MDAwMDAgbiAKMDAwMDAwNDcwMSAwMDAwMCBuIAowMDAwMDA1NDA3IDAwMDAwIG4gCjAw
+ MDAwMDU0MjcgMDAwMDAgbiAKMDAwMDAwNTkzMiAwMDAwMCBuIAowMDAwMDQyNzg0IDAw
+ MDAwIG4gCjAwMDAwNjExMDkgMDAwMDAgbiAKMDAwMDA0ODk5MCAwMDAwMCBuIAowMDAw
+ MDI2MjkzIDAwMDAwIG4gCjAwMDAwMjg0MTUgMDAwMDAgbiAKMDAwMDAzODc3MiAwMDAw
+ MCBuIAowMDAwMDQxOTM1IDAwMDAwIG4gCjAwMDAwMjAxMDkgMDAwMDAgbiAKMDAwMDAy
+ NjI3MiAwMDAwMCBuIAowMDAwMDI4NDM2IDAwMDAwIG4gCjAwMDAwMzg3NTAgMDAwMDAg
+ biAKMDAwMDA0MTk1NiAwMDAwMCBuIAowMDAwMDQyNzY0IDAwMDAwIG4gCjAwMDAwNDI4
+ MjEgMDAwMDAgbiAKMDAwMDA0ODk2OSAwMDAwMCBuIAowMDAwMDQ5MDI3IDAwMDAwIG4g
+ CjAwMDAwNDk4NjcgMDAwMDAgbiAKMDAwMDA1MDAwNiAwMDAwMCBuIAowMDAwMDUwMjQ5
+ IDAwMDAwIG4gCjAwMDAwNTAxMzQgMDAwMDAgbiAKMDAwMDA1MDIyNyAwMDAwMCBuIAow
+ MDAwMDUwMzQyIDAwMDAwIG4gCjAwMDAwNjA1NzYgMDAwMDAgbiAKMDAwMDA2MDU5OCAw
+ MDAwMCBuIAowMDAwMDYwODIzIDAwMDAwIG4gCjAwMDAwNjEyODQgMDAwMDAgbiAKMDAw
+ MDA2MTMxMSAwMDAwMCBuIAowMDAwMDYxMzYzIDAwMDAwIG4gCjAwMDAwNjEzOTcgMDAw
+ MDAgbiAKMDAwMDA2MTQ0MCAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDQ3IC9Sb290
+ IDM0IDAgUiAvSW5mbyAxIDAgUiAvSUQgWyA8MjcxMmU2MjU3ZDg2ZmVmMzU1YTAwNjEz
+ ZGE5ODQzYTY+CjwyNzEyZTYyNTdkODZmZWYzNTVhMDA2MTNkYTk4NDNhNj4gXSA+Pgpz
+ dGFydHhyZWYKNjE2MDIKJSVFT0YKMSAwIG9iago8PC9BdXRob3IgKFdpbGZyZWRvIFNh
+ bmNoZXpcbkdseXBoIExlZmtvd2l0eikvQ3JlYXRpb25EYXRlIChEOjIwMTAwMTExMTky
+ MTAwWikvQ3JlYXRvciAoT21uaUdyYWZmbGUgUHJvZmVzc2lvbmFsIDUuMi4xKS9Nb2RE
+ YXRlIChEOjIwMTAwMTE0MjE0NjAwWikvUHJvZHVjZXIgNDMgMCBSIC9UaXRsZSAoQ2Fs
+ ZW5kYXIgU3RvcmUuZ3JhZmZsZSk+PgplbmRvYmoKeHJlZgoxIDEKMDAwMDA2MjcwMCAw
+ MDAwMCBuIAp0cmFpbGVyCjw8L0lEIFs8MjcxMmU2MjU3ZDg2ZmVmMzU1YTAwNjEzZGE5
+ ODQzYTY+IDwyNzEyZTYyNTdkODZmZWYzNTVhMDA2MTNkYTk4NDNhNj5dIC9JbmZvIDEg
+ MCBSIC9QcmV2IDYxNjAyIC9Sb290IDM0IDAgUiAvU2l6ZSA0Nz4+CnN0YXJ0eHJlZgo2
+ MjkxMwolJUVPRgo=
+ </data>
+ <key>QuickLookThumbnail</key>
+ <data>
+ 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
+ HBuoZAXwYxOIdg+YDQCJtSRQg4b4bZ7YLYMgIgAAChfVf1pwoYgIAA8BAAADAAAAAQBx
+ AAABAQADAAAAAQBbAAABAgADAAAABAAAGJYBAwADAAAAAQAFAAABBgADAAAAAQACAAAB
+ EQAEAAAAAQAAAAgBEgADAAAAAQABAAABFQADAAAAAQAEAAABFgADAAAAAQBbAAABFwAE
+ AAAAAQAAF9QBHAADAAAAAQABAAABPQADAAAAAQACAAABUgADAAAAAQABAAABUwADAAAA
+ BAAAGJ6HcwAHAAApmAAAGKYAAAAAAAgACAAIAAgAAQABAAEAAQAAKZhhcHBsAgAAAG1u
+ dHJSR0IgWFlaIAfaAAEAAgAAABwACmFjc3BBUFBMAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAD21gABAAAAANMtYXBwbB5XET7FGnu84JaBzKU8KrcAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAEXJYWVoAAAFQAAAAFGdYWVoAAAFkAAAAFGJYWVoAAAF4AAAA
+ FHd0cHQAAAGMAAAAFGNoYWQAAAGgAAAALHJUUkMAAAHMAAAIDGdUUkMAAAnYAAAIDGJU
+ UkMAABHkAAAIDGFhcmcAABnwAAAAIGFhZ2cAABoQAAAAIGFhYmcAABowAAAAIHZjZ3QA
+ ABpQAAAGEm5kaW4AACBkAAAGPmRlc2MAACakAAAAZGRzY20AACcIAAACQm1tb2QAAClM
+ AAAAKGNwcnQAACl0AAAAJFhZWiAAAAAAAABvcAAAOZ4AAAGiWFlaIAAAAAAAAGEuAAC2
+ pQAADsRYWVogAAAAAAAAJjgAAA++AADCx1hZWiAAAAAAAADzUgABAAAAARbPc2YzMgAA
+ AAAAAQxCAAAF3v//8yYAAAeSAAD9kf//+6L///2jAAAD3AAAwGxjdXJ2AAAAAAAABAAA
+ AAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABtAHIAdwB8
+ AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANoA4ADlAOoA8AD1APsB
+ AQEHAQwBEgEYAR4BJQErATEBOAE+AUUBSwFSAVkBYAFmAW0BdQF8AYMBigGSAZkBoQGo
+ AbABuAHAAcgB0AHYAeAB6QHxAfoCAgILAhQCHAIlAi4CNwJAAkoCUwJcAmYCcAJ5AoMC
+ jQKXAqECqwK1Ar8CygLUAt8C6gL0Av8DCgMVAyADKwM3A0IDTQNZA2UDcAN8A4gDlAOg
+ A6wDuQPFA9ID3gPrA/gEBAQRBB4ELAQ5BEYEVARhBG8EfASKBJgEpgS0BMIE0QTfBO4E
+ /AULBRoFKAU3BUcFVgVlBXQFhAWTBaMFswXDBdMF4wXzBgMGFAYkBjUGRQZWBmcGeAaJ
+ BpoGqwa9Bs4G4AbyBwMHFQcnBzkHTAdeB3AHgweWB6gHuwfOB+EH9AgICBsILwhCCFYI
+ agh+CJIIpgi6CM4I4wj3CQwJIQk2CUsJYAl1CYoJoAm1CcsJ4An2CgwKIgo5Ck8KZQp8
+ CpIKqQrACtcK7gsFCx0LNAtLC2MLewuTC6sLwwvbC/MMDAwkDD0MVgxuDIcMoQy6DNMM
+ 7Q0GDSANOg1UDW4NiA2iDbwN1w3xDgwOJw5CDl0OeA6TDq8Oyg7mDwIPHg86D1YPcg+O
+ D6sPyA/kEAEQHhA7EFgQdhCTELEQzhDsEQoRKBFGEWQRgxGhEcAR3xH+Eh0SPBJbEnoS
+ mhK5EtkS+RMZEzkTWRN6E5oTuxPbE/wUHRQ+FF8UgRSiFMQU5RUHFSkVSxVtFZAVshXV
+ FfcWGhY9FmAWgxanFsoW7hcSFzUXWRd9F6IXxhfqGA8YNBhZGH0YoxjIGO0ZExk4GV4Z
+ hBmqGdAZ9hodGkMaahqQGrca3hsGGy0bVBt8G6MbyxvzHBscQxxsHJQcvRzmHQ4dNx1g
+ HYodsx3dHgYeMB5aHoQerh7YHwMfLR9YH4Mfrh/ZIAQgMCBbIIcgsyDeIQohNyFjIY8h
+ vCHpIhUiQiJwIp0iyiL4IyUjUyOBI68j3SQMJDokaSSXJMYk9SUkJVQlgyWzJeImEiZC
+ JnImoybTJwMnNCdlJ5Ynxyf4KCooWyiNKL4o8CkiKVUphym5KewqHypSKoUquCrrKx4r
+ UiuGK7or7iwiLFYsiiy/LPQtKS1eLZMtyC39LjMuaS6eLtQvCy9BL3cvri/kMBswUjCJ
+ MMEw+DEwMWcxnzHXMg8ySDKAMrgy8TMqM2MznDPVNA80SDSCNLw09jUwNWo1pTXfNho2
+ VTaQNss3BjdCN343uTf1ODE4bTiqOOY5IzlgOZ052joXOlQ6kjrPOw07SzuJO8c8BjxE
+ PIM8wj0BPUA9fz2/Pf4+Pj5+Pr4+/j8/P38/wEAAQEFAgkDEQQVBR0GIQcpCDEJOQpFC
+ 00MWQ1hDm0PeRCFEZUSoROxFMEV0RbhF/EZARoVGykcOR1NHmUfeSCNIaUivSPVJO0mB
+ ScdKDkpVSptK4ksqS3FLuEwATEhMkEzYTSBNaE2xTfpOQk6MTtVPHk9nT7FP+1BFUI9Q
+ 2VEkUW5RuVIEUk9SmlLlUzFTfFPIVBRUYFStVPlVRlWSVd9WLFZ6VsdXFFdiV7BX/lhM
+ WJpY6Vk4WYZZ1VokWnRaw1sTW2NbslwDXFNco1z0XURdlV3mXjdeiV7aXyxffl/QYCJg
+ dGDHYRlhbGG/YhJiZWK5YwxjYGO0ZAhkXGSxZQVlWmWvZgRmWWavZwRnWmewaAZoXGiy
+ aQlpX2m2ag1qZGq8axNra2vDbBtsc2zLbSNtfG3Vbi5uh27gbzpvk2/tcEdwoXD7cVZx
+ sHILcmZywXMcc3hz03QvdIt053VDdaB1/HZZdrZ3E3dwd854K3iJeOd5RXmjegJ6YHq/
+ ex57fXvcfDx8m3z7fVt9u34bfnx+3H89f55//4BggMKBI4GFgeeCSYKrgw6DcIPThDaE
+ mYT8hWCFw4YnhouG74dUh7iIHYiBiOaJTImxihaKfIrii0iLrowUjHuM4o1Ija+OF45+
+ juWPTY+1kB2QhZDukVaRv5IokpGS+pNkk82UN5ShlQuVdZXglkqWtZcgl4uX95himM6Z
+ OpmmmhKafprrm1ebxJwxnJ+dDJ15neeeVZ7DnzGfoKAPoH2g7KFbocuiOqKqoxqjiqP6
+ pGqk26VMpbymLqafpxCngqf0qGWo2KlKqbyqL6qiqxWriKv7rG+s461WrcuuP66zryiv
+ nbARsIew/LFxseeyXbLTs0mzv7Q2tK21JLWbthK2ibcBt3m38bhpuOG5WrnSuku6xLs+
+ u7e8MLyqvSS9nr4ZvpO/Dr+JwATAf8D6wXbB8cJtwunDZsPixF/E3MVZxdbGU8bRx07H
+ zMhKyMnJR8nGykXKxMtDy8LMQszBzUHNwc5CzsLPQ8/D0ETQxtFH0cjSStLM007T0NRT
+ 1NbVWNXb1l7W4tdl1+nYbdjx2XXZ+tp/2wPbiNwO3JPdGd2e3iTeqt8x37fgPuDF4Uzh
+ 0+Ja4uLjauPy5HrlAuWL5hPmnOcl56/oOOjC6Uzp1upg6urrdev/7IrtFu2h7izuuO9E
+ 79DwXPDp8XXyAvKP8xzzqvQ39MX1U/Xh9m/2/veM+Bv4qvk5+cn6Wfro+3j8CPyZ/Sn9
+ uv5L/tz/bmN1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBK
+ AE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYA
+ ywDQANUA2gDgAOUA6gDwAPUA+wEBAQcBDAESARgBHgElASsBMQE4AT4BRQFLAVIBWQFg
+ AWYBbQF1AXwBgwGKAZIBmQGhAagBsAG4AcAByAHQAdgB4AHpAfEB+gICAgsCFAIcAiUC
+ LgI3AkACSgJTAlwCZgJwAnkCgwKNApcCoQKrArUCvwLKAtQC3wLqAvQC/wMKAxUDIAMr
+ AzcDQgNNA1kDZQNwA3wDiAOUA6ADrAO5A8UD0gPeA+sD+AQEBBEEHgQsBDkERgRUBGEE
+ bwR8BIoEmASmBLQEwgTRBN8E7gT8BQsFGgUoBTcFRwVWBWUFdAWEBZMFowWzBcMF0wXj
+ BfMGAwYUBiQGNQZFBlYGZwZ4BokGmgarBr0GzgbgBvIHAwcVBycHOQdMB14HcAeDB5YH
+ qAe7B84H4Qf0CAgIGwgvCEIIVghqCH4IkgimCLoIzgjjCPcJDAkhCTYJSwlgCXUJigmg
+ CbUJywngCfYKDAoiCjkKTwplCnwKkgqpCsAK1wruCwULHQs0C0sLYwt7C5MLqwvDC9sL
+ 8wwMDCQMPQxWDG4MhwyhDLoM0wztDQYNIA06DVQNbg2IDaINvA3XDfEODA4nDkIOXQ54
+ DpMOrw7KDuYPAg8eDzoPVg9yD44Pqw/ID+QQARAeEDsQWBB2EJMQsRDOEOwRChEoEUYR
+ ZBGDEaERwBHfEf4SHRI8ElsSehKaErkS2RL5ExkTORNZE3oTmhO7E9sT/BQdFD4UXxSB
+ FKIUxBTlFQcVKRVLFW0VkBWyFdUV9xYaFj0WYBaDFqcWyhbuFxIXNRdZF30XohfGF+oY
+ Dxg0GFkYfRijGMgY7RkTGTgZXhmEGaoZ0Bn2Gh0aQxpqGpAatxreGwYbLRtUG3wboxvL
+ G/McGxxDHGwclBy9HOYdDh03HWAdih2zHd0eBh4wHloehB6uHtgfAx8tH1gfgx+uH9kg
+ BCAwIFsghyCzIN4hCiE3IWMhjyG8IekiFSJCInAinSLKIvgjJSNTI4EjryPdJAwkOiRp
+ JJckxiT1JSQlVCWDJbMl4iYSJkImciajJtMnAyc0J2UnlifHJ/goKihbKI0ovijwKSIp
+ VSmHKbkp7CofKlIqhSq4KusrHitSK4YruivuLCIsViyKLL8s9C0pLV4tky3ILf0uMy5p
+ Lp4u1C8LL0Evdy+uL+QwGzBSMIkwwTD4MTAxZzGfMdcyDzJIMoAyuDLxMyozYzOcM9U0
+ DzRINII0vDT2NTA1ajWlNd82GjZVNpA2yzcGN0I3fje5N/U4MThtOKo45jkjOWA5nTna
+ Ohc6VDqSOs87DTtLO4k7xzwGPEQ8gzzCPQE9QD1/Pb89/j4+Pn4+vj7+Pz8/fz/AQABA
+ QUCCQMRBBUFHQYhBykIMQk5CkULTQxZDWEObQ95EIURlRKhE7EUwRXRFuEX8RkBGhUbK
+ Rw5HU0eZR95II0hpSK9I9Uk7SYFJx0oOSlVKm0riSypLcUu4TABMSEyQTNhNIE1oTbFN
+ +k5CToxO1U8eT2dPsU/7UEVQj1DZUSRRblG5UgRST1KaUuVTMVN8U8hUFFRgVK1U+VVG
+ VZJV31YsVnpWx1cUV2JXsFf+WExYmljpWThZhlnVWiRadFrDWxNbY1uyXANcU1yjXPRd
+ RF2VXeZeN16JXtpfLF9+X9BgImB0YMdhGWFsYb9iEmJlYrljDGNgY7RkCGRcZLFlBWVa
+ Za9mBGZZZq9nBGdaZ7BoBmhcaLJpCWlfabZqDWpkarxrE2tra8NsG2xzbMttI218bdVu
+ Lm6HbuBvOm+Tb+1wR3ChcPtxVnGwcgtyZnLBcxxzeHPTdC90i3TndUN1oHX8dll2tncT
+ d3B3zngreIl453lFeaN6Anpger97Hnt9e9x8PHybfPt9W327fht+fH7cfz1/nn//gGCA
+ woEjgYWB54JJgquDDoNwg9OENoSZhPyFYIXDhieGi4bvh1SHuIgdiIGI5olMibGKFop8
+ iuKLSIuujBSMe4zijUiNr44Xjn6O5Y9Nj7WQHZCFkO6RVpG/kiiSkZL6k2STzZQ3lKGV
+ C5V1leCWSpa1lyCXi5f3mGKYzpk6maaaEpp+muubV5vEnDGcn50MnXmd555VnsOfMZ+g
+ oA+gfaDsoVuhy6I6oqqjGqOKo/qkaqTbpUylvKYupp+nEKeCp/SoZajYqUqpvKovqqKr
+ FauIq/usb6zjrVaty64/rrOvKK+dsBGwh7D8sXGx57JdstOzSbO/tDa0rbUktZu2EraJ
+ twG3ebfxuGm44blaudK6S7rEuz67t7wwvKq9JL2evhm+k78Ov4nABMB/wPrBdsHxwm3C
+ 6cNmw+LEX8TcxVnF1sZTxtHHTsfMyErIyclHycbKRcrEy0PLwsxCzMHNQc3BzkLOws9D
+ z8PQRNDG0UfRyNJK0szTTtPQ1FPU1tVY1dvWXtbi12XX6dht2PHZddn62n/bA9uI3A7c
+ k90Z3Z7eJN6q3zHft+A+4MXhTOHT4lri4uNq4/LkeuUC5YvmE+ac5yXnr+g46MLpTOnW
+ 6mDq6ut16//siu0W7aHuLO6470Tv0PBc8OnxdfIC8o/zHPOq9Df0xfVT9eH2b/b+94z4
+ G/iq+Tn5yfpZ+uj7ePwI/Jn9Kf26/kv+3P9uY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZ
+ AB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUA
+ mgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDaAOAA5QDqAPAA9QD7AQEBBwEMARIBGAEe
+ ASUBKwExATgBPgFFAUsBUgFZAWABZgFtAXUBfAGDAYoBkgGZAaEBqAGwAbgBwAHIAdAB
+ 2AHgAekB8QH6AgICCwIUAhwCJQIuAjcCQAJKAlMCXAJmAnACeQKDAo0ClwKhAqsCtQK/
+ AsoC1ALfAuoC9AL/AwoDFQMgAysDNwNCA00DWQNlA3ADfAOIA5QDoAOsA7kDxQPSA94D
+ 6wP4BAQEEQQeBCwEOQRGBFQEYQRvBHwEigSYBKYEtATCBNEE3wTuBPwFCwUaBSgFNwVH
+ BVYFZQV0BYQFkwWjBbMFwwXTBeMF8wYDBhQGJAY1BkUGVgZnBngGiQaaBqsGvQbOBuAG
+ 8gcDBxUHJwc5B0wHXgdwB4MHlgeoB7sHzgfhB/QICAgbCC8IQghWCGoIfgiSCKYIugjO
+ COMI9wkMCSEJNglLCWAJdQmKCaAJtQnLCeAJ9goMCiIKOQpPCmUKfAqSCqkKwArXCu4L
+ BQsdCzQLSwtjC3sLkwurC8ML2wvzDAwMJAw9DFYMbgyHDKEMugzTDO0NBg0gDToNVA1u
+ DYgNog28DdcN8Q4MDicOQg5dDngOkw6vDsoO5g8CDx4POg9WD3IPjg+rD8gP5BABEB4Q
+ OxBYEHYQkxCxEM4Q7BEKESgRRhFkEYMRoRHAEd8R/hIdEjwSWxJ6EpoSuRLZEvkTGRM5
+ E1kTehOaE7sT2xP8FB0UPhRfFIEUohTEFOUVBxUpFUsVbRWQFbIV1RX3FhoWPRZgFoMW
+ pxbKFu4XEhc1F1kXfReiF8YX6hgPGDQYWRh9GKMYyBjtGRMZOBleGYQZqhnQGfYaHRpD
+ GmoakBq3Gt4bBhstG1QbfBujG8sb8xwbHEMcbByUHL0c5h0OHTcdYB2KHbMd3R4GHjAe
+ Wh6EHq4e2B8DHy0fWB+DH64f2SAEIDAgWyCHILMg3iEKITchYyGPIbwh6SIVIkIicCKd
+ Isoi+CMlI1MjgSOvI90kDCQ6JGkklyTGJPUlJCVUJYMlsyXiJhImQiZyJqMm0ycDJzQn
+ ZSeWJ8cn+CgqKFsojSi+KPApIilVKYcpuSnsKh8qUiqFKrgq6yseK1Irhiu6K+4sIixW
+ LIosvyz0LSktXi2TLcgt/S4zLmkuni7ULwsvQS93L64v5DAbMFIwiTDBMPgxMDFnMZ8x
+ 1zIPMkgygDK4MvEzKjNjM5wz1TQPNEg0gjS8NPY1MDVqNaU13zYaNlU2kDbLNwY3Qjd+
+ N7k39TgxOG04qjjmOSM5YDmdOdo6FzpUOpI6zzsNO0s7iTvHPAY8RDyDPMI9AT1APX89
+ vz3+Pj4+fj6+Pv4/Pz9/P8BAAEBBQIJAxEEFQUdBiEHKQgxCTkKRQtNDFkNYQ5tD3kQh
+ RGVEqETsRTBFdEW4RfxGQEaFRspHDkdTR5lH3kgjSGlIr0j1STtJgUnHSg5KVUqbSuJL
+ KktxS7hMAExITJBM2E0gTWhNsU36TkJOjE7VTx5PZ0+xT/tQRVCPUNlRJFFuUblSBFJP
+ UppS5VMxU3xTyFQUVGBUrVT5VUZVklXfVixWelbHVxRXYlewV/5YTFiaWOlZOFmGWdVa
+ JFp0WsNbE1tjW7JcA1xTXKNc9F1EXZVd5l43Xole2l8sX35f0GAiYHRgx2EZYWxhv2IS
+ YmViuWMMY2BjtGQIZFxksWUFZVplr2YEZllmr2cEZ1pnsGgGaFxosmkJaV9ptmoNamRq
+ vGsTa2trw2wbbHNsy20jbXxt1W4ubodu4G86b5Nv7XBHcKFw+3FWcbByC3JmcsFzHHN4
+ c9N0L3SLdOd1Q3Wgdfx2WXa2dxN3cHfOeCt4iXjneUV5o3oCemB6v3see3173Hw8fJt8
+ +31bfbt+G358ftx/PX+ef/+AYIDCgSOBhYHngkmCq4MOg3CD04Q2hJmE/IVghcOGJ4aL
+ hu+HVIe4iB2IgYjmiUyJsYoWinyK4otIi66MFIx7jOKNSI2vjheOfo7lj02PtZAdkIWQ
+ 7pFWkb+SKJKRkvqTZJPNlDeUoZULlXWV4JZKlrWXIJeLl/eYYpjOmTqZppoSmn6a65tX
+ m8ScMZyfnQydeZ3nnlWew58xn6CgD6B9oOyhW6HLojqiqqMao4qj+qRqpNulTKW8pi6m
+ n6cQp4Kn9KhlqNipSqm8qi+qoqsVq4ir+6xvrOOtVq3Lrj+us68or52wEbCHsPyxcbHn
+ sl2y07NJs7+0NrSttSS1m7YStom3Abd5t/G4abjhuVq50rpLusS7Pru3vDC8qr0kvZ6+
+ Gb6Tvw6/icAEwH/A+sF2wfHCbcLpw2bD4sRfxNzFWcXWxlPG0cdOx8zISsjJyUfJxspF
+ ysTLQ8vCzELMwc1BzcHOQs7Cz0PPw9BE0MbRR9HI0krSzNNO09DUU9TW1VjV29Ze1uLX
+ Zdfp2G3Y8dl12fraf9sD24jcDtyT3Rndnt4k3qrfMd+34D7gxeFM4dPiWuLi42rj8uR6
+ 5QLli+YT5pznJeev6DjowulM6dbqYOrq63Xr/+yK7Rbtoe4s7rjvRO/Q8Fzw6fF18gLy
+ j/Mc86r0N/TF9VP14fZv9v73jPgb+Kr5OfnJ+ln66Pt4/Aj8mf0p/br+S/7c/25wYXJh
+ AAAAAAADAAAAAmZmAADypwAADVkAABPQAAALA3BhcmEAAAAAAAMAAAACZmYAAPKnAAAN
+ WQAAE9AAAAsDcGFyYQAAAAAAAwAAAAJmZgAA8qcAAA1ZAAAT0AAACwN2Y2d0AAAAAAAA
+ AAAAAwEAAAIAAAARAE8AwAE1AacCKQKoAzgD0QRyBSEF2gaYB2MIPwkjCg8LDQwRDSUO
+ PQ9cEIcRuxL2FDsVexbKGBYZaRrBHBgddB7QIC0hkyMbJKEmLCezKUUq0ixlLfovkDEm
+ MsM0XTX6N5g5OTrXPHo+Gj++QWFDAkSqRk5H9UmdS0JMzE4TT1FQj1HNUw1UTVWOVs9Y
+ EFlUWpZb110aXltfn2DiYiVjamStZfFnNWh6ab9rBmwpbTFuNm87cEFxRnJKc050UnVW
+ dlh3WXhaeVp6WntYfFd9VH5Rf02ASoFGgkKDPYQ3hTCGKocmiCKJHoobixmMF40WjheP
+ F5AZkRySH5MjlCeVLZYzlzmYP5lFmkibSZxKnUyeTZ9PoFGhUqJTo1OkU6VTplKnUahP
+ qU2qSqtHrEWtQq4/r0CwS7FesnCzg7SWtai2ubfKuNy57Lr7vAq9Gb4nvzTAQsFOwlvD
+ Z8R0xXvGc8dnyFrJTco+yy/MHs0NzfvO5s/Q0LnRoNKG02rUTtUw1hLW9NfV2KXZc9pB
+ 2w3b2tyk3W3eNd7838DgguFE4gTiwuN+5Dnk9OWu5mbnG+fF6GzpE+m56lzq/+ue7Dzs
+ 1+1u7gTulu8m77PwPfDG8Uzx0vJa8uTzcfP99IX1DfWQ9hP2kfcO94n4BfiB+P/5iPoY
+ +sP7k/yd/g///wAAAAwAOACJAQEBTgGvAhsCgAL1A2cD5gRqBPsFjwYvBt0HlAhXCSYJ
+ /ArgC9EMzw3bDu4QDBEvEmATmRTaFiEXcBjAGhgbeRzrHnMf+yGGIxIkniYpJ7UpOirB
+ LEItxC9BMLkyMjOfNQ02dzfaOTo6kzvqPT4+kD/eQSpCc0OxRNpGAUcoSFBJdkqeS8RM
+ 6U4OTzNQV1F6Up1TvlTfVgBXIFhAWV9afVucXLtd2V75YAthEmIYYx9kJWUsZjJnOGg8
+ aUBqQ2tFbERtQm5AbztwNHEtciNzGHQMdP918Xbdd8F4pXmJem57VHw6fSF+Cn7zf92A
+ yYG1gqKDkIR9hWyGW4dMiDyJLIodiw6MAIzyjeWO2I/NkMKRuJKtk6OUmpWPloWXephu
+ mWGaU5tEnDSdJJ4TnwGf86DwofOi9qP5pPul/ab9p/2o/an7qvmr96z2rfSu8q/ysPCx
+ 8LLxs/O097YCtw24GLkiuiu7NLw7vUK+SL9OwFPBWcJew2TEasVxxnjHgciJyZLKjcuE
+ zHzNdc5tz2XQXNFT0krTQNQ11SjWG9cM1/3Y69nY2sXbsNyY3XzeXt9B4CThB+Hp4svj
+ ruSP5W/mT+cu6Azo6enE6p7rd+xQ7SvuD+757+bw1fHH8rvzsPSn9Z/2mPeR+Ij5fvpy
+ +2X8Vf1C/i3/F///AAAAEQBPAMABLAGMAgQCYQLRA0QDvgQ9BMAFRQXKBlcG6weACBwI
+ uAlaCgIKrQteDBYMzA2IDkoPDw/VEKARbxJAExQT6BTAFbgWyxfoGQYaJRtCHGUdhR6l
+ H8cg6SIMIzEkUCV0JpYnuCjdKgArIixFLWkuiy+vMNIx9jMbNDc1JzYWNwg3+jjtOeA6
+ 1DvIPL09sj6oP55AlUGMQoRDfER0RW1GZkdfSFpJVUpQS0tMPE0lTg1O9U/dUMdRsVKa
+ U4RUblVZVkRXLlgYWQRZ71raW8Zcsl2eXotfeGBlYUtiJGL7Y9Jkq2WDZlxnNGgMaOVp
+ vWqWa25sRW0dbfRuy2+jcHpxUnIpcwBz0XSadV92I3bod614dHk6egJ6ynuSfFx9Jn3w
+ frt/h4BTgSCB7YK6g4mEV4UmhfSGw4eSiGGJMIoAitCLoYxyjUSOFo7pj7yQj5FjkjeT
+ DJPhlLeVjJZll0SYJZkHmemay5uunJCddJ5XnzugIKEEoemiz6O1pJulgaZop0+oPak7
+ qkSrTaxXrWKuba94sIaxlLKjs7O0xLXWtui3/LkQuiW7O7xSvXK+pb/fwRzCW8OdxOPG
+ LMd5yMjKG8twzMbOH8950NTSM9OQ1O7WTtev2Q/abtv83cXfl+Ft40nlL+cj6SjrRO13
+ 78fyM/S992X6Kf0I//8AAG5kaW4AAAAAAAAGNgAApaEAAFanAABPbwAAoWgAACX9AAAO
+ 0gAAUA0AAFQ5AAL1wgACXrgAAZHrAAMBAAACAAAABQAPAB0ALQA/AFIAZwB8AJIAqQDA
+ ANgA8AEJASMBPQFYAXMBjwGrAckB5wIFAiUCRQJmAocCqgLNAvEDFgM8A2MDhwOrA9AD
+ 9gQcBEQEawSTBLwE5gUQBToFZgWSBb4F7AYZBkgGdwanBtcHCAc6B2wHnwfTCAcIPAhy
+ CKgI3wkXCVAJiQnCCf0KOAp0CrAK7QsrC2oLqQv4DE8Mpw0ADVsNtg4TDnEO0A8wD5IP
+ 9RBYEL0RJBGMEfUSYBLLEzgTphQWFIYU+BVsFeAWVhbNF0UXvhg4GMsZaBoHGqgbSxvw
+ HJgdQh3vHp0fTyAEILshdSIxIvEjsyR4JUAmCibXJ6YoeClNKiUrACvdLLotmi58L18w
+ RDErMhMy/TPpNNU1xDa0N6Y4mTmOOoU7fjx4PXc+ez+CQItBlkKkQ7RExkXbRvNIDkkr
+ SktLb0yVTb9O61AaUUxSgFO3VPBWJFdKWHFZm1rGW/RdJF5YX45gxWIAYz5kf2XCZwho
+ UmmcauxsPW2QbuZwPnGjcyR0pnYtd7h5R3rcfHV+En+3gWKDEYTHhoSIRooNi9qNq4+A
+ kYCTiJWXl6yZypvxniCgW6KhpPCnTam0rCSunrEfs922rLmKvHq/gMKhxeXJS8zX0IjU
+ W9ga28rfpeOs5+nsTvCv9LH38Ppu/En9tv7o//8AAAAHABYAKwBEAF8AfACZALcA1QD0
+ ARMBMgFRAXABkAGwAdEB8gITAjUCVwJ6Ap0CwQLmAwsDMANWA3oDngPCA+gEDgQ0BFwE
+ hAStBNcFAQUtBVoFhwW2BeYGFgZIBnsGrwblBxsHVAeNB8gIBAhCCIIIwwkGCUsJkQnZ
+ CiIKbQq6CwgLWAuqDAQMYgzBDSINhA3oDk0OtA8dD4gP9BBiENIRRBG3Ei0SpRMeE5kU
+ FhSVFRYVmRYdFqMXKxe1GD8Y1xl0GhIashtVG/kcoB1JHfUepB9VIAogwiF+Ijwi/yPF
+ JI4lXCYtJwEn2ii1KZ8qjit/LHItZi5dL1YwTzFLMkgzRzRINUo2TzdWOF45aDp1O4U8
+ lj2qPr8/10DwQgtDKERGRWdGikevSNhKA0syTGVNnE7WUBVRWFKeU+hVNVZ3V61Y51oj
+ W2NcpV3sXzZggmHSYyZkfGXUZy9ojWnra01ssG4Ub3pw4HI+c550/3Zkd815OHqofBt9
+ kX8KgIaCBoOHhQqGkIgXiaCLKoy1jkKP0ZGAkzGU45aYmE+aC5vKnYufUaEcou2kwaac
+ qHuqYqxOrj6wNbI2tEi2W7hxuoq8p77JwO3DGcVKx3/JvcwAzkzQntL21VXXnNnS3AXe
+ NuBk4o/kuebj6Q3rOe1p76Dx3PQh9m74xfsl/Y///wAAAAUAEQAkADsAVgB2AJgAvQDl
+ AQ8BOwFoAZgByQH8AjECZwKfAtkDFQNSA4YDuQPsBCEEVwSPBMcFAQU9BXoFuAX4BjkG
+ ewbABwUHTAeVB98IKgh3CMYJFglnCbsKDwplCr0LFgtwC88MQQy2DSwNpA4eDpoPGA+Y
+ EBoQnhEkEawSNhLCE1AT4BRyFQYVnRY0Fs4XahgIGK8ZXxoSGscbfxw4HPQdsx50Hzcf
+ /SDGIZEiXiMuJAAk1SWsJoUnYSg/KSYqISsfLB8tIi4oLzIwPjFOMmEzeDSSNbA20jf2
+ OR86Sjt5PKs99T9MQKdCBUNlRMhGLUeVSP9Ka0vbTUxOwFA3UbFTLVSsVi1XtVk+Wstc
+ Wl3tX4JhGWKzZFBl72eRaTVq3GyGbjJv4XGNcy100HZ1eB15x3t1fSN+1ICIgj+D94Wy
+ h2+JL4ryjLaOfZAzkcaTW5TxlomYIZm7m1ic856QoC6hzaNtpQ2msKhRqfarm61Bruiw
+ kLIls6S1IraguB25mLsTvIu+A794wO3CYcPTxUXGtsgoyZrLDMx+zfHPYdDV0knTv9U0
+ 1qrYIdma2xXckd3V3wDgI+FG4mjji+Sr5cvm6OgC6RrqLes97EntTu5R703wRvE68inz
+ E/P59Nz1uvaV9234QPkS+d/6rPt0/Dz8//3C/oL/Qf//AABkZXNjAAAAAAAAAApDb2xv
+ ciBMQ0QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbWx1YwAAAAAAAAASAAAADG5s
+ TkwAAAAWAAAA6GRhREsAAAAcAAAA/nBsUEwAAAASAAABGmVuVVMAAAASAAABLG5iTk8A
+ AAASAAABPmZyRlIAAAAWAAABUHB0QlIAAAAYAAABZnB0UFQAAAAWAAABfnpoQ04AAAAM
+ AAABlGVzRVMAAAASAAABoGphSlAAAAAOAAABsnJ1UlUAAAAkAAABwHN2U0UAAAAQAAAB
+ 5HpoVFcAAAAOAAAB9GRlREUAAAAQAAACAmZpRkkAAAAQAAACEml0SVQAAAAUAAACImtv
+ S1IAAAAMAAACNgBLAGwAZQB1AHIAZQBuAC0ATABDAEQATABDAEQALQBmAGEAcgB2AGUA
+ cwBrAOYAcgBtAEsAbwBsAG8AcgAgAEwAQwBEAEMAbwBsAG8AcgAgAEwAQwBEAEYAYQBy
+ AGcAZQAtAEwAQwBEAEwAQwBEACAAYwBvAHUAbABlAHUAcgBMAEMARAAgAEMAbwBsAG8A
+ cgBpAGQAbwBMAEMARAAgAGEAIABDAG8AcgBlAHNfaYJyACAATABDAEQATABDAEQAIABj
+ AG8AbABvAHIwqzDpMPwAIABMAEMARAQmBDIENQRCBD0EPgQ5ACAEFgQaAC0ENAQ4BEEE
+ PwQ7BDUEOQBGAOQAcgBnAC0ATABDAERfaYJybbJmdphveTpWaABGAGEAcgBiAC0ATABD
+ AEQAVgDkAHIAaQAtAEwAQwBEAEwAQwBEACAAYwBvAGwAbwByAGnO7LfsACAATABDAEQA
+ AG1tb2QAAAAAAAAGEAAAnKMAAAAAxXh9gAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENv
+ cHlyaWdodCBBcHBsZSwgSW5jLiwgMjAxMAA=
+ </data>
+ <key>ReadOnly</key>
+ <string>NO</string>
+ <key>RowAlign</key>
+ <integer>1</integer>
+ <key>RowSpacing</key>
+ <real>36</real>
+ <key>SheetTitle</key>
+ <string>Canvas 1</string>
+ <key>SmartAlignmentGuidesActive</key>
+ <string>YES</string>
+ <key>SmartDistanceGuidesActive</key>
+ <string>YES</string>
+ <key>UniqueID</key>
+ <integer>1</integer>
+ <key>UseEntirePage</key>
+ <false/>
+ <key>VPages</key>
+ <integer>1</integer>
+ <key>WindowInfo</key>
+ <dict>
+ <key>CurrentSheet</key>
+ <integer>0</integer>
+ <key>ExpandedCanvases</key>
+ <array>
+ <dict>
+ <key>name</key>
+ <string>Canvas 1</string>
+ </dict>
+ </array>
+ <key>Frame</key>
+ <string>{{1, 0}, {1022, 878}}</string>
+ <key>ListView</key>
+ <true/>
+ <key>OutlineWidth</key>
+ <integer>142</integer>
+ <key>RightSidebar</key>
+ <false/>
+ <key>ShowRuler</key>
+ <true/>
+ <key>Sidebar</key>
+ <false/>
+ <key>SidebarWidth</key>
+ <integer>120</integer>
+ <key>VisibleRegion</key>
+ <string>{{-25, -13}, {806.4, 579.2}}</string>
+ <key>Zoom</key>
+ <real>1.25</real>
+ <key>ZoomValues</key>
+ <array>
+ <array>
+ <string>Canvas 1</string>
+ <real>1.25</real>
+ <real>1</real>
+ </array>
+ </array>
+ </dict>
+ <key>saveQuickLookFiles</key>
+ <string>YES</string>
+</dict>
+</plist>
Property changes on: CalendarServer/branches/users/cdaboo/partition-4464/doc/Extensions/caldav-privatecomments.txt
___________________________________________________________________
Deleted: svn:mergeinfo
- /CalendarServer/branches/config-separation/doc/Extensions/caldav-privatecomments.txt:4379-4443
/CalendarServer/branches/users/cdaboo/attendee-comments-2886/doc/Extensions/caldav-privatecomments-00.txt:2887-2910
/CalendarServer/branches/users/cdaboo/byebye-serviceslocator-2937/doc/Extensions/caldav-privatecomments-00.txt:2938-3097
/CalendarServer/branches/users/cdaboo/implicit-if-match-3306/doc/Extensions/caldav-privatecomments.txt:3307-3349
/CalendarServer/branches/users/cdaboo/implicitauto-2947/doc/Extensions/caldav-privatecomments-00.txt:2948-2989
/CalendarServer/branches/users/cdaboo/location-partial-accept-3573/doc/Extensions/caldav-privatecomments.txt:3574-3581
/CalendarServer/branches/users/sagen/resource-delegates-4038/doc/Extensions/caldav-privatecomments.txt:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/doc/Extensions/caldav-privatecomments.txt:4068-4075
/CalendarServer/trunk/doc/Extensions/caldav-privatecomments.txt:4465-4858
Property changes on: CalendarServer/branches/users/cdaboo/partition-4464/doc/Extensions/caldav-privatecomments.xml
___________________________________________________________________
Deleted: svn:mergeinfo
- /CalendarServer/branches/config-separation/doc/Extensions/caldav-privatecomments.xml:4379-4443
/CalendarServer/branches/users/cdaboo/attendee-comments-2886/doc/Extensions/caldav-privatecomments-00.xml:2887-2910
/CalendarServer/branches/users/cdaboo/byebye-serviceslocator-2937/doc/Extensions/caldav-privatecomments-00.xml:2938-3097
/CalendarServer/branches/users/cdaboo/implicit-if-match-3306/doc/Extensions/caldav-privatecomments.xml:3307-3349
/CalendarServer/branches/users/cdaboo/implicitauto-2947/doc/Extensions/caldav-privatecomments-00.xml:2948-2989
/CalendarServer/branches/users/cdaboo/location-partial-accept-3573/doc/Extensions/caldav-privatecomments.xml:3574-3581
/CalendarServer/branches/users/sagen/resource-delegates-4038/doc/Extensions/caldav-privatecomments.xml:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/doc/Extensions/caldav-privatecomments.xml:4068-4075
/CalendarServer/trunk/doc/Extensions/caldav-privatecomments.xml:4465-4858
Copied: CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-daboo-srv-caldav.txt (from rev 4951, CalendarServer/trunk/doc/RFC/draft-daboo-srv-caldav.txt)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-daboo-srv-caldav.txt (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-daboo-srv-caldav.txt 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,504 @@
+
+
+
+Network Working Group C. Daboo
+Internet-Draft Apple Inc.
+Intended status: Standards Track October 4, 2009
+Expires: April 7, 2010
+
+
+ Use of SRV records for locating CalDAV and CardDAV services
+ draft-daboo-srv-caldav-01
+
+Status of This Memo
+
+ This Internet-Draft is submitted to IETF in full conformance with the
+ provisions of BCP 78 and BCP 79.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF), its areas, and its working groups. Note that
+ other groups may also distribute working documents as Internet-
+ Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt.
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+ This Internet-Draft will expire on April 7, 2010.
+
+Copyright Notice
+
+ Copyright (c) 2009 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents in effect on the date of
+ publication of this document (http://trustee.ietf.org/license-info).
+ Please review these documents carefully, as they describe your rights
+ and restrictions with respect to this document.
+
+Abstract
+
+ This specification describes how SRV records and well-known URIs can
+ be used to locate Calendaring Extensions to WebDAV (CalDAV) or vCard
+ Extensions to WebDAV (CardDAV) services.
+
+
+
+Daboo Expires April 7, 2010 [Page 1]
+
+Internet-Draft SRV for CalDAV October 2009
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2. Conventions Used in This Document . . . . . . . . . . . . . . . 3
+ 3. CalDAV SRV Service Types . . . . . . . . . . . . . . . . . . . 4
+ 4. CalDAV and CardDAV Service Well-Known URI . . . . . . . . . . . 4
+ 4.1. Example: well-known URI as context path . . . . . . . . . . 4
+ 4.2. Example: well-known URI redirects to actual context
+ path . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 5. Client "Bootstrapping" Guidelines . . . . . . . . . . . . . . . 5
+ 6. Security Considerations . . . . . . . . . . . . . . . . . . . . 6
+ 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 6
+ 7.1. caldav Well-Known URI Registration . . . . . . . . . . . . 7
+ 7.2. carddav Well-Known URI Registration . . . . . . . . . . . . 7
+ 8. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . 7
+ 9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 7
+ 9.1. Normative References . . . . . . . . . . . . . . . . . . . 7
+ 9.2. Informative References . . . . . . . . . . . . . . . . . . 8
+ Appendix A. Change History (to be removed prior to
+ publication as an RFC) . . . . . . . . . . . . . . . . 9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo Expires April 7, 2010 [Page 2]
+
+Internet-Draft SRV for CalDAV October 2009
+
+
+1. Introduction
+
+ [RFC2782] defines a DNS-based service discovery protocol that has
+ been widely adopted as a means of locating particular services within
+ a local area network and beyond, using SRV RR records.
+
+ [RFC4791] defines the CalDAV Calendar Access protocol, based on HTTP
+ [RFC2616], for accessing calendar data stored on a server. CalDAV
+ clients need to be able to discover appropriate CalDAV servers within
+ their local area network and at other domains, e.g., to minimize the
+ need for end users to know specific details such as hostname and port
+ for their servers.
+
+ [I-D.ietf-vcarddav-carddav] defines the CardDAV vCard Access protocol
+ based on HTTP [RFC2616], for accessing contact data stored on a
+ server. As with CalDAV, clients also need to be able to discover
+ CardDAV servers.
+
+ This specification defines new SRV service types for the CalDAV
+ protocol, and gives an example of how clients can use this together
+ with other protocol features to enable simple client configuration.
+ SRV service types for CardDAV are already defined in Section 11 of
+ [I-D.ietf-vcarddav-carddav].
+
+ Another issue with CalDAV or CardDAV service discovery is that the
+ service may not be located at the "root" URI of the HTTP server
+ hosting it. For example, if CalDAV is implemented as a "servlet" in
+ a web server "container", the servlet "context path" might be
+ "/caldav/". So the URI for the CalDAV service would be, e.g.,
+ "http://caldav.example.com/caldav/" rather than
+ "http://caldav.example.com/". SRV records by themselves only provide
+ a hostname and port for the service, not a path. Since the client
+ "bootstrapping" process requires initial access to the "context path"
+ of the service, there needs to be a simple way for clients to also
+ discover what that path is.
+
+ This specification makes use of the "well known URI" feature
+ [I-D.nottingham-site-meta] of HTTP servers to provide a well known
+ URI for CalDAV or CardDAV services that clients can make use of. The
+ well known URI will point to a resource on the server that might be
+ the actual "context path" of the CalDAV or CardDAV service, or it
+ might simply be a "stub" resource that provides a redirect to the
+ actual "context path".
+
+2. Conventions Used in This Document
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+
+
+
+Daboo Expires April 7, 2010 [Page 3]
+
+Internet-Draft SRV for CalDAV October 2009
+
+
+ document are to be interpreted as described in [RFC2119].
+
+3. CalDAV SRV Service Types
+
+ This specification adds two service types for use with SRV records:
+
+ caldav: Identifies a CalDAV server that uses HTTP without transport
+ layer security ([RFC2818]).
+
+ caldavs: Identifies a CalDAV server that uses HTTP with transport
+ layer security ([RFC2818]).
+
+ Clients SHOULD honor "TTL", "Priority" and "Weight" values in the SRV
+ records, as described by [RFC2782].
+
+ Example: service record for server without transport layer security
+
+ _caldav._tcp SRV 0 1 80 calendar.example.com.
+
+ Example: service record for server with transport layer security
+
+ _caldavs._tcp SRV 0 1 443 calendar.example.com.
+
+4. CalDAV and CardDAV Service Well-Known URI
+
+ Two "well-known" URIs are registered by this specification for CalDAV
+ and CardDAV services, "caldav" and "carddav" respectively (see
+ Section 7). These URIs point to a resource that the client can use
+ as the "context path" for the service they are trying to use. The
+ actual service could be located at that specific path. Alternatively
+ the server MAY redirect HTTP requests for that resource (using the
+ "301 Moved Permanently" status response) to the actual "context
+ path". Clients MUST handle HTTP redirects on the well-known URI.
+
+4.1. Example: well-known URI as context path
+
+ A CalDAV server has a "context path" that is the same as the well-
+ known URI, so the client will use "/.well-known/caldav" as the path
+ for its "bootstrapping" process after it has first found the hostname
+ and port via an SRV lookup.
+
+4.2. Example: well-known URI redirects to actual context path
+
+ A CalDAV server has a "context path" that is "/servlet/caldav". The
+ client will use "/.well-known/caldav" as the path for its
+ "bootstrapping" process after it has first found the hostname and
+ port via an SRV lookup. When the client makes its initial HTTP
+ request against "/.well-known/caldav", the server would issue an HTTP
+
+
+
+Daboo Expires April 7, 2010 [Page 4]
+
+Internet-Draft SRV for CalDAV October 2009
+
+
+ 301 redirect response with a Location response header using the path
+ "/servlet/caldav". The client would then "follow" this redirect to
+ the new resource and continue making HTTP requests there to complete
+ its "bootstrapping" process.
+
+5. Client "Bootstrapping" Guidelines
+
+ This section describes a procedure that CalDAV or CardDAV clients MAY
+ use to do their initial configuration based on minimal user input.
+
+ For a CalDAV server, minimal input from a user would consist of a
+ calendar user address. A calendar user address is defined by
+ iCalendar [RFC5545] to be a URI [RFC3986]. Provided a user
+ identifier and a domain name can be extracted from the URI, this
+ simple "bootstrap" configuration can be done.
+
+ If the calendar user address is a "mailto:" [RFC2368] URI, the
+ "mailbox" portion of the URI is examined and the "local-part" and
+ "domain" portions extracted. The "local-part" is used for the user
+ identifier and the "domain" is used as the service domain.
+
+ If the calendar user address is an "http:" [RFC2616] or "https:"
+ [RFC2818] URI, the "userinfo" and "host" portion of the URI is
+ extracted. The "userinfo" is used for the user identifier and the
+ "host" is used as the service domain.
+
+ For a CardDAV server, minimal input from a user would consist of
+ their email address [RFC5322] for the domain where the CardDAV
+ service is hosted. The "mailbox" portion of the email address is
+ examined and the "local-part" and "domain" portions extracted. The
+ "local-part" is used for the user identifier and the "domain" is used
+ as the service domain.
+
+ Once the user identifier and service domain have been extracted, the
+ following is done:
+
+ 1. An SRV lookup for _caldavs._tcp (for CalDAV) or _carddavs._tcp
+ (for CardDAV) is done against the extracted service domain.
+
+ 2. If no result is found for that, the client can try _caldav._tcp
+ (for CalDAV) or _carddav._tcp (for CardDAV) provided non-SSL
+ connections are appropriate.
+
+ 3. If an SRV record is returned the client extracts the server host
+ name and port number.
+
+ 4. The client does an authenticated "PROPFIND" [RFC4791] request
+ using the user identifier, host name and port number and a
+
+
+
+Daboo Expires April 7, 2010 [Page 5]
+
+Internet-Draft SRV for CalDAV October 2009
+
+
+ request URI of "/.well-known/caldav" (for CalDAV) or "/.well-
+ known/carddav" (for CardDAV). The body of the request should
+ include the DAV:current-user-principal [RFC5397] property as one
+ of the properties to return. Note that clients MUST properly
+ handle HTTP redirect responses for the request.
+
+ 5. If the server returns a 404 Not Found HTTP status response to the
+ request on the well-known URI, clients MAY try repeating the
+ request on the "root" URI "/".
+
+ 6. If the DAV:current-user-principal property is returned on the
+ initial request, the client uses that value for the principal-URI
+ of the authenticated user. With that, it can do a "PROPFIND" on
+ the principal-URI and discover additional properties for
+ configuration.
+
+ 7. If the DAV:current-user-principal property is not returned, then
+ the client will need to request the principal-URI path from the
+ user in order to continue with configuration.
+
+6. Security Considerations
+
+ Clients that support transport layer security as defined by [RFC2818]
+ SHOULD try the "caldavs" or "carddavs" services first before trying
+ the "caldav" or "carddav" services respectively. If a user has
+ explicitly requested a connection with transport layer security, the
+ client MUST NOT use any service information returned for the "caldav"
+ or "carddav" services. Clients MUST follow the certificate
+ verification process specified in
+ [I-D.saintandre-tls-server-id-check].
+
+ A malicious attacker with access to the DNS server data can
+ potentially cause clients to connect to any server chosen by the
+ attacker. In the absence of a secure DNS option, clients SHOULD
+ check that the host name returned in the SRV record matches the
+ original service domain that was queried. If the host is not in the
+ queried domain, clients SHOULD verify with the user that the SRV host
+ name is suitable for use before executing any CalDAV or CardDAV
+ requests against the host.
+
+7. IANA Considerations
+
+ This document defines two "well-known" URIs using the registration
+ procedure and template from Section 5.1 of
+ [I-D.nottingham-site-meta].
+
+
+
+
+
+
+Daboo Expires April 7, 2010 [Page 6]
+
+Internet-Draft SRV for CalDAV October 2009
+
+
+7.1. caldav Well-Known URI Registration
+
+ URI suffix: caldav
+
+ Change controller: IETF.
+
+ Specification document(s): This RFC.
+
+ Related information: See also [RFC4791].
+
+7.2. carddav Well-Known URI Registration
+
+ URI suffix: carddav
+
+ Change controller: IETF.
+
+ Specification document(s): This RFC.
+
+ Related information: See also [I-D.ietf-vcarddav-carddav].
+
+8. Acknowledgments
+
+ This specification was suggested by discussion that took place within
+ the Calendaring and Scheduling Consortium's CalDAV Technical
+ Committee. The authors thank the participants of that group for
+ their input. The "bootstrapping" process is based on diagrams
+ developed by Wilfredo Sanchez.
+
+9. References
+
+9.1. Normative References
+
+ [I-D.ietf-vcarddav-carddav] Daboo, C., "vCard Extensions to
+ WebDAV (CardDAV)",
+ draft-ietf-vcarddav-carddav-09
+ (work in progress),
+ September 2009.
+
+ [I-D.nottingham-site-meta] Nottingham, M. and E. Hammer-
+ Lahav, "Defining Well-Known
+ URIs",
+ draft-nottingham-site-meta-03
+ (work in progress),
+ September 2009.
+
+ [I-D.saintandre-tls-server-id-check] Saint-Andre, P., Zeilenga, K.,
+ and J. Hodges, "Server Identity
+ Verification in Application
+
+
+
+Daboo Expires April 7, 2010 [Page 7]
+
+Internet-Draft SRV for CalDAV October 2009
+
+
+ Protocols", draft-saintandre-
+ tls-server-id-check-02 (work in
+ progress), October 2009.
+
+ [RFC2119] Bradner, S., "Key words for use
+ in RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119,
+ March 1997.
+
+ [RFC2368] Hoffman, P., Masinter, L., and
+ J. Zawinski, "The mailto URL
+ scheme", RFC 2368, July 1998.
+
+ [RFC2616] Fielding, R., Gettys, J.,
+ Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P., and T.
+ Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1",
+ RFC 2616, June 1999.
+
+ [RFC2782] Gulbrandsen, A., Vixie, P., and
+ L. Esibov, "A DNS RR for
+ specifying the location of
+ services (DNS SRV)", RFC 2782,
+ February 2000.
+
+ [RFC2818] Rescorla, E., "HTTP Over TLS",
+ RFC 2818, May 2000.
+
+ [RFC3986] Berners-Lee, T., Fielding, R.,
+ and L. Masinter, "Uniform
+ Resource Identifier (URI):
+ Generic Syntax", STD 66,
+ RFC 3986, January 2005.
+
+ [RFC4791] Daboo, C., Desruisseaux, B.,
+ and L. Dusseault, "Calendaring
+ Extensions to WebDAV (CalDAV)",
+ RFC 4791, March 2007.
+
+9.2. Informative References
+
+ [RFC5322] Resnick, P., Ed., "Internet
+ Message Format", RFC 5322,
+ October 2008.
+
+ [RFC5397] Sanchez, W. and C. Daboo,
+ "WebDAV Current Principal
+
+
+
+Daboo Expires April 7, 2010 [Page 8]
+
+Internet-Draft SRV for CalDAV October 2009
+
+
+ Extension", RFC 5397,
+ December 2008.
+
+ [RFC5545] Desruisseaux, B., "Internet
+ Calendaring and Scheduling Core
+ Object Specification
+ (iCalendar)", RFC 5545,
+ September 2009.
+
+Appendix A. Change History (to be removed prior to publication as an
+ RFC)
+
+ Changes in -01:
+
+ 1. Added discovery of CardDAV service.
+
+ 2. Now makes use of well-known URIs for the service "context path".
+
+ 3. Updated to RFC 5545 reference.
+
+ 4. Added reference to certificate verification spec.
+
+Author's Address
+
+ Cyrus Daboo
+ Apple Inc.
+ 1 Infinite Loop
+ Cupertino, CA 95014
+ USA
+
+ EMail: cyrus at daboo.name
+ URI: http://www.apple.com/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo Expires April 7, 2010 [Page 9]
+
Copied: CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-daboo-webdav-sync.txt (from rev 4951, CalendarServer/trunk/doc/RFC/draft-daboo-webdav-sync.txt)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-daboo-webdav-sync.txt (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-daboo-webdav-sync.txt 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,952 @@
+
+
+
+Network Working Group C. Daboo
+Internet-Draft Apple, Inc.
+Intended status: Standards Track A. Quillaud
+Expires: May 22, 2010 Sun Microsystems
+ November 18, 2009
+
+
+ Collection Synchronization for WebDAV
+ draft-daboo-webdav-sync-02
+
+Abstract
+
+ This specification defines an extension to WebDAV that allows
+ efficient synchronization of the contents of a WebDAV collection.
+
+Editorial Note (To be removed by RFC Editor before publication)
+
+ Please send comments to the Distributed Authoring and Versioning
+ (WebDAV) working group at <mailto:w3c-dist-auth at w3.org>, which may be
+ joined by sending a message with subject "subscribe" to
+ <mailto:w3c-dist-auth-request at w3.org>. Discussions of the WEBDAV
+ working group are archived at
+ <http://lists.w3.org/Archives/Public/w3c-dist-auth/>.
+
+Status of This Memo
+
+ This Internet-Draft is submitted to IETF in full conformance with the
+ provisions of BCP 78 and BCP 79.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF), its areas, and its working groups. Note that
+ other groups may also distribute working documents as Internet-
+ Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt.
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+ This Internet-Draft will expire on May 22, 2010.
+
+Copyright Notice
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 1]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ Copyright (c) 2009 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the BSD License.
+
+ This document may contain material from IETF Documents or IETF
+ Contributions published or made publicly available before November
+ 10, 2008. The person(s) controlling the copyright in some of this
+ material may not have granted the IETF Trust the right to allow
+ modifications of such material outside the IETF Standards Process.
+ Without obtaining an adequate license from the person(s) controlling
+ the copyright in such materials, this document may not be modified
+ outside the IETF Standards Process, and derivative works of it may
+ not be created outside the IETF Standards Process, except to format
+ it for publication as an RFC or to translate it into languages other
+ than English.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 2]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2. Conventions Used in This Document . . . . . . . . . . . . . . 3
+ 3. Open Issues . . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 4. WebDAV Synchronization . . . . . . . . . . . . . . . . . . . . 4
+ 4.1. Overview . . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 4.2. DAV:sync-collection report . . . . . . . . . . . . . . . . 5
+ 4.3. Types of changes reported . . . . . . . . . . . . . . . . 7
+ 4.3.1. New resource . . . . . . . . . . . . . . . . . . . . . 7
+ 4.3.2. Modified resource . . . . . . . . . . . . . . . . . . 7
+ 4.3.3. Removed resource . . . . . . . . . . . . . . . . . . . 7
+ 4.4. Example: Initial DAV:sync-collection REPORT . . . . . . . 8
+ 4.5. Example: DAV:sync-collection Report with token . . . . . . 10
+ 5. DAV:sync-token Property . . . . . . . . . . . . . . . . . . . 11
+ 6. XML Element Definitions . . . . . . . . . . . . . . . . . . . 12
+ 6.1. DAV:sync-collection XML Element . . . . . . . . . . . . . 12
+ 6.2. DAV:sync-token XML Element . . . . . . . . . . . . . . . . 12
+ 6.3. DAV:multistatus XML Element . . . . . . . . . . . . . . . 13
+ 6.4. DAV:sync-response XML Element . . . . . . . . . . . . . . 13
+ 7. Security Considerations . . . . . . . . . . . . . . . . . . . 14
+ 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 14
+ 9. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 14
+ 10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 14
+ 10.1. Normative References . . . . . . . . . . . . . . . . . . . 14
+ 10.2. Informative References . . . . . . . . . . . . . . . . . . 14
+ Appendix A. Change History (to be removed prior to
+ publication as an RFC) . . . . . . . . . . . . . . . 15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 3]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+1. Introduction
+
+ WebDAV [RFC4918] defines the concept of 'collections' which are
+ hierarchical groupings of WebDAV resources on an HTTP [RFC2616]
+ server. Collections can be of arbitrary size and depth (i.e.,
+ collections within collections). WebDAV clients that cache resource
+ content need a way to synchronize that data with the server (i.e.,
+ detect what has changed and update their cache). This can currently
+ be done using a WebDAV PROPFIND request on a collection to list all
+ members of a collection along with their DAV:getetag property values,
+ which allows the client to determine which resources were changed,
+ added or deleted. However, this does not scale well to large
+ collections as the XML response to the PROPFIND request will grow
+ with the collection size.
+
+ This specification defines a new WebDAV report that results in the
+ server returning to the client only information about those resources
+ which have changed, are new or were deleted since a previous
+ execution of the report on the collection.
+
+ Additionally, a new property is added to collection resources that is
+ used to convey a "synchronization token" that is guaranteed to change
+ when resources within the collection have changed.
+
+2. Conventions Used in This Document
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC2119].
+
+ This document uses XML DTD fragments ([W3C.REC-xml-20081126], Section
+ 3.2) as a purely notational convention. WebDAV request and response
+ bodies cannot be validated by a DTD due to the specific extensibility
+ rules defined in Section 17 of [RFC4918] and due to the fact that all
+ XML elements defined by this specification use the XML namespace name
+ "DAV:". In particular:
+
+ 1. element names use the "DAV:" namespace,
+
+ 2. element ordering is irrelevant unless explicitly stated,
+
+ 3. extension elements (elements not already defined as valid child
+ elements) may be added anywhere, except when explicitly stated
+ otherwise,
+
+ 4. extension attributes (attributes not already defined as valid for
+ this element) may be added anywhere, except when explicitly
+ stated otherwise.
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 4]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ When an XML element type in the "DAV:" namespace is referenced in
+ this document outside of the context of an XML fragment, the string
+ "DAV:" will be prefixed to the element type.
+
+ This document inherits, and sometimes extends, DTD productions from
+ Section 14 of [RFC4918].
+
+3. Open Issues
+
+ 1. We are extending the multistatus response element in a
+ significant way. The DAV:sync-response differs from a regular
+ DAV:response because, in the case of a created or modified
+ resource, it contains both a DAV:status (201 for created, 200 for
+ modified) and a DAV:propstat. The DAV:response on the other hand
+ contains either a DAV:status or a DAV:propstat but not both.
+ Shall we define a DAV:multisyncstatus response element instead of
+ overloading DAV:multistatus ?
+
+ 2. Do clients really need to be notified that a resource was created
+ versus modified ? They should be able to figure that out by
+ looking at the state of their current cache. If this information
+ is not necessary, the response would not need to contain a DAV:
+ status along with the DAV:propstat. This would allow the use of
+ a regular multistatus (simply extended with a sync-token
+ element).
+
+4. WebDAV Synchronization
+
+4.1. Overview
+
+ One way to synchronize data between two entities is to use some form
+ of synchronization token. The token defines the state of the data
+ being synchronized at a particular point in time. It can then be
+ used to determine what has changed since one point in time and
+ another.
+
+ This specification defines a new WebDAV report that is used to enable
+ client-server collection synchronization based on such a token.
+
+ In order to synchronize the contents of a collection between a server
+ and client, the server provides the client with a synchronization
+ token each time the synchronization report is executed. That token
+ represents the state of the data being synchronized at that point in
+ time. The client can then present that same token back to the server
+ at some later time and the server will return only those items that
+ are new, have changed or were deleted since that token was generated.
+ The server also returns a new token representing the new state at the
+ time the report was run.
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 5]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ Typically the first time a client connects to the server it will need
+ to be informed of the entire state of the collection (i.e., a full
+ list of all resources that are currently contained in the
+ collection). That is done by the client sending an empty token value
+ to the server. This indicates to the server that a full listing is
+ required. As an alternative, the client may choose to do its first
+ synchronization using some other mechanism on the collection (e.g.
+ some other form of batch resource information retrieval such as
+ PROPFIND, SEARCH [RFC5323], or specialized REPORTs such as those
+ defined in CalDAV [RFC4791] and CardDAV [I-D.ietf-vcarddav-carddav])
+ and ask for the DAV:sync-token property to be returned. This
+ property (defined in Section 5) contains the same token that can be
+ used later on to issue a DAV:sync-collection report.
+
+ In some cases a server may only wish to maintain a limited amount of
+ history about changes to a collection. In that situation it will
+ return an error to the client when the client presents a token that
+ is "out of date". At that point the client has to fall back to
+ synchronizing the entire collection by re-running the report request
+ using an empty token value. ACL changes may also cause a token to
+ become invalid.
+
+4.2. DAV:sync-collection report
+
+ This specification defines the DAV:sync-collection report.
+
+ If this report is implemented by a WebDAV server, then the server
+ MUST list the report in the "DAV:supported-report-set" property on
+ any collection supporting synchronization.
+
+ To implement the behavior for this report a server needs to keep
+ track of changes to any resources in a collection. This includes
+ noting the addition of new resources, changes to existing resources
+ and removal of resources (where "removal" could be the result of a
+ DELETE or MOVE WebDAV request). Only internal members of the
+ collection (as defined in [RFC4918]) are to be considered. The
+ server will track each change and provide a synchronization "token"
+ to the client that describes the state of the server at a specific
+ point in time. This "token" is returned as part of the response to
+ the "sync-collection" report. Clients include the last token they
+ got from the server in the next "sync-collection" report that they
+ execute and the server provides the changes from the previous state,
+ represented by the token, to the current state, represented by the
+ new token returned.
+
+ The synchronization token itself is an "opaque" string - i.e., the
+ actual string data has no specific meaning or syntax. A simple
+ implementation of such a token would be a numeric counter that counts
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 6]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ each change as it occurs and relates that change to the specific
+ object that changed.
+
+ Marshalling:
+
+ The request URI MUST be a collection. The request body MUST be a
+ DAV:sync-collection XML element (see Section 6.1), which MUST
+ contain one DAV:sync-token XML element, and optionally a DAV:
+ propstat XML element.
+
+ The request MUST include a Depth header with a value of "1".
+
+ The response body for a successful request MUST be a DAV:
+ multistatus XML element, which MUST contain one DAV:sync-token
+ element in addition to any DAV:sync-response elements.
+
+ The response body for a successful DAV:sync-collection report
+ request MUST contain a DAV:sync-response element for each resource
+ that was created, has changed or been deleted since the last
+ synchronization operation as specified by the DAV:sync-token
+ provided in the request. A given resource MUST appear only once
+ in the response.
+
+ The DAV:status element in each DAV:sync-response element is used
+ to indicate how the resource may have changed:
+
+ A status code of '201 Created' is used to indicate resources
+ that are new.
+
+ A status code of '200 OK' is used to indicate resources that
+ have changed.
+
+ A status code of '404 Not Found' is used to indicate resources
+ that have been removed.
+
+ The conditions under which each type of change may occur is
+ further described in Section 4.3.
+
+ Preconditions:
+
+ (DAV:valid-sync-token): The DAV:sync-token element value MUST map
+ to a valid token previously returned by the server. A token may
+ become invalid as the result of being "out of date" (out of the
+ range of change history maintained by the server), or for other
+ reasons (e.g. collection deleted, then recreated, ACL changes,
+ etc...).
+
+ Postconditions:
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 7]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ None.
+
+4.3. Types of changes reported
+
+ Three types of resource state changes can be returned by the DAV:
+ sync-collection report (new, modified, removed). This section
+ further defines under which condition each of them shall be used. It
+ also clarifies the case where a resource may have undergone multiple
+ changes in between two synchronizations.
+
+4.3.1. New resource
+
+ A resource MUST be reported as new if it has been mapped directly
+ under the target collection since the request sync token was
+ generated. This includes resources that have been mapped as the
+ result of a COPY, MOVE or BIND ([I-D.ietf-webdav-bind]) operation.
+ This also includes collection resources that have been created.
+
+ In the case where a mapping between a resource and the target
+ collection was removed, then a new mapping with the same URI created,
+ the new resource MUST be reported as new, while the old resource MUST
+ NOT be reported as removed. For example, if a resource was deleted,
+ then recreated using the same URI, it should be reported as a new
+ resource only.
+
+ A resource MAY be reported as new if the user issuing the request was
+ granted access to this resource, due to access control changes.
+
+4.3.2. Modified resource
+
+ A resource MUST be reported as modified if it is not reported as new
+ and if its entity tag value (defined in [RFC2616]) has changed since
+ the request sync token was generated. In other words, the new
+ resource change indicator takes precedence over the modified resource
+ change indicator.
+
+ Collection resources MUST NOT be returned as modified. Instead
+ clients are expected to synchronize changes in child collection
+ resources on an individual basis.
+
+4.3.3. Removed resource
+
+ A resource MUST be reported as removed if its mapping under the
+ target collection has been removed since the request sync token was
+ generated, and it has not been re-mapped since it was removed. This
+ includes resources that have been unmapped as the result of a MOVE or
+ UNBIND ([I-D.ietf-webdav-bind]) operation. This also includes
+ collection resources that have been removed.
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 8]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ If a resource was created (and possibly modified), then removed in
+ between two synchronizations, it MUST NOT be reported as new,
+ modified or removed.
+
+ A resource MAY be reported as removed if the user issuing the request
+ has no longer access to this resource, due to access control changes.
+
+4.4. Example: Initial DAV:sync-collection REPORT
+
+ In this example, the client is making its first synchronization
+ request to the server, so the DAV:sync-token element in the request
+ is empty. It also asks for the DAV:getetag property. The server
+ responds with the items currently in the targeted collection
+ (indicating that they are 'new' via the '201 Created' status code).
+ The current synchronization token is also returned.
+
+ >> Request <<
+
+
+ REPORT /home/cyrusdaboo/ HTTP/1.1
+ Host: webdav.example.com
+ Depth: 1
+ Content-Type: text/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:sync-collection xmlns:D="DAV:">
+ <D:sync-token/>
+ <D:prop>
+ <D:getetag/>
+ </D:prop>
+ </D:sync-collection>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 9]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ >> Response <<
+
+
+ HTTP/1.1 207 Multi-Status
+ Content-Type: text/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:">
+ <D:sync-response>
+ <D:href
+ >http://webdav.example.com/home/cyrusdaboo/test.doc</D:href>
+ <D:status>HTTP/1.1 201 Created</D:status>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"00001-abcd1"</D:getetag>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:sync-response>
+ <D:sync-response>
+ <D:href
+ >http://webdav.example.com/home/cyrusdaboo/vcard.vcf</D:href>
+ <D:status>HTTP/1.1 201 Created</D:status>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"00002-abcd1"</D:getetag>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:sync-response>
+ <D:sync-response>
+ <D:href
+ >http://webdav.example.com/home/cyrusdaboo/calendar.ics</D:href>
+ <D:status>HTTP/1.1 201 Created</D:status>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"00003-abcd1"</D:getetag>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:sync-response>
+ <D:sync-token>1234</D:sync-token>
+ </D:multistatus>
+
+
+
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 10]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+4.5. Example: DAV:sync-collection Report with token
+
+ In this example, the client is making a synchronization request to
+ the server and is using the DAV:sync-token element returned from the
+ last report it ran on this collection. The server responds listing
+ the items that have been added, changed or removed. The (new)
+ current synchronization token is also returned.
+
+ >> Request <<
+
+
+ REPORT /home/cyrusdaboo/ HTTP/1.1
+ Host: webdav.example.com
+ Depth: 1
+ Content-Type: text/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:sync-collection xmlns:D="DAV:">
+ <D:sync-token>1234</D:sync-token>
+ <D:prop>
+ <D:getetag/>
+ </D:prop>
+ </D:sync-collection>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 11]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ >> Response <<
+
+
+ HTTP/1.1 207 Multi-Status
+ Content-Type: text/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:">
+ <D:sync-response>
+ <D:href
+ >http://webdav.example.com/home/cyrusdaboo/file.xml</D:href>
+ <D:status>HTTP/1.1 201 Created</D:status>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"00004-abcd1"</D:getetag>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:sync-response>
+ <D:sync-response>
+ <D:href
+ >http://webdav.example.com/home/cyrusdaboo/vcard.vcf</D:href>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"00002-abcd2"</D:getetag>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:sync-response>
+ <D:sync-response>
+ <D:href
+ >http://webdav.example.com/home/cyrusdaboo/test.doc</D:href>
+ <D:status>HTTP/1.1 404 Not Found</D:status>
+ </D:sync-response>
+ <D:sync-token>1238</D:sync-token>
+ </D:multistatus>
+
+
+5. DAV:sync-token Property
+
+ Name: sync-token
+
+ Namespace: DAV:
+
+
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 12]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ Purpose: Contains the value of the synchronization token as it would
+ be returned by a DAV:sync-collection report.
+
+ Value: Any text.
+
+ Protected: MUST be protected because this value is created and
+ controlled by the server.
+
+ COPY/MOVE behavior: This property value is dependent on the final
+ state of the destination resource, not the value of the property
+ on the source resource.
+
+ Description: The DAV:sync-token property MUST be defined on all
+ resources that support the DAV:sync-collection report. It
+ contains the value of the synchronization token as it would be
+ returned by a DAV:sync-collection report on that resource at the
+ same point in time. It SHOULD NOT be returned by a PROPFIND DAV:
+ allprop request (as defined in [RFC4918]).
+
+ Definition:
+
+
+ <!ELEMENT sync-token #PCDATA>
+
+
+6. XML Element Definitions
+
+6.1. DAV:sync-collection XML Element
+
+ Name: sync-collection
+
+ Namespace: DAV:
+
+ Purpose: WebDAV report used to synchronize data between client and
+ server.
+
+ Description: See Section 4.
+
+
+
+ <!ELEMENT sync-collection (sync-token, DAV:prop?)>
+
+
+6.2. DAV:sync-token XML Element
+
+
+
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 13]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ Name: sync-token
+
+ Namespace: DAV:
+
+ Purpose: The synchronization token provided by the server and
+ returned by the client.
+
+ Description: See Section 4.
+
+
+
+ <!ELEMENT sync-token CDATA>
+
+
+6.3. DAV:multistatus XML Element
+
+ Name: multistatus
+
+ Namespace: DAV:
+
+ Purpose: Extends the DAV:multistatus element to include
+ synchronization details.
+
+ Description: See Section 4.
+
+
+
+ <!ELEMENT multistatus ((DAV:response*, DAV:responsedescription?) |
+ (DAV:sync-response*, DAV:sync-token,
+ DAV:responsedescription?))>
+
+
+6.4. DAV:sync-response XML Element
+
+ Name: sync-response
+
+ Namespace: DAV:
+
+ Purpose: Contains the synchronization results returned by the
+ server.
+
+ Description: See Section 4.
+
+
+
+ <!ELEMENT sync-response (DAV:href, DAV:status, DAV:propstat?)>
+
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 14]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+7. Security Considerations
+
+ This extension does not introduce any new security concerns than
+ those already described in HTTP and WebDAV.
+
+8. IANA Considerations
+
+ This document does not require any actions on the part of IANA.
+
+9. Acknowledgments
+
+ The following individuals contributed their ideas and support for
+ writing this specification: Bernard Desruisseaux, Mike Douglass, Ciny
+ Joy and Julian Reschke.
+
+10. References
+
+10.1. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs
+ to Indicate Requirement Levels", BCP 14,
+ RFC 2119, March 1997.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J.,
+ Frystyk, H., Masinter, L., Leach, P.,
+ and T. Berners-Lee, "Hypertext Transfer
+ Protocol -- HTTP/1.1", RFC 2616,
+ June 1999.
+
+ [RFC4918] Dusseault, L., "HTTP Extensions for Web
+ Distributed Authoring and Versioning
+ (WebDAV)", RFC 4918, June 2007.
+
+ [W3C.REC-xml-20081126] Sperberg-McQueen, C., Yergeau, F., Bray,
+ T., Paoli, J., and E. Maler, "Extensible
+ Markup Language (XML) 1.0 (Fifth
+ Edition)", World Wide Web Consortium
+ Recommendation REC-xml-20081126,
+ November 2008, <http://www.w3.org/TR/
+ 2008/REC-xml-20081126>.
+
+10.2. Informative References
+
+ [I-D.ietf-vcarddav-carddav] Daboo, C., "vCard Extensions to WebDAV
+ (CardDAV)",
+ draft-ietf-vcarddav-carddav-10 (work in
+ progress), November 2009.
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 15]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+ [I-D.ietf-webdav-bind] Clemm, G., Crawford, J., Reschke, J.,
+ and J. Whitehead, "Binding Extensions to
+ Web Distributed Authoring and Versioning
+ (WebDAV)", draft-ietf-webdav-bind-26
+ (work in progress), September 2009.
+
+ [RFC4791] Daboo, C., Desruisseaux, B., and L.
+ Dusseault, "Calendaring Extensions to
+ WebDAV (CalDAV)", RFC 4791, March 2007.
+
+ [RFC5323] Reschke, J., Reddy, S., Davis, J., and
+ A. Babich, "Web Distributed Authoring
+ and Versioning (WebDAV) SEARCH",
+ RFC 5323, November 2008.
+
+Appendix A. Change History (to be removed prior to publication as an
+ RFC)
+
+ Changes in -02:
+
+ 1. Added definition of sync-token WebDAV property.
+
+ 2. Added references to SEARCH, CalDAV, CardDAV as alternative ways
+ to first synchronize a collection.
+
+ 3. Added section defining under which condition each state change
+ (new, modified, removed) should be reported. Added reference to
+ BIND.
+
+ 4. Incorporated feedback from Julian Reschke and Ciny Joy.
+
+ 5. More details on the use of the DAV:valid-sync-token precondition.
+
+ Changes in -01:
+
+ 1. Updated to 4918 reference.
+
+ 2. Fixed examples to properly include DAV:status in DAV:propstat
+
+ 3. Switch to using XML conventions text from RFC5323.
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 16]
+
+Internet-Draft WebDAV Sync November 2009
+
+
+Authors' Addresses
+
+ Cyrus Daboo
+ Apple Inc.
+ 1 Infinite Loop
+ Cupertino, CA 95014
+ USA
+
+ EMail: cyrus at daboo.name
+ URI: http://www.apple.com/
+
+
+ Arnaud Quillaud
+ Sun Microsystems
+ 180, Avenue de l'Europe
+ Saint Ismier cedex, 38334
+ France
+
+ EMail: arnaud.quillaud at sun.com
+ URI: http://www.sun.com/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Quillaud Expires May 22, 2010 [Page 17]
+
\ No newline at end of file
Copied: CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-desruisseaux-ischedule.txt (from rev 4951, CalendarServer/trunk/doc/RFC/draft-desruisseaux-ischedule.txt)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-desruisseaux-ischedule.txt (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-desruisseaux-ischedule.txt 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,1904 @@
+
+
+
+Network Working Group C. Daboo
+Internet-Draft Apple
+Intended status: Standards Track B. Desruisseaux
+Expires: May 19, 2010 Oracle
+ November 15, 2009
+
+
+ Internet Calendar Scheduling Protocol (iSchedule)
+ draft-desruisseaux-ischedule-00
+
+Abstract
+
+ This document defines the Internet Calendar Scheduling Protocol
+ (iSchedule), which is a binding from the iCalendar Transport-
+ independent Interoperability Protocol (iTIP) to the Hypertext
+ Transfer Protocol (HTTP) to enable interoperability between
+ calendaring and scheduling systems over the Internet.
+
+Status of This Memo
+
+ This Internet-Draft is submitted to IETF in full conformance with the
+ provisions of BCP 78 and BCP 79.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF), its areas, and its working groups. Note that
+ other groups may also distribute working documents as Internet-
+ Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt.
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+ This Internet-Draft will expire on May 19, 2010.
+
+Copyright Notice
+
+ Copyright (c) 2009 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 1]
+
+Internet-Draft iSchedule November 2009
+
+
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the BSD License.
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 1.1. Motivations . . . . . . . . . . . . . . . . . . . . . . . 4
+ 1.2. Related Memos . . . . . . . . . . . . . . . . . . . . . . 5
+ 1.3. Notational Conventions . . . . . . . . . . . . . . . . . . 5
+ 2. iSchedule Model . . . . . . . . . . . . . . . . . . . . . . . 6
+ 3. iSchedule Intermediaries . . . . . . . . . . . . . . . . . . . 6
+ 4. iSchedule Receiver Discovery . . . . . . . . . . . . . . . . . 7
+ 4.1. iSchedule SRV Service Types . . . . . . . . . . . . . . . 7
+ 4.2. iSchedule Receiver Request-URI . . . . . . . . . . . . . . 8
+ 4.3. Resolving Calendar User Addresses . . . . . . . . . . . . 8
+ 4.4. Using the SRV Record Result . . . . . . . . . . . . . . . 9
+ 5. iSchedule Receiver Capabilities . . . . . . . . . . . . . . . 9
+ 5.1. Example: Querying iSchedule Receiver Capabilities . . . . 9
+ 6. Scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . 11
+ 6.1. POST Method . . . . . . . . . . . . . . . . . . . . . . . 11
+ 6.1.1. Schedule Response . . . . . . . . . . . . . . . . . . 11
+ 6.1.2. Status Codes for use with the POST method . . . . . . 12
+ 6.1.3. Example: Simple meeting invitation . . . . . . . . . . 13
+ 6.1.4. Example: Search for Busy Time Information . . . . . . 15
+ 6.1.5. Example: Simple Task Assignment . . . . . . . . . . . 17
+ 7. HTTP Headers . . . . . . . . . . . . . . . . . . . . . . . . . 18
+ 7.1. iSchedule-Version General Header . . . . . . . . . . . . . 18
+ 7.2. iSchedule-Via General Header . . . . . . . . . . . . . . . 18
+ 7.3. Originator Request Header . . . . . . . . . . . . . . . . 19
+ 7.4. Recipient Request Header . . . . . . . . . . . . . . . . . 19
+ 8. XML Element Definitions . . . . . . . . . . . . . . . . . . . 19
+ 8.1. schedule-response XML Element . . . . . . . . . . . . . . 19
+ 8.1.1. response XML Element . . . . . . . . . . . . . . . . . 20
+ 8.1.1.1. recipient XML Element . . . . . . . . . . . . . . 20
+ 8.1.1.2. request-status XML Element . . . . . . . . . . . . 20
+ 8.1.1.3. calendar-data XML Element . . . . . . . . . . . . 21
+ 8.1.1.4. error XML Element . . . . . . . . . . . . . . . . 21
+ 8.1.1.5. responsedescription XML Element . . . . . . . . . 21
+ 8.2. query-result XML Element . . . . . . . . . . . . . . . . . 22
+ 8.2.1. capability-set XML Element . . . . . . . . . . . . . . 22
+ 8.2.1.1. supported-version-set XML Element . . . . . . . . 23
+ 8.2.1.2. supported-scheduling-message-set XML Element . . . 23
+ 8.2.1.3. supported-calendar-data XML Element . . . . . . . 24
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 2]
+
+Internet-Draft iSchedule November 2009
+
+
+ 8.2.1.4. supported-attachment-values XML Element . . . . . 25
+ 8.2.1.5. supported-recipient-uri-scheme-set XML Element . . 26
+ 8.2.1.6. max-content-length XML Element . . . . . . . . . . 27
+ 8.2.1.7. min-date-time XML Element . . . . . . . . . . . . 27
+ 8.2.1.8. max-date-time XML Element . . . . . . . . . . . . 28
+ 8.2.1.9. max-instances XML Element . . . . . . . . . . . . 28
+ 8.2.1.10. max-recipients XML Element . . . . . . . . . . . . 28
+ 8.2.1.11. administrator XML Element . . . . . . . . . . . . 29
+ 9. Security Considerations . . . . . . . . . . . . . . . . . . . 29
+ 9.1. Privacy . . . . . . . . . . . . . . . . . . . . . . . . . 29
+ 9.2. Authentication . . . . . . . . . . . . . . . . . . . . . . 29
+ 9.3. Authorization . . . . . . . . . . . . . . . . . . . . . . 30
+ 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 30
+ 10.1. Namespace Registration . . . . . . . . . . . . . . . . . . 30
+ 10.1.1. iSchedule Namespace Registration . . . . . . . . . . . 30
+ 10.2. HTTP Headers Registration . . . . . . . . . . . . . . . . 30
+ 10.2.1. iSchedule-Version General Header Registration . . . . 30
+ 10.2.2. iSchedule-Via General Header Registration . . . . . . 31
+ 10.2.3. Originator Request Header Registration . . . . . . . . 31
+ 10.2.4. Recipient Request Header Registration . . . . . . . . 31
+ 10.3. Well-Known URI Registration . . . . . . . . . . . . . . . 31
+ 10.3.1. iSchedule Well-Known URI Registration . . . . . . . . 32
+ 11. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 32
+ 12. References . . . . . . . . . . . . . . . . . . . . . . . . . . 32
+ 12.1. Normative References . . . . . . . . . . . . . . . . . . . 32
+ 12.2. Informative References . . . . . . . . . . . . . . . . . . 33
+ Appendix A. Open Issues . . . . . . . . . . . . . . . . . . . . . 34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 3]
+
+Internet-Draft iSchedule November 2009
+
+
+1. Introduction
+
+ This binding document provides the transport specific information
+ necessary to convey iCalendar Transport-independent Interoperability
+ Protocol (iTIP) [I-D.ietf-calsify-2446bis] messages over the
+ Hypertext Transfer Protocol (HTTP) [RFC2616].
+
+ The Internet Calendar Scheduling Protocol (iSchedule) enables
+ interoperability between different calendaring and scheduling
+ systems. Calendaring and scheduling systems that provide support for
+ iSchedule allows their users to perform scheduling transactions such
+ as schedule, reschedule, respond to scheduling request or cancel
+ scheduled calendar components, as well as search for busy time
+ information with users of other calendaring and scheduling systems on
+ the Internet.
+
+ Discussion of this Internet-Draft is taking place on the mailing list
+ <https://www.ietf.org/mailman/listinfo/ischedule>.
+
+1.1. Motivations
+
+ The iCalendar Message-Based Interoperability Protocol (iMIP)
+ [I-D.ietf-calsify-rfc2447bis], has proven to be insufficient to allow
+ users to seamlessly perform the same scheduling operations with users
+ of other calendaring and scheduling systems on the Internet than with
+ users of their own system. This section clarifies the motivations
+ for a binding from the iCalendar Transport-independent
+ Interoperability Protocol (iTIP) [I-D.ietf-calsify-2446bis] to a
+ transport that allows synchronous end-to-end connectivity.
+
+ A binding to an email-based transport is clearly inadequate to search
+ for busy time information since users need and expect to get an
+ immediate response. As such, some calendaring and scheduling systems
+ allow users to publish their free busy information in a resource
+ accessible to others on the Internet. In the absence of a
+ standardized mechanism to locate the resource that provides the free
+ busy information of a user, one thus needs to know the location of
+ this resource in addition to the calendar user address of the users
+ one wish to schedule with.
+
+ With an email-based transport, the transparent processing of incoming
+ scheduling messages on the server is only possible when the
+ calendaring and scheduling system is integrated with the email
+ system. Commonly, the processing of incoming scheduling messages
+ occurs on the client instead and requires user intervention, which
+ yield the following consequences:
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 4]
+
+Internet-Draft iSchedule November 2009
+
+
+ 1. The processing of incoming scheduling messages and the
+ corresponding updates to the calendar only occurs when the client
+ is active. As such, free busy information may be inaccurate
+ (e.g., user still appears busy when the organizer actually
+ rescheduled or canceled the meeting).
+
+ 2. Calendaring and scheduling systems generally restrain the number
+ of updates sent to users to reduce the number of messages that
+ will clutter their email inbox. As a result, attendees rarely
+ obtain up to date participation status of other attendees.
+
+ 3. The client becomes responsible to verify the authenticity and
+ integrity of the scheduling message.
+
+1.2. Related Memos
+
+ Implementers will need to be familiar with other documents that,
+ along with this document, form a framework for Internet calendaring
+ and scheduling standards.
+
+ This document specifies a binding from iTIP to HTTP.
+
+ o iCalendar [RFC5545] specifies a core specification of objects,
+ data types, properties and property parameters;
+
+ o iTIP [I-D.ietf-calsify-2446bis] specifies an interoperability
+ protocol for scheduling between different implementations.
+
+ This document does not attempt to repeat the specification of
+ concepts or definitions from these other documents. Where possible,
+ references are made to the document that provides the specification
+ of these concepts or definitions.
+
+1.3. Notational Conventions
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC2119].
+
+ The augmented BNF used by this document to describe protocol elements
+ is described in Section 2.1 of [RFC2616]. Because this augmented BNF
+ uses the basic production rules provided in Section 2.2 of [RFC2616],
+ those rules apply to this document as well.
+
+ Definitions of XML elements in this document use XML element type
+ declarations (as found in XML Document Type Declarations), described
+ in Section 3.2 of [W3C.REC-xml-20081126].
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 5]
+
+Internet-Draft iSchedule November 2009
+
+
+ The namespace "urn:ietf:params:xml:ns:ischedule" is reserved for the
+ XML elements defined in this specification, or in other Standards
+ Track IETF RFCs written to extend iSchedule. It MUST NOT be used for
+ proprietary extensions.
+
+ Note that the XML declarations used in this document are incomplete,
+ in that they do not include namespace information. Thus, the reader
+ MUST NOT use these declarations as the only way to validate iSchedule
+ XML element types.
+
+2. iSchedule Model
+
+ The iSchedule design can be pictured as:
+
+
+ +----------+ +----------+ +----------+ +----------+
+ | Calendar | | Calendar | iSchedule | Calendar | | Calendar |
+ | User |-->| Service |------------>| Service |-->| Store |
+ | Agent | | | | | | |
+ +----------+ +----------+ +----------+ +----------+
+ iSchedule iSchedule
+ Sender Receiver
+
+ When an iSchedule Sender has a scheduling message to transmit, it
+ determines the iSchedule Receivers to delivers the message to and
+ sends the appropriate iSchedule requests. The responsability of an
+ iSchedule Sender is to transfer scheduling messages to one or more
+ iSchedule Receivers, or report its failure to do so.
+
+ The means by which a Calendar User Agent instructs a Calendar
+ Service, acting as an iSchedule Sender, to transmit scheduling
+ messages is outside the scope of this document. A Calendar Service
+ could provide support for a standard calendar access protocol, such
+ as CalDAV [RFC4791], [I-D.desruisseaux-caldav-sched] or any other
+ protocol, to allow a Calendar User Agent to perform scheduling
+ operations with users of other Calendar Services.
+
+ Likewise, the actual processing of scheduling messages received by a
+ Calendar Service, acting as an iSchedule Receiver, is also outside
+ the scope of this document. Some Calendar Service implementations
+ may decide to process some or all received scheduling messages, while
+ other implementations may decide to leave that work to Calendar User
+ Agent implementations.
+
+3. iSchedule Intermediaries
+
+ From the end-to-end view, an iSchedule request is sent to an
+ iSchedule Receiver and a response is returned to the iSchedule
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 6]
+
+Internet-Draft iSchedule November 2009
+
+
+ Sender. In practice, this may not always be the case. An iSchedule
+ request may travel through several iSchedule intermediaries.
+
+ iSchedule intermediaries can be used for different purposes, namely:
+
+ o Dispatch iSchedule request to the appropriate iSchedule Receivers
+ for each specified Recipient; Users of the same domain could
+ actually be hosted on different iSchedule Receivers.
+
+ o Dispatch iSchedule request to the appropriate iSchedule Receivers
+ according to the calendar component type specified in the
+ requests. Different iSchedule Receivers could be responsible of
+ handling, VEVENT, VTODO, VJOURNAL and VFREEBUSY requests.
+
+ o Scan iSchedule requests, particularly attachments, for virus.
+
+ iSchedule intermediaries are REQUIRED to identify their hostname and
+ the version number of the preceding server from which the request or
+ response arrived. iSchedule intermediaries append this information to
+ the "iSchedule-Via" general header, in sequential order, as the
+ request travels between Sender and Receiver.
+
+ For example, an iSchedule request might be submitted to an iSchedule
+ Receiver with the following "iSchedule-Via" header:
+
+
+ iSchedule-Via: 1.0 ischedule.example.com:443 (VendorX/2.0),
+ 1.0 cal.internal.example.com:80 (VendorZ/4.3)
+
+4. iSchedule Receiver Discovery
+
+ This section describes how an iSchedule Sender can discover the host
+ name, the port as well as the Request-URI to use to submit a request
+ to an iSchedule Receiver.
+
+4.1. iSchedule SRV Service Types
+
+ This specification adds two service types for use with SRV records:
+
+ ischedule: Identifies an iSchedule Receiver that uses HTTP without
+ transport layer security ([RFC2818]).
+
+ ischedules: Identifies an iSchedule Receiver that uses HTTP with
+ transport layer security ([RFC2818]).
+
+ Example: service record for server without transport layer security
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 7]
+
+Internet-Draft iSchedule November 2009
+
+
+ _ischedule._tcp SRV 0 1 80 ischedule.example.com.
+
+ Example: service record for server with transport layer security
+
+
+ _ischedules._tcp SRV 0 1 443 ischedule.example.com.
+
+4.2. iSchedule Receiver Request-URI
+
+ This specification registers a well-known URI for the iSchedule
+ service, namely, "ischedule" (see Section 10.3.1). iSchedule
+ Receivers MUST support requests targeted at this well-known URI.
+ iSchedule Sender MUST handle HTTP redirects on the well-known URI.
+
+4.3. Resolving Calendar User Addresses
+
+ To deliver a scheduling message via the iSchedule protocol, an
+ iSchedule Sender needs to determine what iSchedule Receiver it needs
+ to deliver a scheduling message to for a particular Recipient. Each
+ Recipient's calendar user address is specified in the Recipient
+ request header.
+
+ A calendar user address as defined by iCalendar is simply a URI.
+ This is typically a mailto URI, but could potentially be any URI
+ type.
+
+ To map a mailto URI to an SRV record name to query, the "domain"
+ portion of the URI is extracted and appended to the service
+ identifier "_ischedule._tcp." or "_ischedules._tcp." to form the
+ record name.
+
+ Example:
+
+
+ Calendar User Address: mailto:cyrus at example.com
+
+ Query SRV Record Names: _ischedules._tcp.example.com
+ _ischedule._tcp.example.com
+
+ In cases where the "domain" portion of the mailto URI contains one or
+ more levels of sub-domain, clients MAY choose to remove successive
+ levels of "sub-domain" if queries for that sub-domain fail to return
+ any SRV records. For example, a mailto URI with the full domain
+ "host.calendar.example.com" would first trigger a querying using the
+ domain "host.calendar.example.com", then if that failed, the domain
+ "calendar.example.com" would be tried, then if that failed the domain
+ "example.com" would be tried.
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 8]
+
+Internet-Draft iSchedule November 2009
+
+
+4.4. Using the SRV Record Result
+
+ As defined in [RFC2782] the result of an SRV record lookup will be a
+ target host name and a port. An iSchedule Sender uses these to
+ contact the iSchedule Receiver. iSchedule Senders MUST honor the full
+ behavior of SRV records as defined by [RFC2782], in particular the
+ TTL, Priority and Weight options in the record, as well as handling
+ multiple records being returned.
+
+ Since an iSchedule server is an HTTP server, an iSchedule client
+ needs to supply a Request-URI in the HTTP request it makes to the
+ server, in addition to the host name and port information. When SRV
+ records are being used there is no way to specify the Request-URI in
+ the SRV record. As a result clients MUST use "/" as the Request-URI
+ for the iSchedule server identified by an SRV record.
+
+5. iSchedule Receiver Capabilities
+
+ iSchedule Receivers supporting the features described in this
+ document MUST allow iSchedule Sender to query their capabilities by
+ accepting GET requests targeted at the Request-URI "/.well-known/
+ ischedule?query=capabilities". The response body for a successful
+ GET request targeted at this URI MUST be an XML document with query-
+ result as its root element.
+
+5.1. Example: Querying iSchedule Receiver Capabilities
+
+ >> Request <<
+
+
+ GET /.well-known/ischedule?query=capabilities HTTP/1.1
+ Host: cal.example.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 9]
+
+Internet-Draft iSchedule November 2009
+
+
+ >> Response <<
+
+
+ HTTP/1.1 200 OK
+ Date: Mon, 15 Dec 2008 09:32:12 GMT
+ Content-Type: application/xml; charset=utf-8
+ Content-Length: xxxx
+ iSchedule-Version: 1.0
+ ETag: "afasdf-132afds"
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <query-result xmlns="urn:ietf:params:xml:ns:ischedule">
+ <capability-set>
+ <supported-version-set>
+ <version>1</version>
+ </supported-version-set>
+ <supported-scheduling-message-set>
+ <comp name="VEVENT">
+ <method name="REQUEST"/>
+ <method name="ADD"/>
+ <method name="REPLY"/>
+ <method name="CANCEL"/>
+ </comp>
+ <comp name="VTODO"/>
+ <comp name="VFREEBUSY"/>
+ </supported-scheduling-message-set>
+ <supported-calendar-data>
+ <calendar-data content-type="text/calendar" version="2.0"/>
+ </supported-calendar-data>
+ <supported-attachment-values>
+ <inline-attachment/>
+ <external-attachment/>
+ </supported-attachment-values>
+ <supported-recipient-uri-scheme-set>
+ <scheme>mailto</scheme>
+ </supported-recipient-uri-scheme-set>
+ <max-content-length>102400</max-content-length>
+ <min-date-time>19910101T000000Z</min-date-time>
+ <max-date-time>20381231T000000Z</max-date-time>
+ <max-instances>150</max-instances>
+ <max-recipients>250</max-recipients>
+ <administrator>mailto:ischedule-admin at example.com</administrator>
+ </capability-set>
+ </query-result>
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 10]
+
+Internet-Draft iSchedule November 2009
+
+
+6. Scheduling
+
+ This section defines how an iSchedule Sender can use the HTTP POST
+ method to submit a scheduling message to an iSchedule Receiver.
+
+6.1. POST Method
+
+ The POST method submits a scheduling message to one or more
+ recipients by targeting the request at the Request-URI of an
+ iSchedule Receiver. The request body of a POST method MUST contain a
+ scheduling message or free-busy message (e.g., an iCalendar object
+ that follows the iTIP semantic).
+
+ A submitted scheduling message will be delivered to the calendar user
+ addresses specified in the Recipient request header. A submitted
+ free-busy message will be immediately executed and a free-busy
+ response returned.
+
+ Every POST request MUST include the iSchedule-Version request header.
+
+ Every POST request MUST include a single Originator request header
+ that specifies the calendar user address of the originator of the
+ scheduling message.
+
+ Every POST request MUST include one or more Recipient request
+ headers. The value of this header is a list of one or more calendar
+ user addresses and corresponds to the set of calendar users who will
+ have the scheduling message delivered to them.
+
+6.1.1. Schedule Response
+
+ A POST request may deliver a scheduling message to one or more
+ calendar users specified in the Recipient request header. Since the
+ behavior of each recipient may vary, it is useful to get response
+ status information for each recipient in the overall POST response.
+ This specification defines a new XML response to convey multiple
+ recipient status.
+
+ A response to a POST method that indicates status for one or more
+ recipients MUST be a schedule-response XML element. This MUST
+ contain one or more response elements for each recipient, with each
+ of those containing elements that indicate which recipient they
+ correspond to, the scheduling status of the request for that
+ recipient, any error codes and an optional description.
+
+ In the case of a free-busy request, the response elements can also
+ contain calendar-data elements which contain free busy information
+ (e.g., an iCalendar VFREEBUSY component) indicating the busy state of
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 11]
+
+Internet-Draft iSchedule November 2009
+
+
+ the corresponding recipient, assuming that the free-busy request for
+ that recipient succeeded.
+
+ TODO: Define the response body for a failed request.
+
+ (supported-calendar-data): The resource submitted in the POST
+ request MUST be a supported media type (i.e. text/calendar) for
+ scheduling or free-busy messages;
+
+ (valid-calendar-data): The resource submitted in the POST request
+ MUST be valid data for the media type being specified (i.e. valid
+ iCalendar object);
+
+ (valid-scheduling-message): The resource submitted in the POST
+ request MUST obey all restrictions specified for the POST request
+ (e.g., the scheduling message follows the restrictions of iTIP);
+
+ (originator-specified): The POST request MUST include a valid
+ Originator request header specifying a single calendar user
+ address of the currently authenticated user;
+
+ (recipient-specified): The POST request MUST include one or more
+ valid Recipient request headers specifying the calendar user
+ address of users to whom the scheduling message will be delivered.
+
+ (originator-reply): The calendar user identified by the Originator
+ request header in the POST request MUST have previously received
+ the scheduling message that is being replied to when the
+ scheduling message is an incoming scheduling message;
+
+ (max-content-length): The request body submitted in the POST
+ request MUST have an octet size less than or equal to the value of
+ the max-content-length capability of the iSchedule Receiver.
+
+6.1.2. Status Codes for use with the POST method
+
+ The following are examples of response codes one would expect to be
+ used for this method. Note, however, that unless explicitly
+ prohibited any 2/3/4/5xx series response code may be used in a
+ response.
+
+ 200 (OK) - The command succeeded.
+
+ 400 (Bad Request) - The Sender has provided an invalid scheduling
+ message.
+
+ 403 (Forbidden) - The Sender cannot submit a scheduling message to
+ the specified Request-URI.
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 12]
+
+Internet-Draft iSchedule November 2009
+
+
+ 404 (Not Found) - The URL in the Request-URI was not present.
+
+ 507 (Insufficient Storage) - The server did not have sufficient
+ space to record the scheduling message.
+
+6.1.3. Example: Simple meeting invitation
+
+ >> Request <<
+
+
+ POST /.well-known/ischedule HTTP/1.1
+ Host: cal.example.org
+ iSchedule-Version: 1.0
+ Originator: mailto:bernard at example.com
+ Recipient: mailto:cyrus at example.org
+ Content-Type: text/calendar
+ Content-Length: xxxx
+
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//EN
+ METHOD:REQUEST
+ BEGIN:VEVENT
+ DTSTAMP:20040901T200200Z
+ ORGANIZER:mailto:bernard at example.com
+ DTSTART:20040902T130000Z
+ DTEND:20040902T140000Z
+ SUMMARY:Design meeting
+ UID:34222-232 at example.com
+ ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR;CUTYPE=IND
+ IVIDUAL;CN=Bernard Desruisseaux:mailto:bernard@
+ example.com
+ ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;ROLE=RE
+ Q-PARTICIPANT;CUTYPE=INDIVIDUAL;CN=Cyrus Daboo:
+ mailto:cyrus at example.org
+ END:VEVENT
+ END:VCALENDAR
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 13]
+
+Internet-Draft iSchedule November 2009
+
+
+ >> Response <<
+
+
+ HTTP/1.1 200 OK
+ Date: Thu, 02 Sep 2004 16:53:32 GMT
+ Content-Type: application/xml; charset=utf-8
+ Content-Length: xxxx
+ iSchedule-Version: 1.0
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <schedule-response xmlns="urn:ietf:params:xml:ns:ischedule">
+ <response>
+ <recipient>mailto:cyrus at example.org</recipient>
+ <request-status>2.0;Success</request-status>
+ <responsedescription>Delivered to recipient
+ scheduling inbox</responsedescription>
+ </response>
+ </schedule-response>
+
+
+ In this example, the iSchedule Sender requests the iSchedule Receiver
+ to deliver a meeting invitation (scheduling REQUEST) to the calendar
+ user mailto:cyrus at example.org. The response indicates that delivery
+ of the scheduling message was successful.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 14]
+
+Internet-Draft iSchedule November 2009
+
+
+6.1.4. Example: Search for Busy Time Information
+
+ >> Request <<
+
+
+ POST /.well-known/ischedule HTTP/1.1
+ Host: cal.example.org
+ iSchedule-Version: 1.0
+ Originator: mailto:bernard at example.com
+ Recipient: mailto:cyrus at example.org
+ Content-Type: text/calendar
+ Content-Length: xxxx
+
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//EN
+ METHOD:REQUEST
+ BEGIN:VFREEBUSY
+ DTSTAMP:20040901T200200Z
+ ORGANIZER:mailto:bernard at example.com
+ DTSTART:20040902T000000Z
+ DTEND:20040903T000000Z
+ UID:34222-232 at example.com
+ ATTENDEE;CN=Cyrus Daboo:mailto:cyrus at example.org
+ END:VFREEBUSY
+ END:VCALENDAR
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 15]
+
+Internet-Draft iSchedule November 2009
+
+
+ >> Response <<
+
+
+ HTTP/1.1 200 OK
+ Date: Thu, 02 Sep 2004 16:53:32 GMT
+ Content-Type: application/xml; charset=utf-8
+ Content-Length: xxxx
+ iSchedule-Version: 1.0
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <schedule-response xmlns="urn:ietf:params:xml:ns:ischedule">
+ <response>
+ <recipient>mailto:cyrus at example.org</recipient>
+ <request-status>2.0;Success</request-status>
+ <calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//EN
+ METHOD:REPLY
+ BEGIN:VFREEBUSY
+ DTSTAMP:20040901T200200Z
+ ORGANIZER:mailto:bernard at example.com
+ DTSTART:20040902T000000Z
+ DTEND:20040903T000000Z
+ UID:34222-232 at example.com
+ ATTENDEE;CN=Cyrus Daboo:mailto:cyrus at example.org
+ FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20040902T000000Z/
+ 20040902T090000Z,20040902T170000Z/20040903T000000Z
+ FREEBUSY;FBTYPE=BUSY:20040902T120000Z/20040902T130000Z
+ END:VFREEBUSY
+ END:VCALENDAR
+ </calendar-data>
+ </response>
+ </schedule-response>
+
+
+ In this example, the iSchedule Sender requests the iSchedule Receiver
+ to determine the busy information of the calendar user
+ mailto:cyrus at example.org, over the time range specified by the
+ scheduling message sent in the request. The response includes
+ VFREEBUSY components with the busy time of the requested calendar
+ user.
+
+
+
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 16]
+
+Internet-Draft iSchedule November 2009
+
+
+6.1.5. Example: Simple Task Assignment
+
+ >> Request <<
+
+
+ POST /.well-known/ischedule HTTP/1.1
+ Host: cal.example.org
+ iSchedule-Version: 1.0
+ Originator: mailto:bernard at example.com
+ Recipient: mailto:cyrus at example.org
+ Content-Type: text/calendar
+ Content-Length: xxxx
+
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ METHOD:REQUEST
+ BEGIN:VTODO
+ DTSTAMP:20040901T200200Z
+ ORGANIZER:mailto:bernard at example.com
+ DUE:20070505
+ SUMMARY:Review Internet-Draft
+ UID:34222-456 at example.com
+ ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;ROLE=RE
+ Q-PARTICIPANT;CUTYPE=INDIVIDUAL;CN=Cyrus Daboo:
+ mailto:cyrus at example.org
+ END:VEVENT
+ END:VCALENDAR
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 17]
+
+Internet-Draft iSchedule November 2009
+
+
+ >> Response <<
+
+
+ HTTP/1.1 200 OK
+ Date: Thu, 02 Sep 2004 16:53:32 GMT
+ Content-Type: application/xml; charset=utf-8
+ Content-Length: xxxx
+ iSchedule-Version: 1.0
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <schedule-response
+ xmlns="urn:ietf:params:xml:ns:ischedule">
+ <response>
+ <recipient>mailto:cyrus at example.org</recipient>
+ <request-status>2.0;Success</request-status>
+ <responsedescription>Delivered to recipient
+ scheduling inbox</responsedescription>
+ </response>
+ </schedule-response>
+
+
+ In this example, the iSchedule Sender requests the iSchedule Sender
+ to deliver a task assignment (scheduling REQUEST) to the calendar
+ user mailto:cyrus at example.org. The response indicates that delivery
+ of the scheduling message was successful.
+
+7. HTTP Headers
+
+7.1. iSchedule-Version General Header
+
+
+ iSchedule-Version = "iSchedule-Version" ":" 1*DIGIT "." 1*DIGIT
+
+ The iSchedule-Version general header field MUST be specified by the
+ iSchedule Sender on requests, and by the iSchedule Receiver on
+ responses.
+
+ TODO: Consider whether the iSchedule-Version should be returned on a
+ per recipient basis in the response body.
+
+7.2. iSchedule-Via General Header
+
+
+ iSchedule-Via = "iSchedule-Via" ":" 1#( received-protocol
+ received-by [ comment ] )
+ ; received-protocol as defined in [RFC2616]
+ ; received-by as defined in [RFC2616]
+ ; comment as defined in [RFC2616]
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 18]
+
+Internet-Draft iSchedule November 2009
+
+
+ The iSchedule-Via general header field MUST be used by iSchedule
+ intermediaries to indicate the intermediate protocols and recipients
+ between the iSchedule Sender and the iSchedule Receiver on requests.
+
+ TODO: Consider whether the iSchedule-Via should be returned on a per
+ recipient basis in the response body.
+
+7.3. Originator Request Header
+
+
+ Originator = "Originator" ":" absoluteURI
+
+ ; absoluteURI as defined in [RFC3986]
+
+
+ The Originator request header value is a URI which specifies the
+ calendar user address of the originator of the scheduling message.
+ Note that the absoluteURI production is defined in RFC3986 [RFC3986].
+
+7.4. Recipient Request Header
+
+
+ Recipient = "Recipient" ":" 1#absoluteURI
+
+ ; absoluteURI as defined in [RFC3986]
+
+ The Recipient request header value is a URI which specifies the
+ calendar user address of the recipients to which the POST method
+ should deliver the submitted scheduling message. Note that the
+ absoluteURI production is defined in RFC3986 [RFC3986]
+
+8. XML Element Definitions
+
+8.1. schedule-response XML Element
+
+ Name: schedule-response
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Contains the set of responses for a POST method request.
+
+ Description: See Section 6.1.1.
+
+ Definition:
+
+
+ <!ELEMENT schedule-response (response*)>
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 19]
+
+Internet-Draft iSchedule November 2009
+
+
+8.1.1. response XML Element
+
+ Name: response
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Contains a single response for a POST method request.
+
+ Description: See Section 6.1.1.
+
+ Definition:
+
+
+ <!ELEMENT response (recipient,
+ request-status,
+ calendar-data?,
+ error?,
+ responsedescription?)>
+
+8.1.1.1. recipient XML Element
+
+ Name: recipient
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: The calendar user address (recipient header value) that the
+ enclosing response for a POST method request is for.
+
+ Description: See Section 6.1.1.
+
+ Definition:
+
+
+ <!ELEMENT recipient (href)>
+
+8.1.1.2. request-status XML Element
+
+ Name: request-status
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: The iTIP REQUEST-STATUS property value for this response.
+
+ Description: See Section 6.1.1.
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 20]
+
+Internet-Draft iSchedule November 2009
+
+
+ Definition:
+
+
+ <!ELEMENT request-status (#PCDATA)>
+
+8.1.1.3. calendar-data XML Element
+
+ Name: calendar-data
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: An iCalendar object in a response to a seach for busy time
+ information.
+
+ Description: See Section 6.1.1.
+
+ Definition:
+
+
+ <!ELEMENT calendar-data (#PCDATA)>
+
+8.1.1.4. error XML Element
+
+ Name: error
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Error responses sometimes need more information to indicate
+ what went wrong.
+
+ Description: See Section 6.1.1.
+
+ Definition:
+
+
+ <!ELEMENT error ANY>
+
+8.1.1.5. responsedescription XML Element
+
+ Name: responsedescription
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Contains information about a status response
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 21]
+
+Internet-Draft iSchedule November 2009
+
+
+ Description: See Section 6.1.1.
+
+ Definition:
+
+
+ <!ELEMENT responsedescription (#PCDATA)>
+
+8.2. query-result XML Element
+
+ Name: query-result
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Contains result of a query request.
+
+ Description: A generic container for the result of a query request,
+ such as a query of the capabilities of an iSchedule Receiver.
+
+ Definition:
+
+
+ <!ELEMENT query-result (capability-set)>
+
+8.2.1. capability-set XML Element
+
+ Name: capability-set
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Contains iSchedule Receiver capabilities.
+
+ Description: The capability-set element contains capabilities of the
+ iSchedule Receiver.
+
+ Definition:
+
+
+ <!ELEMENT capability-set (supported-version-set,
+ supported-scheduling-message-set,
+ supported-calendar-data,
+ supported-attachment-values,
+ supported-recipient-uri-scheme-set,
+ max-content-length,
+ min-date-time,
+ max-date-time,
+ max-instances,
+ max-recipients,
+ administrator) >
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 22]
+
+Internet-Draft iSchedule November 2009
+
+
+8.2.1.1. supported-version-set XML Element
+
+ Name: supported-version-set
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Identifies the iSchedule versions supported by the
+ iSchedule Receiver.
+
+ Description: An iSchedule Receiver MAY advertise support for
+ multiple versions of the iSchedule protocol.
+
+ Definition:
+
+
+ <!ELEMENT supported-version-set (version)+>
+
+8.2.1.1.1. version XML Element
+
+ Name: version
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specifies an iSchedule version.
+
+ Definition:
+
+
+ <!ELEMENT version (#PCDATA)>
+ <!-- PCDATA value: version number -->
+
+8.2.1.2. supported-scheduling-message-set XML Element
+
+ Name: supported-scheduling-message-set
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Identifies the type of supported scheduling messages.
+
+ Description: An iSchedule Receiver could advertise that it only
+ provides support for event and free-busy scheduling messages, and
+ not for to-do scheduling messages, with this capabilities.
+
+ Definition:
+
+
+ <!ELEMENT supported-scheduling-message-set (comp)+>
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 23]
+
+Internet-Draft iSchedule November 2009
+
+
+8.2.1.2.1. comp XML Element
+
+ Name: comp
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Identifies a calendar component type.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT comp (method)*>
+
+ <!ATTLIST comp name CDATA #REQUIRED>
+ <!-- name value: a calendar component name -->
+
+8.2.1.2.1.1. method XML Element
+
+ Name: method
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specifies an iCalendar method type.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT method EMPTY>
+
+ <!ATTLIST method name CDATA #REQUIRED>
+ <!-- name value: a method type -->
+
+8.2.1.3. supported-calendar-data XML Element
+
+ Name: supported-calendar-data
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Contains
+
+ Description:
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 24]
+
+Internet-Draft iSchedule November 2009
+
+
+ Definition:
+
+
+ <!ELEMENT supported-calendar-data (calendar-data)+>
+
+8.2.1.3.1. calendar-data XML Element
+
+ Name: calendar-data
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specified a supported media type for scheduling messages.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT calendar-data EMPTY>
+
+ <!ATTLIST calendar-data content-type CDATA "text/calendar"
+ version CDATA "2.0">
+ <!-- content-type value: a MIME media type -->
+ <!-- version value: a version string -->
+
+8.2.1.4. supported-attachment-values XML Element
+
+ Name: supported-attachment-values
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Identifies the attachment values supported.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT supported-attachment-values (inline-attachment?,
+ external-attachment?)>
+
+8.2.1.4.1. inline-attachment XML Element
+
+ Name: inline-attachment
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 25]
+
+Internet-Draft iSchedule November 2009
+
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specifies inline attachment as a supported attachment
+ value.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT inline-attachment EMPTY>
+
+8.2.1.4.2. external-attachment XML Element
+
+ Name: external-attachment
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specifies external attachment as a supported attachment
+ value.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT external-attachment EMPTY>
+
+8.2.1.5. supported-recipient-uri-scheme-set XML Element
+
+ Name: supported-recipient-uri-scheme-set
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Identifies the supported URI schemes supported in the
+ Recipient HTTP request header.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT supported-recipient-uri-scheme-set (scheme+)>
+
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 26]
+
+Internet-Draft iSchedule November 2009
+
+
+8.2.1.5.1. scheme XML Element
+
+ Name: scheme
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specifies a supported URI scheme.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT scheme (#PCDATA)>
+ <!-- PCDATA value: URI scheme (e.g., mailto) -->
+
+8.2.1.6. max-content-length XML Element
+
+ Name: max-content-length
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specifies the maximum size allowed for a scheduling message
+ in octets.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT max-content-length (#PCDATA)>
+ <!-- PCDATA value: a numeric value (positive integer) -->
+
+8.2.1.7. min-date-time XML Element
+
+ Name: min-date-time
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specifies a DATE-TIME value indicating the earliest date
+ and time in UTC that the server is willing to accept for any DATE
+ or DATE-TIME value in a scheduling message.
+
+ Description:
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 27]
+
+Internet-Draft iSchedule November 2009
+
+
+ Definition:
+
+
+ <!ELEMENT min-date-time (#PCDATA)>
+ <!-- PCDATA value: an iCalendar format DATE-TIME value in UTC -->
+
+8.2.1.8. max-date-time XML Element
+
+ Name: max-date-time
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specifies a DATE-TIME value indicating the latest date and
+ time in UTC that the server is willing to accept for any DATE or
+ DATE-TIME value in a scheduling message.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT max-date-time (#PCDATA)>
+ <!-- PCDATA value: an iCalendar format DATE-TIME value in UTC -->
+
+8.2.1.9. max-instances XML Element
+
+ Name: max-instances
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specifies the maximum number of recurrence instances
+ allowed in a scheduling message.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT max-instances (#PCDATA)>
+ <!-- PCDATA value: a numeric value (positive integer) -->
+
+8.2.1.10. max-recipients XML Element
+
+ Name: max-recipients
+
+
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 28]
+
+Internet-Draft iSchedule November 2009
+
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Specifies the maximum number of recipients allowed for a
+ scheduling message.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT max-recipients (#PCDATA)>
+ <!-- PCDATA value: a numeric value (positive integer) -->
+
+8.2.1.11. administrator XML Element
+
+ Name: administrator
+
+ Namespace: urn:ietf:params:xml:ns:ischedule
+
+ Purpose: Provides contact information for the administrator of the
+ iSchedule Receiver.
+
+ Description:
+
+ Definition:
+
+
+ <!ELEMENT administrator (#PCDATA)>
+ <!-- PCDATA value: URI to contact administrator -->
+
+9. Security Considerations
+
+ The process of scheduling involves the sending and receiving of
+ scheduling messages. As a result, the security problems related to
+ messaging in general are relevant here. In particular the
+ authenticity of the scheduling messages needs to be verified.
+
+9.1. Privacy
+
+ iSchedule Senders and iSchedule Receivers MUST use an HTTP connection
+ protected with TLS as defined in [RFC2818] for all scheduling
+ transactions.
+
+9.2. Authentication
+
+ Mutual authentication is done with TLS [RFC5246] using certificates
+ exchanged between both the iSchedule Sender and the iSchedule
+ Receiver.
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 29]
+
+Internet-Draft iSchedule November 2009
+
+
+9.3. Authorization
+
+ Once an iSchedule Sender has been successfully authenticated, the
+ iSchedule Receiver MUST verify that the iSchedule Sender has the
+ authority to send a scheduling message on behalf of the Originator.
+
+ TODO: Clarify how verification must be done. Should trusted
+ iSchedule Sender be identified as such in DNS (e.g., by storing their
+ certificate in the DNS (see [RFC4398])) Should the iSchedule Receiver
+ contact the iSchedule Receiver of the domain of the iSchedule Sender
+ to find out whether it should be trusted or not?
+
+10. IANA Considerations
+
+10.1. Namespace Registration
+
+ This specification registers a new URN to identify a new XML
+ namespace as per [RFC3688].
+
+10.1.1. iSchedule Namespace Registration
+
+ Registration request for the iSchedule namespace:
+
+ URI: urn:ietf:params:xml:ns:ischedule
+
+ Registrant Contact: See the "Authors' Addresses" section of this
+ document.
+
+ XML: None. Namespace URIs do not represent an XML specification.
+
+10.2. HTTP Headers Registration
+
+ This specification registers three new headers for use with HTTP as
+ per [RFC3864].
+
+10.2.1. iSchedule-Version General Header Registration
+
+ Header field name: iSchedule-Version
+
+ Applicable protocol: http
+
+ Status: standard
+
+ Author/Change controller: IETF
+
+ Specification document(s): this specification
+
+ Related information: none
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 30]
+
+Internet-Draft iSchedule November 2009
+
+
+10.2.2. iSchedule-Via General Header Registration
+
+ Header field name: iSchedule-Via
+
+ Applicable protocol: http
+
+ Status: standard
+
+ Author/Change controller: IETF
+
+ Specification document(s): this specification
+
+ Related information: none
+
+10.2.3. Originator Request Header Registration
+
+ Header field name: Originator
+
+ Applicable protocol: http
+
+ Status: standard
+
+ Author/Change controller: IETF
+
+ Specification document(s): this specification
+
+ Related information: none
+
+10.2.4. Recipient Request Header Registration
+
+ Header field name: Recipient
+
+ Applicable protocol: http
+
+ Status: standard
+
+ Author/Change controller: IETF
+
+ Specification document(s): this specification
+
+ Related information: none
+
+10.3. Well-Known URI Registration
+
+ This specification registers a new well-known URI as per
+ [I-D.nottingham-site-meta].
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 31]
+
+Internet-Draft iSchedule November 2009
+
+
+10.3.1. iSchedule Well-Known URI Registration
+
+ URI suffix: ischedule
+
+ Change controller: IETF.
+
+ Specification document(s): this specification
+
+ Related information: none
+
+11. Acknowledgments
+
+ The authors would like to thank the following individuals for
+ contributing their ideas and support for writing this specification:
+ Mattias Amnefelt, Mike Douglass, Tomas Hnetila, Ciny Joy, Arnaud
+ Quillaud, Simon Vaillancourt, and Wilfredo Sanchez Vega.
+
+ The authors would also like to thank the Calendaring and Scheduling
+ Consortium for advice with this specification, and for organizing
+ interoperability testing events to help refine it.
+
+12. References
+
+12.1. Normative References
+
+ [I-D.desruisseaux-caldav-sched] Daboo, C. and B. Desruisseaux,
+ "CalDAV Scheduling Extensions to
+ WebDAV",
+ draft-desruisseaux-caldav-sched-08
+ (work in progress), August 2009.
+
+ [I-D.ietf-calsify-2446bis] Daboo, C., "iCalendar Transport-
+ Independent Interoperability
+ Protocol (iTIP)",
+ draft-ietf-calsify-2446bis-10 (work
+ in progress), October 2009.
+
+ [I-D.nottingham-site-meta] Nottingham, M. and E. Hammer-Lahav,
+ "Defining Well-Known URIs",
+ draft-nottingham-site-meta-03 (work
+ in progress), September 2009.
+
+ [RFC2119] Bradner, S., "Key words for use in
+ RFCs to Indicate Requirement
+ Levels", BCP 14, RFC 2119,
+ March 1997.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J.,
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 32]
+
+Internet-Draft iSchedule November 2009
+
+
+ Frystyk, H., Masinter, L., Leach,
+ P., and T. Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1",
+ RFC 2616, June 1999.
+
+ [RFC2782] Gulbrandsen, A., Vixie, P., and L.
+ Esibov, "A DNS RR for specifying the
+ location of services (DNS SRV)",
+ RFC 2782, February 2000.
+
+ [RFC2818] Rescorla, E., "HTTP Over TLS",
+ RFC 2818, May 2000.
+
+ [RFC3688] Mealling, M., "The IETF XML
+ Registry", BCP 81, RFC 3688,
+ January 2004.
+
+ [RFC3986] Berners-Lee, T., Fielding, R., and
+ L. Masinter, "Uniform Resource
+ Identifier (URI): Generic Syntax",
+ STD 66, RFC 3986, January 2005.
+
+ [RFC5246] Dierks, T. and E. Rescorla, "The
+ Transport Layer Security (TLS)
+ Protocol Version 1.2", RFC 5246,
+ August 2008.
+
+ [RFC5545] Desruisseaux, B., "Internet
+ Calendaring and Scheduling Core
+ Object Specification (iCalendar)",
+ RFC 5545, September 2009.
+
+ [W3C.REC-xml-20081126] Yergeau, F., Maler, E., Paoli, J.,
+ Sperberg-McQueen, C., and T. Bray,
+ "Extensible Markup Language (XML)
+ 1.0 (Fifth Edition)", World Wide Web
+ Consortium Recommendation REC-xml-
+ 20081126, November 2008, <http://
+ www.w3.org/TR/2008/
+ REC-xml-20081126>.
+
+12.2. Informative References
+
+ [I-D.faltstrom-uri] Faltstrom, P. and O. Kolkman, "The
+ Uniform Resource Identifier (URI)
+ DNS Resource Record",
+ draft-faltstrom-uri-04 (work in
+ progress), May 2009.
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 33]
+
+Internet-Draft iSchedule November 2009
+
+
+ [I-D.ietf-calsify-rfc2447bis] Melnikov, A., "iCalendar Message-
+ Based Interoperability Protocol
+ (iMIP)",
+ draft-ietf-calsify-rfc2447bis-07
+ (work in progress), October 2009.
+
+ [RFC3864] Klyne, G., Nottingham, M., and J.
+ Mogul, "Registration Procedures for
+ Message Header Fields", BCP 90,
+ RFC 3864, September 2004.
+
+ [RFC4398] Josefsson, S., "Storing Certificates
+ in the Domain Name System (DNS)",
+ RFC 4398, March 2006.
+
+ [RFC4791] Daboo, C., Desruisseaux, B., and L.
+ Dusseault, "Calendaring Extensions
+ to WebDAV (CalDAV)", RFC 4791,
+ March 2007.
+
+Appendix A. Open Issues
+
+ 1. Should we consider [I-D.faltstrom-uri] as another approach to
+ discover iSchedule Receiver?
+
+Authors' Addresses
+
+ Cyrus Daboo
+ Apple Inc.
+ 1 Infinite Loop
+ Cupertino, CA 95014
+ USA
+
+ EMail: cyrus at daboo.name
+ URI: http://www.apple.com/
+
+
+ Bernard Desruisseaux
+ Oracle Corporation
+ 600 Blvd. de Maisonneuve West
+ Suite 1900
+ Montreal, QC H3A 3J2
+ CANADA
+
+ EMail: bernard.desruisseaux at oracle.com
+ URI: http://www.oracle.com/
+
+
+
+
+
+Daboo & Desruisseaux Expires May 19, 2010 [Page 34]
+
\ No newline at end of file
Copied: CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-nottingham-site-meta.txt (from rev 4951, CalendarServer/trunk/doc/RFC/draft-nottingham-site-meta.txt)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-nottingham-site-meta.txt (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-nottingham-site-meta.txt 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,448 @@
+
+
+
+Network Working Group M. Nottingham
+Internet-Draft E. Hammer-Lahav
+Updates: 2616 2818 November 20, 2009
+(if approved)
+Intended status: Standards Track
+Expires: May 24, 2010
+
+
+ Defining Well-Known URIs
+ draft-nottingham-site-meta-04
+
+Abstract
+
+ This memo defines a path prefix for "well-known locations", "/.well-
+ known/" in selected URI schemes.
+
+Status of this Memo
+
+ This Internet-Draft is submitted to IETF in full conformance with the
+ provisions of BCP 78 and BCP 79.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF), its areas, and its working groups. Note that
+ other groups may also distribute working documents as Internet-
+ Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt.
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+ This Internet-Draft will expire on May 24, 2010.
+
+Copyright Notice
+
+ Copyright (c) 2009 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+
+
+
+Nottingham & Hammer-Lahav Expires May 24, 2010 [Page 1]
+
+Internet-Draft Defining Well-Known URIs November 2009
+
+
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the BSD License.
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2. Notational Conventions . . . . . . . . . . . . . . . . . . . . 3
+ 3. Well-Known URIs . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 4. Security Considerations . . . . . . . . . . . . . . . . . . . . 4
+ 5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 4
+ 5.1. The Well-Known URI Registry . . . . . . . . . . . . . . . . 4
+ 5.1.1. Registration Template . . . . . . . . . . . . . . . . . 5
+ 6. References . . . . . . . . . . . . . . . . . . . . . . . . . . 5
+ 6.1. Normative References . . . . . . . . . . . . . . . . . . . 5
+ 6.2. Informative References . . . . . . . . . . . . . . . . . . 6
+ Appendix A. Acknowledgements . . . . . . . . . . . . . . . . . . . 6
+ Appendix B. Frequently Asked Questions . . . . . . . . . . . . . . 6
+ B.1. Aren't well-known locations bad for the Web? . . . . . . . 6
+ B.2. Why /.well-known? . . . . . . . . . . . . . . . . . . . . . 7
+ B.3. What impact does this have on existing mechanisms,
+ such as P3P and robots.txt? . . . . . . . . . . . . . . . . 7
+ B.4. Why aren't per-directory well-known locations defined? . . 7
+ Appendix C. Document History . . . . . . . . . . . . . . . . . . . 7
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Nottingham & Hammer-Lahav Expires May 24, 2010 [Page 2]
+
+Internet-Draft Defining Well-Known URIs November 2009
+
+
+1. Introduction
+
+ It is increasingly common for Web-based protocols to require the
+ discovery of policy or metadata before making a request. For
+ example, the Robots Exclusion Protocol specifies a way for automated
+ processes to obtain permission to access resources; likewise, the
+ Platform for Privacy Preferences [W3C.REC-P3P-20020416] tells user-
+ agents how to discover privacy policy beforehand.
+
+ While there are several ways to access per-resource metadata (e.g.,
+ HTTP headers, WebDAV's PROPFIND [RFC4918]), the perceived overhead
+ associated with them often precludes their use in these scenarios.
+
+ When this happens, it is common to designate a "well-known location"
+ for such metadata, so that it can be easily located. However, this
+ approach has the drawback of risking collisions, both with other such
+ designated "well-known locations" and with pre-existing resources.
+
+ To address this, this memo defines a path prefix in HTTP(S) URIs for
+ these "well-known locations", "/.well-known/". Future specifications
+ that need to define a resource for such site-wide metadata can
+ register their use to avoid collisions and minimise impingement upon
+ sites' URI space.
+
+ [[ Please discuss this draft on the apps-discuss at ietf.org [1] mailing
+ list. ]]
+
+
+2. Notational Conventions
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [RFC2119].
+
+
+3. Well-Known URIs
+
+ A well-known URI is a URI [RFC3986] whose path component begins with
+ the characters "/.well-known/", and whose scheme is "HTTP", "HTTPS",
+ or another scheme which has explicitly been specified to use well-
+ known URIs.
+
+ Applications that wish to mint new well-known URIs MUST register
+ them, following the procedures in Section 5.1.
+
+ For example, if an application registers the value 'example', the
+ corresponding well-known URI on 'http://www.example.com/' would be
+ 'http://www.example.com/.well-known/example'.
+
+
+
+Nottingham & Hammer-Lahav Expires May 24, 2010 [Page 3]
+
+Internet-Draft Defining Well-Known URIs November 2009
+
+
+ Note that this specification defines neither how to determine the
+ authority to use for a particular context, nor the scope of the
+ metadata discovered by dereferencing the well-known URI; both should
+ be defined by the application itself.
+
+ Typically, a registration will reference a specification that defines
+ the format and associated media type to be obtained by dereferencing
+ the well-known URI.
+
+ It MAY also contain additional information, such as the syntax of
+ additional path components, query strings and/or fragment identifiers
+ to be appended to the well-known URI, or protocol-specific details
+ (e.g., HTTP [RFC2616] method handling).
+
+ Note that this specification also does not define a format or media-
+ type for the resource at located at "/.well-known/" and clients
+ should not expect a resource to exist at that location.
+
+
+4. Security Considerations
+
+ This memo does not specify the scope of applicability of metadata or
+ policy obtained from a well-known URI, and does not specify how to
+ discover a well-known URI for a particular application. Individual
+ applications using this mechanism must define both aspects.
+
+ An attacker with certain types of limited access to a server may be
+ able to affect how well-known URIs are served; for example, they may
+ be able to upload a file at that location, or they may be able to
+ cause a server to redirect a well-known URI to a URI that they
+ control.
+
+ Because most URI schemes rely on DNS to resolve names, they are
+ vulnerable to "DNS rebinding" attacks, whereby a request can be
+ directed to a server under the control of an attacker.
+
+
+5. IANA Considerations
+
+5.1. The Well-Known URI Registry
+
+ This document establishes the well-known URI registry.
+
+ Well-known URIs are registered on the advice of one or more
+ Designated Experts (appointed by the IESG or their delegate), with a
+ Specification Required (using terminology from [RFC5226]).
+
+ Registration requests consist of the completed registration template
+
+
+
+Nottingham & Hammer-Lahav Expires May 24, 2010 [Page 4]
+
+Internet-Draft Defining Well-Known URIs November 2009
+
+
+ (see Section 5.1.1), typically published in an RFC or Open Standard
+ (in the sense described by [RFC2026], section 7). However, to allow
+ for the allocation of values prior to publication, the Designated
+ Expert(s) may approve registration once they are satisfied that an
+ RFC (or other Open Standard) will be published.
+
+ Registration requests should be sent to the [TBD]@ietf.org mailing
+ list for review and comment, with an appropriate subject (e.g.,
+ "Request for well-known URI: example").
+
+ [[NOTE TO RFC-EDITOR: The name of the mailing list should be
+ determined in consultation with the IESG and IANA. Suggested name:
+ wellknown-uri-review. ]]
+
+ Before a period of 14 days has passed, the Designated Expert(s) will
+ either approve or deny the registration request, communicating this
+ decision both to the review list and to IANA. Denials should include
+ an explanation and, if applicable, suggestions as to how to make the
+ request successful.
+
+5.1.1. Registration Template
+
+ URI suffix: The name requested for the well-known URI, relative to
+ "/.well-known/"; e.g., "example". MUST conform to the segment-nz
+ production in [RFC3986].
+ Change controller: For standards-track RFCs, state "IETF". For
+ other open standards, give the name of the publishing body (e.g.,
+ ANSI, ISO, ITU, W3C, etc.). A postal address, home page URI,
+ telephone and fax numbers may also be included.
+ Specification document(s): Reference to document that specifies the
+ field, preferably including a URI that can be used to retrieve a
+ copy of the document. An indication of the relevant sections may
+ also be included, but is not required.
+ Related information: Optionally, citations to additional documents
+ containing further relevant information.
+
+
+6. References
+
+6.1. Normative References
+
+ [RFC2026] Bradner, S., "The Internet Standards Process -- Revision
+ 3", BCP 9, RFC 2026, October 1996.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
+
+
+
+Nottingham & Hammer-Lahav Expires May 24, 2010 [Page 5]
+
+Internet-Draft Defining Well-Known URIs November 2009
+
+
+ Resource Identifier (URI): Generic Syntax", STD 66,
+ RFC 3986, January 2005.
+
+ [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an
+ IANA Considerations Section in RFCs", BCP 26, RFC 5226,
+ May 2008.
+
+6.2. Informative References
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC4918] Dusseault, L., "HTTP Extensions for Web Distributed
+ Authoring and Versioning (WebDAV)", RFC 4918, June 2007.
+
+ [W3C.REC-P3P-20020416]
+ Marchiori, M., "The Platform for Privacy Preferences 1.0
+ (P3P1.0) Specification", W3C REC REC-P3P-20020416,
+ April 2002.
+
+URIs
+
+ [1] <https://www.ietf.org/mailman/listinfo/apps-discuss>
+
+
+Appendix A. Acknowledgements
+
+ We would like to acknowledge the contributions of everyone who
+ provided feedback and use cases for this draft; in particular, Phil
+ Archer, Dirk Balfanz, Adam Barth, Tim Bray, Brian Eaton, Brad
+ Fitzpatrick, Joe Gregorio, Paul Hoffman, Barry Leiba, Ashok Malhotra,
+ Breno de Medeiros, John Panzer, and Drummond Reed. However, they are
+ not responsible for errors and omissions.
+
+
+Appendix B. Frequently Asked Questions
+
+B.1. Aren't well-known locations bad for the Web?
+
+ They are, but for various reasons -- both technical and social --
+ they are commonly used, and their use is increasing. This memo
+ defines a "sandbox" for them, to reduce the risks of collision and to
+ minimise the impact upon pre-existing URIs on sites.
+
+
+
+
+
+
+
+Nottingham & Hammer-Lahav Expires May 24, 2010 [Page 6]
+
+Internet-Draft Defining Well-Known URIs November 2009
+
+
+B.2. Why /.well-known?
+
+ It's short, descriptive and according to search indices, not widely
+ used.
+
+B.3. What impact does this have on existing mechanisms, such as P3P and
+ robots.txt?
+
+ None, until they choose to use this mechanism.
+
+B.4. Why aren't per-directory well-known locations defined?
+
+ Allowing every URI path segment to have a well-known location (e.g.,
+ "/images/.well-known/") would increase the risks of colliding with a
+ pre-existing URI on a site, and generally these solutions are found
+ not to scale well, because they're too "chatty".
+
+
+Appendix C. Document History
+
+ [[RFC Editor: please remove this section before publication.]]
+
+ o -04
+ * Restrict to HTTP(S) by default.
+ * Shorten review SLA to 14 days.
+ * Allow for multiple designated experts.
+ * Identify mailing list for request submission and discussion.
+ o -03
+ * Add fragment identifiers to list of things an application might
+ define.
+ * Note that the /.well-known/ URI doesn't have anything there.
+ o -02
+ * Rewrote to just define a namespace for well-known URIs.
+ * Changed discussion forum to apps-discuss.
+ o -01
+ * Changed "site-meta" to "host-meta" after feedback.
+ * Changed from XML to text-based header-like format.
+ * Remove capability for generic inline content.
+ * Added registry for host-meta fields.
+ * Clarified scope of metadata application.
+ * Added security consideration about HTTP vs. HTTPS, expanding
+ scope.
+
+
+
+
+
+
+
+
+
+Nottingham & Hammer-Lahav Expires May 24, 2010 [Page 7]
+
+Internet-Draft Defining Well-Known URIs November 2009
+
+
+Authors' Addresses
+
+ Mark Nottingham
+
+ Email: mnot at mnot.net
+ URI: http://www.mnot.net/
+
+
+ Eran Hammer-Lahav
+
+ Email: eran at hueniverse.com
+ URI: http://hueniverse.com/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Nottingham & Hammer-Lahav Expires May 24, 2010 [Page 8]
+
\ No newline at end of file
Copied: CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-reschke-webdav-post.txt (from rev 4951, CalendarServer/trunk/doc/RFC/draft-reschke-webdav-post.txt)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-reschke-webdav-post.txt (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/doc/RFC/draft-reschke-webdav-post.txt 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,784 @@
+
+
+
+Network Working Group J. Reschke
+Internet-Draft greenbytes
+Intended status: Standards Track November 22, 2009
+Expires: May 26, 2010
+
+
+ Using POST to add Members to Web Distributed Authoring and Versioning
+ (WebDAV) Collections
+ draft-reschke-webdav-post-05
+
+Abstract
+
+ The Hypertext Transfer Protocol (HTTP) Extensions for the Web
+ Distributed Authoring and Versioning (WebDAV) do not define the
+ behavior for the "POST" method when applied to collections, as the
+ base specification (HTTP) leaves implementers lots of freedom for the
+ semantics of "POST".
+
+ This has led to a situation where many WebDAV servers do not
+ implement POST for collections at all, although it is well suited to
+ be used for the purpose of adding new members to a collection, where
+ the server remains in control of the newly assigned URL. As a matter
+ of fact, the Atom Publishing Protocol (AtomPub) uses POST exactly for
+ that purpose. On the other hand, WebDAV-based protocols such as the
+ Calendar Extensions to WebDAV (CalDAV) frequently require clients to
+ pick a unique URL, although the server could easily perform that
+ task.
+
+ This specification defines a discovery mechanism through which
+ servers can advertise support for POST requests with the
+ aforementioned "add collection member" semantics.
+
+Editorial Note (To be removed by RFC Editor before publication)
+
+ Please send comments to the Distributed Authoring and Versioning
+ (WebDAV) working group at <mailto:w3c-dist-auth at w3.org>, which may be
+ joined by sending a message with subject "subscribe" to
+ <mailto:w3c-dist-auth-request at w3.org>. Discussions of the WEBDAV
+ working group are archived at
+ <http://lists.w3.org/Archives/Public/w3c-dist-auth/>.
+
+ Note that although discussion takes place on the WebDAV working
+ group's mailing list, this is not a working group document.
+
+ XML versions, latest edits and the issues list for this document are
+ available from
+ <http://greenbytes.de/tech/webdav/#draft-reschke-webdav-post>.
+
+
+
+
+Reschke Expires May 26, 2010 [Page 1]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+Status of this Memo
+
+ This Internet-Draft is submitted to IETF in full conformance with the
+ provisions of BCP 78 and BCP 79.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF), its areas, and its working groups. Note that
+ other groups may also distribute working documents as Internet-
+ Drafts.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ The list of current Internet-Drafts can be accessed at
+ http://www.ietf.org/ietf/1id-abstracts.txt.
+
+ The list of Internet-Draft Shadow Directories can be accessed at
+ http://www.ietf.org/shadow.html.
+
+ This Internet-Draft will expire on May 26, 2010.
+
+Copyright Notice
+
+ Copyright (c) 2009 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the BSD License.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Reschke Expires May 26, 2010 [Page 2]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 5
+ 3. Protocol Extension . . . . . . . . . . . . . . . . . . . . . . 6
+ 3.1. Definition of 'Add-Member' URI . . . . . . . . . . . . . . 6
+ 3.2. Discovery . . . . . . . . . . . . . . . . . . . . . . . . 7
+ 3.2.1. DAV:add-member Property (protected) . . . . . . . . . 7
+ 3.2.2. Example . . . . . . . . . . . . . . . . . . . . . . . 7
+ 3.3. Relation to AtomPub's 'Slug' Header Field . . . . . . . . 8
+ 3.4. Example Operation . . . . . . . . . . . . . . . . . . . . 9
+ 4. Additional Semantics for existing Methods . . . . . . . . . . 9
+ 4.1. Additional Preconditions . . . . . . . . . . . . . . . . . 9
+ 4.2. Example: Failed PUT Request . . . . . . . . . . . . . . . 10
+ 5. Relationship to WebDAV Access Control Protocol . . . . . . . . 10
+ 6. Internationalization Considerations . . . . . . . . . . . . . 10
+ 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 11
+ 8. Security Considerations . . . . . . . . . . . . . . . . . . . 11
+ 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 11
+ 10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 11
+ 10.1. Normative References . . . . . . . . . . . . . . . . . . . 11
+ 10.2. Informative References . . . . . . . . . . . . . . . . . . 12
+ Appendix A. Change Log (to be removed by RFC Editor before
+ publication) . . . . . . . . . . . . . . . . . . . . 12
+ A.1. since draft-reschke-webdav-post-00 . . . . . . . . . . . . 12
+ A.2. since draft-reschke-webdav-post-01 . . . . . . . . . . . . 13
+ A.3. since draft-reschke-webdav-post-02 . . . . . . . . . . . . 13
+ A.4. since draft-reschke-webdav-post-03 . . . . . . . . . . . . 13
+ A.5. since draft-reschke-webdav-post-04 . . . . . . . . . . . . 13
+ Appendix B. Open issues (to be removed by RFC Editor prior to
+ publication) . . . . . . . . . . . . . . . . . . . . 13
+ B.1. edit . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
+ B.2. collection . . . . . . . . . . . . . . . . . . . . . . . . 13
+ Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
+ Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 14
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Reschke Expires May 26, 2010 [Page 3]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+1. Introduction
+
+ The Hypertext Transfer Protocol (HTTP) Extensions for the Web
+ Distributed Authoring and Versioning (WebDAV) ([RFC4918], Section
+ 9.5) do not define the behavior for the "POST" method when applied to
+ collections, as the base specification (HTTP) leaves implementers
+ lots of freedom for the semantics of "POST":
+
+ 9.5 POST for Collections
+
+ Since by definition the actual function performed by POST is
+ determined by the server and often depends on the particular
+ resource, the behavior of POST when applied to collections cannot
+ be meaningfully modified because it is largely undefined. Thus,
+ the semantics of POST are unmodified when applied to a collection.
+
+ This has led to a situation where many WebDAV servers do not
+ implement POST for collections at all, although it is well suited to
+ be used for the purpose of adding new members to a collection, where
+ the server remains in control of the newly assigned URL. As a matter
+ of fact, the Atom Publishing Protocol (AtomPub) uses POST exactly for
+ that purpose ([RFC5023], Section 9.2):
+
+ 9.2 Creating Resources with POST
+
+ To add members to a Collection, clients send POST requests to the
+ URI of the Collection.
+
+ On the other hand, WebDAV-based protocols such as Calendaring
+ Extensions to WebDAV (CalDAV) frequently require clients to pick a
+ unique URL, although the server could easily perform that task
+ ([RFC4791], Section 5.3.2):
+
+ 5.3.2 Creating Calendar Object Resources
+
+ ...
+
+ When servers create new resources, it's not hard for the server to
+ choose an unmapped URI. It's slightly tougher for clients,
+ because a client might not want to examine all resources in the
+ collection and might not want to lock the entire collection to
+ ensure that a new resource isn't created with a name collision.
+ (...)
+
+ As a matter of fact, letting the server choose the member URI not
+ only is a simplification for certain types of clients, but can also
+ reduce the complexity of the server (in that it doesn't need to
+ persist an additional client-supplied identifier where it already has
+
+
+
+Reschke Expires May 26, 2010 [Page 4]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+ an internal one like a UUID or a primary key).
+
+ Note: the vCard Extensions to WebDAV (CardDAV)
+ ([draft-ietf-vcarddav-carddav]) suffer from the same issue, and
+ may be able to take advantage of this specification.
+
+ This specification defines a discovery mechanism through which
+ servers can advertise support for POST requests with the
+ aforementioned "add collection member" semantics.
+
+ Note that this specification deliberately only adresses the use case
+ of creating new non-collection resources, and that it was not a goal
+ to supply the same functionality for creating collection resources
+ (MKCOL), or for other operations that require the client to specify a
+ new URL (LOCK, MOVE, or COPY).
+
+ Note: the author previously proposed a new HTTP method for exactly
+ this purpose ([draft-reschke-http-addmember]), but quite a few
+ reviewers pointed out that this would duplicate the original
+ semantics of POST. Thus this proposal that avoids adding a new
+ HTTP method is made.
+
+
+2. Terminology
+
+ The terminology used here follows that in the WebDAV specification
+ ([RFC4918]).
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [RFC2119].
+
+ This document uses XML DTD fragments ([XML]) as a purely notational
+ convention. In particular:
+
+ o Element ordering is irrelevant.
+
+ o Extension elements/attributes (elements/attributes not already
+ defined as valid child elements) may be added anywhere, except
+ when explicitly stated otherwise.
+
+ Note: this specification defines new properties and precondition
+ names in the "DAV:" namespace, which the WebDAV specification
+ reserves for use by the IETF ([RFC4918], Section 21.1). However,
+ there was rough consensus in the WebDAV community that the
+ specification is of general applicability to other WebDAV related
+ standards efforts, and thus deserves inclusion into the base
+ namespace.
+
+
+
+Reschke Expires May 26, 2010 [Page 5]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+3. Protocol Extension
+
+ Due to the reasons stated in Section 1, clients can not rely on a
+ specific server behavior when POST is applied to a collection. This
+ problem is addressed by this specification by allowing servers to
+ advertise a URI that has the desired "add member" semantics.
+
+ Note that servers that already use POST for a different purpose can
+ just expose a separate URI. Other servers can just advertise the
+ collection's own URI, thus avoiding minting another URI for a limited
+ purpose.
+
+3.1. Definition of 'Add-Member' URI
+
+ The "Add-Member" URI of a WebDAV collection is a URI that will accept
+ HTTP POST requests, and will interpret these as requests to store the
+ enclosed entity as a new internal member of the collection (see
+ Section 3 of [RFC4918] for the definition of "internal member"). It
+ MUST identify a resource on the same server as the WebDAV collection
+ (the host and port components ([RFC2616], Section 3.2.2) of the URIs
+ must match).
+
+ If there are pre-conditions related to creating a resource in the
+ collection using a PUT request, then those same pre-conditions apply
+ to the new POST request behavior, and the same HTTP response body
+ will returned on failure.
+
+ The URI of the newly created resource is returned in the HTTP
+ Location response header field ([RFC2616], Section 14.30).
+
+ Note: the fact that a server advertises an "Add-Member" URI does
+ not imply any special semantics of the collection itself. For
+ instance, member URIs assigned by the server are not necessarily
+ unique over time (a member URI may be assigned again to a new
+ resource when it previously was removed).
+
+ Note: the "Add-Member" URI can be the identical to the
+ collection's URI (in which case the server just advertises the
+ fact that POST to the WebDAV collection's URI is supported as
+ defined within this specification). But it can also be different
+ from it, in which case it doesn't need to have any relation to the
+ collection's URI.
+
+ Given a collection URI of
+
+ /docs/collection/
+
+
+
+
+
+Reschke Expires May 26, 2010 [Page 6]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+ all of the URIs below might occur as "Add-Member" URIs:
+
+ /docs/collection/
+ /docs/collection/;post
+ /docs/collection;post/
+ /docs/collection/&post
+ /post-service?path=/collection/
+
+ The remainder of the document uses the same format just for
+ reasons of consistency; any other HTTP URI on the same server
+ would do as well.
+
+3.2. Discovery
+
+3.2.1. DAV:add-member Property (protected)
+
+ DAV:add-member is a protected property (see [RFC4918], Section 15)
+ defined on WebDAV collections, and contains the "Add-Member" URI for
+ that collection (embedded inside a DAV:href element).
+
+ <!ELEMENT add-member (href)>
+ <!-- href: defined in [RFC4918], Section 14.7 -->
+
+ A PROPFIND/allprop request SHOULD NOT return this property (see
+ [RFC4918], Section 9.1). Servers MUST implement the DAV:supported-
+ live-property-set property defined in Section 3.1.4 of [RFC3253], and
+ report the property DAV:add-member as a supported live property.
+
+3.2.2. Example
+
+ >>Request
+
+ PROPFIND /collection/ HTTP/1.1
+ Host: example.com
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: 118
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <propfind xmlns="DAV:">
+ <prop>
+ <add-member/>
+ </prop>
+ </propfind>
+
+
+
+
+
+
+
+
+Reschke Expires May 26, 2010 [Page 7]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+ >>Response
+
+ HTTP/1.1 207 Multi-Status
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: 340
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <multistatus xmlns="DAV:">
+ <response>
+ <href>/collection/</href>
+ <propstat>
+ <prop>
+ <add-member>
+ <href>/collection;add-member/</href>
+ </add-member>
+ </prop>
+ <status>HTTP/1.1 200 OK</status>
+ </propstat>
+ </response>
+ </multistatus>
+
+ Note that in this case, the server has minted a separate URI for the
+ purpose of adding new content.
+
+3.3. Relation to AtomPub's 'Slug' Header Field
+
+ In the AtomPub protocol, clients can use the entity header field
+ "Slug" to suggest parts of the URI to be created (see [RFC5023],
+ Section 9.7). Note that servers are free to ignore this suggestion,
+ or to use whatever algorithm that makes sense to generate the new
+ URI.
+
+ The same applies to the extension defined here: clients can use the
+ "Slug" header field as by its definition of a generic HTTP header
+ field. Servers should process it exactly in the way defined by
+ AtomPub.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Reschke Expires May 26, 2010 [Page 8]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+3.4. Example Operation
+
+ >>Request
+
+ POST /collection;add-member/ HTTP/1.1
+ Host: example.com
+ Content-Type: text/plain
+ Slug: Sample Title
+ Content-Length: 12
+
+ Sample text.
+
+ >>Response
+
+ HTTP/1.1 201 Created
+ Location: http://example.com/collection/sample%20title
+
+
+4. Additional Semantics for existing Methods
+
+ One important use case for this specification are collections that
+ act as WebDAV collections for the purpose of read access (PROPFIND
+ Depth 1/Infinity), but which only support internal member URIs
+ assigned by the server. These collections will not allow a client to
+ create a new member using methods like PUT, MKCOL, LOCK, COPY or
+ MOVE. Therefore, this specification defines a new precondition name
+ ([RFC4918], Section 16) that can be used to provide the client with
+ additional information about why exactly the request failed.
+
+ Note: although the precondition defined below can be used for
+ methods other than PUT, the "Add-Member" mechanism defined by this
+ specification deliberately is restricted to PUT.
+
+4.1. Additional Preconditions
+
+ (DAV:allow-client-defined-URI): the server allows clients to specify
+ the last path segment for newly created resources.
+
+ The precondition element MAY contain a add-member-uri XML element
+ specifying the "Add-Member" URI associated with the collection, on
+ which the creation of a new child resource was attempted:
+
+ <!ELEMENT allow-client-defined-uri (add-member?)>
+
+
+
+
+
+
+
+
+Reschke Expires May 26, 2010 [Page 9]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+4.2. Example: Failed PUT Request
+
+ In this example, the client tries to use PUT to create a new internal
+ member of /collection/.
+
+ >>Request
+
+ PUT /collection/new.txt HTTP/1.1
+ Host: example.com
+ Content-Type: text/plain
+ Content-Length: 12
+
+ Sample text.
+
+ >>Response
+
+ HTTP/1.1 405 Method Not Allowed
+ Allow: GET, HEAD, TRACE, PROPFIND, COPY, MOVE
+ Content-Type: application/xml; charset=UTF-8
+ Content-Length: 172
+
+ <error xmlns="DAV:">
+ <allow-client-defined-uri>
+ <add-member>
+ <href>/collection;add-member/</href>
+ </add-member>
+ </allow-client-defined-uri>
+ </error>
+
+ The request fails with a 405 (Method Not Allowed) status, but also
+ provides the reason, and a pointer to the "Add-Member" URI in the
+ response body.
+
+
+5. Relationship to WebDAV Access Control Protocol
+
+ The WebDAV ACL specification requires the DAV:bind privilege to be
+ granted on a collection for the client to be able add new collection
+ members ([RFC3744], Section 3.9). Consistent with that, a server
+ MUST reject a POST request to the Add-Member URI of a collection
+ unless the principal executing the request is granted DAV:bind
+ privilege on the associated WebDAV collection resource.
+
+
+6. Internationalization Considerations
+
+ This document does not introduce any new internationalization
+ considerations beyond those discussed in Section 20 of [RFC4918].
+
+
+
+Reschke Expires May 26, 2010 [Page 10]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+7. IANA Considerations
+
+ This specification does not require any actions from IANA.
+
+
+8. Security Considerations
+
+ All security considerations connected to HTTP/WebDAV and XML apply
+ for this specification as well, namely, [RFC4918] (Section 20) and
+ [RFC3470] (Section 7).
+
+ Furthermore, servers should be aware that deriving the member path
+ from the data being stored in the resource could potentially expose
+ confidential information. This could even be the case when only a
+ hash code of the content is used.
+
+ In addition, on servers that do not support this specification, a
+ malevolent user could set the DAV:add-member URI as a custom
+ property, tricking other users to post content to an entirely
+ different URI. Clients can protect themselves against this scenario
+ by
+
+ o not following DAV:add-member URIs to different servers, and/or
+
+ o verifying that the DAV:add-member property is indeed a live
+ property (this can be achieved by testing the DAV:supported-live-
+ property-set property, or by checking whether DAV:add-member is
+ returned upon PROPFIND/allprop)
+
+
+9. Acknowledgements
+
+ This document has benefited from thoughtful discussion by Cyrus Daboo
+ and Bernard Desruissaux.
+
+
+10. References
+
+10.1. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+ [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
+ Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
+ Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
+
+ [RFC3253] Clemm, G., Amsden, J., Ellison, T., Kaler, C., and J.
+
+
+
+Reschke Expires May 26, 2010 [Page 11]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+ Whitehead, "Versioning Extensions to WebDAV", RFC 3253,
+ March 2002.
+
+ [RFC3744] Clemm, G., Reschke, J., Sedlar, E., and J. Whitehead, "Web
+ Distributed Authoring and Versioning (WebDAV) Access
+ Control Protocol", RFC 3744, May 2004.
+
+ [RFC4918] Dusseault, L., Ed., "HTTP Extensions for Web Distributed
+ Authoring and Versioning (WebDAV)", RFC 4918, June 2007.
+
+ [XML] Bray, T., Paoli, J., Sperberg-McQueen, C., Maler, E., and
+ F. Yergeau, "Extensible Markup Language (XML) 1.0 (Fifth
+ Edition)", W3C REC-xml-20081126, November 2008,
+ <http://www.w3.org/TR/2008/REC-xml-20081126/>.
+
+10.2. Informative References
+
+ [RFC3470] Hollenbeck, S., Rose, M., and L. Masinter, "Guidelines for
+ the Use of Extensible Markup Language (XML) within IETF
+ Protocols", RFC 3470, BCP 70, January 2003.
+
+ [RFC4791] Daboo, C., Desruisseaux, B., and L. Dusseault,
+ "Calendaring Extensions to WebDAV (CalDAV)", RFC 4791,
+ March 2007.
+
+ [RFC5023] Gregorio, J. and B. de hOra, "The Atom Publishing
+ Protocol", RFC 5023, October 2007.
+
+ [draft-ietf-vcarddav-carddav]
+ Daboo, C., "vCard Extensions to WebDAV (CardDAV)",
+ draft-ietf-vcarddav-carddav-10 (work in progress),
+ November 2009.
+
+ [draft-reschke-http-addmember]
+ Reschke, J., "The HTTP ADDMEMBER Method",
+ draft-reschke-http-addmember-00 (work in progress),
+ February 2005.
+
+
+Appendix A. Change Log (to be removed by RFC Editor before publication)
+
+A.1. since draft-reschke-webdav-post-00
+
+ Added Acknowledgements.
+
+ Added and resolved issues "acl", "forbidden-put", "member-uri-
+ content", "post-error-semantics", "property-trust", "rational-server-
+ uri", ""remote-uri", "uri-format" and "uri-uniqueness".
+
+
+
+Reschke Expires May 26, 2010 [Page 12]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+A.2. since draft-reschke-webdav-post-01
+
+ Add and resolve issue "containment".
+
+ Update draft-ietf-vcarddav-carddav reference.
+
+A.3. since draft-reschke-webdav-post-02
+
+ Update XML, draft-ietf-vcarddav-carddav and
+ draft-nottingham-http-link-header references.
+
+ Add and resolve issues "link-header" and "ns".
+
+A.4. since draft-reschke-webdav-post-03
+
+ Add and resolve issues "put-only" and "protected".
+
+A.5. since draft-reschke-webdav-post-04
+
+ Update vcarddav reference. In the example, do not use the same
+ content for Slug header field and request body. Add issue
+ "collection".
+
+
+Appendix B. Open issues (to be removed by RFC Editor prior to
+ publication)
+
+B.1. edit
+
+ Type: edit
+
+ julian.reschke at greenbytes.de (2008-09-22): Umbrella issue for
+ editorial fixes/enhancements.
+
+B.2. collection
+
+ Type: change
+
+ cyrus at daboo.name (2009-11-05): I have heard from some implementors
+ that they would like collection creation to also be part of this
+ draft. In particular, CalDAV and/or CardDAV clients creating
+ calendars or address books would prefer to leave specification of the
+ resource name to the client.
+ Proposal:
+ - Add a DAV:add-collection property containing a URI (which must be
+ different than DAV:add-member)
+ - A POST on that URI creates a collection within the parent
+ collection, with a server chosen resource name
+
+
+
+Reschke Expires May 26, 2010 [Page 13]
+
+Internet-Draft POST to add to WebDAV Collections November 2009
+
+
+ - If the POST contains an XML body with DAV:mkcol as the root
+ element, then that body is interpreted the same way as MKCOL ext.
+
+
+Index
+
+ A
+ Add-Member URI 6
+
+ C
+ Condition Names
+ DAV:allow-client-defined-URI (pre) 9
+ COPY method
+ Additional Preconditions 9
+
+ D
+ DAV:allow-client-defined-URI 9
+
+ L
+ LOCK method
+ Additional Preconditions 9
+
+ M
+ MKCOL method
+ Additional Preconditions 9
+ MOVE method
+ Additional Preconditions 9
+
+ P
+ PUT method
+ Additional Preconditions 9
+
+
+Author's Address
+
+ Julian F. Reschke
+ greenbytes GmbH
+ Hafenweg 16
+ Muenster, NW 48155
+ Germany
+
+ Phone: +49 251 2807760
+ Email: julian.reschke at greenbytes.de
+ URI: http://greenbytes.de/tech/webdav/
+
+
+
+
+
+
+
+Reschke Expires May 26, 2010 [Page 14]
+
\ No newline at end of file
Copied: CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/Twisted/twisted.web2.dav.element.parser.patch (from rev 4951, CalendarServer/trunk/lib-patches/Twisted/twisted.web2.dav.element.parser.patch)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/Twisted/twisted.web2.dav.element.parser.patch (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/Twisted/twisted.web2.dav.element.parser.patch 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,14 @@
+Index: twisted/web2/dav/element/parser.py
+===================================================================
+--- twisted/web2/dav/element/parser.py (revision 27622)
++++ twisted/web2/dav/element/parser.py (working copy)
+@@ -54,7 +54,8 @@
+ """
+ element_names = []
+
+- for element_class_name in dir(module):
++ items = module.__all__ if hasattr(module, "__all__") else dir(module)
++ for element_class_name in items:
+ element_class = getattr(module, element_class_name)
+
+ if type(element_class) is type and issubclass(element_class, WebDAVElement):
Deleted: CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/vobject/vobject.base.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/vobject/vobject.base.patch 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/vobject/vobject.base.patch 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,45 +0,0 @@
-Index: vobject/base.py
-===================================================================
---- vobject/base.py (revision 212)
-+++ vobject/base.py (working copy)
-@@ -284,6 +284,8 @@
- self.value = copy.copy(copyit.value)
- self.encoded = self.encoded
- self.params = copy.copy(copyit.params)
-+ for k,v in self.params.items():
-+ self.params[k] = copy.copy(v)
- self.singletonparams = copy.copy(copyit.singletonparams)
- self.lineNumber = copyit.lineNumber
-
-@@ -627,16 +629,16 @@
- print
-
- class VObjectError(Exception):
-- def __init__(self, message, lineNumber=None):
-- self.message = message
-+ def __init__(self, msg, lineNumber=None):
-+ self.msg = msg
- if lineNumber is not None:
- self.lineNumber = lineNumber
- def __str__(self):
- if hasattr(self, 'lineNumber'):
- return "At line %s: %s" % \
-- (self.lineNumber, self.message)
-+ (self.lineNumber, self.msg)
- else:
-- return repr(self.message)
-+ return repr(self.msg)
-
- class ParseError(VObjectError):
- pass
-@@ -953,7 +955,9 @@
- if obj.group is not None:
- s.write(obj.group + '.')
- s.write(obj.name.upper())
-- for key, paramvals in obj.params.iteritems():
-+ keys = sorted(obj.params.iterkeys())
-+ for key in keys:
-+ paramvals = obj.params[key]
- s.write(';' + key + '=' + ','.join(dquoteEscape(p) for p in paramvals))
- s.write(':' + obj.value)
- if obj.behavior and not startedEncoded: obj.behavior.decode(obj)
Modified: CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/vobject/vobject.icalendar.patch
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/vobject/vobject.icalendar.patch 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/lib-patches/vobject/vobject.icalendar.patch 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,36 +1,8 @@
Index: vobject/icalendar.py
===================================================================
---- vobject/icalendar.py (revision 212)
+--- vobject/icalendar.py (revision 219)
+++ vobject/icalendar.py (working copy)
-@@ -426,6 +426,18 @@
-
- if dtstart.tzinfo is not None:
- until = until.astimezone(dtstart.tzinfo)
-+
-+ # RFC2445 actually states that UNTIL must be a UTC value. Whilst the
-+ # changes above work OK, one problem case is if DTSTART is floating but
-+ # UNTIL is properly specified as UTC (or with a TZID). In that case dateutil
-+ # will fail datetime comparisons. There is no easy solution to this as
-+ # there is no obvious timezone (at this point) to do proper floating time
-+ # offset compisons. The best we can do is treat the UNTIL value as floating.
-+ # This could mean incorrect determination of the last instance. The better
-+ # solution here is to encourage clients to use COUNT rather than UNTIL
-+ # when DTSTART is floating.
-+ if dtstart.tzinfo is None:
-+ until = until.replace(tzinfo=None)
-
- rule._until = until
-
-@@ -473,7 +485,7 @@
- untilSerialize = lambda x: dateTimeToString(x, True)
-
- for name in DATESANDRULES:
-- if hasattr(self.contents, name):
-+ if name in self.contents:
- del self.contents[name]
- setlist = getattr(rruleset, '_' + name)
- if name in DATENAMES:
-@@ -1661,9 +1673,10 @@
+@@ -1675,9 +1675,10 @@
else:
current.append(char)
else:
Modified: CalendarServer/branches/users/cdaboo/partition-4464/pyflakes
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/pyflakes 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/pyflakes 2010-01-21 20:33:21 UTC (rev 4953)
@@ -9,7 +9,7 @@
export PYTHONPATH="${flakes}:${PYTHONPATH:-}";
if [ $# -eq 0 ]; then
- set - calendarserver twistedcaldav twext;
+ set - calendarserver twistedcaldav twext txdav txcaldav txcarddav;
fi;
cd "${wd}" && "${flakes}/bin/pyflakes" "$@" | sed \
@@ -18,4 +18,5 @@
-e "/redefinition of unused/d" \
-e "/'from .* import \\*' used; unable to detect undefined names/d" \
-e "/redefinition of function/d" \
+ -e "/i[a-z]*store.py:[0-9][0-9]*: '.*' imported but unused/d" \
;
Modified: CalendarServer/branches/users/cdaboo/partition-4464/support/build.sh
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/support/build.sh 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/support/build.sh 2010-01-21 20:33:21 UTC (rev 4953)
@@ -2,7 +2,7 @@
# -*- sh-basic-offset: 2 -*-
##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -332,7 +332,6 @@
# Declare a dependency on a Python project.
py_dependency () {
-
# args
local name="$1"; shift; # the name of the package (for display)
local module="$1"; shift; # the name of the python module.
@@ -349,9 +348,9 @@
local skip_egg="$1"; shift; # skip even the 'egg_info' step, because nothing
# needs to be built.
local revision="$1"; shift; # what revision to check out (for SVN dependencies)
- # end args
- local srcdir="${top}/${distribution}"
+ local srcdir="${top}/${distribution}"
+
if "${override_system}" || ! py_have_module "${module}"; then
"${get_type}_get" "${name}" "${srcdir}" "${get_uri}" "${revision}"
if "${inplace}"; then
@@ -372,9 +371,9 @@
fi;
if "$inplace"; then
- local add_path="${srcdir}";
+ local add_path="${srcdir}";
else
- local add_path="${srcdir}/build/${py_platform_libdir}";
+ local add_path="${srcdir}/build/${py_platform_libdir}";
fi;
export PYTHONPATH="${PYTHONPATH}:${add_path}";
}
@@ -415,8 +414,11 @@
# or, it may do as much as download and install all dependencies.
dependencies () {
- if ! type memcached >& /dev/null; then
- # Dependencies compiled from C source code
+ #
+ # Dependencies compiled from C source code
+ #
+
+ if ! type memcached > /dev/null 2>&1; then
local le="libevent-1.4.8-stable";
c_dependency "libevent" "${le}" \
"http://monkey.org/~provos/libevent-1.4.8-stable.tar.gz";
@@ -425,7 +427,17 @@
--enable-threads --with-libevent="${top}/${le}/_root";
fi;
+ if ! type postgres > /dev/null 2>&1; then
+ c_dependency "PostgreSQL" "postgresql-8.4.2" \
+ "http://ftp9.us.postgresql.org/pub/mirrors/postgresql/source/v8.4.2/postgresql-8.4.2.tar.gz" \
+ --with-python;
+ :;
+ fi;
+
+ #
# Python dependencies
+ #
+
py_dependency "Zope Interface" "zope.interface" "zope.interface-3.3.0" \
"www" "http://www.zope.org/Products/ZopeInterface/3.3.0/zope.interface-3.3.0.tar.gz" \
false false false false 0;
@@ -435,7 +447,7 @@
py_dependency "PyOpenSSL" "OpenSSL" "pyOpenSSL-0.9" \
"www" "http://pypi.python.org/packages/source/p/pyOpenSSL/pyOpenSSL-0.9.tar.gz" \
false false false false 0;
- if type krb5-config > /dev/null; then
+ if type krb5-config > /dev/null 2>&1; then
py_dependency "PyKerberos" "kerberos" "PyKerberos" \
"svn" "${svn_uri_base}/PyKerberos/trunk" \
false false false false 4241;
@@ -454,25 +466,12 @@
true false false false 0;
fi;
- if ! type psql >& /dev/null; then
- c_dependency "postgresql" "postgresql-8.4.1" \
- "http://wwwmaster.postgresql.org/redir/198/h/source/v8.4.1/postgresql-8.4.1.tar.bz2";
- fi;
py_dependency "PyGreSQL" "pgdb" "PyGreSQL-4.0" \
"www" "ftp://ftp.pygresql.org/pub/distrib/PyGreSQL.tgz" \
false false false false 0;
- case "${USER}" in
- wsanchez)
- proto="svn+ssh";
- ;;
- *)
- proto="svn";
- ;;
- esac;
-
py_dependency "Twisted" "twisted" "Twisted" \
- "svn" "${proto}://svn.twistedmatrix.com/svn/Twisted/branches/dav-take-two-3081-4" \
+ "svn" "svn://svn.twistedmatrix.com/svn/Twisted/branches/dav-take-two-3081-4" \
false true true false 27622;
# twisted.web2 doesn't get installed by default, so in the install phase
@@ -501,11 +500,11 @@
# XXX actually vObject should be imported in-place.
py_dependency "vObject" "vobject" "vobject" \
"svn" "${base}/vobject/trunk" \
- false true true true 212;
+ false true true true 219;
# Tool dependencies. The code itself doesn't depend on these, but you probably want them.
- svn_get "CalDAVTester" "${top}/CalDAVTester" "${svn_uri_base}/CalDAVTester/trunk" 4874;
- svn_get "Pyflakes" "${top}/Pyflakes" http://divmod.org/svn/Divmod/trunk/Pyflakes 17198;
+ svn_get "CalDAVTester" "${top}/CalDAVTester" "${svn_uri_base}/CalDAVTester/trunk" 4912;
+ svn_get "Pyflakes" "${top}/Pyflakes" http://divmod.org/svn/Divmod/trunk/Pyflakes HEAD;
}
Modified: CalendarServer/branches/users/cdaboo/partition-4464/support/submit
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/support/submit 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/support/submit 2010-01-21 20:33:21 UTC (rev 4953)
@@ -36,7 +36,8 @@
install=false;
package=false;
-submission_enabled=true;
+ submission_enabled=true;
+ignore_uncommitted_changes=false;
usage ()
{
@@ -51,18 +52,20 @@
echo " -b Run buildit";
echo " -i Install resulting build on this system";
echo " -p Create a package with the resulting build";
+ echo " -f Ignore uncommitted changes";
if [ "${1-}" == "-" ]; then return 0; fi;
exit 64;
}
-while getopts 'hbip' option; do
+while getopts 'hbipf' option; do
case "$option" in
'?') usage; ;;
'h') usage -; exit 0; ;;
- 'b') build=true; ;;
- 'i') install=true; ;;
- 'p') package=true; ;;
+ 'b') build=true; ;;
+ 'i') install=true; ;;
+ 'p') package=true; ;;
+ 'f') ignore_uncommitted_changes=true; ;;
esac;
done;
shift $((${OPTIND} - 1));
@@ -108,7 +111,7 @@
#
# Make sure changes are checked in.
#
- if [ "$(svn st "${src}" | grep -v support/submit)" != "" ]; then
+ if [ ! "${ignore_uncommitted_changes}" ] && [ "$(svn st "${src}" | grep -v support/submit)" != "" ]; then
echo "Working copy has uncommitted changes. Aborting.";
exit 1;
fi;
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twext/internet/tcp.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twext/internet/tcp.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twext/internet/tcp.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -19,38 +19,43 @@
"""
__all__ = [
- "InheritedPort",
- "InheritedSSLPort",
- "InheritTCPServer",
- "InheritSSLServer",
+ "MaxAcceptTCPServer",
+ "MaxAcceptSSLServer",
]
from OpenSSL import SSL
from twisted.application import internet
from twisted.internet import tcp, ssl
-from twistedcaldav.log import Logger, logLevelForNamespace, setLogLevelForNamespace
+from twistedcaldav.log import Logger
import socket
log = Logger()
class MaxAcceptPortMixin(object):
- """ Mixin for resetting maxAccepts """
-
+ """
+ Mixin for resetting maxAccepts.
+ """
def doRead(self):
self.numberAccepts = min(self.factory.maxRequests - self.factory.outstandingRequests, self.factory.maxAccepts)
tcp.Port.doRead(self)
class MaxAcceptTCPPort(MaxAcceptPortMixin, tcp.Port):
- """ Use for non-inheriting tcp ports """
+ """
+ Use for non-inheriting tcp ports.
+ """
pass
class MaxAcceptSSLPort(MaxAcceptPortMixin, ssl.Port):
- """ Use for non-inheriting SSL ports """
+ """
+ Use for non-inheriting SSL ports.
+ """
pass
class InheritedTCPPort(MaxAcceptTCPPort):
- """ A tcp port which uses an inherited file descriptor """
+ """
+ A tcp port which uses an inherited file descriptor.
+ """
def __init__(self, fd, factory, reactor):
tcp.Port.__init__(self, 0, factory, reactor=reactor)
@@ -72,7 +77,9 @@
class InheritedSSLPort(InheritedTCPPort):
- """ An SSL port which uses an inherited file descriptor """
+ """
+ An SSL port which uses an inherited file descriptor.
+ """
_socketShutdownMethod = 'sock_shutdown'
@@ -88,9 +95,10 @@
return tcp.Port._preMakeConnection(self, transport)
class MaxAcceptTCPServer(internet.TCPServer):
- """ TCP server which will uses MaxAcceptTCPPorts (and optionally,
- inherited ports)
"""
+ TCP server which will uses MaxAcceptTCPPorts (and optionally,
+ inherited ports)
+ """
def __init__(self, *args, **kwargs):
internet.TCPServer.__init__(self, *args, **kwargs)
@@ -112,9 +120,10 @@
return port
class MaxAcceptSSLServer(internet.SSLServer):
- """ SSL server which will uses MaxAcceptSSLPorts (and optionally,
- inherited ports)
"""
+ SSL server which will uses MaxAcceptSSLPorts (and optionally,
+ inherited ports)
+ """
def __init__(self, *args, **kwargs):
internet.SSLServer.__init__(self, *args, **kwargs)
Copied: CalendarServer/branches/users/cdaboo/partition-4464/twext/python/icalendar.py (from rev 4951, CalendarServer/trunk/twext/python/icalendar.py)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twext/python/icalendar.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twext/python/icalendar.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,24 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+"""
+iCalendar utilities
+"""
+
+# FIXME: Move twistedcaldav.ical here, but that module needs some
+# cleanup first. Perhaps after porting to libical?
+
+from twistedcaldav.ical import *
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twext/web2/dav/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twext/web2/dav/__init__.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twext/web2/dav/__init__.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2009 Apple Inc. All rights reserved.
+# Copyright (c) 2009-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,5 +15,14 @@
##
"""
-Extentions to twisted.web2.dav
+Extensions to twisted.web2.dav
"""
+
+#
+# Register additional WebDAV XML elements
+#
+
+from twext.web2.dav import davxml
+import twisted.web2.dav.davxml
+
+twisted.web2.dav.davxml.registerElements(davxml)
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twext/web2/dav/davxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twext/web2/dav/davxml.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twext/web2/dav/davxml.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -21,12 +21,15 @@
__all__ = [
"sname2qname",
"qname2sname",
+ "ErrorDescription",
"ErrorResponse",
+ "SyncCollection",
+ "SyncToken",
]
from twisted.web2.http import Response
from twisted.web2.dav.http import ErrorResponse as SuperErrorResponse
-from twisted.web2.dav.davxml import twisted_dav_namespace, WebDAVTextElement
+from twisted.web2.dav.davxml import dav_namespace, twisted_dav_namespace, WebDAVElement, WebDAVTextElement
from twisted.web2.dav.davxml import WebDAVUnknownElement, Error
from twisted.web2.http_headers import MimeType
@@ -88,6 +91,7 @@
Renders itself as a DAV:error XML document.
"""
error = None
+ unregistered = True # base class is already registered
def __init__(self, code, error, description=None):
"""
@@ -120,3 +124,47 @@
def __repr__(self):
return "<%s %s %s>" % (self.__class__.__name__, self.code, self.error.sname())
+class SyncCollection (WebDAVElement):
+ """
+ DAV report used to retrieve specific calendar component items via their
+ URIs.
+ (CalDAV-access-09, section 9.9)
+ """
+ name = "sync-collection"
+
+ # To allow for an empty element in a supported-report-set property we need
+ # to relax the child restrictions
+ allowed_children = {
+ (dav_namespace, "sync-token"): (0, 1), # When used in the REPORT this is required
+ (dav_namespace, "prop" ): (0, 1),
+ }
+
+ def __init__(self, *children, **attributes):
+ super(SyncCollection, self).__init__(*children, **attributes)
+
+ self.property = None
+ self.sync_token = None
+
+ for child in self.children:
+ qname = child.qname()
+
+ if qname == (dav_namespace, "sync-token"):
+
+ self.sync_token = str(child)
+
+ elif qname in (
+ (dav_namespace, "prop" ),
+ ):
+ if property is not None:
+ raise ValueError("Only one of DAV:prop allowed")
+ self.property = child
+
+class SyncToken (WebDAVTextElement):
+ """
+ Synchronization token used in report and as a property.
+ """
+ name = "sync-token"
+ hidden = True
+ protected = True
+
+
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/appleopendirectory.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/appleopendirectory.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -349,7 +349,7 @@
# specified in the last field in the fields list
def collectResults(results):
- self.log_info("Got back %d records from OD" % (len(results),))
+ self.log_debug("Got back %d records from OD" % (len(results),))
for key, value in results:
self.log_debug("OD result: %s %s" % (key, value))
try:
@@ -421,7 +421,7 @@
complexExpression = dsquery.expression(operand, expressions).generate()
- self.log_info("Calling OD: Types %s, Operand %s, Caseless %s, %s" %
+ self.log_debug("Calling OD: Types %s, Operand %s, Caseless %s, %s" %
(recordTypes, operand, caseless, complexExpression))
results.extend(
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/cachingdirectory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/cachingdirectory.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/cachingdirectory.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -254,13 +254,9 @@
else:
# Only use recordTypes this service supports:
supportedRecordTypes = self.recordTypes()
- typesToQuery = []
- for recordType in recordTypes:
- if recordType in supportedRecordTypes:
- typesToQuery.append(recordType)
- if not typesToQuery:
+ recordTypes = [t for t in recordTypes if t in supportedRecordTypes]
+ if not recordTypes:
return None
- recordTypes = typesToQuery
def lookup():
for recordType in recordTypes:
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -35,6 +35,8 @@
from urllib import unquote
from urlparse import urlparse
+from weakref import WeakValueDictionary
+
from twisted.cred.credentials import UsernamePassword
from twisted.python.failure import Failure
from twisted.internet.defer import inlineCallbacks, returnValue
@@ -441,6 +443,7 @@
)
self.parent = parent
+ self._principalResourceCache = WeakValueDictionary()
def principalForUID(self, uid):
return self.parent.principalForUID(uid)
@@ -452,10 +455,13 @@
if record is None:
return None
+ if record in self._principalResourceCache:
+ return self._principalResourceCache[record]
if record.enabledForCalendaring:
principal = DirectoryCalendarPrincipalResource(self, record)
else:
principal = DirectoryPrincipalResource(self, record)
+ self._principalResourceCache[record] = principal
return principal
##
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/resourceinfo.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/resourceinfo.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/resourceinfo.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -76,7 +76,7 @@
self.setAutoScheduleInDatabase(guid, autoSchedule)
# Update cache
- _ignore = (yield self._memcacher.setAutoSchedule(guid, autoSchedule))
+ (yield self._memcacher.setAutoSchedule(guid, autoSchedule))
def setAutoScheduleInDatabase(self, guid, autoSchedule):
"""
@@ -104,7 +104,7 @@
autoSchedule = self._db_value_for_sql("select AUTOSCHEDULE from RESOURCEINFO where GUID = :1", guid)
if autoSchedule is not None:
autoSchedule = autoSchedule == 1
- result = (yield self._memcacher.setAutoSchedule(guid, autoSchedule))
+ (yield self._memcacher.setAutoSchedule(guid, autoSchedule))
returnValue(autoSchedule)
def _add_to_db(self, guid, autoSchedule):
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_principal.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_principal.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -175,6 +175,19 @@
self.failIf(principal is None)
self.assertEquals(record, principal.record)
+
+ def test_principalForUIDCache(self):
+ """
+ L{DirectoryPrincipalUIDProvisioningResource.principalForUID} should
+ return an identical principal resource when passed the same principal.
+ """
+ for provisioningResource, recordType, recordResource, record in self._allRecords():
+ principal = provisioningResource.principalForRecord(record)
+ principal2 = provisioningResource.principalForRecord(record)
+ self.assertIdentical(principal, principal2,
+ ("mismatch from %s" % (provisioningResource,)))
+
+
def test_principalForRecord(self):
"""
DirectoryPrincipalProvisioningResource.principalForRecord()
@@ -465,13 +478,12 @@
self.fail("%s should have %s privilege on %r" % (principal.sname(), privilege.sname(), resource))
d.addErrback(onError)
else:
- def onError(f):
+ def expectAccessDenied(f):
f.trap(AccessDeniedError)
def onSuccess(_):
#print resource.readDeadProperty(davxml.ACL)
self.fail("%s should not have %s privilege on %r" % (principal.sname(), privilege.sname(), resource))
- d.addCallback(onSuccess)
- d.addErrback(onError)
+ d.addCallbacks(onSuccess, expectAccessDenied)
return d
d = request.locateResource(url)
@@ -481,12 +493,8 @@
def _authReadOnlyPrivileges(self, resource, url):
items = []
for provisioningResource, recordType, recordResource, record in self._allRecords():
- if recordResource == resource:
- items.append(( davxml.HRef().fromString(recordResource.principalURL()), davxml.Read() , True ))
- items.append(( davxml.HRef().fromString(recordResource.principalURL()), davxml.Write() , True ))
- else:
- items.append(( davxml.HRef().fromString(recordResource.principalURL()), davxml.Read() , True ))
- items.append(( davxml.HRef().fromString(recordResource.principalURL()), davxml.Write() , False ))
+ items.append(( davxml.HRef().fromString(recordResource.principalURL()), davxml.Read() , True ))
+ items.append(( davxml.HRef().fromString(recordResource.principalURL()), davxml.Write() , False ))
items.append(( davxml.Unauthenticated() , davxml.Read() , False ))
items.append(( davxml.Unauthenticated() , davxml.Write() , False ))
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlfile.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlfile.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -129,7 +129,7 @@
return True
elif matchType == 'contains':
try:
- _ignore_discard = testValue.index(value)
+ testValue.index(value)
return True
except ValueError:
pass
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/dropbox.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/dropbox.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/dropbox.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -21,7 +21,6 @@
__all__ = [
"DropBoxHomeResource",
"DropBoxCollectionResource",
- "DropBoxChildResource",
]
from twext.web2.dav.davxml import ErrorResponse
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/extensions.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/extensions.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -26,7 +26,7 @@
"DAVFile",
"ReadOnlyWritePropertiesResourceMixIn",
"ReadOnlyResourceMixIn",
- "CachingXattrPropertyStore",
+ "CachingPropertyStore",
]
import cPickle as pickle
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/ical.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/ical.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/ical.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1242,8 +1242,8 @@
timezone_refs = set()
timezones = set()
got_master = False
-# got_override = False
-# master_recurring = False
+ #got_override = False
+ #master_recurring = False
for subcomponent in self.subcomponents():
# Disallowed in CalDAV-Access-08, section 4.1
@@ -1291,9 +1291,9 @@
raise ValueError(msg)
else:
got_master = True
-# master_recurring = subcomponent.hasProperty("RRULE") or subcomponent.hasProperty("RDATE")
-# else:
-# got_override = True
+ # master_recurring = subcomponent.hasProperty("RRULE") or subcomponent.hasProperty("RDATE")
+ else:
+ pass # got_override = True
# Check that if an override is present then the master is recurring
# Leopard iCal sometimes does this for overridden instances that an Attendee receives and
@@ -1301,6 +1301,7 @@
# scheduling will verify the validity of the components and raise if they don't make sense.
# If no scheduling is happening then we allow this - that may cause other clients to choke.
# If it does we will have to reinstate this check but only after we have checked for implicit.
+# UNCOMMENT OUT master_recurring AND got_override ASSIGNMENTS ABOVE
# if got_override and got_master and not master_recurring:
# msg = "Calendar resources must have a recurring master component if there is an overridden one (%s)" % (subcomponent.propertyValue("UID"),)
# log.debug(msg)
@@ -1511,6 +1512,18 @@
return None
+ def getOrganizerScheduleAgent(self):
+
+ is_server = False
+ organizerProp = self.getOrganizerProperty()
+ if "SCHEDULE-AGENT" in organizerProp.params():
+ if organizerProp.paramValue("SCHEDULE-AGENT") == "SERVER":
+ is_server = True
+ else:
+ is_server = True
+
+ return is_server
+
def getAttendees(self):
"""
Get the attendee value. Works on either a VCALENDAR or on a component.
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/index.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/index.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/index.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@
log = Logger()
db_basename = db_prefix + "sqlite"
-schema_version = "8"
+schema_version = "9"
collection_types = {"Calendar": "Regular Calendar Collection", "iTIP": "iTIP Calendar Collection"}
icalfbtype_to_indexfbtype = {
@@ -101,6 +101,9 @@
class IndexedSearchException(ValueError):
pass
+class SyncTokenValidException(ValueError):
+ pass
+
class AbstractCalendarIndex(AbstractSQLDatabase, LoggingMixIn):
"""
Calendar collection index abstract base class that defines the apis for the index.
@@ -180,7 +183,7 @@
if name is not None and self.resource.getChild(name_utf8) is None:
# Clean up
log.err("Stale resource record found for child %s with UID %s in %s" % (name, uid, self.resource))
- self._delete_from_db(name, uid)
+ self._delete_from_db(name, uid, None)
self._db_commit()
else:
resources.append(name)
@@ -212,7 +215,7 @@
return uid
- def addResource(self, name, calendar, fast=False, reCreate=False):
+ def addResource(self, name, calendar, revision, fast=False, reCreate=False):
"""
Adding or updating an existing resource.
To check for an update we attempt to get an existing UID
@@ -225,12 +228,12 @@
"""
oldUID = self.resourceUIDForName(name)
if oldUID is not None:
- self._delete_from_db(name, oldUID)
- self._add_to_db(name, calendar, reCreate=reCreate)
+ self._delete_from_db(name, oldUID, None)
+ self._add_to_db(name, calendar, revision, reCreate=reCreate)
if not fast:
self._db_commit()
- def deleteResource(self, name):
+ def deleteResource(self, name, revision):
"""
Remove this resource from the index.
@param name: the name of the resource to add.
@@ -238,7 +241,7 @@
"""
uid = self.resourceUIDForName(name)
if uid is not None:
- self._delete_from_db(name, uid)
+ self._delete_from_db(name, uid, revision)
self._db_commit()
def resourceExists(self, name):
@@ -274,6 +277,26 @@
self.log_info("Search falls outside range of index for %s %s" % (name, minDate))
self.reExpandResource(name, minDate)
+ def whatchanged(self, revision):
+
+ results = [(name.encode("utf-8"), created, wasdeleted) for name, created, wasdeleted in self._db_execute("select NAME, CREATEDREVISION, WASDELETED from REVISIONS where REVISION > :1", revision)]
+ results.sort(key=lambda x:x[1])
+
+ changed = []
+ deleted = []
+ for name, created, wasdeleted in results:
+ if name:
+ if wasdeleted == 'Y':
+ # Don't report items that were created/deleted since the requested revision
+ if created <= revision:
+ deleted.append(name)
+ else:
+ changed.append(name)
+ else:
+ raise SyncTokenValidException
+
+ return changed, deleted,
+
def indexedSearch(self, filter, fbtype=False):
"""
Finds resources matching the given qualifiers.
@@ -357,7 +380,7 @@
"""
return schema_version
- def _add_to_db(self, name, calendar, cursor = None, expand_until=None, reCreate=False):
+ def _add_to_db(self, name, calendar, revision, cursor=None, expand_until=None, reCreate=False):
"""
Records the given calendar resource in the index with the given name.
Resource names and UIDs must both be unique; only one resource name may
@@ -370,7 +393,7 @@
"""
raise NotImplementedError
- def _delete_from_db(self, name, uid):
+ def _delete_from_db(self, name, uid, revision):
"""
Deletes the specified entry from all dbs.
@param name: the name of the resource to delete.
@@ -445,6 +468,28 @@
"""
)
+ #
+ # REVISIONS table tracks changes
+ # NAME: Last URI component (eg. <uid>.ics, RESOURCE primary key)
+ # REVISION: revision number
+ # WASDELETED: Y if revision deleted, N if added or changed
+ #
+ q.execute(
+ """
+ create table REVISIONS (
+ NAME text unique,
+ REVISION integer,
+ CREATEDREVISION integer,
+ WASDELETED text(1)
+ )
+ """
+ )
+ q.execute(
+ """
+ create index REVISION on REVISIONS (REVISION)
+ """
+ )
+
if uidunique:
#
# RESERVED table tracks reserved UIDs
@@ -473,15 +518,29 @@
Upgrade the data from an older version of the DB.
"""
- # When going to version 8 all we need to do is add an index
- if old_version < "8":
- q.execute("create index STARTENDFLOAT on TIMESPAN (START, END, FLOAT)")
-
- # When going to version 7,8 all we need to do is add a column to the resource and timespan
+ # When going to version 7+ all we need to do is add a column to the resource and timespan
if old_version < "7":
q.execute("alter table RESOURCE add column ORGANIZER text default '?'")
q.execute("alter table TIMESPAN add column FBTYPE text(1) default '?'")
+ # When going to version 8+ all we need to do is add an index
+ if old_version < "8":
+ q.execute("create index STARTENDFLOAT on TIMESPAN (START, END, FLOAT)")
+
+ # When going to version 9+ all we need to do is add revision table and index
+ if old_version < "9":
+ q.execute(
+ """
+ create table REVISIONS (
+ NAME text unique,
+ REVISION integer,
+ CREATEDREVISION integer,
+ WASDELETED text(1)
+ )
+ """
+ )
+ q.execute("create index REVISION on REVISIONS (REVISION)")
+
def notExpandedBeyond(self, minDate):
"""
Gives all resources which have not been expanded beyond a given date
@@ -495,10 +554,10 @@
with a longer expansion.
"""
calendar = self.resource.getChild(name).iCalendar()
- self._add_to_db(name, calendar, expand_until=expand_until, reCreate=True)
+ self._add_to_db(name, calendar, None, expand_until=expand_until, reCreate=True)
self._db_commit()
- def _add_to_db(self, name, calendar, cursor = None, expand_until=None, reCreate=False):
+ def _add_to_db(self, name, calendar, revision, cursor = None, expand_until=None, reCreate=False):
"""
Records the given calendar resource in the index with the given name.
Resource names and UIDs must both be unique; only one resource name may
@@ -536,7 +595,7 @@
log.err("Invalid instance %s when indexing %s in %s" % (e.rid, name, self.resource,))
raise
- self._delete_from_db(name, uid)
+ self._delete_from_db(name, uid, None)
for key in instances:
instance = instances[key]
@@ -562,7 +621,7 @@
values (:1, :2, :3, :4, :5)
""", name, float, start, end, '?'
)
-
+
self._db_execute(
"""
insert into RESOURCE (NAME, UID, TYPE, RECURRANCE_MAX, ORGANIZER)
@@ -570,7 +629,18 @@
""", name, uid, calendar.resourceType(), instances.limit, organizer
)
- def _delete_from_db(self, name, uid):
+ if revision is not None:
+ created = self._db_value_for_sql("select CREATEDREVISION from REVISIONS where NAME = :1", name)
+ if created is None:
+ created = revision
+ self._db_execute(
+ """
+ insert or replace into REVISIONS (NAME, REVISION, CREATEDREVISION, WASDELETED)
+ values (:1, :2, :3, :4)
+ """, name, revision, revision, 'N',
+ )
+
+ def _delete_from_db(self, name, uid, revision):
"""
Deletes the specified entry from all dbs.
@param name: the name of the resource to delete.
@@ -578,6 +648,13 @@
"""
self._db_execute("delete from TIMESPAN where NAME = :1", name)
self._db_execute("delete from RESOURCE where NAME = :1", name)
+ if revision is not None:
+ self._db_execute(
+ """
+ update REVISIONS SET REVISION = :1, WASDELETED = :2
+ where NAME = :3
+ """, revision, 'Y', name
+ )
def wrapInDeferred(f):
@@ -832,13 +909,16 @@
log.err("Non-calendar resource: %s" % (name,))
else:
#log.msg("Indexing resource: %s" % (name,))
- self.addResource(name, calendar, True, reCreate=True)
+ self.addResource(name, calendar, 0, True, reCreate=True)
finally:
stream.close()
# Do commit outside of the loop for better performance
if do_commit:
self._db_commit()
+
+ # This is a deferred but we can't defer at this point...
+ self.resource.bumpSyncToken(True)
class IndexSchedule (CalendarIndex):
"""
@@ -944,10 +1024,13 @@
log.err("Non-calendar resource: %s" % (name,))
else:
#log.msg("Indexing resource: %s" % (name,))
- self.addResource(name, calendar, True, reCreate=True)
+ self.addResource(name, calendar, 0, True, reCreate=True)
finally:
stream.close()
# Do commit outside of the loop for better performance
if do_commit:
self._db_commit()
+
+ # This is a deferred but we can't defer at this point...
+ self.resource.bumpSyncToken(True)
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/mail.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/mail.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/mail.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -603,7 +603,6 @@
)
# Authenticated /inbox
- credentialFactories = []
portal = Portal(auth.DavRealm())
portal.registerChecker(directory)
realm = directory.realmName or ""
@@ -647,7 +646,7 @@
def checkDSN(self, message):
# returns (isDSN, Action, icalendar attachment)
- report = deliveryStatus = original = calBody = None
+ report = deliveryStatus = calBody = None
for part in message.walk():
content_type = part.get_content_type()
@@ -658,7 +657,7 @@
deliveryStatus = part
continue
elif content_type == "message/rfc822":
- original = part
+ #original = part
continue
elif content_type == "text/calendar":
calBody = part.get_payload(decode=True)
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/memcacher.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/memcacher.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/memcacher.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -33,6 +33,8 @@
# Translation table: all ctrls (0x00 - 0x1F) and space and 0x7F mapped to _
keyNormalizeTranslateTable = string.maketrans("".join([chr(i) for i in range(33)]) + chr(0x7F), "_"*33 + "_")
+ allowTestCache = False
+
class memoryCacher():
"""
A class implementing the memcache client API we care about but
@@ -118,7 +120,7 @@
if config.Memcached.Pools.Default.ClientEnabled:
self._memcacheProtocol = self.getCachePool()
- elif config.ProcessType == "Single" or self._noInvalidation:
+ elif config.ProcessType == "Single" or self._noInvalidation or self.allowTestCache:
# NB no need to pickle the memory cacher as it handles python types natively
self._memcacheProtocol = Memcacher.memoryCacher()
self._pickle = False
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/__init__.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/__init__.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -33,4 +33,5 @@
"report_calquery",
"report_freebusy",
"report_multiget",
+ "report_sync_collection",
]
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/delete_common.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/delete_common.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/delete_common.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2006-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -105,11 +105,9 @@
if response == responsecode.NO_CONTENT:
if isPseudoCalendarCollectionResource(parent):
+ newrevision = (yield parent.bumpSyncToken())
index = parent.index()
- index.deleteResource(delresource.fp.basename())
-
- # Change CTag on the parent calendar collection
- yield parent.updateCTag()
+ index.deleteResource(delresource.fp.basename(), newrevision)
returnValue(response)
@@ -161,12 +159,10 @@
yield delresource.quotaSizeAdjust(self.request, -old_size)
if response == responsecode.NO_CONTENT:
+ newrevision = (yield parent.bumpSyncToken())
index = parent.index()
- index.deleteResource(delresource.fp.basename())
+ index.deleteResource(delresource.fp.basename(), newrevision)
- # Change CTag on the parent calendar collection
- yield parent.updateCTag()
-
# Do scheduling
if scheduler and not self.internal_request:
yield scheduler.doImplicitScheduling()
@@ -217,7 +213,7 @@
# Now do normal delete
# Change CTag
- yield delresource.updateCTag()
+ yield delresource.bumpSyncToken()
more_responses = (yield self.deleteResource(delresource, deluri, parent))
if isinstance(more_responses, MultiStatusResponse):
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/put_common.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/put_common.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,6 +1,6 @@
# -*- test-case-name: twistedcaldav.test.test_validation -*-
##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -273,6 +273,7 @@
self.rollback = None
self.access = None
+ self.newrevision = None
@inlineCallbacks
def fullValidation(self):
@@ -830,7 +831,8 @@
def doSourceDelete(self):
# Delete index for original item
if self.sourcecal:
- self.source_index.deleteResource(self.source.fp.basename())
+ self.newrevision = (yield self.sourceparent.bumpSyncToken())
+ self.source_index.deleteResource(self.source.fp.basename(), self.newrevision)
self.rollback.source_index_deleted = True
log.debug("Source index removed %s" % (self.source.fp.path,))
@@ -838,10 +840,6 @@
delete(self.source_uri, self.source.fp, "0")
self.rollback.source_deleted = True
log.debug("Source removed %s" % (self.source.fp.path,))
-
- # Change CTag on the parent calendar collection
- if self.sourcecal:
- yield self.sourceparent.updateCTag()
returnValue(None)
@@ -878,7 +876,7 @@
# Add or update the index for this resource.
try:
- self.source_index.addResource(self.source.fp.basename(), self.calendar)
+ self.source_index.addResource(self.source.fp.basename(), self.calendar, self.newrevision)
except TooManyInstancesError, ex:
raise HTTPError(ErrorResponse(
responsecode.FORBIDDEN,
@@ -899,7 +897,7 @@
# Add or update the index for this resource.
try:
- self.destination_index.addResource(self.destination.fp.basename(), caltoindex)
+ self.destination_index.addResource(self.destination.fp.basename(), caltoindex, self.newrevision)
log.debug("Destination indexed %s" % (self.destination.fp.path,))
except TooManyInstancesError, ex:
log.err("Cannot index calendar resource as there are too many recurrence instances %s" % self.destination)
@@ -926,7 +924,7 @@
# Delete index for original item
if self.destinationcal:
- self.destination_index.deleteResource(self.destination.fp.basename())
+ self.destination_index.deleteResource(self.destination.fp.basename(), None)
self.rollback.destination_index_deleted = True
log.debug("Destination index removed %s" % (self.destination.fp.path,))
@@ -1088,6 +1086,7 @@
# Index the new resource if storing to a calendar.
if self.destinationcal:
+ self.newrevision = (yield self.destinationparent.bumpSyncToken())
result = self.doDestinationIndex(self.calendar)
if result is not None:
self.rollback.Rollback()
@@ -1101,10 +1100,6 @@
if self.destquota is not None:
yield self.doDestinationQuotaCheck()
- if self.destinationcal:
- # Change CTag on the parent calendar collection
- yield self.destinationparent.updateCTag()
-
# Can now commit changes and forget the rollback details
self.rollback.Commit()
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/report_common.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/report_common.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/report_common.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+# Copyright (c) 2006-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -452,7 +452,7 @@
processEventFreeBusy(calendar, fbinfo, timerange, tzinfo)
# Lets also force an index rebuild for this resource so that next time we have the fbtype set
- calresource.index().addResource(name, calendar, reCreate=True)
+ calresource.index().addResource(name, calendar, None, reCreate=True)
elif calendar.mainType() == "VFREEBUSY":
processFreeBusyFreeBusy(calendar, fbinfo, timerange)
Copied: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/report_sync_collection.py (from rev 4951, CalendarServer/trunk/twistedcaldav/method/report_sync_collection.py)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/report_sync_collection.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/method/report_sync_collection.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,146 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS IS" 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.
+##
+
+"""
+DAV sync-collection report
+"""
+
+__all__ = ["report_DAV__sync_collection"]
+
+from twext.web2.dav.davxml import ErrorResponse, SyncToken
+
+from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.python.failure import Failure
+from twisted.web2 import responsecode
+from twisted.web2.dav import davxml
+from twisted.web2.dav.element.base import WebDAVElement
+from twisted.web2.dav.http import MultiStatusResponse, statusForFailure
+from twisted.web2.dav.method.prop_common import responseForHref
+from twisted.web2.dav.method.propfind import propertyName
+from twisted.web2.dav.util import joinURL
+from twisted.web2.http import HTTPError
+
+from twistedcaldav.config import config
+from twistedcaldav.log import Logger
+
+import functools
+
+log = Logger()
+
+ at inlineCallbacks
+def report_DAV__sync_collection(self, request, sync_collection):
+ """
+ Generate a sync-collection REPORT.
+ """
+ if not self.isPseudoCalendarCollection() or not config.EnableSyncReport:
+ log.err("sync-collection report is only allowed on calendar/inbox collection resources %s" % (self,))
+ raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, davxml.SupportedReport()))
+
+ responses = []
+
+ propertyreq = sync_collection.property
+
+ @inlineCallbacks
+ def _namedPropertiesForResource(request, props, resource, forbidden=False):
+ """
+ Return the specified properties on the specified resource.
+ @param request: the L{IRequest} for the current request.
+ @param props: a list of property elements or qname tuples for the properties of interest.
+ @param resource: the L{DAVFile} for the targeted resource.
+ @return: a map of OK and NOT FOUND property values.
+ """
+ properties_by_status = {
+ responsecode.OK : [],
+ responsecode.FORBIDDEN : [],
+ responsecode.NOT_FOUND : [],
+ }
+
+ for property in props:
+ if isinstance(property, WebDAVElement):
+ qname = property.qname()
+ else:
+ qname = property
+
+ if forbidden:
+ properties_by_status[responsecode.FORBIDDEN].append(propertyName(qname))
+ else:
+ props = (yield resource.listProperties(request))
+ if qname in props:
+ try:
+ prop = (yield resource.readProperty(qname, request))
+ properties_by_status[responsecode.OK].append(prop)
+ except:
+ f = Failure()
+ log.err("Error reading property %r for resource %s: %s" % (qname, request.uri, f.value))
+ status = statusForFailure(f, "getting property: %s" % (qname,))
+ if status not in properties_by_status: properties_by_status[status] = []
+ properties_by_status[status].append(propertyName(qname))
+ else:
+ properties_by_status[responsecode.NOT_FOUND].append(propertyName(qname))
+
+ yield properties_by_status
+
+ # Do some optimization of access control calculation by determining any inherited ACLs outside of
+ # the child resource loop and supply those to the checkPrivileges on each child.
+ filteredaces = (yield self.inheritedACEsforChildren(request))
+
+ changed, removed, newtoken = self.whatchanged(sync_collection.sync_token)
+
+ # Now determine which valid resources are readable and which are not
+ ok_resources = []
+ forbidden_resources = []
+ if changed:
+ yield self.findChildrenFaster(
+ "1",
+ request,
+ lambda x, y: ok_resources.append((x, y)),
+ lambda x, y: forbidden_resources.append((x, y)),
+ changed,
+ (davxml.Read(),),
+ inherited_aces=filteredaces
+ )
+
+ for child, child_uri in ok_resources:
+ href = davxml.HRef.fromString(child_uri)
+ yield responseForHref(
+ request,
+ responses,
+ href,
+ child,
+ functools.partial(_namedPropertiesForResource, forbidden=False) if propertyreq else None,
+ propertyreq)
+
+ for child, child_uri in forbidden_resources:
+ href = davxml.HRef.fromString(child_uri)
+ yield responseForHref(
+ request,
+ responses,
+ href,
+ child,
+ functools.partial(_namedPropertiesForResource, forbidden=True) if propertyreq else None,
+ propertyreq)
+
+ for name in removed:
+ href = davxml.HRef.fromString(joinURL(request.uri, name))
+ responses.append(davxml.StatusResponse(davxml.HRef.fromString(href), davxml.Status.fromResponseCode(responsecode.NOT_FOUND)))
+
+ if not hasattr(request, "extendedLogItems"):
+ request.extendedLogItems = {}
+ request.extendedLogItems["responses"] = len(responses)
+
+ responses.append(SyncToken.fromString(newtoken))
+
+ returnValue(MultiStatusResponse(responses))
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/notify.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/notify.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/notify.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -641,8 +641,7 @@
publishElement['node'] = nodeName
if self.settings["NodeConfiguration"]["pubsub#deliver_payloads"] == '1':
itemElement = publishElement.addElement('item')
- payloadElement = itemElement.addElement('plistfrag',
- defaultUri='plist-apple')
+ itemElement.addElement('plistfrag', defaultUri='plist-apple')
self.sendDebug("Publishing (%s)" % (nodeName,), iq)
d = iq.send(to=self.settings['ServiceAddress'])
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/resource.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/resource.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@
from zope.interface import implements
-from twext.web2.dav.davxml import ErrorResponse
+from twext.web2.dav.davxml import ErrorResponse, SyncCollection
from twisted.internet import reactor
from twisted.internet.defer import Deferred, maybeDeferred, succeed
@@ -690,9 +690,12 @@
result = super(CalDAVResource, self).supportedReports()
result.append(davxml.Report(caldavxml.CalendarQuery(),))
result.append(davxml.Report(caldavxml.CalendarMultiGet(),))
- if (self.isCollection()):
+ if self.isCollection():
# Only allowed on collections
result.append(davxml.Report(caldavxml.FreeBusyQuery(),))
+ if self.isPseudoCalendarCollection() and config.EnableSyncReport:
+ # Only allowed on calendar/inbox collections
+ result.append(davxml.Report(SyncCollection(),))
return result
def writeNewACEs(self, newaces):
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/implicit.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/implicit.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -762,13 +762,19 @@
if not self.internal_request:
yield self.doAccessControl(self.attendeePrincipal, False)
+ # Check SCHEDULE-AGENT
+ doScheduling = self.checkOrganizerScheduleAgent()
+
if self.action == "remove":
if self.calendar.hasPropertyValueInAllComponents(Property("STATUS", "CANCELLED")):
log.debug("Implicit - attendee '%s' is removing cancelled UID: '%s'" % (self.attendee, self.uid))
# Nothing else to do
- else:
+ elif doScheduling:
log.debug("Implicit - attendee '%s' is cancelling UID: '%s'" % (self.attendee, self.uid))
yield self.scheduleCancelWithOrganizer()
+ else:
+ log.debug("Implicit - attendee '%s' is removing UID without server scheduling: '%s'" % (self.attendee, self.uid))
+ # Nothing else to do
else:
# Make sure ORGANIZER is not changed
@@ -835,9 +841,30 @@
log.debug("Attendee '%s' is allowed to update UID: '%s' with remote organizer '%s'" % (self.attendee, self.uid, self.organizer))
changedRids = None
- log.debug("Implicit - attendee '%s' is updating UID: '%s'" % (self.attendee, self.uid))
- yield self.scheduleWithOrganizer(changedRids)
+ if doScheduling:
+ log.debug("Implicit - attendee '%s' is updating UID: '%s'" % (self.attendee, self.uid))
+ yield self.scheduleWithOrganizer(changedRids)
+ else:
+ log.debug("Implicit - attendee '%s' is updating UID without server scheduling: '%s'" % (self.attendee, self.uid))
+ # Nothing else to do
+ def checkOrganizerScheduleAgent(self):
+
+ is_server = self.calendar.getOrganizerScheduleAgent()
+ local_organizer = isinstance(self.organizerAddress, LocalCalendarUser)
+
+ if local_organizer and not is_server:
+ log.error("Attendee '%s' is not allowed to change SCHEDULE-AGENT on organizer: UID:%s" % (self.attendeePrincipal, self.uid,))
+ raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-attendee-change")))
+ elif not local_organizer and is_server:
+ # Coerce ORGANIZER to SCHEDULE-AGENT=NONE
+ log.debug("Attendee '%s' is not allowed to use SCHEDULE-AGENT=SERVER on organizer: UID:%s" % (self.attendeePrincipal, self.uid,))
+ self.calendar.setParameterToValueForPropertyWithValue("SCHEDULE-AGENT", "NONE", "ORGANIZER", None)
+ self.calendar.setParameterToValueForPropertyWithValue("SCHEDULE-STATUS", iTIPRequestStatus.NO_USER_SUPPORT_CODE, "ORGANIZER", None)
+ is_server = False
+
+ return is_server
+
@inlineCallbacks
def getOrganizersCopy(self):
"""
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/processing.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/processing.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -30,6 +30,7 @@
from twistedcaldav.scheduling.itip import iTipProcessing, iTIPRequestStatus
from twistedcaldav.scheduling.utils import getCalendarObjectForPrincipals
from vobject.icalendar import utc
+from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
import datetime
import time
@@ -410,6 +411,7 @@
returnValue(result)
+ @inlineCallbacks
def sendAttendeeAutoReply(self, calendar, resource, partstat):
"""
Auto-process the calendar option to generate automatic accept/decline status and
@@ -421,12 +423,29 @@
@return: L{Component} for the new calendar data to write
"""
- # Send out a reply
- log.debug("ImplicitProcessing - recipient '%s' processing UID: '%s' - auto-reply: %s" % (self.recipient.cuaddr, self.uid, partstat))
- from twistedcaldav.scheduling.implicit import ImplicitScheduler
- scheduler = ImplicitScheduler()
- scheduler.sendAttendeeReply(self.request, resource, calendar, self.recipient)
+ # We need to get the UID lock for implicit processing whilst we send the auto-reply
+ # as the Organizer processing will attempt to write out data to other attendees to
+ # refresh them. To prevent a race we need a lock.
+ lock = MemcacheLock("ImplicitUIDLock", calendar.resourceUID(), timeout=60.0)
+ try:
+ if lock:
+ yield lock.acquire()
+
+ # Send out a reply
+ log.debug("ImplicitProcessing - recipient '%s' processing UID: '%s' - auto-reply: %s" % (self.recipient.cuaddr, self.uid, partstat))
+ from twistedcaldav.scheduling.implicit import ImplicitScheduler
+ scheduler = ImplicitScheduler()
+ scheduler.sendAttendeeReply(self.request, resource, calendar, self.recipient)
+ except MemcacheLockTimeoutError:
+
+ # Just try again to get the lock
+ reactor.callLater(2.0, self.sendAttendeeAutoReply, *(calendar, resource, partstat))
+
+ finally:
+ if lock:
+ yield lock.clean()
+
@inlineCallbacks
def checkAttendeeAutoReply(self, calendar):
"""
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -38,6 +38,7 @@
import os
import errno
from urlparse import urlsplit
+from uuid import uuid4
from twext.web2.dav.davxml import ErrorResponse
@@ -47,6 +48,7 @@
from twisted.web2 import responsecode, http, http_headers
from twisted.web2.http import HTTPError, StatusResponse
from twisted.web2.dav import davxml
+from twisted.web2.dav.element.base import dav_namespace
from twisted.web2.dav.fileop import mkcollection, rmdir
from twisted.web2.dav.idav import IDAVResource
from twisted.web2.dav.noneprops import NonePropertyStore
@@ -61,11 +63,12 @@
from twistedcaldav.config import config
from twistedcaldav.customxml import TwistedCalendarAccessProperty, TwistedScheduleMatchETags
from twistedcaldav.extensions import DAVFile, CachingPropertyStore
+from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
from twistedcaldav.memcacheprops import MemcachePropertyCollection
from twistedcaldav.freebusyurl import FreeBusyURLResource
from twistedcaldav.ical import Component as iComponent
from twistedcaldav.ical import Property as iProperty
-from twistedcaldav.index import Index, IndexSchedule
+from twistedcaldav.index import Index, IndexSchedule, SyncTokenValidException
from twistedcaldav.resource import CalDAVResource, isCalendarCollectionResource, isPseudoCalendarCollectionResource
from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource, IScheduleInboxResource
from twistedcaldav.dropbox import DropBoxHomeResource, DropBoxCollectionResource
@@ -209,7 +212,7 @@
raise HTTPError(status)
# Initialize CTag on the calendar collection
- d1 = self.updateCTag()
+ d1 = self.bumpSyncToken()
# Calendar is initially transparent to freebusy
self.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Transparent()))
@@ -374,6 +377,94 @@
"""
return Index(self)
+ def whatchanged(self, client_token):
+
+ current_token = str(self.readDeadProperty(customxml.GETCTag))
+ current_uuid, current_revision = current_token.split("#", 1)
+ current_revision = int(current_revision)
+
+ if client_token:
+ try:
+ caluuid, revision = client_token.split("#", 1)
+ revision = int(revision)
+
+ # Check client token validity
+ if caluuid != current_uuid:
+ raise ValueError
+ if revision > current_revision:
+ raise ValueError
+ except ValueError:
+ raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (dav_namespace, "valid-sync-token")))
+ else:
+ revision = 0
+
+ try:
+ changed, removed = self.index().whatchanged(revision)
+ except SyncTokenValidException:
+ raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (dav_namespace, "valid-sync-token")))
+
+ return changed, removed, current_token
+
+ @inlineCallbacks
+ def bumpSyncToken(self, reset=False):
+ """
+ Increment the sync-token which is also the ctag.
+
+ return: a deferred that returns the new revision number
+ """
+ assert self.isCollection()
+
+ # Need to lock
+ lock = MemcacheLock("ResourceLock", self.fp.path, timeout=60.0)
+ try:
+ try:
+ yield lock.acquire()
+ except MemcacheLockTimeoutError:
+ raise HTTPError(StatusResponse(responsecode.CONFLICT, "Resource: %s currently in use on the server." % (self.uri,)))
+
+ try:
+ if reset:
+ raise ValueError
+ token = str(self.readDeadProperty(customxml.GETCTag))
+ caluuid, revision = token.split("#", 1)
+ revision = int(revision) + 1
+ token = "%s#%d" % (caluuid, revision,)
+
+ except (HTTPError, ValueError):
+ # Initialise it
+ caluuid = uuid4()
+ revision = 1
+ token = "%s#%d" % (caluuid, revision,)
+
+ yield self.updateCTag(token)
+ returnValue(revision)
+ finally:
+ yield lock.clean()
+
+ def updateCTag(self, token=None):
+ assert self.isCollection()
+
+ if not token:
+ token = str(datetime.datetime.now())
+ try:
+ self.writeDeadProperty(customxml.GETCTag(token))
+ except:
+ return fail(Failure())
+
+ if hasattr(self, 'clientNotifier'):
+ self.clientNotifier.notify(op="update")
+ else:
+ log.debug("%r does not have a clientNotifier but the CTag changed"
+ % (self,))
+
+ if hasattr(self, 'cacheNotifier'):
+ return self.cacheNotifier.changed()
+ else:
+ log.debug("%r does not have a cacheNotifier but the CTag changed"
+ % (self,))
+
+ return succeed(True)
+
##
# File
##
@@ -440,28 +531,6 @@
return similar
- def updateCTag(self):
- assert self.isCollection()
- try:
- self.writeDeadProperty(customxml.GETCTag(
- str(datetime.datetime.now())))
- except:
- return fail(Failure())
-
- if hasattr(self, 'clientNotifier'):
- self.clientNotifier.notify(op="update")
- else:
- log.debug("%r does not have a clientNotifier but the CTag changed"
- % (self,))
-
- if hasattr(self, 'cacheNotifier'):
- return self.cacheNotifier.changed()
- else:
- log.debug("%r does not have a cacheNotifier but the CTag changed"
- % (self,))
-
- return succeed(True)
-
##
# Quota
##
@@ -901,7 +970,7 @@
if self.provisionFile():
# Initialize CTag on the calendar collection
- self.updateCTag()
+ self.bumpSyncToken()
# Initialize the index
self.index().create()
@@ -928,10 +997,7 @@
ScheduleOutboxResource.__init__(self, parent)
def provision(self):
- if self.provisionFile():
- # Initialize CTag on the calendar collection
- self.updateCTag()
-
+ self.provisionFile()
return super(ScheduleOutboxFile, self).provision()
def __repr__(self):
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,6 +1,6 @@
# -*- test-case-name: twistedcaldav.test.test_stdconfig -*-
##
-# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -246,6 +246,11 @@
"EnableSACLs": False,
#
+ # Standard (or draft) WebDAV extensions
+ #
+ "EnableSyncReport" : True, # REPORT collection-sync
+
+ #
# Non-standard CalDAV extensions
#
"EnableDropBox" : False, # Calendar Drop Box
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_index.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_index.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_index.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2010 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
from twistedcaldav.ical import Component
from twistedcaldav.index import Index, default_future_expansion_duration,\
maximum_future_expansion_duration, IndexedSearchException,\
- AbstractCalendarIndex
+ AbstractCalendarIndex, icalfbtype_to_indexfbtype
from twistedcaldav.index import ReservationError, MemcachedUIDReserver
from twistedcaldav.instance import InvalidOverriddenInstanceError
from twistedcaldav.test.util import InMemoryMemcacheProtocol
@@ -230,17 +230,19 @@
),
)
+ revision = 0
for description, name, calendar_txt, reCreate, ok in data:
+ revision += 1
calendar = Component.fromString(calendar_txt)
if ok:
f = open(os.path.join(self.site.resource.fp.path, name), "w")
f.write(calendar_txt)
del f
- self.db.addResource(name, calendar, reCreate=reCreate)
+ self.db.addResource(name, calendar, revision, reCreate=reCreate)
self.assertTrue(self.db.resourceExists(name), msg=description)
else:
- self.assertRaises(InvalidOverriddenInstanceError, self.db.addResource, name, calendar)
+ self.assertRaises(InvalidOverriddenInstanceError, self.db.addResource, name, calendar, revision)
self.assertFalse(self.db.resourceExists(name), msg=description)
self.db._db_recreate()
@@ -402,14 +404,16 @@
),
)
+ revision = 0
for description, name, calendar_txt, trstart, trend, organizer, instances in data:
+ revision += 1
calendar = Component.fromString(calendar_txt)
f = open(os.path.join(self.site.resource.fp.path, name), "w")
f.write(calendar_txt)
del f
- self.db.addResource(name, calendar)
+ self.db.addResource(name, calendar, revision)
self.assertTrue(self.db.resourceExists(name), msg=description)
# Create fake filter element to match time-range
@@ -434,6 +438,69 @@
self.assertEqual(set(instances), index_results, msg=description)
+ def test_index_revisions(self):
+ data1 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1.1
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+END:VEVENT
+END:VCALENDAR
+"""
+ data2 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-2.1
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+RRULE:FREQ=WEEKLY;COUNT=2
+END:VEVENT
+END:VCALENDAR
+"""
+ data3 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-2.3
+DTSTART:20080601T120000Z
+DTEND:20080601T130000Z
+ORGANIZER;CN="User 01":mailto:user1 at example.com
+ATTENDEE:mailto:user1 at example.com
+ATTENDEE:mailto:user2 at example.com
+RRULE:FREQ=WEEKLY;COUNT=2
+END:VEVENT
+END:VCALENDAR
+"""
+
+ calendar = Component.fromString(data1)
+ self.db.addResource("data1.ics", calendar, 1)
+ calendar = Component.fromString(data2)
+ self.db.addResource("data2.ics", calendar, 2)
+ calendar = Component.fromString(data3)
+ self.db.addResource("data3.ics", calendar, 3)
+ self.db.deleteResource("data3.ics", 4)
+
+ tests = (
+ (0, (["data1.ics", "data2.ics",], [],)),
+ (1, (["data2.ics",], [],)),
+ (2, ([], [],)),
+ (3, ([], ["data3.ics",],)),
+ (4, ([], [],)),
+ (5, ([], [],)),
+ )
+
+ for revision, results in tests:
+ self.assertEquals(self.db.whatchanged(revision), results, "Mismatched results for whatchanged with revision %d" % (revision,))
+
class SQLIndexUpgradeTests (twistedcaldav.test.util.TestCase):
"""
Test abstract SQL DB class
@@ -556,7 +623,7 @@
except InvalidOverriddenInstanceError:
raise
- self._delete_from_db(name, uid)
+ self._delete_from_db(name, uid, None)
for key in instances:
instance = instances[key]
@@ -675,6 +742,77 @@
"""
)
+ def _add_to_db(self, name, calendar, cursor = None, expand_until=None, reCreate=False):
+ """
+ Records the given calendar resource in the index with the given name.
+ Resource names and UIDs must both be unique; only one resource name may
+ be associated with any given UID and vice versa.
+ NB This method does not commit the changes to the db - the caller
+ MUST take care of that
+ @param name: the name of the resource to add.
+ @param calendar: a L{Calendar} object representing the resource
+ contents.
+ """
+ uid = calendar.resourceUID()
+ organizer = calendar.getOrganizer()
+ if not organizer:
+ organizer = ""
+
+ # Decide how far to expand based on the component
+ master = calendar.masterComponent()
+ if master is None or not calendar.isRecurring() and not calendar.isRecurringUnbounded():
+ # When there is no master we have a set of overridden components - index them all.
+ # When there is one instance - index it.
+ # When bounded - index all.
+ expand = datetime.datetime(2100, 1, 1, 0, 0, 0, tzinfo=utc)
+ else:
+ if expand_until:
+ expand = expand_until
+ else:
+ expand = datetime.date.today() + default_future_expansion_duration
+
+ if expand > (datetime.date.today() + maximum_future_expansion_duration):
+ raise IndexedSearchException
+
+ try:
+ instances = calendar.expandTimeRanges(expand, ignoreInvalidInstances=reCreate)
+ except InvalidOverriddenInstanceError:
+ raise
+
+ self._delete_from_db(name, uid, None)
+
+ for key in instances:
+ instance = instances[key]
+ start = instance.start.replace(tzinfo=utc)
+ end = instance.end.replace(tzinfo=utc)
+ float = 'Y' if instance.start.tzinfo is None else 'N'
+ self._db_execute(
+ """
+ insert into TIMESPAN (NAME, FLOAT, START, END, FBTYPE)
+ values (:1, :2, :3, :4, :5)
+ """, name, float, start, end, icalfbtype_to_indexfbtype.get(instance.component.getFBType(), 'F')
+ )
+
+ # Special - for unbounded recurrence we insert a value for "infinity"
+ # that will allow an open-ended time-range to always match it.
+ if calendar.isRecurringUnbounded():
+ start = datetime.datetime(2100, 1, 1, 0, 0, 0, tzinfo=utc)
+ end = datetime.datetime(2100, 1, 1, 1, 0, 0, tzinfo=utc)
+ float = 'N'
+ self._db_execute(
+ """
+ insert into TIMESPAN (NAME, FLOAT, START, END, FBTYPE)
+ values (:1, :2, :3, :4, :5)
+ """, name, float, start, end, '?'
+ )
+
+ self._db_execute(
+ """
+ insert into RESOURCE (NAME, UID, TYPE, RECURRANCE_MAX, ORGANIZER)
+ values (:1, :2, :3, :4, :5)
+ """, name, uid, calendar.resourceType(), instances.limit, organizer
+ )
+
def setUp(self):
super(SQLIndexUpgradeTests, self).setUp()
self.site.resource.isCalendarCollection = lambda: True
@@ -749,7 +887,7 @@
END:VCALENDAR
"""
- olddb.addResource(calendar_name, Component.fromString(calendar_data))
+ olddb.addResource(calendar_name, Component.fromString(calendar_data), 1)
self.assertTrue(olddb.resourceExists(calendar_name))
if olddb._db_version() == "6":
@@ -772,7 +910,7 @@
else:
self.assertEqual(value, "B")
- self.db.addResource(calendar_name, Component.fromString(calendar_data))
+ self.db.addResource(calendar_name, Component.fromString(calendar_data), 2)
self.assertTrue(olddb.resourceExists(calendar_name))
value = self.db._db_value_for_sql("select ORGANIZER from RESOURCE where NAME = :1", calendar_name)
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_mkcalendar.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_mkcalendar.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_mkcalendar.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -157,7 +157,6 @@
Make calendar with no parent
"""
uri = "/no/parent/for/calendar"
- path = os.path.join(self.docroot, uri[1:])
def do_test(response):
response = IResponse(response)
@@ -214,7 +213,6 @@
self.fail("Incorrect response to nested MKCALENDAR: %s" % (response.code,))
nested_uri = os.path.join(first_uri, "nested")
- nested_path = os.path.join(self.docroot, nested_uri[1:])
request = SimpleRequest(self.site, "MKCALENDAR", nested_uri)
self.send(request, do_test)
Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/util.py 2010-01-21 20:13:00 UTC (rev 4952)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/util.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -23,6 +23,7 @@
from twisted.internet.defer import succeed, fail
from twisted.web2.http import HTTPError, StatusResponse
+from twistedcaldav import memcacher
from twistedcaldav.config import config
from twistedcaldav.static import CalDAVFile
import memcacheclient
@@ -44,6 +45,7 @@
config.Memcached.Pools.Default.ClientEnabled = False
config.Memcached.Pools.Default.ServerEnabled = False
memcacheclient.ClientFactory.allowTestCache = True
+ memcacher.Memcacher.allowTestCache = True
def createHierarchy(self, structure, root=None):
if root is None:
Deleted: CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/__init__.py
===================================================================
--- CalendarServer/trunk/txcaldav/__init__.py 2010-01-21 19:38:46 UTC (rev 4951)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/__init__.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,19 +0,0 @@
-##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS IS" 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.
-##
-
-"""
-CalDAV support for Twisted.
-"""
Copied: CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/__init__.py (from rev 4951, CalendarServer/trunk/txcaldav/__init__.py)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/__init__.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/__init__.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,19 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS IS" 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.
+##
+
+"""
+CalDAV support for Twisted.
+"""
Deleted: CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/icalendarstore.py
===================================================================
--- CalendarServer/trunk/txcaldav/icalendarstore.py 2010-01-21 19:38:46 UTC (rev 4951)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/icalendarstore.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,308 +0,0 @@
-##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS IS" 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.
-##
-
-"""
-Calendar store interfaces
-"""
-
-__all__ = [
- "ICalendarHome",
- "ICalendar",
- "ICalendarObject",
-]
-
-from zope.interface import Interface #, Attribute
-
-from datetime import datetime, date, tzinfo
-from twext.icalendar import Component
-from txdav.idav import IPropertyStore
-
-#
-# Exceptions
-#
-
-class CalendarStoreError(RuntimeError):
- """
- Calendar store generic error.
- """
-
-class AlreadyExistsError(CalendarStoreError):
- """
- Attempt to create an object that already exists.
- """
-
-class CalendarAlreadyExistsError(AlreadyExistsError):
- """
- Calendar already exists.
- """
-
-class CalendarObjectNameAlreadyExistsError(AlreadyExistsError):
- """
- A calendar object with the requested name already exists.
- """
-
-class CalendarObjectUIDAlreadyExistsError(AlreadyExistsError):
- """
- A calendar object with the requested UID already exists.
- """
-
-class NotFoundError(CalendarStoreError):
- """
- Requested data not found.
- """
-
-class NoSuchCalendarError(NotFoundError):
- """
- The requested calendar does not exist.
- """
-
-class NoSuchCalendarObjectError(NotFoundError):
- """
- The requested calendar object does not exist.
- """
-
-class InvalidCalendarComponentError(CalendarStoreError):
- """
- Invalid calendar component.
- """
-
-#
-# Interfaces
-#
-
-class ICalendarHome(Interface):
- """
- Calendar home
- """
- def calendars(self):
- """
- Retrieve calendars contained in this calendar home.
-
- @return: an iterable of L{ICalendar}s.
- """
-
- def calendarWithName(self, name):
- """
- Retrieve the calendar with the given C{name} contained in this
- calendar home.
-
- @param name: a string.
- @return: an L{ICalendar} or C{None} if no such calendar
- exists.
- """
-
- def createCalendarWithName(self, name):
- """
- Create a calendar with the given C{name} in this calendar
- home.
-
- @param name: a string.
- @raise CalendarAlreadyExistsError: if a calendar with the
- given C{name} already exists.
- """
-
- def removeCalendarWithName(self, name):
- """
- Remove the calendar with the given C{name} from this calendar
- home. If this calendar home owns the calendar, also remove
- the calendar from all calendar homes.
-
- @param name: a string.
- @raise NoSuchCalendarObjectError: if no such calendar exists.
- """
-
- def properties(self):
- """
- Retrieve the property store for this calendar home.
-
- @return: an L{IPropertyStore}.
- """
-
-class ICalendar(Interface):
- """
- Calendar
- """
- def ownerCalendarHome(self):
- """
- Retrieve the calendar home for the owner of this calendar.
- Calendars may be shared from one (the owner's) calendar home
- to other (the sharee's) calendar homes.
-
- @return: an L{ICalendarHome}.
- """
-
- def calendarObjects(self):
- """
- Retrieve the calendar objects contained in this calendar.
-
- @return: an iterable of L{ICalendarObject}s.
- """
-
- def calendarObjectWithName(self, name):
- """
- Retrieve the calendar object with the given C{name} contained
- in this calendar.
-
- @param name: a string.
- @return: an L{ICalendarObject} or C{None} if no such calendar
- object exists.
- """
-
- def calendarObjectWithUID(self, uid):
- """
- Retrieve the calendar object with the given C{uid} contained
- in this calendar.
-
- @param uid: a string.
- @return: an L{ICalendarObject} or C{None} if no such calendar
- object exists.
- """
-
- def createCalendarObjectWithName(self, name, component):
- """
- Create a calendar component with the given C{name} in this
- calendar from the given C{component}.
-
- @param name: a string.
- @param component: a C{VCALENDAR} L{Component}
- @raise CalendarObjectNameAlreadyExistsError: if a calendar
- object with the given C{name} already exists.
- @raise CalendarObjectUIDAlreadyExistsError: if a calendar
- object with the same UID as the given C{component} already
- exists.
- @raise InvalidCalendarComponentError: if the given
- C{component} is not a valid C{VCALENDAR} L{Component} for
- a calendar object.
- """
-
- def removeCalendarComponentWithName(self, name):
- """
- Remove the calendar component with the given C{name} from this
- calendar.
-
- @param name: a string.
- @raise NoSuchCalendarObjectError: if no such calendar object
- exists.
- """
-
- def removeCalendarComponentWithUID(self, uid):
- """
- Remove the calendar component with the given C{uid} from this
- calendar.
-
- @param uid: a string.
- @raise NoSuchCalendarObjectError: if the calendar object does
- not exist.
- """
-
- def syncToken(self):
- """
- Retrieve the current sync token for this calendar.
-
- @return: a string containing a sync token.
- """
-
- def calendarObjectsInTimeRange(self, start, end, timeZone):
- """
- Retrieve all calendar objects in this calendar which have
- instances that occur within the time range that begins at
- C{start} and ends at C{end}.
-
- @param start: a L{datetime} or L{date}.
- @param end: a L{datetime} or L{date}.
- @param timeZone: a L{tzinfo}.
- @return: an iterable of L{ICalendarObject}s.
- """
-
- def calendarObjectsSinceToken(self, token):
- """
- Retrieve all calendar objects in this calendar that have
- changed since the given C{token} was last valid.
-
- @param token: a sync token.
- @return: a 3-tuple containing an iterable of
- L{ICalendarObject}s that have changed, an iterable of uids
- that have been removed, and the current sync token.
- """
-
- def properties(self):
- """
- Retrieve the property store for this calendar.
-
- @return: an L{IPropertyStore}.
- """
-
-class ICalendarObject(Interface):
- """
- Calendar object (event, to-do, etc.).
- """
- def setComponent(self, component):
- """
- Rewrite this calendar object to match the given C{component}.
- C{component} must have the same UID and be of the same
- component type as this calendar object.
-
- @param component: a C{VCALENDAR} L{Component}.
- @raise InvalidCalendarComponentError: if the given
- C{component} is not a valid C{VCALENDAR} L{Component} for
- a calendar object.
- """
-
- def component(self):
- """
- Retrieve the calendar component for this calendar object.
-
- @return: a C{VCALENDAR} L{Component}.
- """
-
- def iCalendarText(self):
- """
- Retrieve the iCalendar text data for this calendar object.
-
- @return: a string containing iCalendar data for a single
- calendar object.
- """
-
- def uid(self):
- """
- Retrieve the UID for this calendar object.
-
- @return: a string containing a UID.
- """
-
- def componentType(self):
- """
- Retrieve the iCalendar component type for the main component
- in this calendar object.
-
- @return: a string containing the component type.
- """
-
- def organizer(self):
- # FIXME: Ideally should return a URI object
- """
- Retrieve the organizer's calendar user address for this
- calendar object.
-
- @return: a URI string.
- """
-
- def properties(self):
- """
- Retrieve the property store for this calendar object.
-
- @return: an L{IPropertyStore}.
- """
Copied: CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/icalendarstore.py (from rev 4951, CalendarServer/trunk/txcaldav/icalendarstore.py)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/icalendarstore.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txcaldav/icalendarstore.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,308 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS IS" 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.
+##
+
+"""
+Calendar store interfaces
+"""
+
+__all__ = [
+ "ICalendarHome",
+ "ICalendar",
+ "ICalendarObject",
+]
+
+from zope.interface import Interface #, Attribute
+
+from datetime import datetime, date, tzinfo
+from twext.icalendar import Component
+from txdav.idav import IPropertyStore
+
+#
+# Exceptions
+#
+
+class CalendarStoreError(RuntimeError):
+ """
+ Calendar store generic error.
+ """
+
+class AlreadyExistsError(CalendarStoreError):
+ """
+ Attempt to create an object that already exists.
+ """
+
+class CalendarAlreadyExistsError(AlreadyExistsError):
+ """
+ Calendar already exists.
+ """
+
+class CalendarObjectNameAlreadyExistsError(AlreadyExistsError):
+ """
+ A calendar object with the requested name already exists.
+ """
+
+class CalendarObjectUIDAlreadyExistsError(AlreadyExistsError):
+ """
+ A calendar object with the requested UID already exists.
+ """
+
+class NotFoundError(CalendarStoreError):
+ """
+ Requested data not found.
+ """
+
+class NoSuchCalendarError(NotFoundError):
+ """
+ The requested calendar does not exist.
+ """
+
+class NoSuchCalendarObjectError(NotFoundError):
+ """
+ The requested calendar object does not exist.
+ """
+
+class InvalidCalendarComponentError(CalendarStoreError):
+ """
+ Invalid calendar component.
+ """
+
+#
+# Interfaces
+#
+
+class ICalendarHome(Interface):
+ """
+ Calendar home
+ """
+ def calendars(self):
+ """
+ Retrieve calendars contained in this calendar home.
+
+ @return: an iterable of L{ICalendar}s.
+ """
+
+ def calendarWithName(self, name):
+ """
+ Retrieve the calendar with the given C{name} contained in this
+ calendar home.
+
+ @param name: a string.
+ @return: an L{ICalendar} or C{None} if no such calendar
+ exists.
+ """
+
+ def createCalendarWithName(self, name):
+ """
+ Create a calendar with the given C{name} in this calendar
+ home.
+
+ @param name: a string.
+ @raise CalendarAlreadyExistsError: if a calendar with the
+ given C{name} already exists.
+ """
+
+ def removeCalendarWithName(self, name):
+ """
+ Remove the calendar with the given C{name} from this calendar
+ home. If this calendar home owns the calendar, also remove
+ the calendar from all calendar homes.
+
+ @param name: a string.
+ @raise NoSuchCalendarObjectError: if no such calendar exists.
+ """
+
+ def properties(self):
+ """
+ Retrieve the property store for this calendar home.
+
+ @return: an L{IPropertyStore}.
+ """
+
+class ICalendar(Interface):
+ """
+ Calendar
+ """
+ def ownerCalendarHome(self):
+ """
+ Retrieve the calendar home for the owner of this calendar.
+ Calendars may be shared from one (the owner's) calendar home
+ to other (the sharee's) calendar homes.
+
+ @return: an L{ICalendarHome}.
+ """
+
+ def calendarObjects(self):
+ """
+ Retrieve the calendar objects contained in this calendar.
+
+ @return: an iterable of L{ICalendarObject}s.
+ """
+
+ def calendarObjectWithName(self, name):
+ """
+ Retrieve the calendar object with the given C{name} contained
+ in this calendar.
+
+ @param name: a string.
+ @return: an L{ICalendarObject} or C{None} if no such calendar
+ object exists.
+ """
+
+ def calendarObjectWithUID(self, uid):
+ """
+ Retrieve the calendar object with the given C{uid} contained
+ in this calendar.
+
+ @param uid: a string.
+ @return: an L{ICalendarObject} or C{None} if no such calendar
+ object exists.
+ """
+
+ def createCalendarObjectWithName(self, name, component):
+ """
+ Create a calendar component with the given C{name} in this
+ calendar from the given C{component}.
+
+ @param name: a string.
+ @param component: a C{VCALENDAR} L{Component}
+ @raise CalendarObjectNameAlreadyExistsError: if a calendar
+ object with the given C{name} already exists.
+ @raise CalendarObjectUIDAlreadyExistsError: if a calendar
+ object with the same UID as the given C{component} already
+ exists.
+ @raise InvalidCalendarComponentError: if the given
+ C{component} is not a valid C{VCALENDAR} L{Component} for
+ a calendar object.
+ """
+
+ def removeCalendarComponentWithName(self, name):
+ """
+ Remove the calendar component with the given C{name} from this
+ calendar.
+
+ @param name: a string.
+ @raise NoSuchCalendarObjectError: if no such calendar object
+ exists.
+ """
+
+ def removeCalendarComponentWithUID(self, uid):
+ """
+ Remove the calendar component with the given C{uid} from this
+ calendar.
+
+ @param uid: a string.
+ @raise NoSuchCalendarObjectError: if the calendar object does
+ not exist.
+ """
+
+ def syncToken(self):
+ """
+ Retrieve the current sync token for this calendar.
+
+ @return: a string containing a sync token.
+ """
+
+ def calendarObjectsInTimeRange(self, start, end, timeZone):
+ """
+ Retrieve all calendar objects in this calendar which have
+ instances that occur within the time range that begins at
+ C{start} and ends at C{end}.
+
+ @param start: a L{datetime} or L{date}.
+ @param end: a L{datetime} or L{date}.
+ @param timeZone: a L{tzinfo}.
+ @return: an iterable of L{ICalendarObject}s.
+ """
+
+ def calendarObjectsSinceToken(self, token):
+ """
+ Retrieve all calendar objects in this calendar that have
+ changed since the given C{token} was last valid.
+
+ @param token: a sync token.
+ @return: a 3-tuple containing an iterable of
+ L{ICalendarObject}s that have changed, an iterable of uids
+ that have been removed, and the current sync token.
+ """
+
+ def properties(self):
+ """
+ Retrieve the property store for this calendar.
+
+ @return: an L{IPropertyStore}.
+ """
+
+class ICalendarObject(Interface):
+ """
+ Calendar object (event, to-do, etc.).
+ """
+ def setComponent(self, component):
+ """
+ Rewrite this calendar object to match the given C{component}.
+ C{component} must have the same UID and be of the same
+ component type as this calendar object.
+
+ @param component: a C{VCALENDAR} L{Component}.
+ @raise InvalidCalendarComponentError: if the given
+ C{component} is not a valid C{VCALENDAR} L{Component} for
+ a calendar object.
+ """
+
+ def component(self):
+ """
+ Retrieve the calendar component for this calendar object.
+
+ @return: a C{VCALENDAR} L{Component}.
+ """
+
+ def iCalendarText(self):
+ """
+ Retrieve the iCalendar text data for this calendar object.
+
+ @return: a string containing iCalendar data for a single
+ calendar object.
+ """
+
+ def uid(self):
+ """
+ Retrieve the UID for this calendar object.
+
+ @return: a string containing a UID.
+ """
+
+ def componentType(self):
+ """
+ Retrieve the iCalendar component type for the main component
+ in this calendar object.
+
+ @return: a string containing the component type.
+ """
+
+ def organizer(self):
+ # FIXME: Ideally should return a URI object
+ """
+ Retrieve the organizer's calendar user address for this
+ calendar object.
+
+ @return: a URI string.
+ """
+
+ def properties(self):
+ """
+ Retrieve the property store for this calendar object.
+
+ @return: an L{IPropertyStore}.
+ """
Deleted: CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/__init__.py
===================================================================
--- CalendarServer/trunk/txcarddav/__init__.py 2010-01-21 19:38:46 UTC (rev 4951)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/__init__.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,19 +0,0 @@
-##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS IS" 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.
-##
-
-"""
-CardDAV support for Twisted.
-"""
Copied: CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/__init__.py (from rev 4951, CalendarServer/trunk/txcarddav/__init__.py)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/__init__.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/__init__.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,19 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS IS" 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.
+##
+
+"""
+CardDAV support for Twisted.
+"""
Deleted: CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/iaddressbookstore.py
===================================================================
--- CalendarServer/trunk/txcarddav/iaddressbookstore.py 2010-01-21 19:38:46 UTC (rev 4951)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/iaddressbookstore.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,232 +0,0 @@
-##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS IS" 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.
-##
-
-"""
-Address book store interfaces
-"""
-
-__all__ = [
-]
-
-from zope.interface import Interface #, Attribute
-
-from twext.icalendar import Component
-from txdav.idav import IPropertyStore
-
-#
-# Exceptions
-#
-
-class AddressBookStoreError(RuntimeError):
- """
- Address book store generic error.
- """
-
-class AlreadyExistsError(AddressBookStoreError):
- """
- Attempt to create an object that already exists.
- """
-
-class AddressBookAlreadyExistsError(AlreadyExistsError):
- """
- Address book already exists.
- """
-
-class ContactCardNameAlreadyExistsError(AlreadyExistsError):
- """
- A contact card with the requested name already exists.
- """
-
-class ContactCardUIDAlreadyExistsError(AlreadyExistsError):
- """
- A contact card with the requested UID already exists.
- """
-
-class NotFoundError(AddressBookStoreError):
- """
- Requested data not found.
- """
-
-class NoSuchAddressBookError(NotFoundError):
- """
- The requested address book does not exist.
- """
-
-class NoSuchContactCardError(NotFoundError):
- """
- The requested contact card does not exist.
- """
-
-class InvalidCardComponentError(AddressBookStoreError):
- """
- Invalid card component.
- """
-
-#
-# Interfaces
-#
-
-class IAddressBookHome(Interface):
- """
- Address book home
- """
- def addressBooks(self):
- """
- Retrieve address books contained in this address book home.
-
- @return: an iterable of L{IAddressBook}s.
- """
-
- def addressBookWithName(self, name):
- """
- Retrieve the address book with the given C{name} contained in
- this address book home.
-
- @param name: a string.
- @return: an L{IAddressBook} or C{None} if no such address book
- exists.
- """
-
- def createAddressBookWithName(self, name):
- """
- Create an address book with the given C{name} in this address
- book home.
-
- @param name: a string.
- @raise AddressBookAlreadyExistsError: if an address book
- with the given C{name} already exists.
- """
-
- def properties(self):
- """
- Retrieve the property store for this address book home.
-
- @return: an L{IPropertyStore}.
- """
-
-class IAddressBook(Interface):
- """
- Address book
- """
- def contactCards(self):
- """
- Retrieve the contact cards contains in this address book.
-
- @return: an iterable of L{IContactCard}s.
- """
-
- def contactCardWithName(self, name):
- """
- Retrieve the contact card with the given C{name} in this
- address book.
-
- @param name: a string.
- @return: an L{IContactCard} or C{None} is no such contact card
- exists.
- """
-
- def contactCardWithUID(self, uid):
- """
- Retrieve the contact card with the given C{uid} in this
- address book.
-
- @param uid: a string.
- @return: an L{IContactCard} or C{None} is no such contact card
- exists.
- """
-
- def createContactCardWithName(self, name):
- """
- Create a contact card with the given C{name} in this address
- book from the given C{component}.
-
- @param name: a string.
- @param component: a C{VCARD} L{Component}.
- @raise ContactCardNameAlreadyExistsError: if a contact card
- with the given C{name} already exists.
- @raise ContactCardUIDAlreadyExistsError: if a contact card
- with the same UID as the given C{component} already
- exists.
- @raise InvalidCardComponentError: if the given C{component} is
- not a valid C{VCARD} L{Component} for a contact card.
- """
-
- def syncToken(self):
- """
- Retrieve the current sync token for this address book.
-
- @return: a sync token.
- """
-
- def contactCardsSinceToken(self, token):
- """
- Retrieve all contact cards in this address book that have
- changed since the given C{token} was last valid.
-
- @return: a 3-tuple containing an iterable of L{IContactCard}s
- that have changed, an iterable of uids that have been
- removed, and the current sync token.
- """
-
- def properties(self):
- """
- Retrieve the property store for this address book.
-
- @return: an L{IPropertyStore}.
- """
-
-class IContactCard(Interface):
- """
- Contact card
- """
- def setComponent(self):
- """
- Rewrite this contact card to match the given C{component}.
- C{component} must have the same UID as this contact card.
-
- @param component: a C{VCARD} L{Component}.
- @raise InvalidCardComponentError: if the given C{component} is
- not a valid C{VCARD} L{Component} for a contact card.
- """
-
- def component(self):
- """
- Retrieve the contact component for this contact card.
-
- @return: a C{VCARD} L{Component}.
- """
-
- def vCardText(self):
- """
- Retrieve the vCard text data for this contact card.
-
- @return: a string containing vCard data for a single vCard
- contact.
- """
-
- def uid(self):
- """
- Retrieve the UID for this contact card.
-
- @return: a string containing a UID.
- """
-
- def properties(self):
- """
- Retrieve the property store for this contact card.
-
- @return: an L{IPropertyStore}.
- """
Copied: CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/iaddressbookstore.py (from rev 4951, CalendarServer/trunk/txcarddav/iaddressbookstore.py)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/iaddressbookstore.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txcarddav/iaddressbookstore.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,232 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS IS" 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.
+##
+
+"""
+Address book store interfaces
+"""
+
+__all__ = [
+]
+
+from zope.interface import Interface #, Attribute
+
+from twext.icalendar import Component
+from txdav.idav import IPropertyStore
+
+#
+# Exceptions
+#
+
+class AddressBookStoreError(RuntimeError):
+ """
+ Address book store generic error.
+ """
+
+class AlreadyExistsError(AddressBookStoreError):
+ """
+ Attempt to create an object that already exists.
+ """
+
+class AddressBookAlreadyExistsError(AlreadyExistsError):
+ """
+ Address book already exists.
+ """
+
+class ContactCardNameAlreadyExistsError(AlreadyExistsError):
+ """
+ A contact card with the requested name already exists.
+ """
+
+class ContactCardUIDAlreadyExistsError(AlreadyExistsError):
+ """
+ A contact card with the requested UID already exists.
+ """
+
+class NotFoundError(AddressBookStoreError):
+ """
+ Requested data not found.
+ """
+
+class NoSuchAddressBookError(NotFoundError):
+ """
+ The requested address book does not exist.
+ """
+
+class NoSuchContactCardError(NotFoundError):
+ """
+ The requested contact card does not exist.
+ """
+
+class InvalidCardComponentError(AddressBookStoreError):
+ """
+ Invalid card component.
+ """
+
+#
+# Interfaces
+#
+
+class IAddressBookHome(Interface):
+ """
+ Address book home
+ """
+ def addressBooks(self):
+ """
+ Retrieve address books contained in this address book home.
+
+ @return: an iterable of L{IAddressBook}s.
+ """
+
+ def addressBookWithName(self, name):
+ """
+ Retrieve the address book with the given C{name} contained in
+ this address book home.
+
+ @param name: a string.
+ @return: an L{IAddressBook} or C{None} if no such address book
+ exists.
+ """
+
+ def createAddressBookWithName(self, name):
+ """
+ Create an address book with the given C{name} in this address
+ book home.
+
+ @param name: a string.
+ @raise AddressBookAlreadyExistsError: if an address book
+ with the given C{name} already exists.
+ """
+
+ def properties(self):
+ """
+ Retrieve the property store for this address book home.
+
+ @return: an L{IPropertyStore}.
+ """
+
+class IAddressBook(Interface):
+ """
+ Address book
+ """
+ def contactCards(self):
+ """
+ Retrieve the contact cards contains in this address book.
+
+ @return: an iterable of L{IContactCard}s.
+ """
+
+ def contactCardWithName(self, name):
+ """
+ Retrieve the contact card with the given C{name} in this
+ address book.
+
+ @param name: a string.
+ @return: an L{IContactCard} or C{None} is no such contact card
+ exists.
+ """
+
+ def contactCardWithUID(self, uid):
+ """
+ Retrieve the contact card with the given C{uid} in this
+ address book.
+
+ @param uid: a string.
+ @return: an L{IContactCard} or C{None} is no such contact card
+ exists.
+ """
+
+ def createContactCardWithName(self, name):
+ """
+ Create a contact card with the given C{name} in this address
+ book from the given C{component}.
+
+ @param name: a string.
+ @param component: a C{VCARD} L{Component}.
+ @raise ContactCardNameAlreadyExistsError: if a contact card
+ with the given C{name} already exists.
+ @raise ContactCardUIDAlreadyExistsError: if a contact card
+ with the same UID as the given C{component} already
+ exists.
+ @raise InvalidCardComponentError: if the given C{component} is
+ not a valid C{VCARD} L{Component} for a contact card.
+ """
+
+ def syncToken(self):
+ """
+ Retrieve the current sync token for this address book.
+
+ @return: a sync token.
+ """
+
+ def contactCardsSinceToken(self, token):
+ """
+ Retrieve all contact cards in this address book that have
+ changed since the given C{token} was last valid.
+
+ @return: a 3-tuple containing an iterable of L{IContactCard}s
+ that have changed, an iterable of uids that have been
+ removed, and the current sync token.
+ """
+
+ def properties(self):
+ """
+ Retrieve the property store for this address book.
+
+ @return: an L{IPropertyStore}.
+ """
+
+class IContactCard(Interface):
+ """
+ Contact card
+ """
+ def setComponent(self):
+ """
+ Rewrite this contact card to match the given C{component}.
+ C{component} must have the same UID as this contact card.
+
+ @param component: a C{VCARD} L{Component}.
+ @raise InvalidCardComponentError: if the given C{component} is
+ not a valid C{VCARD} L{Component} for a contact card.
+ """
+
+ def component(self):
+ """
+ Retrieve the contact component for this contact card.
+
+ @return: a C{VCARD} L{Component}.
+ """
+
+ def vCardText(self):
+ """
+ Retrieve the vCard text data for this contact card.
+
+ @return: a string containing vCard data for a single vCard
+ contact.
+ """
+
+ def uid(self):
+ """
+ Retrieve the UID for this contact card.
+
+ @return: a string containing a UID.
+ """
+
+ def properties(self):
+ """
+ Retrieve the property store for this contact card.
+
+ @return: an L{IPropertyStore}.
+ """
Deleted: CalendarServer/branches/users/cdaboo/partition-4464/txdav/__init__.py
===================================================================
--- CalendarServer/trunk/txdav/__init__.py 2010-01-21 19:38:46 UTC (rev 4951)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txdav/__init__.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,19 +0,0 @@
-##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS IS" 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.
-##
-
-"""
-WebDAV support for Twisted.
-"""
Copied: CalendarServer/branches/users/cdaboo/partition-4464/txdav/__init__.py (from rev 4951, CalendarServer/trunk/txdav/__init__.py)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/txdav/__init__.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txdav/__init__.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,19 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS IS" 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.
+##
+
+"""
+WebDAV support for Twisted.
+"""
Deleted: CalendarServer/branches/users/cdaboo/partition-4464/txdav/idav.py
===================================================================
--- CalendarServer/trunk/txdav/idav.py 2010-01-21 19:38:46 UTC (rev 4951)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txdav/idav.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -1,45 +0,0 @@
-##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# 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 "AS IS" 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.
-##
-
-"""
-WebDAV interfaces
-"""
-
-__all__ = [
- "IPropertyStore",
-]
-
-#from zope.interface import Attribute, Interface
-
-from zope.interface.common.mapping import IMapping
-
-class IPropertyStore(IMapping):
- """
- WebDAV property store
-
- This interface is based on L{IMapping}, but any changed to data
- are not persisted until C{flush()} is called, and can be undone
- using C{abort()}.
- """
- def flush(self):
- """
- Write out any pending changes.
- """
-
- def abort(self):
- """
- Abort any pending changes.
- """
Copied: CalendarServer/branches/users/cdaboo/partition-4464/txdav/idav.py (from rev 4951, CalendarServer/trunk/txdav/idav.py)
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/txdav/idav.py (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/txdav/idav.py 2010-01-21 20:33:21 UTC (rev 4953)
@@ -0,0 +1,45 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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 "AS IS" 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.
+##
+
+"""
+WebDAV interfaces
+"""
+
+__all__ = [
+ "IPropertyStore",
+]
+
+#from zope.interface import Attribute, Interface
+
+from zope.interface.common.mapping import IMapping
+
+class IPropertyStore(IMapping):
+ """
+ WebDAV property store
+
+ This interface is based on L{IMapping}, but any changed to data
+ are not persisted until C{flush()} is called, and can be undone
+ using C{abort()}.
+ """
+ def flush(self):
+ """
+ Write out any pending changes.
+ """
+
+ def abort(self):
+ """
+ Abort any pending changes.
+ """
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100121/8df4c698/attachment-0001.html>
More information about the calendarserver-changes
mailing list