[CalendarServer-changes] [11205] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Thu May 16 13:35:53 PDT 2013
Revision: 11205
http://trac.calendarserver.org//changeset/11205
Author: gaya at apple.com
Date: 2013-05-16 13:35:53 -0700 (Thu, 16 May 2013)
Log Message:
-----------
merge in sharedgroups-3 branches
Modified Paths:
--------------
CalDAVTester/trunk/Resource/CardDAV/default-addressbook/3.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/2.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/3.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/1.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/2.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/3.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/2.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/3.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/5.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/6.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/1.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/3.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/4.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/setup/2.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/setup/3.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/setup/5.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/setup/6.xml
CalDAVTester/trunk/scripts/tests/CardDAV/aclreports.xml
CalDAVTester/trunk/scripts/tests/CardDAV/add-member.xml
CalDAVTester/trunk/scripts/tests/CardDAV/default-addressbook.xml
CalDAVTester/trunk/scripts/tests/CardDAV/get.xml
CalDAVTester/trunk/scripts/tests/CardDAV/limits.xml
CalDAVTester/trunk/scripts/tests/CardDAV/mkcol.xml
CalDAVTester/trunk/scripts/tests/CardDAV/nonascii.xml
CalDAVTester/trunk/scripts/tests/CardDAV/sharing-addressbooks.xml
CalDAVTester/trunk/scripts/tests/CardDAV/sharing-feature.xml
CalDAVTester/trunk/scripts/tests/CardDAV/sharing-peruser-properties.xml
CalDAVTester/trunk/scripts/tests/CardDAV/sharing-replies.xml
CalDAVTester/trunk/scripts/tests/CardDAV/sharing-unshare.xml
CalDAVTester/trunk/scripts/tests/CardDAV/sync-report.xml
CalendarServer/trunk/calendarserver/tap/caldav.py
CalendarServer/trunk/calendarserver/tools/dbinspect.py
CalendarServer/trunk/calendarserver/tools/obliterate.py
CalendarServer/trunk/testserver
CalendarServer/trunk/twext/web2/resource.py
CalendarServer/trunk/twistedcaldav/customxml.py
CalendarServer/trunk/twistedcaldav/resource.py
CalendarServer/trunk/twistedcaldav/sharing.py
CalendarServer/trunk/twistedcaldav/storebridge.py
CalendarServer/trunk/twistedcaldav/test/test_addressbookmultiget.py
CalendarServer/trunk/twistedcaldav/test/test_addressbookquery.py
CalendarServer/trunk/twistedcaldav/test/test_resource.py
CalendarServer/trunk/twistedcaldav/test/test_sharing.py
CalendarServer/trunk/twistedcaldav/test/test_wrapping.py
CalendarServer/trunk/twistedcaldav/vcard.py
CalendarServer/trunk/txdav/base/propertystore/sql.py
CalendarServer/trunk/txdav/caldav/datastore/sql.py
CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
CalendarServer/trunk/txdav/carddav/datastore/sql.py
CalendarServer/trunk/txdav/carddav/datastore/test/common.py
CalendarServer/trunk/txdav/carddav/datastore/test/test_file.py
CalendarServer/trunk/txdav/carddav/datastore/test/test_sql.py
CalendarServer/trunk/txdav/carddav/iaddressbookstore.py
CalendarServer/trunk/txdav/common/datastore/sql.py
CalendarServer/trunk/txdav/common/datastore/sql_legacy.py
CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql
CalendarServer/trunk/txdav/common/datastore/sql_tables.py
CalendarServer/trunk/txdav/common/datastore/test/test_sql.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py
CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py
Added Paths:
-----------
CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/9.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/1.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/10.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/11.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/12.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/13.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/14.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15a.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/16.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/2.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/3.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/4.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/5.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/6.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/7.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/8.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/9.vcf
CalDAVTester/trunk/scripts/tests/CardDAV/sharing-groups.xml
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/1.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/2.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/3.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/3765A955-1B96-41EA-994D-335192BEDCCD.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44745975-AE6D-4FB0-80A6-A298427E047A.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44EE78BF-8814-4471-899C-92280CEFB098.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/934731C6-1C95-4C40-BE1F-FA4215B2307B.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/F0A6918D-8E09-43FA-9684-226810B8A96F.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/1.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/2.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_empty/
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_empty/addressbook/
CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v18.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v19.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v18.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v19.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_19_to_20.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_19_to_20.sql
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/addressbook_upgrade_from_1_to_2.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_1_to_2.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_2_to_3.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_3_to_4.py
Removed Paths:
-------------
CalDAVTester/trunk/Resource/CardDAV/default-addressbook/4.xml
CalDAVTester/trunk/Resource/CardDAV/mkcol/2.xml
CalDAVTester/trunk/Resource/CardDAV/mkcol/3.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/main/
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/1.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/10.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/11.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/12.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/13.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/14.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15a.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/16.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/2.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/3.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/4.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/5.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/6.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/7.xml
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/8.vcf
CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/9.vcf
CalDAVTester/trunk/scripts/tests/CardDAV/resourceid.xml
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/1.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/2.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/3.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook_1/
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook_2/
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook_empty/
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/3765A955-1B96-41EA-994D-335192BEDCCD.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44745975-AE6D-4FB0-80A6-A298427E047A.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44EE78BF-8814-4471-899C-92280CEFB098.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/934731C6-1C95-4C40-BE1F-FA4215B2307B.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/F0A6918D-8E09-43FA-9684-226810B8A96F.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/1.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/2.vcf
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook_bad/
CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_empty/addressbook/
CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v18.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v18.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_2_to_3.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py
Property Changed:
----------------
CalDAVTester/trunk/
CalDAVTester/trunk/Resource/CardDAV/
CalDAVTester/trunk/scripts/tests/CardDAV/
CalendarServer/trunk/
CalendarServer/trunk/txdav/common/datastore/sql.py
Property changes on: CalDAVTester/trunk
___________________________________________________________________
Modified: svn:mergeinfo
- /CalDAVTester/branches/release/CalDAVTester-3.0-dev:7584
/CalDAVTester/branches/release/CalDAVTester-4.3-dev:10193
/CalDAVTester/branches/users/cdaboo/attendee-comments-2887:2888-2910
/CalDAVTester/branches/users/cdaboo/better-proxy-3148:3149-3163
/CalDAVTester/branches/users/cdaboo/component-set-fixes:8221-8346
/CalDAVTester/branches/users/cdaboo/conditional-4466:4467-4469
/CalDAVTester/branches/users/cdaboo/implicitauto-2948:2949-2989
/CalDAVTester/branches/users/cdaboo/location-partial-accept-3574:3575-3581
/CalDAVTester/branches/users/cdaboo/managed-attachments:9986-10145
/CalDAVTester/branches/users/cdaboo/normalize-cuaddr-3533:3534-3558
/CalDAVTester/branches/users/cdaboo/pycalendar:7160-7206
/CalDAVTester/branches/users/cdaboo/pycard:7226-7237
/CalDAVTester/branches/users/cdaboo/sharing-5228:5229-5440
+ /CalDAVTester/branches/release/CalDAVTester-3.0-dev:7584
/CalDAVTester/branches/release/CalDAVTester-4.3-dev:10193
/CalDAVTester/branches/users/cdaboo/attendee-comments-2887:2888-2910
/CalDAVTester/branches/users/cdaboo/better-proxy-3148:3149-3163
/CalDAVTester/branches/users/cdaboo/component-set-fixes:8221-8346
/CalDAVTester/branches/users/cdaboo/conditional-4466:4467-4469
/CalDAVTester/branches/users/cdaboo/implicitauto-2948:2949-2989
/CalDAVTester/branches/users/cdaboo/location-partial-accept-3574:3575-3581
/CalDAVTester/branches/users/cdaboo/managed-attachments:9986-10145
/CalDAVTester/branches/users/cdaboo/normalize-cuaddr-3533:3534-3558
/CalDAVTester/branches/users/cdaboo/pycalendar:7160-7206
/CalDAVTester/branches/users/cdaboo/pycard:7226-7237
/CalDAVTester/branches/users/cdaboo/sharing-5228:5229-5440
/CalDAVTester/branches/users/gaya/sharedgroupstester-3:11181-11204
Property changes on: CalDAVTester/trunk/Resource/CardDAV
___________________________________________________________________
Added: svn:mergeinfo
+ /CalDAVTester/branches/release/CalDAVTester-3.0-dev/Resource/CardDAV:7584
/CalDAVTester/branches/release/CalDAVTester-4.3-dev/Resource/CardDAV:10193
/CalDAVTester/branches/users/cdaboo/attendee-comments-2887/Resource/CardDAV:2888-2910
/CalDAVTester/branches/users/cdaboo/better-proxy-3148/Resource/CardDAV:3149-3163
/CalDAVTester/branches/users/cdaboo/component-set-fixes/Resource/CardDAV:8221-8346
/CalDAVTester/branches/users/cdaboo/conditional-4466/Resource/CardDAV:4467-4469
/CalDAVTester/branches/users/cdaboo/implicitauto-2948/Resource/CardDAV:2949-2989
/CalDAVTester/branches/users/cdaboo/location-partial-accept-3574/Resource/CardDAV:3575-3581
/CalDAVTester/branches/users/cdaboo/managed-attachments/Resource/CardDAV:9986-10145
/CalDAVTester/branches/users/cdaboo/normalize-cuaddr-3533/Resource/CardDAV:3534-3558
/CalDAVTester/branches/users/cdaboo/pycalendar/Resource/CardDAV:7160-7206
/CalDAVTester/branches/users/cdaboo/pycard/Resource/CardDAV:7226-7237
/CalDAVTester/branches/users/cdaboo/sharing-5228/Resource/CardDAV:5229-5440
/CalDAVTester/branches/users/gaya/sharedgroupstester-2/Resource/CardDAV:11078-11181
/CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV:11181-11204
Modified: CalDAVTester/trunk/Resource/CardDAV/default-addressbook/3.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/default-addressbook/3.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/default-addressbook/3.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -2,7 +2,7 @@
<D:propertyupdate xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
<D:set>
<D:prop>
-<C:default-addressbook-URL><D:href>$addressbookhome1:/adbktest1/</D:href></C:default-addressbook-URL>
+<C:default-addressbook-URL><D:href>$addressbookpath1:/</D:href></C:default-addressbook-URL>
</D:prop>
</D:set>
</D:propertyupdate>
Deleted: CalDAVTester/trunk/Resource/CardDAV/default-addressbook/4.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/default-addressbook/4.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/default-addressbook/4.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<D:propertyupdate xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
-<D:set>
-<D:prop>
-<C:default-addressbook-URL><D:href>$addressbookpath1:/</D:href></C:default-addressbook-URL>
-</D:prop>
-</D:set>
-</D:propertyupdate>
Deleted: CalDAVTester/trunk/Resource/CardDAV/mkcol/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/mkcol/2.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/mkcol/2.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<D:mkcol xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
-<D:set>
-<D:prop>
-<D:resourcetype><D:collection/><C:addressbook/></D:resourcetype>
-<D:getetag>An Address Book</D:getetag>
-<D:displayname>An Address Book</D:displayname>
-<C:addressbook-description xml:lang="en">First CardDAV address book.</C:addressbook-description>
-</D:prop>
-</D:set>
-</D:mkcol>
Deleted: CalDAVTester/trunk/Resource/CardDAV/mkcol/3.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/mkcol/3.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/mkcol/3.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<D:mkcol xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
-<D:set>
-<D:prop>
-<D:resourcetype><D:collection/><D:displayname/></D:resourcetype>
-</D:prop>
-</D:set>
-</D:mkcol>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/2.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/2.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -8,7 +8,7 @@
<read/>
</access>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<organizer>
<href xmlns='DAV:'>$principaluri1:</href>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/3.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/3.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-only/3.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -3,7 +3,7 @@
<href xmlns='DAV:'>mailto:$email2:</href>
<invite-accepted/>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<in-reply-to>$inviteuid:</in-reply-to>
<summary>The Shared Address Book</summary>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/1.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/1.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/1.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -2,7 +2,7 @@
<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
<CS:set>
<D:href>$cuaddr2:</D:href>
- <CS:summary>My Shared Address Book</CS:summary>
+ <CS:summary>My Main Shared Address Book</CS:summary>
<CS:read-write/>
</CS:set>
</CS:share>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/2.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/2.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -8,12 +8,12 @@
<read-write/>
</access>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<organizer>
<href xmlns='DAV:'>$principaluri1:</href>
<common-name>User 01</common-name>
</organizer>
- <summary>My Shared Address Book</summary>
+ <summary>My Main Shared Address Book</summary>
</invite-notification>
</notification>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/3.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/3.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/3.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -3,7 +3,7 @@
<href xmlns='DAV:'>mailto:$email2:</href>
<invite-accepted/>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<in-reply-to>$inviteuid:</in-reply-to>
<summary>The Shared Address Book</summary>
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/9.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/addressbooks/read-write/9.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/9.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/addressbooks/read-write/9.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+UID:8ec61992-d3f4-45cc-b64a-b683c3ba3eff
+FN:user01
+N:user01;;;;
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:A
+ BPerson-1
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:A
+ BPerson-2
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/1.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/1.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/1.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,11 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Thompson;Default;;;
-FN:Default Thompson
-EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
-TEL;type=WORK;type=pref:1-555-555-5555
-TEL;type=CELL:1-555-555-5555
-item1.ADR;type=WORK;type=pref:;;2 Lag;Elk Forest;California;99999;USA
-item1.X-ABADR:us
-UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/1.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/1.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/1.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/1.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-555-555-5555
+item1.ADR;type=WORK;type=pref:;;2 Lag;Elk Forest;California;99999;USA
+item1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/10.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/10.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/10.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,8 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-PRODID:-//Apple Inc.//AddressBook 6.1//EN
-UID:ef5516c6-0efd-4626-98b4-5cd2868f3971
-FN:Subsub Group
-N:Subsub Group;;;;
-X-ADDRESSBOOKSERVER-KIND:group
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/10.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/10.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/10.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/10.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,8 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:ef5516c6-0efd-4626-98b4-5cd2868f3971
+FN:Subsub Group
+N:Subsub Group;;;;
+X-ADDRESSBOOKSERVER-KIND:group
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/11.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/11.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/11.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,11 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-PRODID:-//Apple Inc.//AddressBook 6.1//EN
-UID:760d9b28-5a13-4880-b7eb-5769e6688fa3
-FN:Shared Group
-N:Shared Group;;;;
-REV:20120503T194243Z
-X-ADDRESSBOOKSERVER-KIND:group
-X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:8aa9ed15-5619-44d7-b061-51976dd5a174
-X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ef5516c6-0efd-4626-98b4-5cd2868f3971
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/11.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/11.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/11.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/11.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:760d9b28-5a13-4880-b7eb-5769e6688fa3
+FN:Shared Group
+N:Shared Group;;;;
+REV:20120503T194243Z
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:8aa9ed15-5619-44d7-b061-51976dd5a174
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ef5516c6-0efd-4626-98b4-5cd2868f3971
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/12.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/12.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/12.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,9 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-PRODID:-//Apple Inc.//AddressBook 6.1//EN
-UID:ef5516c6-0efd-4626-98b4-5cd2868f3971
-FN:New Group
-N:New Group;;;;
-X-ADDRESSBOOKSERVER-KIND:group
-X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-2
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/12.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/12.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/12.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/12.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,9 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:ef5516c6-0efd-4626-98b4-5cd2868f3971
+FN:New Group
+N:New Group;;;;
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-2
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/13.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/13.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/13.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,11 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-PRODID:-//Apple Inc.//AddressBook 6.1//EN
-UID:8aa9ed15-5619-44d7-b061-51976dd5a174
-FN:Sub Group
-N:Sub Group;;;;
-REV:20120503T194243Z
-X-ADDRESSBOOKSERVER-KIND:group
-X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
-X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1:ABPerson
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/13.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/13.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/13.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/13.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:8aa9ed15-5619-44d7-b061-51976dd5a174
+FN:Sub Group
+N:Sub Group;;;;
+REV:20120503T194243Z
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1:ABPerson
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/14.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/14.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/14.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,10 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-PRODID:-//Apple Inc.//AddressBook 6.1//EN
-UID:8aa9ed15-5619-44d7-b061-51976dd5a174
-FN:Sub Group
-N:Sub Group;;;;
-REV:20120503T194243Z
-X-ADDRESSBOOKSERVER-KIND:group
-X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1:ABPerson
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/14.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/14.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/14.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/14.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,10 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:8aa9ed15-5619-44d7-b061-51976dd5a174
+FN:Sub Group
+N:Sub Group;;;;
+REV:20120503T194243Z
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1:ABPerson
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/15.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,9 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-PRODID:-//Apple Inc.//AddressBook 6.1//EN
-UID:8aa9ed15-5619-44d7-b061-51976dd5a174
-FN:Sub Group
-N:Sub Group;;;;
-REV:20120503T194243Z
-X-ADDRESSBOOKSERVER-KIND:group
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/15.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,9 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:8aa9ed15-5619-44d7-b061-51976dd5a174
+FN:Sub Group
+N:Sub Group;;;;
+REV:20120503T194243Z
+X-ADDRESSBOOKSERVER-KIND:group
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15a.xml
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/15a.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15a.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
- <CS:remove>
- <D:href>$cuaddr2:</D:href>
- </CS:remove>
-</CS:share>
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15a.xml (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/15a.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15a.xml (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/15a.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
+ <CS:remove>
+ <D:href>$cuaddr2:</D:href>
+ </CS:remove>
+</CS:share>
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/16.xml
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/16.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/16.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,19 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?><notification xmlns='http://calendarserver.org/ns/'>
- <dtstamp></dtstamp>
- <invite-notification shared-type='group'>
- <uid></uid>
- <href xmlns='DAV:'>$cuaddrurn2:</href>
- <invite-deleted/>
- <access>
- <read-write/>
- </access>
- <hosturl>
- <href xmlns='DAV:'>$addressbookpath1:/3.vcf</href>
- </hosturl>
- <organizer>
- <href xmlns='DAV:'>$principaluri1:</href>
- <common-name>User 01</common-name>
- </organizer>
- <summary>Group Address Book</summary>
- </invite-notification>
-</notification>
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/16.xml (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/16.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/16.xml (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/16.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?><notification xmlns='http://calendarserver.org/ns/'>
+ <dtstamp></dtstamp>
+ <invite-notification shared-type='group'>
+ <uid></uid>
+ <href xmlns='DAV:'>$cuaddrurn2:</href>
+ <invite-deleted/>
+ <access>
+ <read-write/>
+ </access>
+ <hosturl>
+ <href xmlns='DAV:'>$addressbookpath1:/3.vcf</href>
+ </hosturl>
+ <organizer>
+ <href xmlns='DAV:'>$principaluri1:</href>
+ <common-name>User 01</common-name>
+ </organizer>
+ <summary>Group Address Book</summary>
+ </invite-notification>
+</notification>
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/2.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/2.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/2.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,12 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Kawado;Saeko;;;
-FN:Snow Leopard
-ORG:Snow Leopard;
-EMAIL;type=INTERNET;type=WORK;type=pref:snowleopard_apple at example.com
-TEL;type=WORK;type=pref:555-555-5555
-item1.ADR;type=WORK;type=pref:;;2 Fidel Ave. Suite 1;Mountain Top;CA;99999;USA
-item1.X-ABADR:us
-X-ABShowAs:COMPANY
-UID:FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1:ABPerson
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/2.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/2.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/2.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/2.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Kawado;Saeko;;;
+FN:Snow Leopard
+ORG:Snow Leopard;
+EMAIL;type=INTERNET;type=WORK;type=pref:snowleopard_apple at example.com
+TEL;type=WORK;type=pref:555-555-5555
+item1.ADR;type=WORK;type=pref:;;2 Fidel Ave. Suite 1;Mountain Top;CA;99999;USA
+item1.X-ABADR:us
+X-ABShowAs:COMPANY
+UID:FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1:ABPerson
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/3.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/3.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/3.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,10 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-PRODID:-//Apple Inc.//AddressBook 6.1//EN
-UID:760d9b28-5a13-4880-b7eb-5769e6688fa3
-FN:Shared Group
-N:Shared Group;;;;
-REV:20120503T194243Z
-X-ADDRESSBOOKSERVER-KIND:group
-X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:8aa9ed15-5619-44d7-b061-51976dd5a174
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/3.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/3.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/3.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/3.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,10 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:760d9b28-5a13-4880-b7eb-5769e6688fa3
+FN:Shared Group
+N:Shared Group;;;;
+REV:20120503T194243Z
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:8aa9ed15-5619-44d7-b061-51976dd5a174
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/4.xml
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/4.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/4.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
- <CS:set>
- <D:href>$cuaddr2:</D:href>
- <CS:summary>Group Address Book</CS:summary>
- <CS:read-write/>
- </CS:set>
-</CS:share>
\ No newline at end of file
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/4.xml (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/4.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/4.xml (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/4.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<CS:share xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/">
+ <CS:set>
+ <D:href>$cuaddr2:</D:href>
+ <CS:summary>Group Address Book</CS:summary>
+ <CS:read-write/>
+ </CS:set>
+</CS:share>
\ No newline at end of file
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/5.xml
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/5.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/5.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,19 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?><notification xmlns='http://calendarserver.org/ns/'>
- <dtstamp></dtstamp>
- <invite-notification shared-type='group'>
- <uid></uid>
- <href xmlns='DAV:'>$cuaddrurn2:</href>
- <invite-noresponse/>
- <access>
- <read-write/>
- </access>
- <hosturl>
- <href xmlns='DAV:'>$addressbookpath1:/3.vcf</href>
- </hosturl>
- <organizer>
- <href xmlns='DAV:'>$principaluri1:</href>
- <common-name>User 01</common-name>
- </organizer>
- <summary>Group Address Book</summary>
- </invite-notification>
-</notification>
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/5.xml (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/5.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/5.xml (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/5.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?><notification xmlns='http://calendarserver.org/ns/'>
+ <dtstamp></dtstamp>
+ <invite-notification shared-type='group'>
+ <uid></uid>
+ <href xmlns='DAV:'>$cuaddrurn2:</href>
+ <invite-noresponse/>
+ <access>
+ <read-write/>
+ </access>
+ <hosturl>
+ <href xmlns='DAV:'>$addressbookpath1:/3.vcf</href>
+ </hosturl>
+ <organizer>
+ <href xmlns='DAV:'>$principaluri1:</href>
+ <common-name>User 01</common-name>
+ </organizer>
+ <summary>Group Address Book</summary>
+ </invite-notification>
+</notification>
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/6.xml
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/6.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/6.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,13 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<invite-reply xmlns='http://calendarserver.org/ns/'>
- <href xmlns='DAV:'>mailto:$email2:</href>
- <invite-accepted/>
- <hosturl>
- <href xmlns='DAV:'>$addressbookpath1:/3.vcf</href>
- </hosturl>
- <in-reply-to>$inviteuid:</in-reply-to>
- <summary>Group Address Book</summary>
- <common-name>$username2:</common-name>
- <first-name>$firstname2:</first-name>
- <last-name>$lastname2:</last-name>
-</invite-reply>
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/6.xml (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/6.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/6.xml (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/6.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<invite-reply xmlns='http://calendarserver.org/ns/'>
+ <href xmlns='DAV:'>mailto:$email2:</href>
+ <invite-accepted/>
+ <hosturl>
+ <href xmlns='DAV:'>$addressbookpath1:/3.vcf</href>
+ </hosturl>
+ <in-reply-to>$inviteuid:</in-reply-to>
+ <summary>Group Address Book</summary>
+ <common-name>$username2:</common-name>
+ <first-name>$firstname2:</first-name>
+ <last-name>$lastname2:</last-name>
+</invite-reply>
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/7.xml
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/7.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/7.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<D:propfind xmlns:D="DAV:">
-<D:prop>
-<D:resourcetype/>
-<D:owner/>
-<D:current-user-privilege-set/>
-</D:prop>
-</D:propfind>
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/7.xml (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/7.xml)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/7.xml (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/7.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<D:propfind xmlns:D="DAV:">
+<D:prop>
+<D:resourcetype/>
+<D:owner/>
+<D:current-user-privilege-set/>
+</D:prop>
+</D:propfind>
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/8.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/8.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/8.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,9 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-PRODID:-//Apple Inc.//AddressBook 6.1//EN
-UID:ef5516c6-0efd-4626-98b4-5cd2868f3971
-FN:Subsub Group
-N:Subsub Group;;;;
-X-ADDRESSBOOKSERVER-KIND:group
-X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-2
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/8.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/8.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/8.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/8.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,9 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:ef5516c6-0efd-4626-98b4-5cd2868f3971
+FN:Subsub Group
+N:Subsub Group;;;;
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson-2
+END:VCARD
Deleted: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/9.vcf
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/9.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/9.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,9 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-PRODID:-//Apple Inc.//AddressBook 6.1//EN
-UID:ef5516c6-0efd-4626-98b4-5cd2868f3971
-FN:Subsub Group
-N:Subsub Group;;;;
-X-ADDRESSBOOKSERVER-KIND:group
-X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
-END:VCARD
Copied: CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/9.vcf (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/Resource/CardDAV/sharing/groups/read-write/9.vcf)
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/9.vcf (rev 0)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/groups/read-write/9.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,9 @@
+BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:ef5516c6-0efd-4626-98b4-5cd2868f3971
+FN:Subsub Group
+N:Subsub Group;;;;
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson
+END:VCARD
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/2.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/2.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -8,7 +8,7 @@
<read-write/>
</access>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<organizer>
<href xmlns='DAV:'>$principaluri1:</href>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/3.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/3.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/3.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -3,7 +3,7 @@
<href xmlns='DAV:'>mailto:$email2:</href>
<invite-accepted/>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<in-reply-to>$inviteuid:</in-reply-to>
<summary>The Shared Address Book</summary>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/5.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/5.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/5.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?><multistatus xmlns='DAV:'>
<response>
- <href>$addressbookhome1:/shared/</href>
+ <href>$addressbookpath1:/</href>
<propstat>
<prop>
<invite xmlns='http://calendarserver.org/ns/'>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/6.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/6.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/replies/accept/6.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -4,7 +4,7 @@
<href xmlns='DAV:'>mailto:$email2:</href>
<invite-accepted/>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<in-reply-to>$inviteuid:</in-reply-to>
<summary>The Shared Address Book</summary>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/1.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/1.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/1.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -3,7 +3,7 @@
<href xmlns='DAV:'>mailto:$email2:</href>
<invite-declined/>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<in-reply-to>$inviteuid:</in-reply-to>
<summary>The Shared Address Book</summary>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/3.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/3.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/3.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?><multistatus xmlns='DAV:'>
<response>
- <href>$addressbookhome1:/shared/</href>
+ <href>$addressbookpath1:/</href>
<propstat>
<prop>
<invite xmlns='http://calendarserver.org/ns/'>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/4.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/4.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/replies/decline/4.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -4,7 +4,7 @@
<href xmlns='DAV:'>mailto:$email2:</href>
<invite-declined/>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<in-reply-to>$inviteuid:</in-reply-to>
<common-name>$username2:</common-name>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/setup/2.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/setup/2.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/setup/2.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -8,7 +8,7 @@
<read-write/>
</access>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<organizer>
<href xmlns='DAV:'>$principaluri1:</href>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/setup/3.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/setup/3.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/setup/3.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -3,7 +3,7 @@
<href xmlns='DAV:'>mailto:$email2:</href>
<invite-accepted/>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<in-reply-to>$inviteuid:</in-reply-to>
<summary>The Shared Address Book</summary>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/setup/5.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/setup/5.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/setup/5.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?><multistatus xmlns='DAV:'>
<response>
- <href>$addressbookhome1:/shared/</href>
+ <href>$addressbookpath1:/</href>
<propstat>
<prop>
<invite xmlns='http://calendarserver.org/ns/'>
Modified: CalDAVTester/trunk/Resource/CardDAV/sharing/setup/6.xml
===================================================================
--- CalDAVTester/trunk/Resource/CardDAV/sharing/setup/6.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/Resource/CardDAV/sharing/setup/6.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -4,7 +4,7 @@
<href xmlns='DAV:'>mailto:$email2:</href>
<invite-accepted/>
<hosturl>
- <href xmlns='DAV:'>$addressbookhome1:/shared</href>
+ <href xmlns='DAV:'>$addressbookpath1:</href>
</hosturl>
<in-reply-to>$inviteuid:</in-reply-to>
<summary>The Shared Address Book</summary>
Property changes on: CalDAVTester/trunk/scripts/tests/CardDAV
___________________________________________________________________
Added: svn:mergeinfo
+ /CalDAVTester/branches/release/CalDAVTester-3.0-dev/scripts/tests/CardDAV:7584
/CalDAVTester/branches/release/CalDAVTester-4.3-dev/scripts/tests/CardDAV:10193
/CalDAVTester/branches/users/cdaboo/attendee-comments-2887/scripts/tests/CardDAV:2888-2910
/CalDAVTester/branches/users/cdaboo/better-proxy-3148/scripts/tests/CardDAV:3149-3163
/CalDAVTester/branches/users/cdaboo/component-set-fixes/scripts/tests/CardDAV:8221-8346
/CalDAVTester/branches/users/cdaboo/conditional-4466/scripts/tests/CardDAV:4467-4469
/CalDAVTester/branches/users/cdaboo/implicitauto-2948/scripts/tests/CardDAV:2949-2989
/CalDAVTester/branches/users/cdaboo/location-partial-accept-3574/scripts/tests/CardDAV:3575-3581
/CalDAVTester/branches/users/cdaboo/managed-attachments/scripts/tests/CardDAV:9986-10145
/CalDAVTester/branches/users/cdaboo/normalize-cuaddr-3533/scripts/tests/CardDAV:3534-3558
/CalDAVTester/branches/users/cdaboo/pycalendar/scripts/tests/CardDAV:7160-7206
/CalDAVTester/branches/users/cdaboo/pycard/scripts/tests/CardDAV:7226-7237
/CalDAVTester/branches/users/cdaboo/sharing-5228/scripts/tests/CardDAV:5229-5440
/CalDAVTester/branches/users/gaya/sharedgroupstester-2/scripts/tests/CardDAV:11078-11181
/CalDAVTester/branches/users/gaya/sharedgroupstester-3/scripts/tests/CardDAV:11181-11204
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/aclreports.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/aclreports.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/aclreports.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -34,6 +34,7 @@
<filepath>Resource/CardDAV/vaclreports/10.xml</filepath>
</data>
</request>
+<!--
<request end-delete='yes'>
<method>MKCOL</method>
<ruri>$addressbookhome1:/adbktest2/</ruri>
@@ -58,6 +59,7 @@
<filepath>Resource/CardDAV/mkcol/1.xml</filepath>
</data>
</request>
+-->
</start>
<test-suite name='acl-principal-prop-set REPORT' ignore='no'>
@@ -295,7 +297,7 @@
</verify>
</request>
</test>
- <test name='6' ignore='no'>
+ <test name='6' ignore='yes'>
<description>Valid principal-search report with DAV:prop</description>
<request print-response='no'>
<method>REPORT</method>
@@ -313,7 +315,7 @@
</verify>
</request>
</test>
- <test name='7' ignore='no'>
+ <test name='7' ignore='yes'>
<description>Valid principal-search report without DAV:prop</description>
<request print-response='no'>
<method>REPORT</method>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/add-member.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/add-member.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/add-member.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -26,7 +26,12 @@
<feature>add-member</feature>
</require-feature>
- <start/>
+ <start>
+ <request print-response='no'>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/</ruri>
+ </request>
+ </start>
<test-suite name='DAV:add-member property'>
<test name='1'>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/default-addressbook.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/default-addressbook.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/default-addressbook.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -51,25 +51,7 @@
</test>
</test-suite>
- <test-suite name='Change property'>
- <test name='1'>
- <description>MKCOL with correct request body</description>
- <request end-delete='yes'>
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/adbktest1/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- <arg>
- <name>status</name>
- <value>201</value>
- </arg>
- </verify>
- </request>
- </test>
+ <test-suite name='Change property' ignore='no'>
<test name='2'>
<description>Set invalid property on home</description>
<request print-response='no'>
@@ -123,54 +105,16 @@
<callback>propfindItems</callback>
<arg>
<name>okprops</name>
- <value><![CDATA[{urn:ietf:params:xml:ns:carddav}default-addressbook-URL$<href xmlns="DAV:">$addressbookhome1:/adbktest1/</href>]]></value>
+ <value><![CDATA[{urn:ietf:params:xml:ns:carddav}default-addressbook-URL$<href xmlns="DAV:">$addressbookpath1:/</href>]]></value>
</arg>
</verify>
</request>
</test>
</test-suite>
- <test-suite name='Move delete'>
- <test name='1'>
- <description>MOVE</description>
- <request end-delete='yes'>
- <method>MOVE</method>
- <ruri>$addressbookhome1:/adbktest1/</ruri>
- <header>
- <name>Destination</name>
- <value>$host:$addressbookhome1:/adbktest2/</value>
- </header>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
- </test>
- <test name='2'>
- <description>PROPFIND on home</description>
- <request end-delete='yes'>
- <method>PROPFIND</method>
- <ruri>$addressbookhome1:/</ruri>
- <header>
- <name>Depth</name>
- <value>0</value>
- </header>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/default-addressbook/1.xml</filepath>
- </data>
- <verify>
- <callback>propfindItems</callback>
- <arg>
- <name>okprops</name>
- <value><![CDATA[{urn:ietf:params:xml:ns:carddav}default-addressbook-URL$<href xmlns="DAV:">$addressbookhome1:/adbktest2/</href>]]></value>
- </arg>
- </verify>
- </request>
- </test>
- </test-suite>
-
<test-suite name='No default delete'>
- <test name='1'>
+<!--
+ <test name='1' ignore='yes'>
<description>DELETE</description>
<request end-delete='yes'>
<method>DELETE</method>
@@ -184,6 +128,7 @@
</verify>
</request>
</test>
+-->
<test name='2'>
<description>Set property on home</description>
<request print-response='no'>
@@ -191,7 +136,7 @@
<ruri>$addressbookhome1:/</ruri>
<data>
<content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/default-addressbook/4.xml</filepath>
+ <filepath>Resource/CardDAV/default-addressbook/3.xml</filepath>
</data>
<verify>
<callback>propfindItems</callback>
@@ -206,7 +151,7 @@
<description>DELETE</description>
<request end-delete='yes'>
<method>DELETE</method>
- <ruri>$addressbookhome1:/adbktest2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<verify>
<callback>statusCode</callback>
</verify>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/get.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/get.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/get.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -230,7 +230,7 @@
</test>
</test-suite>
- <test-suite name='GET on home'>
+ <test-suite name='GET on home' ignore='no'>
<require-feature>
<feature>directory listing</feature>
</require-feature>
@@ -260,51 +260,7 @@
</grabheader>
</request>
</test>
- <test name='2'>
- <description>Create a addressbook</description>
- <request>
- <method>DELAY</method>
- <ruri>1</ruri>
- </request>
- <request end-delete="yes">
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/testadbk/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
- </test>
- <test name='3'>
- <description>GET on addressbook home, changed headers</description>
- <request>
- <method>GET</method>
- <ruri>$addressbookhome1:/</ruri>
- <verify>
- <callback>statusCode</callback>
- </verify>
- <verify>
- <callback>header</callback>
- <arg>
- <name>header</name>
- <value>Etag!$etag1:</value>
- <value>Last-Modified!$last-modified1:</value>
- </arg>
- </verify>
- <grabheader>
- <name>Etag</name>
- <variable>$etag2:</variable>
- </grabheader>
- <grabheader>
- <name>Last-Modified</name>
- <variable>$last-modified2:</variable>
- </grabheader>
- </request>
- </test>
- <test name='4'>
+ <test name='4' ignore='no'>
<description>Conditional GET on addressbook home</description>
<request print-response="no">
<method>GET</method>
@@ -329,7 +285,7 @@
<ruri>$addressbookpath1:/</ruri>
<header>
<name>If-Modified-Since</name>
- <value>$last-modified2:</value>
+ <value>$last-modified1:</value>
</header>
<verify>
<callback>statusCode</callback>
@@ -341,14 +297,14 @@
</request>
</test>
<test name='6'>
- <description>Delete a addressbook</description>
+ <description>Delete the addressbook</description>
<request>
<method>DELAY</method>
<ruri>1</ruri>
</request>
<request end-delete="yes">
<method>DELETE</method>
- <ruri>$addressbookhome1:/testadbk/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<verify>
<callback>statusCode</callback>
</verify>
@@ -366,8 +322,8 @@
<callback>header</callback>
<arg>
<name>header</name>
- <value>Etag!$etag2:</value>
- <value>Last-Modified!$last-modified2:</value>
+ <value>Etag!$etag1:</value>
+ <value>Last-Modified!$last-modified1:</value>
</arg>
</verify>
</request>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/limits.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/limits.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/limits.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -75,7 +75,8 @@
</test>
</test-suite>
- <test-suite name='Collection limit' ignore='no'>
+<!--
+ <test-suite name='Collection limit' ignore='yes'>
<test name='1' count='49' ignore='no'>
<description>Create collections to one below the limit</description>
<request end-delete='yes' print-response='no'>
@@ -113,6 +114,7 @@
</request>
</test>
</test-suite>
+-->
<end/>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/mkcol.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/mkcol.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/mkcol.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -26,8 +26,8 @@
<start/>
<test-suite name='OPTIONS header' ignore='no'>
- <test name='1'>
- <description>Look for options header tag</description>
+ <test name='1' ignore='yes'>
+ <description>OPTIONS DAV: header does not contain extended-mkcol</description>
<request print-response="no">
<method>OPTIONS</method>
<ruri>$addressbookhome1:/</ruri>
@@ -35,122 +35,56 @@
<callback>header</callback>
<arg>
<name>header</name>
- <value>*DAV$.*extended-mkcol.*</value>
+ <value>*DAV!.*extended-mkcol.*</value>
</arg>
</verify>
</request>
</test>
- </test-suite>
-
- <test-suite name='MKCOL with body'>
- <test name='1'>
- <description>MKCOL with correct request body</description>
- <request end-delete='yes'>
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/adbktest1/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/mkcol/1.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- <arg>
- <name>status</name>
- <value>201</value>
- </arg>
- </verify>
- </request>
- </test>
<test name='2'>
- <description>MKCOL with correct request body on existing resource</description>
- <request>
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/adbktest1/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/mkcol/1.xml</filepath>
- </data>
+ <description>OPTIONS Allow: header does not contain MKCOL</description>
+ <request print-response="no">
+ <method>OPTIONS</method>
+ <ruri>$addressbookhome1:/</ruri>
<verify>
- <callback>prepostcondition</callback>
+ <callback>header</callback>
<arg>
- <name>error</name>
- <value>{DAV:}resource-must-be-null</value>
+ <name>header</name>
+ <value>*Allow!.*MKCOL.*</value>
</arg>
</verify>
</request>
</test>
- <test name='3'>
- <description>MKCOL with incorrect request body</description>
- <request end-delete='yes' print-response='no'>
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/adbktest2/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/mkcol/2.xml</filepath>
- </data>
+ <test name='3'>
+ <description>OPTIONS Allow: header does not contain MKCALENDAR</description>
+ <request print-response="no">
+ <method>OPTIONS</method>
+ <ruri>$addressbookhome1:/</ruri>
<verify>
- <callback>propfindItems</callback>
+ <callback>header</callback>
<arg>
- <name>status</name>
- <value>403</value>
+ <name>header</name>
+ <value>*Allow!.*MKCALENDAR.*</value>
</arg>
- <arg>
- <name>root-element</name>
- <value>{DAV:}mkcol-response</value>
- </arg>
- <arg>
- <name>badprops</name>
- <value>{DAV:}resourcetype</value>
- <value>{DAV:}getetag</value>
- <value>{DAV:}displayname</value>
- <value>{urn:ietf:params:xml:ns:carddav}addressbook-description</value>
- </arg>
</verify>
</request>
- <request print-response='no'>
- <method>GET</method>
- <ruri>$addressbookhome1:/adbktest2/</ruri>
- <verify>
- <callback>statusCode</callback>
- <arg>
- <name>status</name>
- <value>404</value>
- </arg>
- </verify>
- </request>
</test>
- <test name='4'>
- <description>MKCOL with incorrect request body on existing resource</description>
- <request>
+ </test-suite>
+
+ <test-suite name='MKCOL with body'>
+ <test name='1'>
+ <description>MKCOL with correct request body</description>
+ <request end-delete='yes'>
<method>MKCOL</method>
<ruri>$addressbookhome1:/adbktest1/</ruri>
<data>
<content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/mkcol/2.xml</filepath>
+ <filepath>Resource/CardDAV/mkcol/1.xml</filepath>
</data>
<verify>
- <callback>prepostcondition</callback>
- <arg>
- <name>error</name>
- <value>{DAV:}resource-must-be-null</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='5'>
- <description>MKCOL with incorrect resourcetype on new resource</description>
- <request>
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/adbktest3/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/mkcol/3.xml</filepath>
- </data>
- <verify>
<callback>statusCode</callback>
<arg>
<name>status</name>
- <value>400</value>
+ <value>403</value>
</arg>
</verify>
</request>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/nonascii.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/nonascii.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/nonascii.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -27,7 +27,8 @@
<start/>
- <test-suite name='non-ascii' ignore="no">
+<!--
+ <test-suite name='non-ascii' ignore="yes">
<test name='1' ignore="no">
<description>MKCOL with high-ascii</description>
<request print-response="no">
@@ -42,7 +43,7 @@
</verify>
</request>
</test>
- <test name='2' ignore="no">
+ <test name='2' ignore="yes">
<description>MKCOL with non-ascii - duplicate</description>
<request print-response="no">
<method>MKCOL</method>
@@ -81,8 +82,10 @@
</request>
</test>
</test-suite>
+ -->
- <test-suite name='double byte' ignore="no">
+<!--
+ <test-suite name='double byte' ignore="yes">
<test name='1' ignore="no">
<description>MKCOL with double byte</description>
<request end-delete="no">
@@ -136,6 +139,7 @@
</request>
</test>
</test-suite>
+ -->
<!--
<test-suite name='Non-ascii resource URI' ignore="no">
<test name='1' ignore="no">
Deleted: CalDAVTester/trunk/scripts/tests/CardDAV/resourceid.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/resourceid.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/resourceid.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,119 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-
-<!DOCTYPE caldavtest SYSTEM "caldavtest.dtd">
-
-<!--
- Copyright (c) 2006-2013 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.
- -->
-
-<caldavtest>
- <require-feature>
- <feature>caldav</feature>
- <feature>resource-id</feature>
- </require-feature>
-
- <start/>
-
- <test-suite name='Address book with move'>
- <test name='1'>
- <description>Simple MKCOL</description>
- <request end-delete='yes'>
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/adbktest1/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- <arg>
- <name>status</name>
- <value>201</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='2' ignore='no'>
- <description>Check property</description>
- <request print-response='no'>
- <method>PROPFIND</method>
- <ruri>$addressbookhome1:/adbktest1/</ruri>
- <header>
- <name>Depth</name>
- <value>0</value>
- </header>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/PROPFIND/resourceid.xml</filepath>
- </data>
- <verify>
- <callback>propfindItems</callback>
- <arg>
- <name>okprops</name>
- <value>{DAV:}resource-id</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='3'>
- <description>MOVE to new address book</description>
- <request>
- <method>MOVE</method>
- <ruri>$addressbookhome1:/adbktest1/</ruri>
- <header>
- <name>Destination</name>
- <value>$host:$addressbookhome1:/adbktest-moved/</value>
- </header>
- <verify>
- <callback>statusCode</callback>
- <arg>
- <name>status</name>
- <value>2xx</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='4' ignore='no'>
- <description>Check property</description>
- <request print-response='no'>
- <method>PROPFIND</method>
- <ruri>$addressbookhome1:/adbktest-moved/</ruri>
- <header>
- <name>Depth</name>
- <value>0</value>
- </header>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/PROPFIND/resourceid.xml</filepath>
- </data>
- <verify>
- <callback>propfindItems</callback>
- <arg>
- <name>okprops</name>
- <value>{DAV:}resource-id</value>
- </arg>
- </verify>
- </request>
- </test>
- </test-suite>
-
- <end>
- <request>
- <method>DELETE</method>
- <ruri>$addressbookhome1:/adbktest-moved/</ruri>
- </request>
- </end>
-
-</caldavtest>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/sharing-addressbooks.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/sharing-addressbooks.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/sharing-addressbooks.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -28,6 +28,10 @@
<start>
<request user="$userid1:" pswd="$pswd1:">
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/</ruri>
+ </request>
+ <request user="$userid1:" pswd="$pswd1:">
<method>DELETEALL</method>
<ruri>$notificationpath1:/</ruri>
</request>
@@ -35,25 +39,14 @@
<method>DELETEALL</method>
<ruri>$notificationpath2:/</ruri>
</request>
- <request end-delete="yes">
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/shared/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
</start>
- <test-suite name='Read-write addressbooks'>
+ <test-suite name='Read-write address book' ignore='no'>
<test name='1' ignore='no'>
<description>POST invitation</description>
- <request print-response='no'>
+ <request print-response="no">
<method>POST</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<data>
<content-type>text/xml; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/addressbooks/read-write/1.xml</filepath>
@@ -63,13 +56,13 @@
</verify>
</request>
</test>
- <test name='2'>
+ <test name='2' ignore='no'>
<description>Check Sharee notification collection</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>WAITCOUNT 1</method>
<ruri>$notificationpath2:/</ruri>
</request>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>GETNEW</method>
<ruri>$notificationpath2:/</ruri>
<verify>
@@ -89,20 +82,13 @@
<variable>$inviteuid:</variable>
</grabelement>
</request>
- <request user="$userid2:" pswd="$pswd2:">
- <method>DELETE</method>
- <ruri>$notificationpath2:/$inviteuid:</ruri>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
</test>
- <test name='3'>
+ <test name='3' ignore='no'>
<description>Sharee replies ACCEPTED</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>POST</method>
<ruri>$addressbookhome2:/</ruri>
- <data substitutions='yes'>
+ <data substitutions="yes">
<content-type>application/xml; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/addressbooks/read-write/3.xml</filepath>
</data>
@@ -115,9 +101,9 @@
</grabelement>
</request>
</test>
- <test name='4'>
+ <test name='4' ignore='no'>
<description>Shared address book exists</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>PROPFIND</method>
<ruri>$sharedaddressbook:/</ruri>
<header>
@@ -133,6 +119,8 @@
<arg>
<name>exists</name>
<value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:carddav}addressbook</value>
<value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value>
<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
@@ -147,9 +135,9 @@
</verify>
</request>
</test>
- <test name='4a'>
+ <test name='5' ignore='no'>
<description>Shared address book exists Depth:1</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>PROPFIND</method>
<ruri>$addressbookhome2:/</ruri>
<header>
@@ -184,10 +172,9 @@
</arg>
</verify>
</request>
- </test>
- <test name='5'>
+ </test><test name='6' ignore='no'>
<description>Sharee creates vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>PUT</method>
<ruri>$sharedaddressbook:/1.vcf</ruri>
<data>
@@ -199,11 +186,11 @@
</verify>
</request>
</test>
- <test name='6'>
+ <test name='7' ignore='no'>
<description>Sharer sees vcard</description>
- <request print-response='no'>
+ <request print-response="no">
<method>GET</method>
- <ruri>$addressbookhome1:/shared/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<verify>
<callback>addressDataMatch</callback>
<arg>
@@ -213,11 +200,11 @@
</verify>
</request>
</test>
- <test name='7'>
+ <test name='8' ignore='no'>
<description>Sharer changes vcard</description>
- <request print-response='no'>
+ <request print-response="no">
<method>PUT</method>
- <ruri>$addressbookhome1:/shared/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/addressbooks/read-write/6.vcf</filepath>
@@ -227,9 +214,9 @@
</verify>
</request>
</test>
- <test name='8'>
+ <test name='9' ignore='no'>
<description>Sharee sees changed vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>GET</method>
<ruri>$sharedaddressbook:/1.vcf</ruri>
<verify>
@@ -241,11 +228,11 @@
</verify>
</request>
</test>
- <test name='9'>
+ <test name='10' ignore='no'>
<description>Sharer creates vcard</description>
- <request print-response='no'>
+ <request print-response="no">
<method>PUT</method>
- <ruri>$addressbookhome1:/shared/2.vcf</ruri>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/addressbooks/read-write/7.vcf</filepath>
@@ -255,9 +242,9 @@
</verify>
</request>
</test>
- <test name='10'>
+ <test name='11' ignore='no'>
<description>Sharee sees new vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>GET</method>
<ruri>$sharedaddressbook:/2.vcf</ruri>
<verify>
@@ -269,9 +256,9 @@
</verify>
</request>
</test>
- <test name='11'>
+ <test name='12' ignore='no'>
<description>Sharee changes vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>PUT</method>
<ruri>$sharedaddressbook:/2.vcf</ruri>
<data>
@@ -283,11 +270,11 @@
</verify>
</request>
</test>
- <test name='12'>
+ <test name='13' ignore='no'>
<description>Sharer sees changed event</description>
- <request print-response='no'>
+ <request print-response="no">
<method>GET</method>
- <ruri>$addressbookhome1:/shared/2.vcf</ruri>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
<verify>
<callback>addressDataMatch</callback>
<arg>
@@ -297,15 +284,47 @@
</verify>
</request>
</test>
+ <test name='14' ignore='no'>
+ <description>Sharee sees group with shared address book members</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
+ <method>GET</method>
+ <ruri>$sharedaddressbook:/addressbook.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/addressbooks/read-write/9.vcf</value>
+ </arg>
+ <arg>
+ <name>filter</name>
+ <value>UID</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='15' ignore='no'>
+ <description>Sharee cannot delete special group</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
+ <method>DELETE</method>
+ <ruri>$sharedaddressbook:/addressbook.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>403</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
</test-suite>
- <test-suite name='Default address book cannot be shared address book' ignore='no'>
+ <test-suite name='Shared address book cannot be default address' ignore='no'>
<require-feature>
<feature>default-addressbook</feature>
</require-feature>
<test name='1'>
<description>Set property on home</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>PROPPATCH</method>
<ruri>$addressbookhome2:/</ruri>
<data>
@@ -348,9 +367,9 @@
<test-suite name='Change to read-only address book' ignore='no'>
<test name='1' ignore='no'>
<description>POST invitation</description>
- <request print-response='no'>
+ <request print-response="no">
<method>POST</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<data>
<content-type>text/xml; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/addressbooks/read-only/1.xml</filepath>
@@ -362,11 +381,11 @@
</test>
<test name='2'>
<description>Check Sharee notification collection</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>WAITCOUNT 1</method>
<ruri>$notificationpath2:/</ruri>
</request>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>GETNEW</method>
<ruri>$notificationpath2:/</ruri>
<verify>
@@ -396,7 +415,7 @@
</test>
<test name='3'>
<description>Sharee replies ACCEPTED</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>POST</method>
<ruri>$addressbookhome2:/</ruri>
<data substitutions='yes'>
@@ -414,7 +433,7 @@
</test>
<test name='4'>
<description>Shared address book exists</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>PROPFIND</method>
<ruri>$sharedaddressbook:/</ruri>
<header>
@@ -430,6 +449,8 @@
<arg>
<name>exists</name>
<value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:carddav}addressbook</value>
<value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value>
<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
</arg>
@@ -446,7 +467,7 @@
</test>
<test name='5'>
<description>Create vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>PUT</method>
<ruri>$sharedaddressbook:/3.vcf</ruri>
<data>
@@ -464,9 +485,9 @@
</test>
<test name='6'>
<description>Sharer creates vcard</description>
- <request print-response='no'>
+ <request print-response="no">
<method>PUT</method>
- <ruri>$addressbookhome1:/shared/4.vcf</ruri>
+ <ruri>$addressbookpath1:/4.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/addressbooks/read-only/6.vcf</filepath>
@@ -478,7 +499,7 @@
</test>
<test name='7'>
<description>Sharee sees new vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>GET</method>
<ruri>$sharedaddressbook:/4.vcf</ruri>
<verify>
@@ -492,7 +513,7 @@
</test>
<test name='8'>
<description>Sharee cannot change vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <request user="$userid2:" pswd="$pswd2:" print-response="no">
<method>PUT</method>
<ruri>$sharedaddressbook:/4.vcf</ruri>
<data>
@@ -509,293 +530,13 @@
</request>
</test>
</test-suite>
- <test-suite name='Share main address book' ignore='no'>
- <test name='1' ignore='no'>
- <description>POST invitation</description>
- <request print-response='no'>
- <method>POST</method>
- <ruri>$addressbookpath1:/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/sharing/addressbooks/main/1.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
- </test>
- <test name='2' ignore='no'>
- <description>Check Sharee notification collection</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>WAITCOUNT 1</method>
- <ruri>$notificationpath2:/</ruri>
- </request>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>GETNEW</method>
- <ruri>$notificationpath2:/</ruri>
- <verify>
- <callback>xmlDataMatch</callback>
- <arg>
- <name>filepath</name>
- <value>Resource/CardDAV/sharing/addressbooks/main/2.xml</value>
- </arg>
- <arg>
- <name>filter</name>
- <value>{http://calendarserver.org/ns/}dtstamp</value>
- <value>{http://calendarserver.org/ns/}uid</value>
- </arg>
- </verify>
- <grabelement>
- <name>{http://calendarserver.org/ns/}invite-notification/{http://calendarserver.org/ns/}uid</name>
- <variable>$inviteuid:</variable>
- </grabelement>
- </request>
- </test>
- <test name='3' ignore='no'>
- <description>Sharee replies ACCEPTED</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>POST</method>
- <ruri>$addressbookhome2:/</ruri>
- <data substitutions='yes'>
- <content-type>application/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/sharing/addressbooks/main/3.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- <grabelement>
- <name>{DAV:}href</name>
- <variable>$sharedaddressbook:</variable>
- </grabelement>
- </request>
- </test>
- <test name='4' ignore='no'>
- <description>Shared address book exists</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>PROPFIND</method>
- <ruri>$sharedaddressbook:/</ruri>
- <header>
- <name>Depth</name>
- <value>0</value>
- </header>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/sharing/addressbooks/main/4.xml</filepath>
- </data>
- <verify>
- <callback>xmlElementMatch</callback>
- <arg>
- <name>exists</name>
- <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
- <value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value>
- <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
- <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
- <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
- <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
- </arg>
- <arg>
- <name>notexists</name>
- <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
- <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='5' ignore='no'>
- <description>Sharee creates vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>PUT</method>
- <ruri>$sharedaddressbook:/1.vcf</ruri>
- <data>
- <content-type>text/vcard; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/sharing/addressbooks/main/5.vcf</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
- </test>
- <test name='6' ignore='no'>
- <description>Sharer sees vcard</description>
- <request print-response='no'>
- <method>GET</method>
- <ruri>$addressbookpath1:/1.vcf</ruri>
- <verify>
- <callback>addressDataMatch</callback>
- <arg>
- <name>filepath</name>
- <value>Resource/CardDAV/sharing/addressbooks/main/5.vcf</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='7' ignore='no'>
- <description>Sharer changes vcard</description>
- <request print-response='no'>
- <method>PUT</method>
- <ruri>$addressbookpath1:/1.vcf</ruri>
- <data>
- <content-type>text/vcard; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/sharing/addressbooks/main/6.vcf</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
- </test>
- <test name='8' ignore='no'>
- <description>Sharee sees changed vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>GET</method>
- <ruri>$sharedaddressbook:/1.vcf</ruri>
- <verify>
- <callback>addressDataMatch</callback>
- <arg>
- <name>filepath</name>
- <value>Resource/CardDAV/sharing/addressbooks/main/6.vcf</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='9' ignore='no'>
- <description>Sharer creates vcard</description>
- <request print-response='no'>
- <method>PUT</method>
- <ruri>$addressbookpath1:/2.vcf</ruri>
- <data>
- <content-type>text/vcard; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/sharing/addressbooks/main/7.vcf</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
- </test>
- <test name='10' ignore='no'>
- <description>Sharee sees new vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>GET</method>
- <ruri>$sharedaddressbook:/2.vcf</ruri>
- <verify>
- <callback>addressDataMatch</callback>
- <arg>
- <name>filepath</name>
- <value>Resource/CardDAV/sharing/addressbooks/main/7.vcf</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='11' ignore='no'>
- <description>Sharee changes vcard</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>PUT</method>
- <ruri>$sharedaddressbook:/2.vcf</ruri>
- <data>
- <content-type>text/vcard; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/sharing/addressbooks/main/8.vcf</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
- </test>
- <test name='12' ignore='no'>
- <description>Sharer sees changed event</description>
- <request print-response='no'>
- <method>GET</method>
- <ruri>$addressbookpath1:/2.vcf</ruri>
- <verify>
- <callback>addressDataMatch</callback>
- <arg>
- <name>filepath</name>
- <value>Resource/CardDAV/sharing/addressbooks/main/8.vcf</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='13' ignore='no'>
- <description>Unshare main address book</description>
- <request print-response='no'>
- <method>POST</method>
- <ruri>$addressbookpath1:/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/sharing/addressbooks/main/9.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- <arg>
- <name>status</name>
- <value>200</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='14' ignore='no'>
- <description>Check Sharee notification collection and delete invite-deleted</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>WAITCOUNT 1</method>
- <ruri>$notificationpath2:/</ruri>
- </request>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>GETNEW</method>
- <ruri>$notificationpath2:/</ruri>
- <verify>
- <callback>xmlDataMatch</callback>
- <arg>
- <name>filepath</name>
- <value>Resource/CardDAV/sharing/addressbooks/main/10.xml</value>
- </arg>
- <arg>
- <name>filter</name>
- <value>{http://calendarserver.org/ns/}dtstamp</value>
- <value>{http://calendarserver.org/ns/}uid</value>
- </arg>
- </verify>
- </request>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>DELETE</method>
- <ruri>$</ruri>
- </request>
- </test>
- <test name='15' ignore='no'>
- <description>No more shared addressbook</description>
- <request user="$userid2:" pswd="$pswd2:" print-response='no'>
- <method>PROPFIND</method>
- <ruri>$shareeaddressbook:/</ruri>
- <header>
- <name>Depth</name>
- <value>0</value>
- </header>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/PROPFIND/resourcetype.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- <arg>
- <name>status</name>
- <value>404</value>
- </arg>
- </verify>
- </request>
- </test>
- <test name='16' ignore='no'>
- <description>Clean up main addressbook</description>
- <request>
- <method>DELETEALL</method>
- <ruri>$addressbookpath1:/</ruri>
- </request>
- </test>
- </test-suite>
-
+
<end>
<request user="$useradmin:" pswd="$pswdadmin:">
<method>DELETEALL</method>
+ <ruri>$addressbookpath1:/</ruri>
<ruri>$notificationpath1:/</ruri>
<ruri>$notificationpath2:/</ruri>
- <ruri>$notificationpath3:/</ruri>
- <ruri>$notificationpath4:/</ruri>
</request>
</end>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/sharing-feature.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/sharing-feature.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/sharing-feature.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -26,7 +26,16 @@
<feature>shared-addressbooks</feature>
</require-feature>
- <start/>
+ <start>
+ <request user="$userid1:" pswd="$pswd1:">
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/</ruri>
+ </request>
+ <request user="$userid1:" pswd="$pswd1:">
+ <method>DELETEALL</method>
+ <ruri>$notificationpath1:/</ruri>
+ </request>
+ </start>
<test-suite name='OPTIONS header' ignore='no'>
<test name='1'>
@@ -84,16 +93,12 @@
</test>
</test-suite>
- <test-suite name='Upgrade addressbook to shared'>
+ <test-suite name='Upgrade addressbook to shared' ignore='no'>
<test name='1'>
- <description>Create new addressbook</description>
- <request end-delete="yes">
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/shared1/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
+ <description>clear addressbook</description>
+ <request>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/</ruri>
<verify>
<callback>statusCode</callback>
</verify>
@@ -103,7 +108,7 @@
<description>Not shared</description>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
@@ -125,7 +130,7 @@
<description>Upgrade via PROPPATCH</description>
<request print-response='no'>
<method>PROPPATCH</method>
- <ruri>$addressbookhome1:/shared1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<data>
<content-type>text/xml; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/feature/upgrade_collection/1.xml</filepath>
Copied: CalDAVTester/trunk/scripts/tests/CardDAV/sharing-groups.xml (from rev 11204, CalDAVTester/branches/users/gaya/sharedgroupstester-3/scripts/tests/CardDAV/sharing-groups.xml)
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/sharing-groups.xml (rev 0)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/sharing-groups.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,668 @@
+<?xml version="1.0" standalone="no"?>
+
+<!DOCTYPE caldavtest SYSTEM "caldavtest.dtd">
+
+<!--
+ Copyright (c) 2006-2013 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.
+ -->
+
+<caldavtest>
+ <description>Test sharing address books</description>
+
+ <require-feature>
+ <feature>carddav</feature>
+ <feature>shared-addressbooks</feature>
+ </require-feature>
+
+ <start>
+ <request user="$userid1:" pswd="$pswd1:">
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/</ruri>
+ </request>
+ <request user="$userid1:" pswd="$pswd1:">
+ <method>DELETEALL</method>
+ <ruri>$notificationpath1:/</ruri>
+ </request>
+ <request user="$userid2:" pswd="$pswd2:">
+ <method>DELETEALL</method>
+ <ruri>$notificationpath2:/</ruri>
+ </request>
+ </start>
+
+
+ <test-suite name='read-write' ignore='no'>
+ <test name='1' ignore='no'>
+ <description>Sharer creates 2 persons and a group</description>
+ <request print-response='no'>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/1.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request print-response='no'>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/2.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request print-response='no'>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/3.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='2' ignore='no'>
+ <description>POST invitation to user vCard</description>
+ <request print-response='no'>
+ <method>POST</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>403</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3' ignore='no'>
+ <description>POST invitation to group vCard</description>
+ <request print-response='no'>
+ <method>POST</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ <value>200</value>
+ </verify>
+ </request>
+ </test>
+ <test name='3a' ignore='yes'>
+ <description>Sharer sees group as shared-owner</description>
+ <request user="$userid1:" pswd="$pswd1:" print-response='no'>
+ <method>PROPFIND</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/7.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared-owner</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4' ignore='no'>
+ <description>Check Sharee notification collection</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>WAITCOUNT 1</method>
+ <ruri>$notificationpath2:/</ruri>
+ </request>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>GETNEW</method>
+ <ruri>$notificationpath2:/</ruri>
+ <verify>
+ <callback>xmlDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/5.xml</value>
+ </arg>
+ <arg>
+ <name>filter</name>
+ <value>{http://calendarserver.org/ns/}dtstamp</value>
+ <value>{http://calendarserver.org/ns/}uid</value>
+ </arg>
+ </verify>
+ <grabelement>
+ <name>{http://calendarserver.org/ns/}invite-notification/{http://calendarserver.org/ns/}uid</name>
+ <variable>$inviteuid:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='5' ignore='no'>
+ <description>Sharee replies ACCEPTED</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>POST</method>
+ <ruri>$addressbookhome2:/</ruri>
+ <data substitutions='yes'>
+ <content-type>application/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/6.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ <grabelement>
+ <name>{DAV:}href</name>
+ <variable>$sharedgroup:</variable>
+ </grabelement>
+ </request>
+ </test>
+ <test name='6' ignore='no'>
+ <description>Sharee sees shared address book</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>PROPFIND</method>
+ <ruri>$addressbookhome2:/$userid1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/7.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:carddav}addressbook</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='6a' ignore='no'>
+ <description>Sharee sees shared address book and shared vCards</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>PROPFIND</method>
+ <ruri>$addressbookhome2:/$userid1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/7.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>exists</name>
+ <value>$verify-property-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:carddav}addressbook</value>
+ <value>$verify-property-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='7'>
+ <description>Shared address book exists Depth:1</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>PROPFIND</method>
+ <ruri>$addressbookhome2:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>1</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/addressbooks/read-write/4.xml</filepath>
+ </data>
+ <verify>
+ <callback>xmlElementMatch</callback>
+ <arg>
+ <name>parent</name>
+ <value>$multistatus-response-prefix:[^{DAV:}href=$addressbookhome2:/$userid1:/]</value>
+ </arg>
+ <arg>
+ <name>exists</name>
+ <value>$verify-response-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+ <value>$verify-response-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+ <value>$verify-response-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:carddav}addressbook</value>
+ <value>$verify-response-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+ <value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+ </arg>
+ <arg>
+ <name>notexists</name>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+ <value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='8' ignore='no'>
+ <description>Sharee sees shared group vcard</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>GET</method>
+ <ruri>$sharedgroup:</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/3.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='9' ignore='no'>
+ <description>Sharee cannot delete shared group vcard</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>DELETE</method>
+ <ruri>$sharedgroup:</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>403</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='10' ignore='no'>
+ <description>Sharee creates group vcard with unknown member UID</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>PUT</method>
+ <ruri>$addressbookhome2:/$userid1:/4.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/8.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>403</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='11' ignore='no'>
+ <description>Sharee creates group vcard with member UID in ab but not in group</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>PUT</method>
+ <ruri>$addressbookhome2:/$userid1:/4.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/9.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>403</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='12' ignore='no'>
+ <description>Sharee creates vcard</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>PUT</method>
+ <ruri>$addressbookhome2:/$userid1:/4.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/10.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='13' ignore='no'>
+ <description>Sharer sees vcard as group member</description>
+ <request print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookpath1:/4.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/10.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ <request print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/11.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='14' ignore='no'>
+ <description>Sharer changes vcard</description>
+ <request print-response='no'>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/4.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/12.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='15' ignore='no'>
+ <description>Sharee sees changed vcard</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookhome2:/$userid1:/4.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/12.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='16' ignore='no'>
+ <description>Sharer creates subgroup that contains 2 already present members</description>
+ <request print-response='no'>
+ <method>PUT</method>
+ <ruri>$addressbookpath1:/5.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/13.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='17' ignore='no'>
+ <description>Sharee sees new vcards</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookhome2:/$userid1:/5.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/13.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookhome2:/$userid1:/2.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/2.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookhome2:/$userid1:/1.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/1.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='18' ignore='no'>
+ <description>Sharee removes vCard from subgroup</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>PUT</method>
+ <ruri>$addressbookhome2:/$userid1:/5.vcf</ruri>
+ <data>
+ <content-type>text/vcard; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/14.vcf</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='19' ignore='no'>
+ <description>Sharee cannot access removed sub group member</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookhome2:/$userid1:/1.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>404</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='20' ignore='no'>
+ <description>Sharer sees subgroup changes and removed subgroup member</description>
+ <request print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookpath1:/5.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/14.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ <request print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/1.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='21' ignore='no'>
+ <description>Sharee deletes vCard in subgroup</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>DELETE</method>
+ <ruri>$addressbookhome2:/$userid1:/2.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ </test>
+ <test name='22' ignore='no'>
+ <description>Sharer sees subgroup changes and sharee-deleted subgroup member</description>
+ <request print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookpath1:/5.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/15.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ <request print-response='no'>
+ <method>GET</method>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
+ <verify>
+ <callback>addressDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/2.vcf</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='23' ignore='no'>
+ <description>Sharer deletes shared group</description>
+ <request print-response='no'>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>204</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='23a' ignore='yes'>
+ <description>Unshare main address book</description>
+ <request print-response="no">
+ <method>POST</method>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/CardDAV/sharing/groups/read-write/15a.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>200</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='24' ignore='no'>
+ <description>Check Sharee notification collection and delete invite-deleted</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>WAITCOUNT 1</method>
+ <ruri>$notificationpath2:/</ruri>
+ </request>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>GETNEW</method>
+ <ruri>$notificationpath2:/</ruri>
+ <verify>
+ <callback>xmlDataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/CardDAV/sharing/groups/read-write/16.xml</value>
+ </arg>
+ <arg>
+ <name>filter</name>
+ <value>{http://calendarserver.org/ns/}dtstamp</value>
+ <value>{http://calendarserver.org/ns/}uid</value>
+ </arg>
+ </verify>
+ </request>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>DELETE</method>
+ <ruri>$</ruri>
+ </request>
+ </test>
+ <test name='25' ignore='no'>
+ <description>No more shared addressbook</description>
+ <request user="$userid2:" pswd="$pswd2:" print-response='no'>
+ <method>PROPFIND</method>
+ <ruri>$addressbookhome2:/$userid1:/</ruri>
+ <header>
+ <name>Depth</name>
+ <value>0</value>
+ </header>
+ <data>
+ <content-type>text/xml; charset=utf-8</content-type>
+ <filepath>Resource/Common/PROPFIND/resourcetype.xml</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ <arg>
+ <name>status</name>
+ <value>404</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='26' ignore='no'>
+ <description>Clean up main addressbook</description>
+ <request>
+ <method>DELETEALL</method>
+ <ruri>$addressbookpath1:/</ruri>
+ </request>
+ </test>
+ </test-suite>
+
+ <end>
+ <request user="$useradmin:" pswd="$pswdadmin:">
+ <method>DELETEALL</method>
+ <ruri>$addressbookpath1:/</ruri>
+ <ruri>$notificationpath1:/</ruri>
+ <ruri>$notificationpath2:/</ruri>
+ <ruri>$notificationpath3:/</ruri>
+ <ruri>$notificationpath4:/</ruri>
+ </request>
+ </end>
+
+</caldavtest>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/sharing-peruser-properties.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/sharing-peruser-properties.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/sharing-peruser-properties.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -28,6 +28,10 @@
<start>
<request user="$userid1:" pswd="$pswd1:">
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/</ruri>
+ </request>
+ <request user="$userid1:" pswd="$pswd1:">
<method>DELETEALL</method>
<ruri>$notificationpath1:/</ruri>
</request>
@@ -35,25 +39,14 @@
<method>DELETEALL</method>
<ruri>$notificationpath2:/</ruri>
</request>
- <request end-delete="yes">
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/shared/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
</start>
- <test-suite name='Set up share'>
+ <test-suite name='Set up share' ignore='no'>
<test name='1' ignore='no'>
<description>POST invitation</description>
<request print-response='no'>
<method>POST</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<data>
<content-type>text/xml; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/setup/1.xml</filepath>
@@ -120,7 +113,7 @@
<description>Check accept status</description>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
@@ -171,7 +164,7 @@
<description>PROPPATCH of displayname</description>
<request print-response='no'>
<method>PROPPATCH</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<data>
<content-type>text/xml; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/peruser-properties/nonglobal/1.xml</filepath>
@@ -186,7 +179,7 @@
</request>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
@@ -220,8 +213,8 @@
<verify>
<callback>propfindItems</callback>
<arg>
- <name>okprops</name>
- <value>{DAV:}displayname$The Shared Address Book</value>
+ <name>badprops</name>
+ <value>{DAV:}displayname</value>
</arg>
</verify>
</request>
@@ -267,7 +260,7 @@
<description>PROPFIND of shared displayname</description>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
@@ -292,7 +285,7 @@
<description>PROPPATCH of addressbook-description</description>
<request print-response='no'>
<method>PROPPATCH</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<data>
<content-type>text/xml; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/peruser-properties/shadowable/1.xml</filepath>
@@ -307,7 +300,7 @@
</request>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
@@ -388,7 +381,7 @@
<description>PROPFIND of shared addressbook-description</description>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/sharing-replies.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/sharing-replies.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/sharing-replies.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -28,6 +28,10 @@
<start>
<request user="$userid1:" pswd="$pswd1:">
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/</ruri>
+ </request>
+ <request user="$userid1:" pswd="$pswd1:">
<method>DELETEALL</method>
<ruri>$notificationpath1:/</ruri>
</request>
@@ -35,25 +39,14 @@
<method>DELETEALL</method>
<ruri>$notificationpath2:/</ruri>
</request>
- <request end-delete="yes">
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/shared/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
</start>
- <test-suite name='Send first reply'>
+ <test-suite name='Send first reply' ignore='no'>
<test name='1' ignore='no'>
<description>POST invitation</description>
<request print-response='no'>
<method>POST</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<data>
<content-type>text/xml; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/replies/accept/1.xml</filepath>
@@ -120,7 +113,7 @@
<description>Check accept status</description>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
@@ -191,7 +184,7 @@
<description>Check sharer addressbook displyname</description>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
@@ -211,7 +204,7 @@
</test>
</test-suite>
- <test-suite name='Update reply'>
+ <test-suite name='Update reply' ignore='no'>
<test name='1'>
<description>Sharee replies DECLINED</description>
<request user="$userid2:" pswd="$pswd2:" print-response='no'>
@@ -230,7 +223,7 @@
<description>Check declined status</description>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/sharing-unshare.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/sharing-unshare.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/sharing-unshare.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -28,6 +28,10 @@
<start>
<request user="$userid1:" pswd="$pswd1:">
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/</ruri>
+ </request>
+ <request user="$userid1:" pswd="$pswd1:">
<method>DELETEALL</method>
<ruri>$notificationpath1:/</ruri>
</request>
@@ -35,25 +39,14 @@
<method>DELETEALL</method>
<ruri>$notificationpath2:/</ruri>
</request>
- <request end-delete="yes">
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/shared/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
- <verify>
- <callback>statusCode</callback>
- </verify>
- </request>
</start>
- <test-suite name='Set up share'>
+ <test-suite name='Set up share' ignore='no'>
<test name='1' ignore='no'>
<description>POST invitation</description>
<request print-response='no'>
<method>POST</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<data>
<content-type>text/xml; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/setup/1.xml</filepath>
@@ -120,7 +113,7 @@
<description>Check accept status</description>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
@@ -166,12 +159,12 @@
</test>
</test-suite>
- <test-suite name='Delete'>
+ <test-suite name='Delete' ignore='no'>
<test name='1'>
<description>Sharer adds event</description>
<request print-response='no'>
<method>PUT</method>
- <ruri>$addressbookhome1:/shared/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/sharing/unshare/shareedelete/1.vcf</filepath>
@@ -221,7 +214,7 @@
<description>Sharer still has addressbook data</description>
<request print-response='no'>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/shared/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
Modified: CalDAVTester/trunk/scripts/tests/CardDAV/sync-report.xml
===================================================================
--- CalDAVTester/trunk/scripts/tests/CardDAV/sync-report.xml 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalDAVTester/trunk/scripts/tests/CardDAV/sync-report.xml 2013-05-16 20:35:53 UTC (rev 11205)
@@ -25,17 +25,13 @@
</require-feature>
<start>
- <request end-delete="yes">
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
+ <request print-response='no'>
+ <method>DELETE</method>
+ <ruri>$addressbookpath1:/</ruri>
</request>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
@@ -43,36 +39,12 @@
</request>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/2.vcf</ruri>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/2.vcf</filepath>
</data>
</request>
- <request end-delete="yes">
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
- </request>
- <request>
- <method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/1.vcf</ruri>
- <data>
- <content-type>text/vcard; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
- </data>
- </request>
- <request>
- <method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/2.vcf</ruri>
- <data>
- <content-type>text/vcard; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/vreports/put/2.vcf</filepath>
- </data>
- </request>
</start>
<test-suite name='support-report-set' ignore='no'>
@@ -174,7 +146,7 @@
<description>On addressbook</description>
<request>
<method>PROPFIND</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>0</value>
@@ -208,7 +180,7 @@
<description>initial query - addressbook depth:1</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -248,8 +220,6 @@
<arg>
<name>okhrefs</name>
<value>$addressbook:/</value>
- <value>syncaddressbook1/</value>
- <value>syncaddressbook2/</value>
</arg>
</verify>
</request>
@@ -275,12 +245,8 @@
<arg>
<name>okhrefs</name>
<value>$addressbook:/</value>
- <value>syncaddressbook1/</value>
- <value>syncaddressbook1/1.vcf</value>
- <value>syncaddressbook1/2.vcf</value>
- <value>syncaddressbook2/</value>
- <value>syncaddressbook2/1.vcf</value>
- <value>syncaddressbook2/2.vcf</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
</arg>
</verify>
</request>
@@ -289,7 +255,7 @@
<description>add new resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
@@ -303,7 +269,7 @@
<description>new resource - addressbook depth:1</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -344,8 +310,6 @@
<arg>
<name>okhrefs</name>
<value>$addressbook:/</value>
- <value>syncaddressbook1/</value>
- <value>syncaddressbook2/</value>
</arg>
</verify>
</request>
@@ -371,13 +335,9 @@
<arg>
<name>okhrefs</name>
<value>$addressbook:/</value>
- <value>syncaddressbook1/</value>
- <value>syncaddressbook1/1.vcf</value>
- <value>syncaddressbook1/2.vcf</value>
- <value>syncaddressbook1/3.vcf</value>
- <value>syncaddressbook2/</value>
- <value>syncaddressbook2/1.vcf</value>
- <value>syncaddressbook2/2.vcf</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
+ <value>$addressbook:/3.vcf</value>
</arg>
</verify>
</request>
@@ -386,7 +346,7 @@
<description>remove new resource</description>
<request>
<method>DELETE</method>
- <ruri>$addressbookhome1:/syncaddressbook1/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<verify>
<callback>statusCode</callback>
</verify>
@@ -396,7 +356,7 @@
<description>remove new resource - addressbook depth:1</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -436,8 +396,6 @@
<arg>
<name>okhrefs</name>
<value>$addressbook:/</value>
- <value>syncaddressbook1/</value>
- <value>syncaddressbook2/</value>
</arg>
</verify>
</request>
@@ -463,12 +421,8 @@
<arg>
<name>okhrefs</name>
<value>$addressbook:/</value>
- <value>syncaddressbook1/</value>
- <value>syncaddressbook1/1.vcf</value>
- <value>syncaddressbook1/2.vcf</value>
- <value>syncaddressbook2/</value>
- <value>syncaddressbook2/1.vcf</value>
- <value>syncaddressbook2/2.vcf</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
</arg>
</verify>
</request>
@@ -477,7 +431,7 @@
<description>changed resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
@@ -491,7 +445,7 @@
<description>changed resource - addressbook depth:1</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -531,8 +485,6 @@
<arg>
<name>okhrefs</name>
<value>$addressbook:/</value>
- <value>syncaddressbook1/</value>
- <value>syncaddressbook2/</value>
</arg>
</verify>
</request>
@@ -558,12 +510,8 @@
<arg>
<name>okhrefs</name>
<value>$addressbook:/</value>
- <value>syncaddressbook1/</value>
- <value>syncaddressbook1/1.vcf</value>
- <value>syncaddressbook1/2.vcf</value>
- <value>syncaddressbook2/</value>
- <value>syncaddressbook2/1.vcf</value>
- <value>syncaddressbook2/2.vcf</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
</arg>
</verify>
</request>
@@ -575,7 +523,7 @@
<description>initial query - grab token</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -602,7 +550,7 @@
<description>new resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
@@ -613,7 +561,7 @@
</request>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -639,14 +587,14 @@
<description>remove resource (treated as new)</description>
<request>
<method>DELETE</method>
- <ruri>$addressbookhome1:/syncaddressbook1/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<verify>
<callback>statusCode</callback>
</verify>
</request>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -668,7 +616,7 @@
<description>remove resource (treated as old)</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -694,7 +642,7 @@
<description>changed resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
@@ -705,7 +653,7 @@
</request>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -731,7 +679,7 @@
<description>no change</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -756,7 +704,7 @@
<description>initial query</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -787,7 +735,7 @@
<description>new resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
@@ -798,7 +746,7 @@
</request>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -830,14 +778,14 @@
<description>remove resource new resource</description>
<request>
<method>DELETE</method>
- <ruri>$addressbookhome1:/syncaddressbook2/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<verify>
<callback>statusCode</callback>
</verify>
</request>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -868,7 +816,7 @@
<description>changed resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
@@ -879,7 +827,7 @@
</request>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -913,7 +861,7 @@
<description>initial query - grab token</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -948,7 +896,7 @@
<description>new resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
@@ -959,7 +907,7 @@
</request>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -993,14 +941,14 @@
<description>remove resource (treated as new)</description>
<request>
<method>DELETE</method>
- <ruri>$addressbookhome1:/syncaddressbook2/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<verify>
<callback>statusCode</callback>
</verify>
</request>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -1022,7 +970,7 @@
<description>remove resource (treated as old)</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -1051,7 +999,7 @@
<description>changed resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
@@ -1062,7 +1010,7 @@
</request>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -1096,7 +1044,7 @@
<description>no change</description>
<request print-response='no'>
<method>REPORT</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
<header>
<name>Depth</name>
<value>1</value>
@@ -1132,23 +1080,11 @@
<description>Initialize</description>
<request print-response='no'>
<method>DELETE</method>
- <ruri>$addressbookhome1:/syncaddressbook1/</ruri>
+ <ruri>$addressbookpath1:/</ruri>
</request>
- <request print-response='no'>
- <method>DELETE</method>
- <ruri>$addressbookhome1:/syncaddressbook2/</ruri>
- </request>
- <request end-delete="yes">
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/syncaddressbook3/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
- </request>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook3/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
@@ -1156,36 +1092,12 @@
</request>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook3/2.vcf</ruri>
+ <ruri>$addressbookpath1:/2.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/2.vcf</filepath>
</data>
</request>
- <request end-delete="yes">
- <method>MKCOL</method>
- <ruri>$addressbookhome1:/syncaddressbook4/</ruri>
- <data>
- <content-type>text/xml; charset=utf-8</content-type>
- <filepath>Resource/Common/MKCOL/addressbook.xml</filepath>
- </data>
- </request>
- <request>
- <method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook4/1.vcf</ruri>
- <data>
- <content-type>text/vcard; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
- </data>
- </request>
- <request>
- <method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook4/2.vcf</ruri>
- <data>
- <content-type>text/vcard; charset=utf-8</content-type>
- <filepath>Resource/CardDAV/vreports/put/2.vcf</filepath>
- </data>
- </request>
</test>
<test name='2' ignore='no'>
<description>initial query - grab token</description>
@@ -1205,12 +1117,8 @@
<arg>
<name>okhrefs</name>
<value>$addressbook:/</value>
- <value>syncaddressbook3/</value>
- <value>syncaddressbook3/1.vcf</value>
- <value>syncaddressbook3/2.vcf</value>
- <value>syncaddressbook4/</value>
- <value>syncaddressbook4/1.vcf</value>
- <value>syncaddressbook4/2.vcf</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
</arg>
</verify>
<grabelement>
@@ -1223,7 +1131,7 @@
<description>new resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook3/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
@@ -1247,8 +1155,8 @@
<callback>multistatusItems</callback>
<arg>
<name>okhrefs</name>
- <value>syncaddressbook3/</value>
- <value>syncaddressbook3/3.vcf</value>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/3.vcf</value>
</arg>
</verify>
<grabelement>
@@ -1261,7 +1169,7 @@
<description>remove resource (treated as new)</description>
<request>
<method>DELETE</method>
- <ruri>$addressbookhome1:/syncaddressbook3/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<verify>
<callback>statusCode</callback>
</verify>
@@ -1281,11 +1189,11 @@
<callback>multistatusItems</callback>
<arg>
<name>okhrefs</name>
- <value>syncaddressbook3/</value>
+ <value>$addressbook:/</value>
</arg>
<arg>
<name>badhrefs</name>
- <value>syncaddressbook3/3.vcf</value>
+ <value>$addressbook:/3.vcf</value>
</arg>
</verify>
</request>
@@ -1307,11 +1215,11 @@
<callback>multistatusItems</callback>
<arg>
<name>okhrefs</name>
- <value>syncaddressbook3/</value>
+ <value>$addressbook:/</value>
</arg>
<arg>
<name>badhrefs</name>
- <value>syncaddressbook3/3.vcf</value>
+ <value>$addressbook:/3.vcf</value>
</arg>
</verify>
<grabelement>
@@ -1324,7 +1232,7 @@
<description>changed resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook3/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
@@ -1348,8 +1256,8 @@
<callback>multistatusItems</callback>
<arg>
<name>okhrefs</name>
- <value>syncaddressbook3/</value>
- <value>syncaddressbook3/1.vcf</value>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/1.vcf</value>
</arg>
</verify>
<grabelement>
@@ -1404,12 +1312,8 @@
<arg>
<name>okhrefs</name>
<value>$addressbook:/</value>
- <value>syncaddressbook3/</value>
- <value>syncaddressbook3/1.vcf</value>
- <value>syncaddressbook3/2.vcf</value>
- <value>syncaddressbook4/</value>
- <value>syncaddressbook4/1.vcf</value>
- <value>syncaddressbook4/2.vcf</value>
+ <value>$addressbook:/1.vcf</value>
+ <value>$addressbook:/2.vcf</value>
</arg>
</verify>
<verify>
@@ -1430,7 +1334,7 @@
<description>new resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook4/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/3.vcf</filepath>
@@ -1454,8 +1358,8 @@
<callback>multistatusItems</callback>
<arg>
<name>okhrefs</name>
- <value>syncaddressbook4/</value>
- <value>syncaddressbook4/3.vcf</value>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/3.vcf</value>
</arg>
</verify>
<verify>
@@ -1476,7 +1380,7 @@
<description>remove resource (treated as new)</description>
<request>
<method>DELETE</method>
- <ruri>$addressbookhome1:/syncaddressbook4/3.vcf</ruri>
+ <ruri>$addressbookpath1:/3.vcf</ruri>
<verify>
<callback>statusCode</callback>
</verify>
@@ -1496,25 +1400,25 @@
<callback>multistatusItems</callback>
<arg>
<name>okhrefs</name>
- <value>syncaddressbook4/</value>
+ <value>$addressbook:/</value>
</arg>
<arg>
<name>badhrefs</name>
- <value>syncaddressbook4/3.vcf</value>
+ <value>$addressbook:/3.vcf</value>
</arg>
</verify>
<verify>
<callback>propfindItems</callback>
<arg>
<name>ignore</name>
- <value>$addressbookhome1:/syncaddressbook4/</value>
+ <value>$addressbookpath1:/</value>
</arg>
</verify>
<verify>
<callback>propfindItems</callback>
<arg>
<name>ignore</name>
- <value>$addressbookhome1:/syncaddressbook4/3.vcf</value>
+ <value>$addressbookpath1:/3.vcf</value>
</arg>
<arg>
<name>okprops</name>
@@ -1541,11 +1445,11 @@
<callback>multistatusItems</callback>
<arg>
<name>okhrefs</name>
- <value>syncaddressbook4/</value>
+ <value>$addressbook:/</value>
</arg>
<arg>
<name>badhrefs</name>
- <value>syncaddressbook4/3.vcf</value>
+ <value>$addressbook:/3.vcf</value>
</arg>
</verify>
<verify>
@@ -1565,7 +1469,7 @@
<description>changed resource</description>
<request>
<method>PUT</method>
- <ruri>$addressbookhome1:/syncaddressbook3/1.vcf</ruri>
+ <ruri>$addressbookpath1:/1.vcf</ruri>
<data>
<content-type>text/vcard; charset=utf-8</content-type>
<filepath>Resource/CardDAV/vreports/put/1.vcf</filepath>
@@ -1589,8 +1493,8 @@
<callback>multistatusItems</callback>
<arg>
<name>okhrefs</name>
- <value>syncaddressbook3/</value>
- <value>syncaddressbook3/1.vcf</value>
+ <value>$addressbook:/</value>
+ <value>$addressbook:/1.vcf</value>
</arg>
</verify>
<verify>
@@ -1639,7 +1543,7 @@
</test>
</test-suite>
- <test-suite name='simple reports - diff token - delete/create addressbook - home depth:infinity' ignore='no'>
+ <test-suite name='simple reports - diff token - delete/create addressbook - home depth:infinity' ignore='yes'>
<require-feature>
<feature>sync-report-home</feature>
</require-feature>
Property changes on: CalendarServer/trunk
___________________________________________________________________
Modified: svn:mergeinfo
- /CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/generic-sqlstore:6167-6191
/CalendarServer/branches/new-store:5594-5934
/CalendarServer/branches/new-store-no-caldavfile:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
/CalendarServer/branches/release/CalendarServer-4.3-dev:10180-10190,10192
/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
/CalendarServer/branches/users/cdaboo/ischedule-dkim:9747-9979
/CalendarServer/branches/users/cdaboo/managed-attachments:9985-10145
/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
/CalendarServer/branches/users/cdaboo/pods:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
/CalendarServer/branches/users/cdaboo/pycard:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
/CalendarServer/branches/users/cdaboo/store-scheduling:10876-11129
/CalendarServer/branches/users/cdaboo/timezones:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
/CalendarServer/branches/users/glyph/always-abort-txn-on-error:9958-9969
/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
/CalendarServer/branches/users/glyph/conn-limit:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
/CalendarServer/branches/users/glyph/dalify:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
/CalendarServer/branches/users/glyph/deploybuild:7563-7572
/CalendarServer/branches/users/glyph/digest-auth-redux:10624-10635
/CalendarServer/branches/users/glyph/disable-quota:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
/CalendarServer/branches/users/glyph/linux-tests:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
/CalendarServer/branches/users/glyph/new-export:7444-7485
/CalendarServer/branches/users/glyph/one-home-list-api:10048-10073
/CalendarServer/branches/users/glyph/oracle:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
/CalendarServer/branches/users/glyph/other-html:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
/CalendarServer/branches/users/glyph/q:9560-9688
/CalendarServer/branches/users/glyph/queue-locking-and-timing:10204-10289
/CalendarServer/branches/users/glyph/quota:7604-7637
/CalendarServer/branches/users/glyph/sendfdport:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
/CalendarServer/branches/users/glyph/sharedpool:6490-6550
/CalendarServer/branches/users/glyph/sharing-api:9192-9205
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
/CalendarServer/branches/users/glyph/sql-store:5929-6073
/CalendarServer/branches/users/glyph/start-service-start-loop:11060-11065
/CalendarServer/branches/users/glyph/subtransactions:7248-7258
/CalendarServer/branches/users/glyph/table-alias:8651-8664
/CalendarServer/branches/users/glyph/uidexport:7673-7676
/CalendarServer/branches/users/glyph/unshare-when-access-revoked:10562-10595
/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
/CalendarServer/branches/users/glyph/uuid-normalize:9268-9296
/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
/CalendarServer/branches/users/sagen/applepush:8126-8184
/CalendarServer/branches/users/sagen/inboxitems:7380-7381
/CalendarServer/branches/users/sagen/locations-resources:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/branches/users/sagen/resources-2:5084-5093
/CalendarServer/branches/users/sagen/testing:10827-10851,10853-10855
/CalendarServer/branches/users/wsanchez/transations:5515-5593
+ /CalDAVTester/trunk:11193-11198
/CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/generic-sqlstore:6167-6191
/CalendarServer/branches/new-store:5594-5934
/CalendarServer/branches/new-store-no-caldavfile:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
/CalendarServer/branches/release/CalendarServer-4.3-dev:10180-10190,10192
/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
/CalendarServer/branches/users/cdaboo/ischedule-dkim:9747-9979
/CalendarServer/branches/users/cdaboo/managed-attachments:9985-10145
/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
/CalendarServer/branches/users/cdaboo/pods:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
/CalendarServer/branches/users/cdaboo/pycard:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
/CalendarServer/branches/users/cdaboo/store-scheduling:10876-11129
/CalendarServer/branches/users/cdaboo/timezones:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
/CalendarServer/branches/users/gaya/sharedgroups-3:11088-11204
/CalendarServer/branches/users/glyph/always-abort-txn-on-error:9958-9969
/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
/CalendarServer/branches/users/glyph/conn-limit:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
/CalendarServer/branches/users/glyph/dalify:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
/CalendarServer/branches/users/glyph/deploybuild:7563-7572
/CalendarServer/branches/users/glyph/digest-auth-redux:10624-10635
/CalendarServer/branches/users/glyph/disable-quota:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
/CalendarServer/branches/users/glyph/linux-tests:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
/CalendarServer/branches/users/glyph/new-export:7444-7485
/CalendarServer/branches/users/glyph/one-home-list-api:10048-10073
/CalendarServer/branches/users/glyph/oracle:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
/CalendarServer/branches/users/glyph/other-html:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
/CalendarServer/branches/users/glyph/q:9560-9688
/CalendarServer/branches/users/glyph/queue-locking-and-timing:10204-10289
/CalendarServer/branches/users/glyph/quota:7604-7637
/CalendarServer/branches/users/glyph/sendfdport:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
/CalendarServer/branches/users/glyph/sharedpool:6490-6550
/CalendarServer/branches/users/glyph/sharing-api:9192-9205
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
/CalendarServer/branches/users/glyph/sql-store:5929-6073
/CalendarServer/branches/users/glyph/start-service-start-loop:11060-11065
/CalendarServer/branches/users/glyph/subtransactions:7248-7258
/CalendarServer/branches/users/glyph/table-alias:8651-8664
/CalendarServer/branches/users/glyph/uidexport:7673-7676
/CalendarServer/branches/users/glyph/unshare-when-access-revoked:10562-10595
/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
/CalendarServer/branches/users/glyph/uuid-normalize:9268-9296
/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
/CalendarServer/branches/users/sagen/applepush:8126-8184
/CalendarServer/branches/users/sagen/inboxitems:7380-7381
/CalendarServer/branches/users/sagen/locations-resources:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/branches/users/sagen/resources-2:5084-5093
/CalendarServer/branches/users/sagen/testing:10827-10851,10853-10855
/CalendarServer/branches/users/wsanchez/transations:5515-5593
Modified: CalendarServer/trunk/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/caldav.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/calendarserver/tap/caldav.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -66,7 +66,8 @@
from txdav.common.datastore.sql_tables import schema
from txdav.common.datastore.upgrade.sql.upgrade import (
- UpgradeDatabaseSchemaStep, UpgradeDatabaseDataStep, UpgradeDatabaseOtherStep,
+ UpgradeDatabaseSchemaStep, UpgradeDatabaseAddressBookDataStep,
+ UpgradeDatabaseCalendarDataStep, UpgradeDatabaseOtherStep,
)
from txdav.common.datastore.upgrade.migrate import UpgradeToDatabaseStep
@@ -1255,10 +1256,15 @@
)
pps.addStep(
- UpgradeDatabaseDataStep(
+ UpgradeDatabaseAddressBookDataStep(
store, uid=overrideUID, gid=overrideGID
)
)
+ pps.addStep(
+ UpgradeDatabaseCalendarDataStep(
+ store, uid=overrideUID, gid=overrideGID
+ )
+ )
pps.addStep(
UpgradeToDatabaseStep(
Modified: CalendarServer/trunk/calendarserver/tools/dbinspect.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/dbinspect.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/calendarserver/tools/dbinspect.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -814,13 +814,11 @@
schema.ADDRESSBOOK_OBJECT_REVISIONS,
- schema.ADDRESSBOOK,
+ schema.ADDRESSBOOK_HOME,
+ #schema.ADDRESSBOOK_HOME_METADATA, - cascades
#schema.ADDRESSBOOK_BIND, - cascades
#schema.ADDRESSBOOK_OBJECT, - cascades
- schema.ADDRESSBOOK_HOME,
- #schema.ADDRESSBOOK_HOME_METADATA, - cascades
-
schema.NOTIFICATION_HOME,
schema.NOTIFICATION,
#schema.NOTIFICATION_OBJECT_REVISIONS - cascades,
Modified: CalendarServer/trunk/calendarserver/tools/obliterate.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/obliterate.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/calendarserver/tools/obliterate.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -196,7 +196,6 @@
ca = schema.CALENDAR
co = schema.CALENDAR_OBJECT
ah = schema.ADDRESSBOOK_HOME
- aa = schema.ADDRESSBOOK
ao = schema.ADDRESSBOOK_OBJECT
rp = schema.RESOURCE_PROPERTY
@@ -222,14 +221,8 @@
From=ah,
SetExpression=Union(
Select(
- [aa.RESOURCE_ID],
- From=aa,
- SetExpression=Union(
- Select(
- [ao.RESOURCE_ID],
- From=ao,
- ),
- ),
+ [ao.RESOURCE_ID],
+ From=ao,
),
),
),
Modified: CalendarServer/trunk/testserver
===================================================================
--- CalendarServer/trunk/testserver 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/testserver 2013-05-16 20:35:53 UTC (rev 11205)
@@ -25,6 +25,8 @@
verbose="";
serverinfo="${cdt}/scripts/server/serverinfo.xml";
+printres="";
+subdir="";
usage ()
{
@@ -32,19 +34,25 @@
echo "Usage: ${program} [-v] [-s serverinfo]";
echo "Options:";
echo " -h Print this help and exit";
+ echo " -t Set the CalDAVTester directory";
+ echo " -d Set the script subdirectory";
echo " -s Set the serverinfo.xml";
+ echo " -r Print request and response";
echo " -v Verbose.";
if [ "${1-}" == "-" ]; then return 0; fi;
exit 64;
}
-while getopts 'hvs:' option; do
+while getopts 'hvrt:s:d:' option; do
case "$option" in
'?') usage; ;;
'h') usage -; exit 0; ;;
+ 't') cdt="${OPTARG}"; serverinfo="${OPTARG}/scripts/server/serverinfo.xml"; ;;
+ 'd') subdir="--subdir=${OPTARG}"; ;;
's') serverinfo="${OPTARG}"; ;;
- 'v') verbose="v"; ;;
+ 'r') printres="--always-print-request --always-print-response"; ;;
+ 'v') verbose="v"; ;;
esac;
done;
@@ -60,5 +68,5 @@
source "${wd}/support/shell.sh";
-cd "${cdt}" && "${python}" testcaldav.py --print-details-onfail -s "${serverinfo}" "$@";
+cd "${cdt}" && "${python}" testcaldav.py --print-details-onfail ${printres} -s "${serverinfo}" ${subdir} "$@";
Modified: CalendarServer/trunk/twext/web2/resource.py
===================================================================
--- CalendarServer/trunk/twext/web2/resource.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twext/web2/resource.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -45,7 +45,8 @@
@return: A tuple of HTTP methods that are allowed to be invoked on this resource.
"""
if not hasattr(self, "_allowed_methods"):
- self._allowed_methods = tuple([name[5:] for name in dir(self) if name.startswith('http_')])
+ self._allowed_methods = tuple([name[5:] for name in dir(self)
+ if name.startswith('http_') and getattr(self, name) is not None])
return self._allowed_methods
def checkPreconditions(self, request):
@@ -189,7 +190,7 @@
of this resource which matches one or more of the given C{segments} in
sequence, and a list of remaining segments.
"""
- w = getattr(self, 'child_%s' % (segments[0], ), None)
+ w = getattr(self, 'child_%s' % (segments[0],), None)
if w:
r = iweb.IResource(w, None)
@@ -227,12 +228,12 @@
resource (e.g. C{/foo/}) specify C{path} as C{""}.
@param child: an object adaptable to L{iweb.IResource}.
"""
- setattr(self, 'child_%s' % (path, ), child)
+ setattr(self, 'child_%s' % (path,), child)
def http_GET(self, request):
if self.addSlash and request.prepath[-1] != '':
# If this is a directory-ish resource...
- return http.RedirectResponse(request.unparseURL(path=request.path+'/'))
+ return http.RedirectResponse(request.unparseURL(path=request.path + '/'))
return super(Resource, self).http_GET(request)
@@ -287,7 +288,7 @@
default to the corresponding component of the URL of the request being
redirected.
"""
- self._args = args
+ self._args = args
self._kwargs = kwargs
def renderHTTP(self, request):
@@ -302,7 +303,7 @@
implements(iweb.IResource)
def __init__(self, resource):
- self.resource=resource
+ self.resource = resource
def hook(self, request):
"""
Modified: CalendarServer/trunk/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/customxml.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twistedcaldav/customxml.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1464,5 +1464,7 @@
ResourceType.sharedcalendar = ResourceType(Collection(), caldavxml.Calendar(), Shared())
ResourceType.sharedowneraddressbook = ResourceType(Collection(), carddavxml.AddressBook(), SharedOwner())
ResourceType.sharedaddressbook = ResourceType(Collection(), carddavxml.AddressBook(), Shared())
+ResourceType.sharedownergroup = ResourceType(SharedOwner())
+ResourceType.sharedgroup = ResourceType(Shared())
ResourceType.link = ResourceType(Link())
Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twistedcaldav/resource.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -75,7 +75,7 @@
from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
from twistedcaldav.linkresource import LinkResource
from calendarserver.push.notifier import getPubSubAPSConfiguration
-from twistedcaldav.sharing import SharedCollectionMixin, SharedHomeMixin
+from twistedcaldav.sharing import SharedResourceMixin, SharedHomeMixin
from twistedcaldav.util import normalizationLookup
from twistedcaldav.vcard import Component as vComponent
@@ -204,7 +204,7 @@
class CalDAVResource (
- CalDAVComplianceMixIn, SharedCollectionMixin,
+ CalDAVComplianceMixIn, SharedResourceMixin,
DAVResourceWithChildrenMixin, DAVResource, LoggingMixIn
):
"""
@@ -653,9 +653,7 @@
returnValue(customxml.AllowedSharingModes(customxml.CanBeShared()))
elif qname == customxml.SharedURL.qname():
- isShareeCollection = self.isShareeCollection()
-
- if isShareeCollection:
+ if self.isShareeResource():
returnValue(customxml.SharedURL(element.HRef.fromString(self._share.url())))
else:
returnValue(None)
@@ -768,8 +766,7 @@
def accessControlList(self, request, *args, **kwargs):
acls = None
- isShareeCollection = self.isShareeCollection()
- if isShareeCollection:
+ if self.isShareeResource():
acls = (yield self.shareeAccessControlList(request, *args, **kwargs))
if acls is None:
@@ -825,8 +822,7 @@
Return the DAV:owner property value (MUST be a DAV:href or None).
"""
- isShareeCollection = self.isShareeCollection()
- if isShareeCollection:
+ if self.isShareeResource():
parent = (yield self.locateParent(request, self._share.url()))
else:
parent = (yield self.locateParent(request, request.urlForResource(self)))
@@ -842,8 +838,7 @@
"""
Return the DAV:owner property value (MUST be a DAV:href or None).
"""
- isShareeCollection = self.isShareeCollection()
- if isShareeCollection:
+ if self.isShareeResource():
parent = (yield self.locateParent(request, self._share.url()))
else:
parent = (yield self.locateParent(request, request.urlForResource(self)))
@@ -1219,15 +1214,13 @@
"""
sharedParent = None
- isShareeCollection = self.isShareeCollection()
- if isShareeCollection:
+ if self.isShareeResource():
# A sharee collection's quota root is the resource owner's root
sharedParent = (yield request.locateResource(parentForURL(self._share.url())))
else:
parent = (yield self.locateParent(request, request.urlForResource(self)))
if isCalendarCollectionResource(parent) or isAddressBookCollectionResource(parent):
- isShareeCollection = parent.isShareeCollection()
- if isShareeCollection:
+ if parent.isShareeResource():
# A sharee collection's quota root is the resource owner's root
sharedParent = (yield request.locateResource(parentForURL(parent._share.url())))
@@ -2677,6 +2670,14 @@
Address book home collection resource.
"""
+
+ def __init__(self, *args, **kw):
+ super(AddressBookHomeResource, self).__init__(*args, **kw)
+ # get some Access header items
+ self.http_MKCOL = None
+ self.http_MKCALENDAR = None
+
+
@classmethod
@inlineCallbacks
def homeFromTransaction(cls, transaction, uid):
@@ -2712,7 +2713,7 @@
if defaultAddressBookProperty and len(defaultAddressBookProperty.children) == 1:
defaultAddressBook = str(defaultAddressBookProperty.children[0])
adbk = (yield request.locateResource(str(defaultAddressBook)))
- if adbk is not None and isAddressBookCollectionResource(adbk) and adbk.exists() and not adbk.isShareeCollection():
+ if adbk is not None and isAddressBookCollectionResource(adbk) and adbk.exists() and not adbk.isShareeResource():
returnValue(defaultAddressBookProperty)
# Default is not valid - we have to try to pick one
@@ -2735,7 +2736,7 @@
if len(new_adbk) == 1:
adbkURI = str(new_adbk[0])
adbk = (yield request.locateResource(str(new_adbk[0])))
- if adbk is None or not adbk.exists() or not isAddressBookCollectionResource(adbk) or adbk.isShareeCollection():
+ if adbk is None or not adbk.exists() or not isAddressBookCollectionResource(adbk) or adbk.isShareeResource():
# Validate that href's point to a valid addressbook.
raise HTTPError(ErrorResponse(
responsecode.CONFLICT,
Modified: CalendarServer/trunk/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/sharing.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twistedcaldav/sharing.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -21,7 +21,7 @@
__all__ = [
- "SharedCollectionMixin",
+ "SharedResourceMixin",
]
from twext.web2 import responsecode
@@ -32,7 +32,7 @@
from txdav.common.datastore.sql_tables import _BIND_MODE_OWN, \
_BIND_MODE_READ, _BIND_MODE_WRITE, _BIND_STATUS_INVITED, \
_BIND_MODE_DIRECT, _BIND_STATUS_ACCEPTED, _BIND_STATUS_DECLINED, \
- _BIND_STATUS_INVALID
+ _BIND_STATUS_INVALID, _ABO_KIND_GROUP
from txdav.xml import element
from twisted.internet.defer import succeed, inlineCallbacks, DeferredList, \
@@ -56,12 +56,12 @@
#ENOTIFICATIONTYPE = 2
-class SharedCollectionMixin(object):
+class SharedResourceMixin(object):
"""
A mix-in for calendar/addressbook resources that implements sharing-related
functionality.
- @ivar _share: If this L{SharedCollectionMixin} is the sharee's version of a
+ @ivar _share: If this L{SharedResourceMixin} is the sharee's version of a
resource, this refers to the L{Share} that describes it.
@type _share: L{Share} or L{NoneType}
"""
@@ -96,7 +96,7 @@
))
# See if it is on the sharee calendar
- if self.isShareeCollection():
+ if self.isShareeResource():
original = (yield request.locateResource(self._share.url()))
yield original.validateInvites(request)
invitations = yield original._allInvitations()
@@ -156,7 +156,7 @@
"Invalid invitation uid: %s" % (inviteUID,),
))
- # Only certain states are sharer controlled
+ # Only certain states are owner controlled
if invitation.state() in ("NEEDS-ACTION", "ACCEPTED", "DECLINED",):
yield self._updateInvitation(invitation, state=state, summary=summary)
@@ -208,7 +208,7 @@
# Get the home collection
if self.isCalendarCollection():
shareeHomeResource = yield sharee.calendarHome(request)
- elif self.isAddressBookCollection():
+ elif self.isAddressBookCollection() or self.isGroup():
shareeHomeResource = yield sharee.addressBookHome(request)
else:
raise HTTPError(ErrorResponse(
@@ -244,18 +244,18 @@
def setShare(self, share):
"""
- Set the L{Share} associated with this L{SharedCollectionMixin}. (This
+ Set the L{Share} associated with this L{SharedResourceMixin}. (This
is only invoked on the sharee's resource, not the owner's.)
"""
- self._isShareeCollection = True
+ self._isShareeResource = True
self._share = share
- def isShareeCollection(self):
+ def isShareeResource(self):
"""
Return True if this is a sharee view of a shared calendar collection.
"""
- return hasattr(self, "_isShareeCollection")
+ return hasattr(self, "_isShareeResource")
@inlineCallbacks
@@ -266,7 +266,7 @@
# Remove from sharee's calendar/address book home
if self.isCalendarCollection():
shareeHome = yield sharee.calendarHome(request)
- elif self.isAddressBookCollection():
+ elif self.isAddressBookCollection() or self.isGroup():
shareeHome = yield sharee.addressBookHome(request)
returnValue((yield shareeHome.removeShare(request, self._share)))
@@ -280,6 +280,9 @@
return "calendar"
elif self.isAddressBookCollection():
return "addressbook"
+ elif self.isGroup():
+ #TODO: Add group xml resource type ?
+ return "group"
else:
return ""
@@ -349,7 +352,8 @@
@rtype: L{davxml.ACL}
"""
- assert self._isShareeCollection, "Only call this for a sharee collection"
+ assert self._isShareeResource, "Only call this for a sharee resource"
+ assert self.isCalendarCollection() or self.isAddressBookCollection(), "Only call this for a address book or calendar resource"
sharee = self.principalForUID(self._share.shareeUID())
access = yield self._checkAccessControl()
@@ -404,7 +408,7 @@
# Give all access to config.AdminPrincipals
aces += config.AdminACEs
- if config.EnableProxyPrincipals:
+ if self.isCalendarCollection() and config.EnableProxyPrincipals:
aces += (
# DAV:read/DAV:read-current-user-privilege-set access for this principal's calendar-proxy-read users.
element.ACE(
@@ -494,8 +498,9 @@
def uninviteUserToShare(self, userid, ace, request):
- """ Send out in uninvite first, and then remove this user from the share list."""
-
+ """
+ Send out in uninvite first, and then remove this user from the share list.
+ """
# Do not validate the userid - we want to allow invalid users to be removed because they
# may have been valid when added, but no longer valid now. Clients should be able to clear out
# anything known to be invalid.
@@ -532,21 +537,20 @@
@inlineCallbacks
def _createInvitation(self, shareeUID, access, summary,):
- '''
+ """
Create a new homeChild and wrap it in an Invitation
- '''
+ """
if self.isCalendarCollection():
shareeHome = yield self._newStoreObject._txn.calendarHomeWithUID(shareeUID, create=True)
- elif self.isAddressBookCollection():
+ elif self.isAddressBookCollection() or self.isGroup():
shareeHome = yield self._newStoreObject._txn.addressbookHomeWithUID(shareeUID, create=True)
- sharedName = yield self._newStoreObject.shareWith(shareeHome,
+ shareUID = yield self._newStoreObject.shareWith(shareeHome,
mode=invitationAccessToBindModeMap[access],
status=_BIND_STATUS_INVITED,
message=summary)
-
- shareeHomeChild = yield shareeHome.invitedChildWithName(sharedName)
- invitation = Invitation(shareeHomeChild)
+ shareeStoreObject = yield shareeHome.invitedObjectWithShareUID(shareUID)
+ invitation = Invitation(shareeStoreObject)
returnValue(invitation)
@@ -554,41 +558,41 @@
def _updateInvitation(self, invitation, access=None, state=None, summary=None):
mode = None if access is None else invitationAccessToBindModeMap[access]
status = None if state is None else invitationStateToBindStatusMap[state]
+ yield self._newStoreObject.updateShare(invitation._shareeStoreObject, mode=mode, status=status, message=summary)
- yield self._newStoreObject.updateShare(invitation._shareeHomeChild, mode=mode, status=status, message=summary)
- assert not access or access == invitation.access(), "access=%s != invitation.access()=%s" % (access, invitation.access())
- assert not state or state == invitation.state(), "state=%s != invitation.state()=%s" % (state, invitation.state())
- assert not summary or summary == invitation.summary(), "summary=%s != invitation.summary()=%s" % (summary, invitation.summary())
-
@inlineCallbacks
- def _allInvitations(self, includeAccepted=True):
+ def _allInvitations(self):
"""
Get list of all invitations to this object
For legacy reasons, all invitations are all invited + shared (accepted, not direct).
Combine these two into a single sorted list so code is similar to that for legacy invite db
"""
- invitedHomeChildren = yield self._newStoreObject.asInvited()
- if includeAccepted:
+ if not self.exists():
+ returnValue([])
+
+ #TODO: Cache
+ if True: #not hasattr(self, "_invitations"):
+
acceptedHomeChildren = yield self._newStoreObject.asShared()
- # remove direct shares (it might be OK not to remove these, that would be different from legacy code)
+ # remove direct shares (it might be OK not to remove these, but that would be different from legacy code)
indirectAccceptedHomeChildren = [homeChild for homeChild in acceptedHomeChildren
if homeChild.shareMode() != _BIND_MODE_DIRECT]
- invitedHomeChildren += indirectAccceptedHomeChildren
+ invitedHomeChildren = (yield self._newStoreObject.asInvited()) + indirectAccceptedHomeChildren
- invitations = [Invitation(homeChild) for homeChild in invitedHomeChildren]
- invitations.sort(key=lambda invitation: invitation.shareeUID())
+ self._invitations = sorted([Invitation(homeChild) for homeChild in invitedHomeChildren],
+ key=lambda invitation:invitation.shareeUID())
- returnValue(invitations)
+ returnValue(self._invitations)
@inlineCallbacks
- def _invitationForShareeUID(self, shareeUID, includeAccepted=True):
+ def _invitationForShareeUID(self, shareeUID):
"""
Get an invitation for this sharee principal UID
"""
- invitations = yield self._allInvitations(includeAccepted=includeAccepted)
+ invitations = yield self._allInvitations()
for invitation in invitations:
if invitation.shareeUID() == shareeUID:
returnValue(invitation)
@@ -596,11 +600,11 @@
@inlineCallbacks
- def _invitationForUID(self, uid, includeAccepted=True):
+ def _invitationForUID(self, uid):
"""
Get an invitation for an invitations uid
"""
- invitations = yield self._allInvitations(includeAccepted=includeAccepted)
+ invitations = yield self._allInvitations()
for invitation in invitations:
if invitation.uid() == uid:
returnValue(invitation)
@@ -608,7 +612,7 @@
@inlineCallbacks
- def inviteSingleUserToShare(self, userid, cn, ace, summary, request):
+ def inviteSingleUserToShare(self, userid, cn, ace, summary, request): #@UnusedVariable
# We currently only handle local users
sharee = self.principalForCalendarUserAddress(userid)
@@ -633,7 +637,7 @@
@inlineCallbacks
- def uninviteSingleUserFromShare(self, userid, aces, request):
+ def uninviteSingleUserFromShare(self, userid, aces, request): #@UnusedVariable
# Cancel invites - we'll just use whatever userid we are given
sharee = self.principalForCalendarUserAddress(userid)
@@ -657,25 +661,28 @@
# Remove any shared calendar or address book
sharee = self.principalForUID(invitation.shareeUID())
if sharee:
+ previousInvitationState = invitation.state()
if self.isCalendarCollection():
shareeHomeResource = yield sharee.calendarHome(request)
- elif self.isAddressBookCollection():
+ displayName = yield shareeHomeResource.removeShareByUID(request, invitation.uid())
+ elif self.isAddressBookCollection() or self.isGroup():
shareeHomeResource = yield sharee.addressBookHome(request)
- displayName = (yield shareeHomeResource.removeShareByUID(request, invitation.uid()))
+ yield shareeHomeResource.removeShareByUID(request, invitation.uid())
+ displayName = None
# If current user state is accepted then we send an invite with the new state, otherwise
# we cancel any existing invites for the user
- if invitation and invitation.state() != "ACCEPTED":
+ if previousInvitationState != "ACCEPTED":
yield self.removeInviteNotification(invitation, request)
- elif invitation:
+ else:
yield self.sendInviteNotification(invitation, request, displayName=displayName, notificationState="DELETED")
# Direct shares for with valid sharee principal will already be deleted
- yield self._newStoreObject.unshareWith(invitation._shareeHomeChild.viewerHome())
+ yield self._newStoreObject.unshareWith(invitation._shareeStoreObject.viewerHome())
returnValue(True)
- def inviteSingleUserUpdateToShare(self, userid, commonName, acesOLD, aceNEW, summary, request):
+ def inviteSingleUserUpdateToShare(self, userid, commonName, acesOLD, aceNEW, summary, request): #@UnusedVariable
# Just update existing
return self.inviteSingleUserToShare(userid, commonName, aceNEW, summary, request)
@@ -795,6 +802,7 @@
"%s: %s" % (", ".join(error_text), inviteset,),
))
+
def _handleInviteRemove(inviteremove):
userid = None
access = []
@@ -938,15 +946,23 @@
customxml.InviteReply: _xmlHandleInviteReply,
}
+
+ def isGroup(self):
+ try:
+ return self._newStoreObject._kind == _ABO_KIND_GROUP
+ except AttributeError:
+ return False
+
+
def POST_handler_content_type(self, request, contentType):
- if self.isCollection():
+ if self.isCollection() or self.isGroup():
if contentType:
if contentType in self._postHandlers:
return self._postHandlers[contentType](self, request)
else:
- self.log_info("Get a POST of an unsupported content type on a collection type: %s" % (contentType,))
+ self.log_info("Got a POST on collection or group with an unsupported content type: %s" % (contentType,))
else:
- self.log_info("Get a POST with no content type on a collection")
+ self.log_info("Got a POST on collection or group with no content type")
return succeed(responsecode.FORBIDDEN)
_postHandlers = {
@@ -954,6 +970,7 @@
("text", "xml") : xmlRequestHandler,
}
+
invitationAccessMapToXML = {
"read-only" : customxml.ReadAccess,
"read-write" : customxml.ReadWriteAccess,
@@ -983,32 +1000,33 @@
}
invitationAccessFromBindModeMap = dict((v, k) for k, v in invitationAccessToBindModeMap.iteritems())
+
class Invitation(object):
"""
Invitation is a read-only wrapper for CommonHomeChild, that uses terms similar LegacyInvite sharing.py code base.
"""
- def __init__(self, shareeHomeChild):
- self._shareeHomeChild = shareeHomeChild
+ def __init__(self, shareeStoreObject):
+ self._shareeStoreObject = shareeStoreObject
def uid(self):
- return self._shareeHomeChild.shareUID()
+ return self._shareeStoreObject.shareUID()
def shareeUID(self):
- return self._shareeHomeChild.viewerHome().uid()
+ return self._shareeStoreObject.viewerHome().uid()
def access(self):
- return invitationAccessFromBindModeMap.get(self._shareeHomeChild.shareMode())
+ return invitationAccessFromBindModeMap.get(self._shareeStoreObject.shareMode())
def state(self):
- return invitationStateFromBindStatusMap.get(self._shareeHomeChild.shareStatus())
+ return invitationStateFromBindStatusMap.get(self._shareeStoreObject.shareStatus())
def summary(self):
- return self._shareeHomeChild.shareMessage()
+ return self._shareeStoreObject.shareMessage()
@@ -1021,11 +1039,11 @@
@inlineCallbacks
def provisionShare(self, child, request=None):
"""
- If the given child resource (a L{SharedCollectionMixin}) of this
+ If the given child resource (a L{SharedResourceMixin}) of this
L{SharedHomeMixin} is a I{sharee}'s view of a shared calendar object,
associate it with a L{Share}.
"""
- share = yield self._shareForHomeChild(child._newStoreObject, request)
+ share = yield self._shareForStoreObject(child._newStoreObject, request)
if share:
child.setShare(share)
access = yield child._checkAccessControl()
@@ -1035,7 +1053,7 @@
@inlineCallbacks
- def _shareForHomeChild(self, child, request=None):
+ def _shareForStoreObject(self, storeObject, request=None):
"""
Determine the L{Share} associated with the given child.
@@ -1049,32 +1067,38 @@
or C{None}.
@rtype: L{Share} or L{NoneType}
"""
- # Try to find a matching share
- if not child or child.owned():
+ # Find a matching share
+ if not storeObject or storeObject.owned():
returnValue(None)
- sharerHomeChild = yield child.ownerHome().childWithID(child._resourceID)
-
# get the shared object's URL
- sharer = self.principalForUID(sharerHomeChild.viewerHome().uid())
+ owner = self.principalForUID(storeObject.ownerHome().uid())
if not request:
- # FIXME: Fake up a request that can be used to get the sharer home
- # resource
- class _FakeRequest(object):
- pass
+ # FIXEME: Fake up a request that can be used to get the owner home resource
+ class _FakeRequest(object):pass
fakeRequest = _FakeRequest()
setattr(fakeRequest, TRANSACTION_KEY, self._newStoreHome._txn)
request = fakeRequest
if self._newStoreHome._homeType == ECALENDARTYPE:
- sharerHomeCollection = yield sharer.calendarHome(request)
+ ownerHomeCollection = yield owner.calendarHome(request)
elif self._newStoreHome._homeType == EADDRESSBOOKTYPE:
- sharerHomeCollection = yield sharer.addressBookHome(request)
+ ownerHomeCollection = yield owner.addressBookHome(request)
- url = joinURL(sharerHomeCollection.url(), sharerHomeChild.name())
- share = Share(shareeHomeChild=child, sharerHomeChild=sharerHomeChild,
- url=url)
+ ownerHomeChild = yield storeObject.ownerHome().childWithID(storeObject._resourceID)
+ if ownerHomeChild:
+ assert ownerHomeChild != storeObject
+ url = joinURL(ownerHomeCollection.url(), ownerHomeChild.name())
+ share = Share(shareeStoreObject=storeObject, ownerStoreObject=ownerHomeChild, url=url)
+ else:
+ for ownerHomeChild in (yield storeObject.ownerHome().children()):
+ if ownerHomeChild.owned():
+ sharedGroup = yield ownerHomeChild.objectResourceWithID(storeObject._resourceID)
+ if sharedGroup:
+ url = joinURL(ownerHomeCollection.url(), ownerHomeChild.name(), sharedGroup.name())
+ share = Share(shareeStoreObject=storeObject, ownerStoreObject=sharedGroup, url=url)
+ break
returnValue(share)
@@ -1082,17 +1106,16 @@
@inlineCallbacks
def _shareForUID(self, shareUID, request):
- # since child.shareUID() == child.name() for indirect shares
- child = yield self._newStoreHome.childWithName(shareUID)
- if child:
- share = yield self._shareForHomeChild(child, request)
- if share and share.uid() == shareUID:
+ shareeStoreObject = yield self._newStoreHome.objectWithShareUID(shareUID)
+ if shareeStoreObject:
+ share = yield self._shareForStoreObject(shareeStoreObject, request)
+ if share:
returnValue(share)
# find direct shares
children = yield self._newStoreHome.children()
for child in children:
- share = yield self._shareForHomeChild(child, request)
+ share = yield self._shareForStoreObject(child, request)
if share and share.uid() == shareUID:
returnValue(share)
@@ -1111,10 +1134,11 @@
if oldShare:
share = oldShare
else:
- sharedCollection = yield request.locateResource(hostUrl)
- shareeHomeChild = yield self._newStoreHome.childWithName(inviteUID)
- share = Share(shareeHomeChild=shareeHomeChild,
- sharerHomeChild=sharedCollection._newStoreObject,
+ sharedResource = yield request.locateResource(hostUrl)
+ shareeStoreObject = yield self._newStoreHome.objectWithShareUID(inviteUID)
+
+ share = Share(shareeStoreObject=shareeStoreObject,
+ ownerStoreObject=sharedResource._newStoreObject,
url=hostUrl)
response = yield self._acceptShare(request, not oldShare, share,
@@ -1132,16 +1156,16 @@
share = oldShare
else:
sharedCollection = yield request.locateResource(hostUrl)
- sharedName = yield sharedCollection._newStoreObject.shareWith(
+ shareUID = yield sharedCollection._newStoreObject.shareWith(
shareeHome=self._newStoreHome,
mode=_BIND_MODE_DIRECT,
status=_BIND_STATUS_ACCEPTED,
message=displayname
)
- shareeHomeChild = yield self._newStoreHome.childWithName(sharedName)
- share = Share(shareeHomeChild=shareeHomeChild,
- sharerHomeChild=sharedCollection._newStoreObject,
+ shareeStoreObject = yield self._newStoreHome.objectWithShareUID(shareUID)
+ share = Share(shareeStoreObject=shareeStoreObject,
+ ownerStoreObject=sharedCollection._newStoreObject,
url=hostUrl)
response = yield self._acceptShare(request, not oldShare, share,
@@ -1172,41 +1196,49 @@
L{customxml.SharedAs} element as its body.
@rtype: L{Deferred} firing L{XMLResponse}
"""
-
# Get shared collection in non-share mode first
- sharedCollection = yield request.locateResource(share.url())
+ sharedResource = yield request.locateResource(share.url())
+ sharee = self.principalForUID(share.shareeUID())
- # For a direct share we will copy any calendar-color over using the owners view
- color = None
- if share.direct() and isNewShare and sharedCollection.isCalendarCollection():
- try:
- color = (yield sharedCollection.readProperty(customxml.CalendarColor, request))
- except HTTPError:
- pass
+ if sharedResource.isCalendarCollection():
+ shareeHomeResource = yield sharee.calendarHome(request)
+ sharedAsURL = joinURL(shareeHomeResource.url(), share.name())
+ shareeCalender = yield request.locateResource(sharedAsURL)
+ shareeCalender.setShare(share)
- sharee = self.principalForUID(share.shareeUID())
- if sharedCollection.isCalendarCollection():
- shareeHomeResource = yield sharee.calendarHome(request)
- elif sharedCollection.isAddressBookCollection():
+ # For calendars only, per-user displayname and color
+ if displayname:
+ yield shareeCalender.writeProperty(element.DisplayName.fromString(displayname), request)
+
+ if isNewShare:
+ # For a direct share we will copy any calendar-color over using the owners view
+ if share.direct():
+ try:
+ color = yield sharedResource.readProperty(customxml.CalendarColor, request)
+ except HTTPError:
+ color = None
+ if color:
+ yield shareeCalender.writeProperty(customxml.CalendarColor.fromString(color), request)
+
+ # Calendars always start out transparent and with empty default alarms
+ yield shareeCalender._newStoreObject.setUsedForFreeBusy(False)
+ yield shareeCalender._newStoreObject.setDefaultAlarm("empty", True, True)
+ yield shareeCalender._newStoreObject.setDefaultAlarm("empty", True, False)
+ yield shareeCalender._newStoreObject.setDefaultAlarm("empty", False, True)
+ yield shareeCalender._newStoreObject.setDefaultAlarm("empty", False, False)
+
+ elif sharedResource.isAddressBookCollection():
shareeHomeResource = yield sharee.addressBookHome(request)
- shareeURL = joinURL(shareeHomeResource.url(), share.name())
- shareeCollection = yield request.locateResource(shareeURL)
- shareeCollection.setShare(share)
+ sharedAsURL = joinURL(shareeHomeResource.url(), share.ownerUID())
+ shareeAddressBook = yield request.locateResource(sharedAsURL)
+ shareeAddressBook.setShare(share)
- # Set per-user displayname or color to whatever was given
- if displayname:
- yield shareeCollection.writeProperty(element.DisplayName.fromString(displayname), request)
- if color:
- yield shareeCollection.writeProperty(customxml.CalendarColor.fromString(color), request)
+ elif sharedResource.isGroup():
+ shareeHomeResource = yield sharee.addressBookHome(request)
+ sharedAsURL = joinURL(shareeHomeResource.url(), share.ownerUID(), share.name())
+ shareeGroup = yield request.locateResource(sharedAsURL)
+ shareeGroup.setShare(share)
- # Calendars always start out transparent and with empty default alarms
- if isNewShare and shareeCollection.isCalendarCollection():
- yield shareeCollection._newStoreObject.setUsedForFreeBusy(False)
- yield shareeCollection._newStoreObject.setDefaultAlarm("empty", True, True)
- yield shareeCollection._newStoreObject.setDefaultAlarm("empty", True, False)
- yield shareeCollection._newStoreObject.setDefaultAlarm("empty", False, True)
- yield shareeCollection._newStoreObject.setDefaultAlarm("empty", False, False)
-
# Notify client of changes
yield self.notifyChanged()
@@ -1214,7 +1246,7 @@
returnValue(XMLResponse(
code=responsecode.OK,
element=customxml.SharedAs(
- element.HRef.fromString(joinURL(self.url(), share.name()))
+ element.HRef.fromString(sharedAsURL)
)
))
@@ -1255,15 +1287,15 @@
Remove a shared collection but do not send a decline back. Return the
current display name of the shared collection.
"""
-
+ #FIXME: This is only works for calendar
shareURL = joinURL(self.url(), share.name())
shared = (yield request.locateResource(shareURL))
displayname = shared.displayName()
if share.direct():
- yield share._sharerHomeChild.unshareWith(share._shareeHomeChild.viewerHome())
+ yield share._ownerStoreObject.unshareWith(share._shareeStoreObject.viewerHome())
else:
- yield share._sharerHomeChild.updateShare(share._shareeHomeChild, status=_BIND_STATUS_DECLINED)
+ yield share._ownerStoreObject.updateShare(share._shareeStoreObject, status=_BIND_STATUS_DECLINED)
returnValue(displayname)
@@ -1273,9 +1305,7 @@
# Remove it if it is in the DB
yield self.removeShareByUID(request, inviteUID)
-
yield self._changeShare(request, "DECLINED", hostUrl, inviteUID)
-
returnValue(Response(code=responsecode.NO_CONTENT))
@@ -1284,12 +1314,11 @@
"""
Accept or decline an invite to a shared collection.
"""
-
- # Change state in sharer invite
+ # Change state in owner invite
ownerPrincipal = (yield self.ownerPrincipal(request))
ownerPrincipalUID = ownerPrincipal.principalUID()
- sharedCollection = (yield request.locateResource(hostUrl))
- if sharedCollection is None:
+ sharedResource = (yield request.locateResource(hostUrl))
+ if sharedResource is None:
# Original shared collection is gone - nothing we can do except ignore it
raise HTTPError(ErrorResponse(
responsecode.FORBIDDEN,
@@ -1298,17 +1327,17 @@
))
# Change the record
- yield sharedCollection.changeUserInviteState(request, replytoUID, ownerPrincipalUID, state, displayname)
+ yield sharedResource.changeUserInviteState(request, replytoUID, ownerPrincipalUID, state, displayname)
- yield self.sendReply(request, ownerPrincipal, sharedCollection, state, hostUrl, replytoUID, displayname)
+ yield self.sendReply(request, ownerPrincipal, sharedResource, state, hostUrl, replytoUID, displayname)
@inlineCallbacks
- def sendReply(self, request, shareePrincipal, sharedCollection, state, hostUrl, replytoUID, displayname=None):
+ def sendReply(self, request, shareePrincipal, sharedResource, state, hostUrl, replytoUID, displayname=None):
- # Locate notifications collection for sharer
- sharer = (yield sharedCollection.ownerPrincipal(request))
- notificationResource = (yield request.locateResource(sharer.notificationURL()))
+ # Locate notifications collection for owner
+ owner = (yield sharedResource.ownerPrincipal(request))
+ notificationResource = (yield request.locateResource(owner.notificationURL()))
notifications = notificationResource._newStoreNotifications
# Generate invite XML
@@ -1349,7 +1378,9 @@
def _handleInviteReply(self, request, invitereplydoc):
- """ Handle a user accepting or declining a sharing invite """
+ """
+ Handle a user accepting or declining a sharing invite
+ """
hostUrl = None
accepted = None
summary = None
@@ -1380,14 +1411,13 @@
return self.declineShare(request, hostUrl, replytoUID)
-
class Share(object):
"""
A L{Share} represents information about a collection which has been shared
from one user to another.
"""
- def __init__(self, sharerHomeChild, shareeHomeChild, url):
+ def __init__(self, ownerStoreObject, shareeStoreObject, url):
"""
@param sharerHomeChild: The data store object representing the shared
collection as present in the owner's home collection; the owner's
@@ -1402,24 +1432,24 @@
@param url: The URL referring to the sharer's version of the resource.
@type url: L{bytes}
"""
- self._shareeHomeChild = shareeHomeChild
- self._sharerHomeChild = sharerHomeChild
- self._sharedResourceURL = url
+ self._shareeStoreObject = shareeStoreObject
+ self._ownerStoreObject = ownerStoreObject
+ self._ownerResourceURL = url
@classmethod
- def directUID(cls, shareeHome, sharerHomeChild):
+ def directUID(cls, shareeHome, ownerHomeChild):
return "Direct-%s-%s" % (shareeHome._resourceID,
- sharerHomeChild._resourceID,)
+ ownerHomeChild._resourceID,)
def uid(self):
# Move to CommonHomeChild shareUID?
- if self._shareeHomeChild.shareMode() == _BIND_MODE_DIRECT:
- return self.directUID(shareeHome=self._shareeHomeChild.viewerHome(),
- sharerHomeChild=self._sharerHomeChild,)
+ if self._shareeStoreObject.shareMode() == _BIND_MODE_DIRECT:
+ return self.directUID(shareeHome=self._shareeStoreObject.viewerHome(),
+ ownerHomeChild=self._ownerStoreObject,)
else:
- return self._shareeHomeChild.shareUID()
+ return self._shareeStoreObject.shareUID()
def direct(self):
@@ -1428,27 +1458,27 @@
@return: a boolean indicating whether it's direct.
"""
- return self._shareeHomeChild.shareMode() == _BIND_MODE_DIRECT
+ return self._shareeStoreObject.shareMode() == _BIND_MODE_DIRECT
def url(self):
"""
@return: The URL to the owner's version of the shared collection.
"""
- return self._sharedResourceURL
+ return self._ownerResourceURL
def name(self):
- return self._shareeHomeChild.name()
+ return self._shareeStoreObject.name()
def summary(self):
- return self._shareeHomeChild.shareMessage()
+ return self._shareeStoreObject.shareMessage()
def shareeUID(self):
- return self._shareeHomeChild.viewerHome().uid()
+ return self._shareeStoreObject.viewerHome().uid()
def ownerUID(self):
- return self._sharerHomeChild.ownerHome().uid()
+ return self._shareeStoreObject.ownerHome().uid()
Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -60,6 +60,8 @@
InvalidPerUserDataMerge, \
AttendeeAllowedError, ResourceDeletedError, InvalidAttachmentOperation, \
ShareeAllowedError
+from txdav.carddav.iaddressbookstore import GroupWithUnsharedAddressNotAllowedError, \
+ GroupForSharedAddressBookDeleteNotAllowedError, SharedGroupDeleteNotAllowedError
from txdav.common.datastore.sql_tables import _BIND_MODE_READ, _BIND_MODE_WRITE, \
_BIND_MODE_DIRECT
from txdav.common.icommondatastore import NoSuchObjectResourceError, \
@@ -272,7 +274,7 @@
def owner_url(self):
- if self.isShareeCollection():
+ if self.isShareeResource():
return joinURL(self._share.url(), "/")
else:
return self.url()
@@ -443,14 +445,6 @@
@type request: L{twext.web2.iweb.IRequest}
- @param viaRequest: Indicates if the delete was a direct result of an http_DELETE
- which for calendars at least will require implicit cancels to be sent.
-
- @type request: C{bool}
-
- @param where: the URI at which the resource is being deleted.
- @type where: C{str}
-
@return: an HTTP response suitable for sending to a client (or
including in a multi-status).
@@ -458,8 +452,7 @@
"""
# Check sharee collection first
- isShareeCollection = self.isShareeCollection()
- if isShareeCollection:
+ if self.isShareeResource():
log.debug("Removing shared collection %s" % (self,))
yield self.removeShareeCollection(request)
returnValue(NO_CONTENT)
@@ -1083,7 +1076,7 @@
def resourceType(self):
if self.isShared():
return customxml.ResourceType.sharedownercalendar
- elif self.isShareeCollection():
+ elif self.isShareeResource():
return customxml.ResourceType.sharedcalendar
else:
return caldavxml.ResourceType.calendar
@@ -1414,7 +1407,7 @@
def resourceType(self,):
- return davxml.ResourceType.dropboxhome # @UndefinedVariable
+ return davxml.ResourceType.dropboxhome # @UndefinedVariable
def listChildren(self):
@@ -1466,7 +1459,7 @@
def resourceType(self):
- return davxml.ResourceType.dropbox # @UndefinedVariable
+ return davxml.ResourceType.dropbox # @UndefinedVariable
@inlineCallbacks
@@ -1711,7 +1704,7 @@
def resourceType(self,):
- return davxml.ResourceType.dropboxhome # @UndefinedVariable
+ return davxml.ResourceType.dropboxhome # @UndefinedVariable
def listChildren(self):
@@ -1814,7 +1807,7 @@
def resourceType(self,):
- return davxml.ResourceType.dropbox # @UndefinedVariable
+ return davxml.ResourceType.dropbox # @UndefinedVariable
@inlineCallbacks
@@ -2006,7 +1999,7 @@
def __init__(self, calendarObject, attachment, attachmentName, managed, **kw):
super(CalendarAttachment, self).__init__(**kw)
- self._newStoreCalendarObject = calendarObject # This can be None for a managed attachment
+ self._newStoreCalendarObject = calendarObject # This can be None for a managed attachment
self._newStoreAttachment = self._newStoreObject = attachment
self._managed = managed
self._dead_properties = NonePropertyStore(self)
@@ -2925,16 +2918,13 @@
def isAddressBookCollection(self):
- """
- Yes, it is a calendar collection.
- """
return True
def resourceType(self):
if self.isShared():
return customxml.ResourceType.sharedowneraddressbook
- elif self.isShareeCollection():
+ elif self.isShareeResource():
return customxml.ResourceType.sharedaddressbook
else:
return carddavxml.ResourceType.addressbook
@@ -2970,7 +2960,7 @@
else:
returnValue(None)
-
+ ''' DELETE just re-creates addressbook
@inlineCallbacks
def storeRemove(self, request):
"""
@@ -3007,27 +2997,17 @@
)
returnValue(response)
+ '''
- # FIXME: access control
- @inlineCallbacks
def http_MOVE(self, request):
"""
- Moving an address book collection is allowed for the purposes of changing
- that address book's name.
+ Addressbooks may not be renamed.
"""
- defaultAddressBook = (yield self.isDefaultAddressBook(request))
+ return FORBIDDEN
- result = (yield super(AddressBookCollectionResource, self).http_MOVE(request))
- if result == NO_CONTENT:
- destinationURI = urlsplit(request.headers.getHeader("destination"))[2]
- destination = yield request.locateResource(destinationURI)
- yield self.movedAddressBook(request, defaultAddressBook,
- destination, destinationURI)
- returnValue(result)
-
class GlobalAddressBookCollectionResource(GlobalAddressBookResource, AddressBookCollectionResource):
"""
Wrapper around a L{txdav.carddav.iaddressbook.IAddressBook}.
@@ -3079,7 +3059,35 @@
InvalidResourceMove: (calendarserver_namespace, "valid-move"),
}
+
+ def resourceType(self):
+ if self.isShared():
+ return customxml.ResourceType.sharedownergroup
+ elif self.isShareeResource():
+ return customxml.ResourceType.sharedgroup
+ else:
+ return super(AddressBookObjectResource, self).resourceType()
+
+
@inlineCallbacks
+ def storeRemove(self, request):
+ """
+ Remove this address book object
+ """
+ # Handle sharing
+ if self.isShared():
+ yield self.downgradeFromShare(request)
+
+ response = (
+ yield super(AddressBookObjectResource, self).storeRemove(
+ request
+ )
+ )
+
+ returnValue(response)
+
+
+ @inlineCallbacks
def http_PUT(self, request):
# Content-type check
@@ -3167,6 +3175,12 @@
returnValue(response)
# Handle the various store errors
+ except GroupWithUnsharedAddressNotAllowedError:
+ raise HTTPError(StatusResponse(
+ FORBIDDEN,
+ "Sharee cannot add unshared group members",)
+ )
+
except Exception as err:
if isinstance(err, ValueError):
@@ -3176,7 +3190,87 @@
raise
+ @inlineCallbacks
+ def http_DELETE(self, request):
+ try:
+ returnValue((yield super(AddressBookObjectResource, self).http_DELETE(request)))
+
+ except GroupForSharedAddressBookDeleteNotAllowedError:
+ raise HTTPError(StatusResponse(
+ FORBIDDEN,
+ "Sharee cannot delete the group for a shared address book",)
+ )
+
+ except SharedGroupDeleteNotAllowedError:
+ raise HTTPError(StatusResponse(
+ FORBIDDEN,
+ "Sharee cannot delete a shared group",)
+ )
+
+ @inlineCallbacks
+ def accessControlList(self, request, *a, **kw):
+ """
+ Return WebDAV ACLs appropriate for the current user accessing the
+ a vcard in a shared addressbook or shared group.
+
+ Items in an "invite" share get read-onlly privileges.
+ (It's not clear if that case ever occurs)
+
+ "direct" shares are not supported.
+
+ @param request: the request used to locate the owner resource.
+ @type request: L{twext.web2.iweb.IRequest}
+
+ @param args: The arguments for
+ L{twext.web2.dav.idav.IDAVResource.accessControlList}
+
+ @param kwargs: The keyword arguments for
+ L{twext.web2.dav.idav.IDAVResource.accessControlList}, plus
+ keyword-only arguments.
+
+ @return: the appropriate WebDAV ACL for the sharee
+ @rtype: L{davxml.ACL}
+ """
+ if not self.exists():
+ log.debug("Resource not found: %s" % (self,))
+ raise HTTPError(NOT_FOUND)
+
+ if self._newStoreObject.addressbook().owned():
+ returnValue((yield super(AddressBookObjectResource, self).accessControlList(request, *a, **kw)))
+
+ # Direct shares use underlying privileges of shared collection
+ userprivs = []
+ userprivs.append(davxml.Privilege(davxml.Read()))
+ userprivs.append(davxml.Privilege(davxml.ReadACL()))
+ userprivs.append(davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()))
+
+ if (yield self._newStoreObject.readWriteAccess()):
+ userprivs.append(davxml.Privilege(davxml.Write()))
+ else:
+ userprivs.append(davxml.Privilege(davxml.WriteProperties()))
+
+ sharee = self.principalForUID(self._newStoreObject.viewerHome().uid())
+ aces = (
+ # Inheritable specific access for the resource's associated principal.
+ davxml.ACE(
+ davxml.Principal(davxml.HRef(sharee.principalURL())),
+ davxml.Grant(*userprivs),
+ davxml.Protected(),
+ TwistedACLInheritable(),
+ ),
+ )
+
+ # Give read access to config.ReadPrincipals
+ aces += config.ReadACEs
+
+ # Give all access to config.AdminPrincipals
+ aces += config.AdminACEs
+
+ returnValue(davxml.ACL(*aces))
+
+
+
class _NotificationChildHelper(object):
"""
Methods for things which are like notification objects.
Modified: CalendarServer/trunk/twistedcaldav/test/test_addressbookmultiget.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_addressbookmultiget.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twistedcaldav/test/test_addressbookmultiget.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -46,7 +46,7 @@
baduids = ["12345%40example.com", "67890%40example.com"]
- return self.simple_vcard_multiget("/addressbook_multiget_vcards/", okuids, baduids)
+ return self.simple_vcard_multiget("/addressbook/", okuids, baduids)
def test_multiget_all_vcards(self):
@@ -57,7 +57,7 @@
baduids = ["12345%40example.com", "67890%40example.com"]
- return self.simple_vcard_multiget("/addressbook_multiget_vcards/", okuids, baduids)
+ return self.simple_vcard_multiget("/addressbook/", okuids, baduids)
def test_multiget_limited_with_data(self):
@@ -78,7 +78,7 @@
baduids = ["12345%40example.com", "67890%40example.com"]
- d = self.simple_vcard_multiget("/addressbook_multiget_vcards/", okuids, baduids)
+ d = self.simple_vcard_multiget("/addressbook/", okuids, baduids)
d.addCallbacks(_restoreValueOK, _restoreValueError)
return d
@@ -101,7 +101,7 @@
baduids = ["12345%40example.com", "67890%40example.com"]
- return self.simple_vcard_multiget("/addressbook_multiget_vcards/", okuids, baduids, withData=False)
+ return self.simple_vcard_multiget("/addressbook/", okuids, baduids, withData=False)
def simple_vcard_multiget(self, vcard_uri, okuids, baduids, data=None, no_init=False, withData=True):
@@ -195,6 +195,7 @@
def addressbook_query(self, addressbook_uri, query, got_xml, data, no_init):
if not no_init:
+ ''' FIXME: clear address book, possibly by removing
mkcol = """<?xml version="1.0" encoding="utf-8" ?>
<D:mkcol xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
<D:set>
@@ -210,7 +211,7 @@
if response.code != responsecode.CREATED:
self.fail("MKCOL failed: %s" % (response.code,))
-
+ '''
if data:
for filename, icaldata in data.iteritems():
request = SimpleStoreRequest(self, "PUT", joinURL(addressbook_uri, filename + ".vcf"), authid="wsanchez")
Modified: CalendarServer/trunk/twistedcaldav/test/test_addressbookquery.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_addressbookquery.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twistedcaldav/test/test_addressbookquery.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -42,7 +42,7 @@
uid = "ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1:ABPerson"
return self.simple_vcard_query(
- "/addressbook_query_uid/",
+ "/addressbook/",
carddavxml.PropertyFilter(
carddavxml.TextMatch.fromString(uid),
name="UID",
@@ -57,7 +57,7 @@
"""
uids = [r[0] for r in (os.path.splitext(f) for f in os.listdir(self.vcards_dir)) if r[1] == ".vcf"]
- return self.simple_vcard_query("/addressbook_query_vcards/", None, uids)
+ return self.simple_vcard_query("/addressbook/", None, uids)
def test_addressbook_query_limited_with_data(self):
@@ -77,7 +77,7 @@
uids = [r[0] for r in (os.path.splitext(f) for f in os.listdir(self.vcards_dir)) if r[1] == ".vcf"]
- d = self.simple_vcard_query("/addressbook_query_vcards/", None, uids, limit=1)
+ d = self.simple_vcard_query("/addressbook/", None, uids, limit=1)
d.addCallbacks(_restoreValueOK, _restoreValueError)
return d
@@ -99,7 +99,7 @@
uids = [r[0] for r in (os.path.splitext(f) for f in os.listdir(self.vcards_dir)) if r[1] == ".vcf"]
- d = self.simple_vcard_query("/addressbook_query_vcards/", None, uids, withData=False)
+ d = self.simple_vcard_query("/addressbook/", None, uids, withData=False)
d.addCallbacks(_restoreValueOK, _restoreValueError)
return d
@@ -174,7 +174,7 @@
@inlineCallbacks
def addressbook_query(self, addressbook_uri, query, got_xml):
-
+ ''' FIXME: clear address book, possibly by removing
mkcol = """<?xml version="1.0" encoding="utf-8" ?>
<D:mkcol xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav">
<D:set>
@@ -190,7 +190,7 @@
if response.code != responsecode.CREATED:
self.fail("MKCOL failed: %s" % (response.code,))
-
+ '''
# Add vCards to addressbook
for child in FilePath(self.vcards_dir).children():
if os.path.splitext(child.basename())[1] != ".vcf":
Modified: CalendarServer/trunk/twistedcaldav/test/test_resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_resource.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twistedcaldav/test/test_resource.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -188,7 +188,7 @@
@inlineCallbacks
def test_pick_default_addressbook(self):
"""
- Make calendar
+ Get adbk
"""
request = SimpleStoreRequest(self, "GET", "/addressbooks/users/wsanchez/", authid="wsanchez")
@@ -213,63 +213,13 @@
@inlineCallbacks
- def test_pick_default_other(self):
- """
- Make adbk
- """
-
- request = SimpleStoreRequest(self, "GET", "/addressbooks/users/wsanchez/", authid="wsanchez")
- home = yield request.locateResource("/addressbooks/users/wsanchez")
-
- # default property not present
- try:
- home.readDeadProperty(carddavxml.DefaultAddressBookURL)
- except HTTPError:
- pass
- else:
- self.fail("carddavxml.DefaultAddressBookURL is not empty")
-
- # Create a new default adbk
- newadbk = yield request.locateResource("/addressbooks/users/wsanchez/newadbk")
- yield newadbk.createAddressBookCollection()
- home.writeDeadProperty(carddavxml.DefaultAddressBookURL(
- HRef("/addressbooks/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newadbk/")
- ))
-
- # Delete the normal adbk
- request = SimpleStoreRequest(self, "GET", "/addressbooks/users/wsanchez/", authid="wsanchez")
- home = yield request.locateResource("/addressbooks/users/wsanchez")
- adbk = yield request.locateResource("/addressbooks/users/wsanchez/addressbook")
- yield adbk.storeRemove(request)
-
- home.removeDeadProperty(carddavxml.DefaultAddressBookURL)
-
- # default property not present
- try:
- home.readDeadProperty(carddavxml.DefaultAddressBookURL)
- except HTTPError:
- pass
- else:
- self.fail("carddavxml.DefaultAddressBookURL is not empty")
-
- yield self.commit()
-
- request = SimpleStoreRequest(self, "GET", "/addressbooks/users/wsanchez/", authid="wsanchez")
- home = yield request.locateResource("/addressbooks/users/wsanchez")
- yield home.pickNewDefaultAddressBook(request)
-
- try:
- default = home.readDeadProperty(carddavxml.DefaultAddressBookURL)
- except HTTPError:
- self.fail("carddavxml.DefaultAddressBookURL is not present")
- else:
- self.assertEqual(str(default.children[0]), "/addressbooks/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newadbk/")
-
-
- @inlineCallbacks
def test_fix_shared_default(self):
+ # I think this would include a test of http_GET()
+ raise NotImplementedError()
+ test_fix_shared_default.todo = "Rewrite with real shared address book"
+ '''
"""
- Make calendar
+ Get adbk
"""
request = SimpleStoreRequest(self, "GET", "/addressbooks/users/wsanchez/", authid="wsanchez")
@@ -289,7 +239,7 @@
self.assertEqual(str(default.children[0]), "/addressbooks/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newadbk/")
# Force the new calendar to think it is a sharee collection
- newadbk._isShareeCollection = True
+ newadbk._isShareeResource = True
try:
default = yield home.readProperty(carddavxml.DefaultAddressBookURL, request)
@@ -297,3 +247,4 @@
self.fail("carddavxml.DefaultAddressBookURL is not present")
else:
self.assertEqual(str(default.children[0]), "/addressbooks/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/addressbook/")
+ '''
Modified: CalendarServer/trunk/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_sharing.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twistedcaldav/test/test_sharing.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -231,8 +231,8 @@
self.assertEquals(rtype, regularCalendarType)
isShared = self.resource.isShared()
self.assertFalse(isShared)
- isShareeCollection = self.resource.isShareeCollection()
- self.assertFalse(isShareeCollection)
+ isShareeResource = self.resource.isShareeResource()
+ self.assertFalse(isShareeResource)
yield self.resource.upgradeToShare()
@@ -240,8 +240,8 @@
self.assertEquals(rtype, sharedOwnerType)
isShared = self.resource.isShared()
self.assertTrue(isShared)
- isShareeCollection = self.resource.isShareeCollection()
- self.assertFalse(isShareeCollection)
+ isShareeResource = self.resource.isShareeResource()
+ self.assertFalse(isShareeResource)
@inlineCallbacks
@@ -253,8 +253,8 @@
self.assertEquals(rtype, sharedOwnerType)
isShared = self.resource.isShared()
self.assertTrue(isShared)
- isShareeCollection = self.resource.isShareeCollection()
- self.assertFalse(isShareeCollection)
+ isShareeResource = self.resource.isShareeResource()
+ self.assertFalse(isShareeResource)
yield self.resource.downgradeFromShare(None)
@@ -262,8 +262,8 @@
self.assertEquals(rtype, regularCalendarType)
isShared = self.resource.isShared()
self.assertFalse(isShared)
- isShareeCollection = self.resource.isShareeCollection()
- self.assertFalse(isShareeCollection)
+ isShareeResource = self.resource.isShareeResource()
+ self.assertFalse(isShareeResource)
@inlineCallbacks
@@ -294,8 +294,8 @@
isShared = self.resource.isShared()
self.assertTrue(isShared)
- isShareeCollection = self.resource.isShareeCollection()
- self.assertFalse(isShareeCollection)
+ isShareeResource = self.resource.isShareeResource()
+ self.assertFalse(isShareeResource)
@inlineCallbacks
@@ -324,8 +324,8 @@
isShared = self.resource.isShared()
self.assertTrue(isShared)
- isShareeCollection = (yield self.resource.isShareeCollection())
- self.assertFalse(isShareeCollection)
+ isShareeResource = (yield self.resource.isShareeResource())
+ self.assertFalse(isShareeResource)
@inlineCallbacks
@@ -752,7 +752,7 @@
@inlineCallbacks
def test_noWikiAccess(self):
"""
- If L{SharedCollectionMixin.shareeAccessControlList} detects missing
+ If L{SharedResourceMixin.shareeAccessControlList} detects missing
access controls for a directly shared collection, it will automatically
un-share that collection.
"""
Modified: CalendarServer/trunk/twistedcaldav/test/test_wrapping.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_wrapping.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twistedcaldav/test/test_wrapping.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -32,7 +32,7 @@
from twistedcaldav.vcard import Component as VCComponent
from twistedcaldav.storebridge import DropboxCollection, \
- CalendarCollectionResource, AddressBookCollectionResource
+ CalendarCollectionResource
from twistedcaldav.test.util import StoreTestCase, SimpleStoreRequest
@@ -55,8 +55,11 @@
from twisted.internet.defer import maybeDeferred
from txdav.caldav.datastore.file import Calendar
+def _todo(f, why):
+ f.todo = why
+ return f
+rewriteOrRemove = lambda f: _todo(f, "Rewrite or remove")
-
class FakeChanRequest(object):
code = 'request-not-finished'
@@ -444,24 +447,6 @@
@inlineCallbacks
- def test_lookupNewAddressBook(self):
- """
- When a L{CalDAVResource} which represents a not-yet-created addressbook
- collection is looked up in a L{AddressBookHomeFile} representing a addressbook
- home, it will initially have a new storage backend set to C{None}, but
- when the addressbook is created via a protocol action, the backend will be
- initialized to match.
- """
- calDavFile = yield self.getResource("addressbooks/users/wsanchez/frobozz")
- self.assertIsInstance(calDavFile, AddressBookCollectionResource)
- self.assertFalse(calDavFile.exists())
- yield calDavFile.createAddressBookCollection()
- self.assertTrue(calDavFile.exists())
- yield self.commit()
- self.checkPrincipalCollections(calDavFile)
-
-
- @inlineCallbacks
def test_lookupAddressBookObject(self):
"""
When a L{CalDAVResource} representing an existing addressbook object is looked
Modified: CalendarServer/trunk/twistedcaldav/vcard.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/vcard.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/twistedcaldav/vcard.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -104,7 +104,7 @@
@return: the duplicated vcard.
"""
return Property(None, None, params=None, pycard=self._pycard.duplicate())
-
+
def name (self): return self._pycard.getName()
def value (self): return self._pycard.getValue().getValue()
@@ -144,7 +144,7 @@
attrs = self._pycard.getAttributes()[name.upper()]
except KeyError:
return []
-
+
for attr in attrs:
results.extend(attr.getValues())
return results
@@ -162,7 +162,7 @@
self._pycard.setAttributes({})
def removeParameterValue(self, paramname, paramvalue):
-
+
paramname = paramname.upper()
for attrName in self.parameterNames():
if attrName.upper() == paramname:
@@ -188,7 +188,7 @@
else:
# Valid utf-8 please
string.decode("utf-8")
-
+
# No BOMs please
if string[:3] == codecs.BOM_UTF8:
string = string[3:]
@@ -222,7 +222,7 @@
else:
# Valid utf-8 please
string.decode("utf-8")
-
+
# No BOMs please
if string[:3] == codecs.BOM_UTF8:
string = string[3:]
@@ -288,11 +288,11 @@
# even though it's names as a private variable.
if "parent" in kwargs:
parent = kwargs["parent"]
-
+
if parent is not None:
if not isinstance(parent, Component):
raise TypeError("Not a Component: %r" % (parent,))
-
+
self._parent = parent
else:
self._parent = None
@@ -317,7 +317,7 @@
# FIXME: Should this not be in __eq__?
def same(self, other):
return self._pycard == other._pycard
-
+
def name(self):
"""
@return: the name of the iCalendar type of this component.
@@ -330,7 +330,7 @@
@return: the duplicated vcard.
"""
return Component(None, pycard=self._pycard.duplicate())
-
+
def hasProperty(self, name):
"""
@param name: the name of the property whose existence is being tested.
@@ -349,7 +349,7 @@
if len(properties) == 1: return properties[0]
if len(properties) > 1: raise InvalidVCardDataError("More than one %s property in component %r" % (name, self))
return None
-
+
def properties(self, name=None):
"""
@param name: if given and not C{None}, restricts the returned properties
@@ -393,12 +393,19 @@
self._pycard.removeProperty(property._pycard)
self._pycard.finalise()
+ def removeProperties(self, name):
+ """
+ remove all properties with name
+ @param name: the name of the properties to remove.
+ """
+ self._pycard.removeProperties(name)
+
def replaceProperty(self, property):
"""
Add or replace a property in this component.
@param property: the L{Property} to add or replace in this component.
"""
-
+
# Remove all existing ones first
self._pycard.removeProperties(property.name())
self.addProperty(property)
@@ -414,6 +421,25 @@
return self._resource_uid
+ def resourceKind(self):
+ """
+ @return: the kind of the subcomponents in this component.
+ """
+ assert self.name() == "VCARD", "Not a vcard: %r" % (self,)
+
+ if not hasattr(self, "_resource_kind"):
+ self._resource_kind = self.propertyValue("X-ADDRESSBOOKSERVER-KIND")
+
+ return self._resource_kind
+
+ def resourceMemberAddresses(self):
+ """
+ @return: an iterable of X-ADDRESSBOOKSERVER-MEMBER property values
+ """
+ assert self.name() == "VCARD", "Not a vcard: %r" % (self,)
+
+ return [prop.value() for prop in list(self.properties("X-ADDRESSBOOKSERVER-MEMBER"))]
+
def validVCardData(self, doFix=True, doRaise=True):
"""
@return: tuple of fixed, unfixed issues
@@ -431,7 +457,7 @@
raise InvalidVCardDataError("Calendar data had unfixable problems:\n %s" % ("\n ".join(unfixed),))
if fixed:
log.debug("vCard data had fixable problems:\n %s" % ("\n ".join(fixed),))
-
+
return fixed, unfixed
def validForCardDAV(self):
@@ -447,7 +473,7 @@
uid = self.propertyValue("UID")
if uid is None:
raise InvalidVCardDataError("All vCards must have UIDs")
-
+
# Control character check - only HTAB, CR, LF allowed for characters in the range 0x00-0x1F
s = str(self)
if len(s.translate(None, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F")) != len(s):
Modified: CalendarServer/trunk/txdav/base/propertystore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/sql.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/base/propertystore/sql.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -304,10 +304,11 @@
prop, Where=(prop.RESOURCE_ID == Parameter("resourceID"))
)
+ @inlineCallbacks
def _removeResource(self):
self._cached = {}
- self._deleteResourceQuery.on(self._txn, resourceID=self._resourceID)
+ yield self._deleteResourceQuery.on(self._txn, resourceID=self._resourceID)
self._cacher.delete(str(self._resourceID))
Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -78,12 +78,8 @@
CommonObjectResource, ECALENDARTYPE
from txdav.common.datastore.sql_legacy import PostgresLegacyIndexEmulator, \
PostgresLegacyInboxIndexEmulator
-from txdav.common.datastore.sql_tables import CALENDAR_TABLE, \
- CALENDAR_BIND_TABLE, CALENDAR_OBJECT_REVISIONS_TABLE, CALENDAR_OBJECT_TABLE, \
- _ATTACHMENTS_MODE_NONE, _ATTACHMENTS_MODE_WRITE, \
- CALENDAR_HOME_TABLE, CALENDAR_HOME_METADATA_TABLE, \
- CALENDAR_AND_CALENDAR_BIND, CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE, \
- CALENDAR_OBJECT_AND_BIND_TABLE, schema, _BIND_MODE_OWN, \
+from txdav.common.datastore.sql_tables import _ATTACHMENTS_MODE_NONE, \
+ _ATTACHMENTS_MODE_WRITE, schema, _BIND_MODE_OWN, \
_ATTACHMENTS_MODE_READ, _TRANSP_OPAQUE, _TRANSP_TRANSPARENT
from txdav.common.icommondatastore import IndexedSearchException, \
InternalDataStoreError, HomeChildNameAlreadyExistsError, \
@@ -326,15 +322,7 @@
_revisionsSchema = schema.CALENDAR_OBJECT_REVISIONS
_objectSchema = schema.CALENDAR_OBJECT
- # string mappings (old, removing)
- _homeTable = CALENDAR_HOME_TABLE
- _homeMetaDataTable = CALENDAR_HOME_METADATA_TABLE
- _childTable = CALENDAR_TABLE
- _bindTable = CALENDAR_BIND_TABLE
- _objectBindTable = CALENDAR_OBJECT_AND_BIND_TABLE
_notifierPrefix = "CalDAV"
- _revisionsTable = CALENDAR_OBJECT_REVISIONS_TABLE
-
_dataVersionKey = "CALENDAR-DATAVERSION"
_cacher = Memcacher("SQL.calhome", pickle=True, key_normalization=False)
@@ -849,14 +837,6 @@
_objectSchema = schema.CALENDAR_OBJECT
_timeRangeSchema = schema.TIME_RANGE
- # string mappings (old, removing)
- _bindTable = CALENDAR_BIND_TABLE
- _homeChildTable = CALENDAR_TABLE
- _homeChildBindTable = CALENDAR_AND_CALENDAR_BIND
- _revisionsTable = CALENDAR_OBJECT_REVISIONS_TABLE
- _revisionsBindTable = CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE
- _objectTable = CALENDAR_OBJECT_TABLE
-
_supportedComponents = None
def __init__(self, *args, **kw):
@@ -1285,7 +1265,7 @@
@classproperty
- def _moveTimeRangeUpdateQuery(cls): # @NoSelf
+ def _moveTimeRangeUpdateQuery(cls): # @NoSelf
"""
DAL query to update a child to be in a new parent.
"""
@@ -1308,13 +1288,6 @@
)
- def unshare(self):
- """
- Unshares a collection, regardless of which "direction" it was shared.
- """
- return super(Calendar, self).unshare(ECALENDARTYPE)
-
-
def creatingResourceCheckAttachments(self, component):
"""
When component data is created or changed we need to look for changes related to managed attachments.
@@ -1358,7 +1331,6 @@
class CalendarObject(CommonObjectResource, CalendarObjectBase):
implements(ICalendarObject)
- _objectTable = CALENDAR_OBJECT_TABLE
_objectSchema = schema.CALENDAR_OBJECT
def __init__(self, calendar, name, uid, resourceID=None, options=None):
@@ -2479,7 +2451,7 @@
@classproperty
- def _recurrenceMinMaxByIDQuery(cls): # @NoSelf
+ def _recurrenceMinMaxByIDQuery(cls): # @NoSelf
"""
DAL query to load RECURRANCE_MIN, RECURRANCE_MAX via an object's resource ID.
"""
@@ -2513,7 +2485,7 @@
@classproperty
- def _instanceQuery(cls): # @NoSelf
+ def _instanceQuery(cls): # @NoSelf
"""
DAL query to load TIME_RANGE data via an object's resource ID.
"""
@@ -3024,11 +2996,11 @@
# We need to know the resource_ID of the home collection of the owner
# (not sharee) of this event
- sharerHomeID = (yield self._parentCollection.sharerHomeID())
+ ownerHomeID = (yield self._parentCollection.ownerHome().id())
managedID = str(uuid.uuid4())
returnValue((
yield ManagedAttachment.create(
- self._txn, managedID, sharerHomeID, self._resourceID,
+ self._txn, managedID, ownerHomeID, self._resourceID,
)
))
@@ -3038,10 +3010,10 @@
# We need to know the resource_ID of the home collection of the owner
# (not sharee) of this event
- sharerHomeID = (yield self._parentCollection.sharerHomeID())
+ ownerHomeID = (yield self._parentCollection.ownerHome().id())
returnValue((
yield ManagedAttachment.update(
- self._txn, managedID, sharerHomeID, self._resourceID, oldattachment._attachmentID,
+ self._txn, managedID, ownerHomeID, self._resourceID, oldattachment._attachmentID,
)
))
@@ -3100,11 +3072,11 @@
# We need to know the resource_ID of the home collection of the owner
# (not sharee) of this event
- sharerHomeID = (yield self._parentCollection.sharerHomeID())
+ ownerHomeID = (yield self._parentCollection.ownerHome().id())
dropboxID = (yield self.dropboxID())
returnValue((
yield DropBoxAttachment.create(
- self._txn, dropboxID, name, sharerHomeID,
+ self._txn, dropboxID, name, ownerHomeID,
)
))
@@ -3349,7 +3321,7 @@
def properties(self):
- pass # stub
+ pass # stub
def store(self, contentType, dispositionName=None):
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1727,13 +1727,13 @@
normalCal = yield self.calendarUnderTest()
self.assertEqual(normalCal._bindRevision, 0)
otherHome = yield self.homeUnderTest(name=OTHER_HOME_UID)
- otherCal = yield Calendar.invitedObjectWithName(otherHome, newCalName)
+ otherCal = yield otherHome.invitedObjectWithShareUID(newCalName)
self.assertEqual(otherCal._bindRevision, 0)
yield self.commit()
normalCal = yield self.calendarUnderTest()
otherHome = yield self.homeUnderTest(name=OTHER_HOME_UID)
- otherCal = yield Calendar.invitedObjectWithName(otherHome, newCalName)
+ otherCal = yield otherHome.invitedObjectWithShareUID(newCalName)
yield normalCal.updateShare(otherCal, status=_BIND_STATUS_ACCEPTED)
yield self.commit()
Modified: CalendarServer/trunk/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/sql.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/sql.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -25,37 +25,43 @@
"AddressBookObject",
]
-from twext.enterprise.dal.syntax import Delete
-from twext.enterprise.dal.syntax import Insert
-from twext.enterprise.dal.syntax import Update
-from twext.enterprise.dal.syntax import utcNowSQL
+from uuid import uuid4
+
+from twext.enterprise.dal.syntax import Delete, Insert, Len, Parameter, \
+ Update, Union, Max, Select, utcNowSQL
from twext.enterprise.locking import NamedLock
+from twext.python.clsprop import classproperty
+from twext.web2.http import HTTPError
from twext.web2.http_headers import MimeType
+from twext.web2.responsecode import FORBIDDEN
from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.python import hashlib
-
from twistedcaldav import carddavxml, customxml
from twistedcaldav.config import config
from twistedcaldav.memcacher import Memcacher
-from twistedcaldav.vcard import Component as VCard, InvalidVCardDataError
+from twistedcaldav.vcard import Component as VCard, InvalidVCardDataError, \
+ vCardProductID, Property
from txdav.base.propertystore.base import PropertyName
+from txdav.base.propertystore.sql import PropertyStore
from txdav.carddav.iaddressbookstore import IAddressBookHome, IAddressBook, \
- IAddressBookObject
+ IAddressBookObject, GroupForSharedAddressBookDeleteNotAllowedError, \
+ GroupWithUnsharedAddressNotAllowedError, SharedGroupDeleteNotAllowedError
from txdav.common.datastore.sql import CommonHome, CommonHomeChild, \
- CommonObjectResource, EADDRESSBOOKTYPE
+ CommonObjectResource, EADDRESSBOOKTYPE, SharingMixIn
from txdav.common.datastore.sql_legacy import PostgresLegacyABIndexEmulator
-from txdav.common.datastore.sql_tables import ADDRESSBOOK_TABLE, \
- ADDRESSBOOK_BIND_TABLE, ADDRESSBOOK_OBJECT_REVISIONS_TABLE, \
- ADDRESSBOOK_OBJECT_TABLE, ADDRESSBOOK_HOME_TABLE, \
- ADDRESSBOOK_HOME_METADATA_TABLE, ADDRESSBOOK_AND_ADDRESSBOOK_BIND, \
- ADDRESSBOOK_OBJECT_AND_BIND_TABLE, \
- ADDRESSBOOK_OBJECT_REVISIONS_AND_BIND_TABLE, schema
+from txdav.common.datastore.sql_tables import _ABO_KIND_PERSON, \
+ _ABO_KIND_GROUP, _ABO_KIND_RESOURCE, _ABO_KIND_LOCATION, schema, \
+ _BIND_MODE_OWN, _BIND_MODE_WRITE, _BIND_STATUS_ACCEPTED, \
+ _BIND_STATUS_DECLINED, _BIND_STATUS_INVITED
from txdav.common.icommondatastore import InternalDataStoreError, \
InvalidUIDError, UIDExistsError, ObjectResourceTooBigError, \
- InvalidObjectResourceError, InvalidComponentForStoreError
+ InvalidObjectResourceError, InvalidComponentForStoreError, \
+ AllRetriesFailed
+from txdav.xml.rfc2518 import ResourceType
+
from zope.interface.declarations import implements
@@ -66,29 +72,28 @@
# structured tables. (new, preferred)
_homeSchema = schema.ADDRESSBOOK_HOME
- _bindSchema = schema.ADDRESSBOOK_BIND
+ _bindSchema = schema.SHARED_ADDRESSBOOK_BIND
_homeMetaDataSchema = schema.ADDRESSBOOK_HOME_METADATA
_revisionsSchema = schema.ADDRESSBOOK_OBJECT_REVISIONS
_objectSchema = schema.ADDRESSBOOK_OBJECT
- # string mappings (old, removing)
- _homeTable = ADDRESSBOOK_HOME_TABLE
- _homeMetaDataTable = ADDRESSBOOK_HOME_METADATA_TABLE
- _childTable = ADDRESSBOOK_TABLE
- _bindTable = ADDRESSBOOK_BIND_TABLE
- _objectBindTable = ADDRESSBOOK_OBJECT_AND_BIND_TABLE
_notifierPrefix = "CardDAV"
- _revisionsTable = ADDRESSBOOK_OBJECT_REVISIONS_TABLE
-
_dataVersionKey = "ADDRESSBOOK-DATAVERSION"
-
_cacher = Memcacher("SQL.adbkhome", pickle=True, key_normalization=False)
+
def __init__(self, transaction, ownerUID):
self._childClass = AddressBook
super(AddressBookHome, self).__init__(transaction, ownerUID)
+ self._addressbookPropertyStoreID = None
+ self._addressbook = None
+
+ def __repr__(self):
+ return '<%s: %s("%s")>' % (self.__class__.__name__, self._resourceID, self.name())
+
+
addressbooks = CommonHome.children
listAddressbooks = CommonHome.listChildren
loadAddressbooks = CommonHome.loadChildren
@@ -97,46 +102,244 @@
removeAddressBookWithName = CommonHome.removeChildWithName
+ @classproperty
+ def _resourceIDAndHomeResourceIDFromOwnerQuery(cls): #@NoSelf
+ home = cls._homeSchema
+ return Select([home.RESOURCE_ID, home.ADDRESSBOOK_PROPERTY_STORE_ID],
+ From=home, Where=home.OWNER_UID == Parameter("ownerUID"))
+
+
@inlineCallbacks
+ def initFromStore(self, no_cache=False):
+ """
+ Initialize this object from the store. We read in and cache all the
+ extra meta-data from the DB to avoid having to do DB queries for those
+ individually later.
+ """
+ result = yield self._cacher.get(self._ownerUID)
+ if result is None:
+ result = yield self._resourceIDAndHomeResourceIDFromOwnerQuery.on(
+ self._txn, ownerUID=self._ownerUID)
+ if result and not no_cache:
+ yield self._cacher.set(self._ownerUID, result)
+
+ if result:
+ self._resourceID, self._addressbookPropertyStoreID = result[0]
+
+ queryCacher = self._txn._queryCacher
+ if queryCacher:
+ # Get cached copy
+ cacheKey = queryCacher.keyForHomeMetaData(self._resourceID)
+ data = yield queryCacher.get(cacheKey)
+ else:
+ data = None
+ if data is None:
+ # Don't have a cached copy
+ data = (yield self._metaDataQuery.on(
+ self._txn, resourceID=self._resourceID))[0]
+ if queryCacher:
+ # Cache the data
+ yield queryCacher.setAfterCommit(self._txn, cacheKey, data)
+
+ #self._created, self._modified = data
+ yield self._loadPropertyStore()
+
+ # created owned address book
+ addressbook = AddressBook(
+ home=self,
+ name="addressbook", resourceID=self._resourceID,
+ mode=_BIND_MODE_OWN, status=_BIND_STATUS_ACCEPTED,
+ )
+ self._created, self._modified = data
+ yield addressbook._loadPropertyStore()
+ self._addressbook = addressbook
+
+ returnValue(self)
+ else:
+ returnValue(None)
+
+
+ @inlineCallbacks
def remove(self):
ah = schema.ADDRESSBOOK_HOME
- ab = schema.ADDRESSBOOK_BIND
+ ahb = schema.SHARED_ADDRESSBOOK_BIND
aor = schema.ADDRESSBOOK_OBJECT_REVISIONS
rp = schema.RESOURCE_PROPERTY
yield Delete(
- From=ab,
- Where=ab.ADDRESSBOOK_HOME_RESOURCE_ID == self._resourceID
+ From=ahb,
+ Where=ahb.ADDRESSBOOK_HOME_RESOURCE_ID == self._resourceID,
).on(self._txn)
yield Delete(
From=aor,
- Where=aor.ADDRESSBOOK_HOME_RESOURCE_ID == self._resourceID
+ Where=aor.ADDRESSBOOK_HOME_RESOURCE_ID == self._resourceID,
).on(self._txn)
yield Delete(
From=ah,
- Where=ah.RESOURCE_ID == self._resourceID
+ Where=ah.RESOURCE_ID == self._resourceID,
).on(self._txn)
yield Delete(
From=rp,
- Where=rp.RESOURCE_ID == self._resourceID
+ Where=(rp.RESOURCE_ID == self._resourceID).Or(
+ rp.RESOURCE_ID == self._addressbookPropertyStoreID
+ )
).on(self._txn)
yield self._cacher.delete(str(self._ownerUID))
+ @inlineCallbacks
def createdHome(self):
- return self.createAddressBookWithName("addressbook")
+ # initialize synctoken
+ yield self.addressbook()._initSyncToken()
+ yield self.addressbook()._initBindRevision()
+ @inlineCallbacks
+ def removeUnacceptedShares(self):
+ """
+ Unbinds any collections that have been shared to this home but not yet
+ accepted. Associated invite entries are also removed.
+ """
+ super(AddressBookHome, self).removeUnacceptedShares()
+ bind = AddressBookObject._bindSchema
+ kwds = {"homeResourceID" : self._resourceID}
+ yield Delete(
+ From=bind,
+ Where=(bind.HOME_RESOURCE_ID == Parameter("homeResourceID")
+ ).And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+ ).on(self._txn, **kwds)
+
+
+ def addressbook(self):
+ return self._addressbook
+
+
+ def shareeAddressBookName(self):
+ return self.uid()
+
+
+ def objectWithShareUID(self, shareUID):
+ """
+ Retrieve the child with the given bind identifier contained in this
+ home.
+
+ @param name: a string.
+ @return: an L{ICalendar} or C{None} if no such child exists.
+ """
+ return self._childClass.objectWithBindName(self, shareUID, accepted=True)
+
+
+ def invitedObjectWithShareUID(self, shareUID):
+ """
+ Retrieve the child invitation with the given bind identifier contained in this
+ home.
+
+ @param name: a string.
+ @return: an L{ICalendar} or C{None} if no such child exists.
+ """
+ return self._childClass.objectWithBindName(self, shareUID, accepted=False)
+
+
+ @inlineCallbacks
+ def ownerHomeWithChildID(self, resourceID):
+ """
+ Get the owner home for a shared child ID
+ """
+ # addressbook and home have same resourceID
+ ownerHome = yield self._txn.homeWithResourceID(self._homeType, resourceID)
+ returnValue(ownerHome)
+
+
+ @inlineCallbacks
+ def ownerHomeAndChildNameForChildID(self, resourceID):
+ """
+ Get the owner home for a shared child ID and the owner's name for that bound child.
+ Subclasses may override.
+ """
+ ownerHome = yield self.ownerHomeWithChildID(resourceID)
+ ownerName = ownerHome.addressbook().name()
+ returnValue((ownerHome, ownerName))
+
+
+ @classproperty
+ def _syncTokenQuery(cls): #@NoSelf
+ """
+ DAL Select statement to find the sync token.
+ """
+ rev = cls._revisionsSchema
+ bind = cls._bindSchema
+ return Select(
+ [Max(rev.REVISION)],
+ # active shared address books
+ From=Select(
+ [rev.REVISION],
+ From=rev,
+ Where=(
+ rev.RESOURCE_ID.In(
+ Select(
+ [bind.RESOURCE_ID],
+ From=bind,
+ Where=bind.HOME_RESOURCE_ID == Parameter("resourceID"),
+ )
+ )
+ ),
+ SetExpression=Union(
+ # deleted shared address books
+ Select(
+ [rev.REVISION],
+ From=rev,
+ Where=(rev.HOME_RESOURCE_ID == Parameter("resourceID")).And(rev.RESOURCE_ID == None),
+ SetExpression=Union(
+ # owned address book: owned address book cannot be deleted: See AddressBook.remove()
+ Select(
+ [rev.REVISION],
+ From=rev,
+ Where=(rev.HOME_RESOURCE_ID == Parameter("resourceID")).And(rev.RESOURCE_ID == rev.HOME_RESOURCE_ID),
+ ),
+ optype=Union.OPTYPE_ALL,
+ )
+ ),
+ optype=Union.OPTYPE_ALL,
+ )
+ ),
+ )
+
+
+ @classproperty
+ def _changesQuery(cls): #@NoSelf
+ rev = cls._revisionsSchema
+ return Select(
+ [rev.COLLECTION_NAME,
+ rev.RESOURCE_NAME,
+ rev.DELETED],
+ From=rev,
+ Where=(rev.REVISION > Parameter("revision")).And(
+ rev.HOME_RESOURCE_ID == Parameter("resourceID")).And(
+ rev.RESOURCE_ID == rev.HOME_RESOURCE_ID)
+ )
+
+ @inlineCallbacks
+ def doChangesQuery(self, revision):
+
+ rows = yield self._changesQuery.on(self._txn,
+ resourceID=self._resourceID,
+ revision=revision)
+
+ bindName = self.addressbook().name()
+ result = [[bindName] + row for row in rows]
+ returnValue(result)
+
+
AddressBookHome._register(EADDRESSBOOKTYPE)
-class AddressBook(CommonHomeChild):
+class AddressBook(CommonHomeChild, SharingMixIn):
"""
SQL-based implementation of L{IAddressBook}.
"""
@@ -144,38 +347,94 @@
# structured tables. (new, preferred)
_homeSchema = schema.ADDRESSBOOK_HOME
- _bindSchema = schema.ADDRESSBOOK_BIND
- _homeChildSchema = schema.ADDRESSBOOK
- _homeChildMetaDataSchema = schema.ADDRESSBOOK_METADATA
+ _bindSchema = schema.SHARED_ADDRESSBOOK_BIND
+ _homeChildSchema = schema.ADDRESSBOOK_HOME
+ _homeChildMetaDataSchema = schema.ADDRESSBOOK_HOME_METADATA
_revisionsSchema = schema.ADDRESSBOOK_OBJECT_REVISIONS
_objectSchema = schema.ADDRESSBOOK_OBJECT
- # string mappings (old, removing)
- _bindTable = ADDRESSBOOK_BIND_TABLE
- _homeChildTable = ADDRESSBOOK_TABLE
- _homeChildBindTable = ADDRESSBOOK_AND_ADDRESSBOOK_BIND
- _revisionsTable = ADDRESSBOOK_OBJECT_REVISIONS_TABLE
- _revisionsBindTable = ADDRESSBOOK_OBJECT_REVISIONS_AND_BIND_TABLE
- _objectTable = ADDRESSBOOK_OBJECT_TABLE
- def __init__(self, *args, **kw):
- super(AddressBook, self).__init__(*args, **kw)
+ def __init__(self, home, name, resourceID, mode, status, revision=0, message=None, ownerHome=None, bindName=None):
+ ownerName = ownerHome.addressbook().name() if ownerHome else None
+ super(AddressBook, self).__init__(home, name, resourceID, mode, status, revision=revision, message=message, ownerHome=ownerHome, ownerName=ownerName)
self._index = PostgresLegacyABIndexEmulator(self)
+ self._bindName = bindName
+ def __repr__(self):
+ return '<%s: %s("%s")>' % (self.__class__.__name__, self._resourceID, self.name())
+
+ @inlineCallbacks
+ def _init_isShared(self):
+ """
+ Temporary hack to set isShared on the owner addressbook
+ 1) This is not up to spec because an addressbook can be shared even without invitations
+ 2) This should be setup in AddressBookHome.initFromStore, but calling asShared() from there creates a loop
+ 3) It would be a better hack to change self.addressbook() to a deferred. But his is sufficient for now.
+ """
+ if not hasattr(self, "_isShared_inited"):
+ isShared = bool((yield self.asShared())) or bool((yield self.asInvited()))
+ yield self.setShared(isShared)
+ self._isShared_inited = True
+ else:
+ yield None
+
+ def getCreated(self):
+ return self.ownerHome()._created
+
+
+ def setCreated(self, newValue):
+ self.ownerHome()._created = newValue
+
+
+ def getModified(self):
+ return self.ownerHome()._modified
+
+
+ def setModified(self, newValue):
+ self.ownerHome()._modified = newValue
+
+
+ _created = property(getCreated, setCreated,)
+ _modified = property(getModified, setModified,)
+
+
@property
def _addressbookHome(self):
return self._home
+
+ def resourceType(self):
+ return ResourceType.addressbook #@UndefinedVariable
+
+
ownerAddressBookHome = CommonHomeChild.ownerHome
+ viewerAddressBookHome = CommonHomeChild.viewerHome
addressbookObjects = CommonHomeChild.objectResources
- listAddressbookObjects = CommonHomeChild.listObjectResources
+ listAddressBookObjects = CommonHomeChild.listObjectResources
addressbookObjectWithName = CommonHomeChild.objectResourceWithName
addressbookObjectWithUID = CommonHomeChild.objectResourceWithUID
createAddressBookObjectWithName = CommonHomeChild.createObjectResourceWithName
addressbookObjectsSinceToken = CommonHomeChild.objectResourcesSinceToken
+ def shareeAddressBookName(self):
+ return self._home.shareeAddressBookName()
+
+
+ @inlineCallbacks
+ def _loadPropertyStore(self, props=None):
+ if props is None:
+ props = yield PropertyStore.load(
+ self.ownerHome().uid(),
+ self.viewerHome().uid(),
+ self._txn,
+ self.ownerHome()._addressbookPropertyStoreID, # not ._resourceID as in CommonHomeChild._loadPropertyStore()
+ notifyCallback=self.notifyChanged
+ )
+ super(AddressBook, self)._loadPropertyStore(props)
+
+
def initPropertyStore(self, props):
# Setup peruser special properties
props.setSpecialProperties(
@@ -190,34 +449,887 @@
def contentType(self):
"""
- The content type of Addresbook objects is text/vcard.
+ The content type of addressbook objects is text/vcard.
"""
return MimeType.fromString("text/vcard; charset=utf-8")
- def unshare(self):
+ @classmethod
+ def create(cls, home, name):
+ if name == home.addressbook().name():
+ #raise HomeChildNameAlreadyExistsError
+ pass
+ else:
+ #raise HomeChildNameNotAllowedError
+ raise HTTPError(FORBIDDEN)
+
+
+ @inlineCallbacks
+ def remove(self):
+
+ if self._resourceID == self._home._resourceID:
+ # allow remove, as a way to reset the address book to an empty state
+ for abo in (yield self.objectResources()):
+ yield abo.remove()
+ yield self.removedObjectResource(abo)
+
+ yield self.unshare() # storebridge should already have done this
+
+ # don't delete. Note that revision table is NOT queried for removes
+ # yield self._deletedSyncToken()
+ yield self._updateRevision(self.name())
+
+ # TODO: See why the following 2 lines do not work reliably
+ # yield self.properties()._removeResource()
+ # yield self._loadPropertyStore()
+ for prop in self.properties():
+ self.properties().pop(prop, None)
+ self.properties()[
+ PropertyName.fromElement(ResourceType)
+ ] = self.resourceType()
+
+ yield self.notifyChanged()
+ yield self._home.bumpModified()
+ else:
+ returnValue((yield super(AddressBook, self).remove()))
+
+
+ def rename(self, name):
+ # better error?
+ # raise HomeChildNameNotAllowedError
+ raise HTTPError(FORBIDDEN)
+
+
+ @classmethod
+ def _objectResourceNamesWithResourceIDsQuery(cls, resourceIDs):
"""
- Unshares a collection, regardless of which "direction" it was shared.
+ DAL statement to retrieve addressbook object name with given resourceIDs
"""
- return super(AddressBook, self).unshare(EADDRESSBOOKTYPE)
+ obj = cls._objectSchema
+ return Select([obj.RESOURCE_NAME], From=obj,
+ Where=obj.RESOURCE_ID.In(Parameter("resourceIDs", len(resourceIDs))),)
+ @inlineCallbacks
+ def listObjectResources(self):
+ if self._objectNames is None:
+ if self.owned() or self.fullyShared():
+ rows = yield self._objectResourceNamesQuery.on(
+ self._txn, resourceID=self._resourceID)
+ else:
+ acceptedGroupIDs = yield self.acceptedGroupIDs()
+ allowedObjectIDs = yield self.expandGroupIDs(self._txn, acceptedGroupIDs)
+ rows = (yield self._objectResourceNamesWithResourceIDsQuery(allowedObjectIDs).on(
+ self._txn, resourceIDs=allowedObjectIDs
+ ))
+ objectNames = [row[0] for row in rows]
-class AddressBookObject(CommonObjectResource):
+ # account for fully-shared address book group
+ if self.fullyShared():
+ if not self._fullySharedAddressBookGroupName() in objectNames:
+ objectNames.append(self._fullySharedAddressBookGroupName())
+ self._objectNames = sorted(objectNames)
+ returnValue(self._objectNames)
+
+
+ @inlineCallbacks
+ def countObjectResources(self):
+ if self._objectNames is None:
+ if self.owned() or self.fullyShared():
+ rows = yield self._objectCountQuery.on(
+ self._txn, resourceID=self._resourceID
+ )
+ count = rows[0][0]
+ else:
+ acceptedGroupIDs = yield self.acceptedGroupIDs()
+ count = len((yield self.expandGroupIDs(self._txn, acceptedGroupIDs)))
+
+ # account for fully-shared address book group
+ if self.fullyShared():
+ count += 1
+ returnValue(count)
+
+ returnValue(len(self._objectNames))
+
+
+ @classmethod
+ def _abObjectColumnsWithAddressBookResourceID(cls, columns):
+ """
+ DAL statement to retrieve addressbook object rows with given columns.
+ """
+ obj = cls._objectSchema
+ return Select(columns, From=obj,
+ Where=obj.ADDRESSBOOK_HOME_RESOURCE_ID == Parameter("addressbookResourceID"),)
+
+
+ def _fullySharedAddressBookGroupRow(self): #@NoSelf
+ return [
+ self._resourceID, # obj.ADDRESSBOOK_HOME_RESOURCE_ID,
+ self._resourceID, # obj.RESOURCE_ID,
+ self._fullySharedAddressBookGroupName(), # obj.RESOURCE_NAME, shared name is UID and thus avoids collisions
+ self._fullySharedAddressBookGroupUID(), # obj.UID, shared name is uuid
+ _ABO_KIND_GROUP, # obj.KIND,
+ "1", # obj.MD5, unused
+ "1", # Len(obj.TEXT), unused
+ self._created, # obj.CREATED,
+ self._modified, # obj.CREATED,
+ ]
+
+
+ def _fullySharedAddressBookGroupName(self):
+ return self.ownerHome().addressbook().name() + ".vcf"
+
+
+ def _fullySharedAddressBookGroupUID(self):
+ return self.name()
+
+
+ @inlineCallbacks
+ def _fullySharedAddressBookGroupComponent(self):
+
+ n = self.ownerHome().shareeAddressBookName()
+ fn = n
+ uid = self.name()
+
+ # store bridge should substitute principal name and full name
+ # owner = yield CalDAVResource.principalForUID(self.ownerHome().uid())
+ # n = owner.name()
+ # fn = owner.displayName()
+
+ component = VCard.fromString(
+ """BEGIN:VCARD
+VERSION:3.0
+PRODID:%s
+UID:%s
+FN:%s
+N:%s;;;;
+X-ADDRESSBOOKSERVER-KIND:group
+END:VCARD
+""".replace("\n", "\r\n") % (vCardProductID, uid, n, fn,)
+ )
+
+ # then get member UIDs
+ abo = schema.ADDRESSBOOK_OBJECT
+ memberUIDRows = yield self._abObjectColumnsWithAddressBookResourceID(
+ [abo.VCARD_UID]
+ ).on(self._txn, addressbookResourceID=self._resourceID)
+ memberUIDs = [memberUIDRow[0] for memberUIDRow in memberUIDRows]
+
+ # add prefix to get property string
+ memberAddresses = ["urn:uuid:" + memberUID for memberUID in memberUIDs]
+
+ # now add the properties to the component
+ for memberAddress in sorted(memberAddresses):
+ component.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", memberAddress))
+
+ returnValue(component)
+
+
+ @inlineCallbacks
+ def bumpModified(self):
+ # TODO: The next line seems the next line work too. Why?
+ # returnValue((yield self.ownerHome().bumpModified()))
+ #
+ if self._resourceID == self._home._resourceID:
+ returnValue((yield self._home.bumpModified()))
+ else:
+ returnValue((yield super(AddressBook, self).bumpModified()))
+
+
+ @classmethod
+ @inlineCallbacks
+ def loadAllObjects(cls, home):
+ """
+ Load all L{CommonHomeChild} instances which are children of a given
+ L{CommonHome} and return a L{Deferred} firing a list of them. This must
+ create the child classes and initialize them using "batched" SQL
+ operations to keep this constant wrt the number of children. This is an
+ optimization for Depth:1 operations on the home.
+ """
+ addressbook = home.addressbook()
+ yield addressbook._init_isShared()
+ results = [addressbook]
+ ownerHomeToDataRowMap = {}
+
+ # Load from the main table first
+ dataRows = yield cls._childrenAndMetadataForHomeID.on(
+ home._txn, homeID=home._resourceID
+ )
+ # get ownerHomeIDs
+ for dataRow in dataRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = dataRow[:cls.bindColumnCount] #@UnusedVariable
+ ownerHome = yield home.ownerHomeWithChildID(resourceID)
+ ownerHomeToDataRowMap[ownerHome] = dataRow
+
+ # now get group rows:
+ groupBindRows = yield AddressBookObject._childrenAndMetadataForHomeID.on(
+ home._txn, homeID=home._resourceID
+ )
+ for groupBindRow in groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = groupBindRow[:cls.bindColumnCount] #@UnusedVariable
+ ownerAddressBookID = yield AddressBookObject.ownerAddressBookFromGroupID(home._txn, resourceID)
+ ownerHome = yield home.ownerHomeWithChildID(ownerAddressBookID)
+ if ownerHome not in ownerHomeToDataRowMap:
+ groupBindRow[0] = _BIND_MODE_WRITE
+ groupBindRow[3] = None # bindName
+ groupBindRow[4] = None # bindStatus
+ groupBindRow[5] = None # bindMessage
+ ownerHomeToDataRowMap[ownerHome] = groupBindRow
+
+ if ownerHomeToDataRowMap:
+ # Get property stores for all these child resources (if any found)
+ addressbookPropertyStoreIDs = [ownerHome._addressbookPropertyStoreID for ownerHome in ownerHomeToDataRowMap]
+ propertyStores = yield PropertyStore.forMultipleResourcesWithResourceIDs(
+ home.uid(), home._txn, addressbookPropertyStoreIDs
+ )
+ addressbookResourceIDs = [ownerHome._resourceID for ownerHome in ownerHomeToDataRowMap]
+ revisions = yield cls._revisionsForResourceIDs(addressbookPropertyStoreIDs).on(home._txn, resourceIDs=addressbookResourceIDs)
+ revisions = dict(revisions)
+
+ # Create the actual objects merging in properties
+ for ownerHome, dataRow in ownerHomeToDataRowMap.iteritems():
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = dataRow[:cls.bindColumnCount] #@UnusedVariable
+ additionalBind = dataRow[cls.bindColumnCount:cls.bindColumnCount + len(cls.additionalBindColumns())]
+ metadata = dataRow[cls.bindColumnCount + len(cls.additionalBindColumns()):]
+
+ child = cls(
+ home=home,
+ name=ownerHome.shareeAddressBookName(),
+ resourceID=ownerHome._resourceID,
+ mode=bindMode, status=bindStatus,
+ revision=bindRevision,
+ message=bindMessage, ownerHome=ownerHome,
+ bindName=bindName
+ )
+
+ for attr, value in zip(cls.additionalBindAttributes(), additionalBind):
+ setattr(child, attr, value)
+ for attr, value in zip(cls.metadataAttributes(), metadata):
+ setattr(child, attr, value)
+ child._syncTokenRevision = revisions[child._resourceID]
+ propstore = propertyStores.get(ownerHome._addressbookPropertyStoreID, None)
+ # We have to re-adjust the property store object to account for possible shared
+ # collections as previously we loaded them all as if they were owned
+ propstore._setDefaultUserUID(ownerHome.uid())
+ yield child._loadPropertyStore(propstore)
+ results.append(child)
+
+ returnValue(results)
+
+
+ @classmethod
+ @inlineCallbacks
+ def objectWithName(cls, home, name, accepted=True):
+ """
+ Retrieve the child with the given C{name} contained in the given
+ C{home}.
+
+ @param home: a L{CommonHome}.
+
+ @param name: a string; the name of the L{CommonHomeChild} to retrieve.
+
+ @return: an L{CommonHomeChild} or C{None} if no such child
+ exists.
+ """
+ if accepted and name == home.addressbook().name():
+ addressbook = home.addressbook()
+ yield addressbook._init_isShared()
+ returnValue(addressbook)
+
+ #all shared address books now
+ rows = None
+ queryCacher = home._txn._queryCacher
+ ownerHome = None
+
+ if queryCacher:
+ # Retrieve data from cache
+ cacheKey = queryCacher.keyForObjectWithName(home._resourceID, name)
+ rows = yield queryCacher.get(cacheKey)
+
+ if rows is None:
+
+ # name must be a home uid
+ ownerHome = yield home._txn.addressbookHomeWithUID(name)
+ if ownerHome:
+ # see if address book resource id in bind table
+ ownerAddressBook = ownerHome.addressbook()
+ rows = yield cls._bindForResourceIDAndHomeID.on(
+ home._txn, resourceID=ownerAddressBook._resourceID, homeID=home._resourceID
+ )
+ if rows:
+ rows[0].append(ownerAddressBook._resourceID)
+ rows[0].append(rows[0][4]) # cachedStatus = bindStatus
+ else:
+ groupBindRows = yield AddressBookObject._bindForHomeIDAndAddressBookID.on(
+ home._txn, homeID=home._resourceID, addressbookID=ownerAddressBook._resourceID
+ )
+ if groupBindRows:
+ groupBindRow = groupBindRows[0]
+ cachedBindStatus = groupBindRow[4] # save off bindStatus
+ groupBindRow[0] = _BIND_MODE_WRITE
+ groupBindRow[3] = None # bindName
+ groupBindRow[4] = None # bindStatus
+ groupBindRow[5] = None # bindMessage
+ groupBindRow.append(ownerAddressBook._resourceID)
+ groupBindRow.append(cachedBindStatus)
+ rows = [groupBindRow]
+
+ if rows and queryCacher:
+ # Cache the result
+ queryCacher.setAfterCommit(home._txn, cacheKey, rows)
+
+ if not rows:
+ returnValue(None)
+
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage, ownerAddressBookID, cachedBindStatus = rows[0] #@UnusedVariable
+ # if wrong status, exit here. Item is in queryCache
+ if (cachedBindStatus == _BIND_STATUS_ACCEPTED) != bool(accepted):
+ returnValue(None)
+
+ ownerHome = yield home.ownerHomeWithChildID(ownerAddressBookID)
+ ownerAddressBook = ownerHome.addressbook()
+ child = cls(
+ home=home,
+ name=ownerAddressBook.shareeAddressBookName(), resourceID=ownerAddressBookID,
+ mode=bindMode, status=bindStatus,
+ revision=bindRevision,
+ message=bindMessage, ownerHome=ownerHome,
+ bindName=bindName,
+ )
+ yield child.initFromStore()
+ returnValue(child)
+
+
+ @classmethod
+ @inlineCallbacks
+ def objectWithBindName(cls, home, name, accepted):
+ """
+ Retrieve the child or objectResource with the given bind name C{name} contained in the given
+ C{home}.
+
+ @param home: a L{CommonHome}.
+
+ @param name: a string; the name of the L{CommonHomeChild} to retrieve.
+
+ @return: an L{CommonHomeChild} or L{ObjectResource} or C{None} if no such child
+ exists.
+ """
+ bindRows = yield cls._bindForNameAndHomeID.on(home._txn, name=name, homeID=home._resourceID)
+ if bindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = bindRows[0] #@UnusedVariable
+ if (bindStatus == _BIND_STATUS_ACCEPTED) != bool(accepted):
+ returnValue(None)
+
+ # alt:
+ # returnValue((yield cls.objectWithID(home, resourceID)))
+ ownerHome = yield home.ownerHomeWithChildID(resourceID)
+ if accepted:
+ returnValue((yield home.childWithName(ownerHome.shareeAddressBookName())))
+ else:
+ returnValue((yield cls.objectWithName(home, ownerHome.shareeAddressBookName(), accepted=False)))
+
+ groupBindRows = yield AddressBookObject._bindForNameAndHomeID.on(
+ home._txn, name=name, homeID=home._resourceID
+ )
+ if groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = groupBindRows[0] #@UnusedVariable
+ if (bindStatus == _BIND_STATUS_ACCEPTED) != bool(accepted):
+ returnValue(None)
+
+ ownerAddressBookID = yield AddressBookObject.ownerAddressBookFromGroupID(home._txn, resourceID)
+ # alt:
+ # addressbook = yield cls.objectWithID(home, ownerAddressBookID)
+ ownerHome = yield home.ownerHomeWithChildID(ownerAddressBookID)
+ addressbook = yield home.childWithName(ownerHome.shareeAddressBookName())
+ if not addressbook:
+ addressbook = yield cls.objectWithName(home, ownerHome.shareeAddressBookName(), accepted=False)
+
+ if accepted:
+ returnValue((yield addressbook.objectResourceWithID(resourceID)))
+ else:
+ returnValue((yield AddressBookObject.objectWithID(addressbook, resourceID))) # avoids object cache
+
+ returnValue(None)
+
+
+ @classmethod
+ @inlineCallbacks
+ def objectWithID(cls, home, resourceID, accepted=True):
+ """
+ Retrieve the child with the given C{resourceID} contained in the given
+ C{home}.
+
+ @param home: a L{CommonHome}.
+ @param resourceID: a string.
+ @return: an L{CommonHomeChild} or C{None} if no such child
+ exists.
+ """
+ if home._resourceID == resourceID:
+ addressbook = home.addressbook()
+ yield addressbook._init_isShared()
+ returnValue(addressbook)
+
+ bindRows = yield cls._bindForResourceIDAndHomeID.on(
+ home._txn, resourceID=resourceID, homeID=home._resourceID
+ )
+ if bindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = bindRows[0] #@UnusedVariable
+ if (bindStatus == _BIND_STATUS_ACCEPTED) != bool(accepted):
+ returnValue(None)
+
+ ownerHome = yield home.ownerHomeWithChildID(resourceID)
+ if accepted:
+ returnValue((yield home.childWithName(ownerHome.shareeAddressBookName())))
+ else:
+ returnValue((yield cls.objectWithName(home, ownerHome.shareeAddressBookName(), accepted=False)))
+
+ groupBindRows = yield AddressBookObject._bindForHomeIDAndAddressBookID.on(
+ home._txn, homeID=home._resourceID, addressbookID=resourceID
+ )
+ if groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = groupBindRows[0] #@UnusedVariable
+ if (bindStatus == _BIND_STATUS_ACCEPTED) != bool(accepted):
+ returnValue(None)
+
+ ownerAddressBookID = yield AddressBookObject.ownerAddressBookFromGroupID(home._txn, resourceID)
+ ownerHome = yield home.ownerHomeWithChildID(ownerAddressBookID)
+ if accepted:
+ returnValue((yield home.childWithName(ownerHome.shareeAddressBookName())))
+ else:
+ returnValue((yield cls.objectWithName(home, ownerHome.shareeAddressBookName(), accepted=False)))
+
+ returnValue(None)
+
+
+ def shareUID(self):
+ """
+ @see: L{ICalendar.shareUID}
+ """
+ return self._bindName
+
+
+ def fullyShared(self):
+ return not self.owned() and self._bindStatus == _BIND_STATUS_ACCEPTED
+
+
+ @inlineCallbacks
+ def setShared(self, shared):
+ """
+ Set an owned collection to shared or unshared state. Technically this is not useful as "shared"
+ really means it has invitees, but the current sharing spec supports a notion of a shared collection
+ that has not yet had invitees added. For the time being we will support that option by using a new
+ MESSAGE value to indicate an owned collection that is "shared".
+
+ @param shared: whether or not the owned collection is "shared"
+ @type shared: C{bool}
+ """
+ assert self.owned()
+
+ self._bindMessage = "shared" if shared else None
+
+ ''' FIXME: Make shared persistent: Owned group does not have a bind table
+ bind = self._bindSchema
+ yield Update(
+ {bind.MESSAGE: self._bindMessage},
+ Where=(bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
+ ).on(self._txn, resourceID=self._resourceID, homeID=self.viewerHome()._resourceID)
+
+ yield self.invalidateQueryCache()
+ yield self.notifyChanged()
+ '''
+ yield None
+
+
+ @classmethod
+ @inlineCallbacks
+ def listObjects(cls, home):
+ """
+ Retrieve the names of the children with invitations in the given home.
+
+ @return: an iterable of C{str}s.
+ """
+ names = set([home.addressbook().name()])
+
+ rows = yield cls._acceptedBindForHomeID.on(
+ home._txn, homeID=home._resourceID
+ )
+ rows.extend((yield AddressBookObject._acceptedBindForHomeID.on(
+ home._txn, homeID=home._resourceID
+ )))
+ for row in rows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = row[:cls.bindColumnCount] #@UnusedVariable
+ ownerHome = yield home._txn.homeWithResourceID(home._homeType, homeID)
+ names |= set([ownerHome.shareeAddressBookName()])
+ returnValue(tuple(names))
+
+
+ @classmethod
+ def _memberIDsWithGroupIDsQuery(cls, groupIDs):
+ """
+ DAL query to load all object resource names for a home child.
+ """
+ aboMembers = schema.ABO_MEMBERS
+ return Select([aboMembers.MEMBER_ID], From=aboMembers,
+ Where=aboMembers.GROUP_ID.In(Parameter("groupIDs", len(groupIDs))),
+ )
+
+
+ @classmethod
+ @inlineCallbacks
+ def expandGroupIDs(cls, txn, groupIDs, includeGroupIDs=True):
+ """
+ Get all AddressBookObject resource IDs contains in the given shared groups with the given groupIDs
+ """
+ objectIDs = set(groupIDs) if includeGroupIDs else set()
+ examinedIDs = set()
+ remainingIDs = set(groupIDs)
+ while remainingIDs:
+ memberRows = yield cls._memberIDsWithGroupIDsQuery(remainingIDs).on(
+ txn, groupIDs=remainingIDs
+ )
+ objectIDs |= set(memberRow[0] for memberRow in memberRows)
+ examinedIDs |= remainingIDs
+ remainingIDs = objectIDs - examinedIDs
+
+ returnValue(tuple(objectIDs))
+
+
+ @inlineCallbacks
+ def unacceptedGroupIDs(self):
+ if self.owned():
+ returnValue([])
+ else:
+ groupBindRows = yield AddressBookObject._unacceptedBindForHomeIDAndAddressBookID.on(
+ self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+ )
+ returnValue([groupBindRow[2] for groupBindRow in groupBindRows])
+
+
+ @inlineCallbacks
+ def acceptedGroupIDs(self):
+ if self.owned():
+ returnValue([])
+ else:
+ groupBindRows = yield AddressBookObject._acceptedBindForHomeIDAndAddressBookID.on(
+ self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+ )
+ returnValue([groupBindRow[2] for groupBindRow in groupBindRows])
+
+
+ @inlineCallbacks
+ def accessControlGroupIDs(self):
+ if self.owned():
+ returnValue(([], []))
+ else:
+ groupBindRows = yield AddressBookObject._acceptedBindForHomeIDAndAddressBookID.on(
+ self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+ )
+ readWriteGroupIDs = []
+ readOnlyGroupIDs = []
+ for groupBindRow in groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = groupBindRow[:self.bindColumnCount] #@UnusedVariable
+ if bindMode == _BIND_MODE_WRITE:
+ readWriteGroupIDs.append(resourceID)
+ else:
+ readOnlyGroupIDs.append(resourceID)
+
+ if readOnlyGroupIDs and readWriteGroupIDs:
+ # expand read-write groups and remove any subgroups from read-only group list
+ allWriteableIDs = yield self.expandGroupIDs(self._txn, readWriteGroupIDs)
+ adjustedReadOnlyGroupIDs = set(readOnlyGroupIDs) - set(allWriteableIDs)
+ adjustedReadWriteGroupIDs = set(readWriteGroupIDs) | (set(readOnlyGroupIDs) - adjustedReadOnlyGroupIDs)
+ else:
+ adjustedReadOnlyGroupIDs = readOnlyGroupIDs
+ adjustedReadWriteGroupIDs = readWriteGroupIDs
+ returnValue((tuple(adjustedReadOnlyGroupIDs), tuple(adjustedReadWriteGroupIDs)))
+
+ #FIXME: Unused
+ @inlineCallbacks
+ def readOnlyGroupIDs(self):
+ returnValue((yield self.accessControlGroupIDs())[0])
+
+
+ @inlineCallbacks
+ def readWriteGroupIDs(self):
+ returnValue((yield self.accessControlGroupIDs())[1])
+
+
+ #FIXME: Unused: Use for caching access
+ @inlineCallbacks
+ def accessControlObjectIDs(self):
+ readOnlyIDs = set()
+ readWriteIDs = set()
+ if self.owned() or self.fullyShared():
+ rows = yield self._allColumnsWithParent(self)
+ ids = set([row[1] for row in rows])
+ if self.fullyShared():
+ ids |= set([self._resourceID, ])
+ if self.owned() or self._bindMode == _BIND_MODE_WRITE:
+ returnValue(tuple(readOnlyIDs), tuple(readWriteIDs))
+ readOnlyIDs = set(ids)
+
+ groupBindRows = yield AddressBookObject._acceptedBindForHomeIDAndAddressBookID.on(
+ self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+ )
+ readWriteGroupIDs = []
+ readOnlyGroupIDs = []
+ for groupBindRow in groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = groupBindRow[:self.bindColumnCount] #@UnusedVariable
+ if bindMode == _BIND_MODE_WRITE:
+ readWriteGroupIDs.append(resourceID)
+ else:
+ readOnlyGroupIDs.append(resourceID)
+
+ if readOnlyGroupIDs:
+ readOnlyIDs |= set((yield self.expandGroupIDs(self._txn, readOnlyGroupIDs)))
+ if readWriteGroupIDs:
+ readWriteIDs |= set((yield self.expandGroupIDs(self._txn, readWriteGroupIDs)))
+ readOnlyIDs -= readWriteIDs
+ returnValue(tuple(readOnlyIDs), tuple(readWriteIDs))
+
+
+ #FIXME: Unused: Use for caching access
+ @inlineCallbacks
+ def readOnlyObjectIDs(self):
+ returnValue((yield self.accessControlObjectIDs())[1])
+
+
+ #FIXME: Unused: Use for caching access
+ @inlineCallbacks
+ def readWriteObjectIDs(self):
+ returnValue((yield self.accessControlObjectIDs())[1])
+
+
+ #FIXME: Unused: Use for caching access
+ @inlineCallbacks
+ def allObjectIDs(self):
+ readOnlyIDs, readWriteIDs = yield self.accessControlObjectIDs()
+ returnValue((readOnlyIDs + readWriteIDs))
+
+
+ @inlineCallbacks
+ def updateShare(self, shareeView, mode=None, status=None, message=None, name=None):
+ """
+ Update share mode, status, and message for a home child shared with
+ this (owned) L{CommonHomeChild}.
+
+ @param shareeView: The sharee home child that shares this.
+ @type shareeView: L{CommonHomeChild}
+
+ @param mode: The sharing mode; L{_BIND_MODE_READ} or
+ L{_BIND_MODE_WRITE} or None to not update
+ @type mode: L{str}
+
+ @param status: The sharing status; L{_BIND_STATUS_INVITED} or
+ L{_BIND_STATUS_ACCEPTED} or L{_BIND_STATUS_DECLINED} or
+ L{_BIND_STATUS_INVALID} or None to not update
+ @type status: L{str}
+
+ @param message: The proposed message to go along with the share, which
+ will be used as the default display name, or None to not update
+ @type message: L{str}
+
+ @param name: The bind resource name or None to not update
+ @type message: L{str}
+
+ @return: the name of the shared item in the sharee's home.
+ @rtype: a L{Deferred} which fires with a L{str}
+ """
+ # TODO: raise a nice exception if shareeView is not, in fact, a shared
+ # version of this same L{CommonHomeChild}
+
+ #remove None parameters, and substitute None for empty string
+ bind = self._bindSchema
+ columnMap = dict([(k, v if v else None)
+ for k, v in {bind.BIND_MODE:mode,
+ bind.BIND_STATUS:status,
+ bind.MESSAGE:message,
+ bind.RESOURCE_NAME:name}.iteritems() if v is not None])
+
+ if len(columnMap):
+
+ # count accepted
+ if status is not None:
+ previouslyAcceptedBindCount = 1 if shareeView.fullyShared() else 0
+ previouslyAcceptedBindCount += len((yield AddressBookObject._acceptedBindForHomeIDAndAddressBookID.on(
+ self._txn, homeID=shareeView._home._resourceID, addressbookID=shareeView._resourceID
+ )))
+
+ sharedname = yield self._updateBindColumnsQuery(columnMap).on(
+ self._txn,
+ resourceID=self._resourceID, homeID=shareeView._home._resourceID
+ )
+
+ #update affected attributes
+ if mode is not None:
+ shareeView._bindMode = columnMap[bind.BIND_MODE]
+
+ if status is not None:
+ shareeView._bindStatus = columnMap[bind.BIND_STATUS]
+ if shareeView._bindStatus == _BIND_STATUS_ACCEPTED:
+ if 0 == previouslyAcceptedBindCount:
+ yield shareeView._initSyncToken()
+ yield shareeView._initBindRevision()
+ shareeView._home._children[shareeView._name] = shareeView
+ shareeView._home._children[shareeView._resourceID] = shareeView
+ elif shareeView._bindStatus == _BIND_STATUS_DECLINED:
+ if 1 == previouslyAcceptedBindCount:
+ shareeView._deletedSyncToken(sharedRemoval=True)
+ shareeView._home._children.pop(shareeView._name, None)
+ shareeView._home._children.pop(shareeView._resourceID, None)
+
+
+ if message is not None:
+ shareeView._bindMessage = columnMap[bind.MESSAGE]
+
+ queryCacher = self._txn._queryCacher
+ if queryCacher:
+ cacheKey = queryCacher.keyForObjectWithName(shareeView._home._resourceID, shareeView._name)
+ queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+
+ shareeView._name = sharedname[0][0]
+
+ # Must send notification to ensure cache invalidation occurs
+ yield self.notifyChanged()
+
+ returnValue(shareeView._name)
+
+
+ @inlineCallbacks
+ def asShared(self):
+ """
+ Retrieve all the versions of this L{CommonHomeChild} as it is shared to
+ everyone.
+
+ @see: L{ICalendarHome.asShared}
+
+ @return: L{CommonHomeChild} objects that represent this
+ L{CommonHomeChild} as a child of different L{CommonHome}s
+ @rtype: a L{Deferred} which fires with a L{list} of L{ICalendar}s.
+ """
+ result = []
+ if self.owned():
+ # get all accepted shared binds
+ bindRows = yield self._sharedBindForResourceID.on(
+ self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+ )
+ for bindRow in bindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = bindRow[:self.bindColumnCount] #@UnusedVariable
+ home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+ new = yield home.childWithName(self.shareeAddressBookName())
+ result.append(new)
+
+ returnValue(result)
+
+
+ @inlineCallbacks
+ def asInvited(self):
+ """
+ Retrieve all the versions of this L{CommonHomeChild} as it is invited to
+ everyone.
+
+ @see: L{ICalendarHome.asInvited}
+
+ @return: L{CommonHomeChild} objects that represent this
+ L{CommonHomeChild} as a child of different L{CommonHome}s
+ @rtype: a L{Deferred} which fires with a L{list} of L{ICalendar}s.
+ """
+ result = []
+ if self.owned():
+ # get all accepted shared binds
+ bindRows = yield self._unacceptedBindForResourceID.on(
+ self._txn, resourceID=self._resourceID
+ )
+ for bindRow in bindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = bindRow[:self.bindColumnCount] #@UnusedVariable
+ home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+ new = yield self.objectWithName(home, self.shareeAddressBookName(), accepted=False)
+ result.append(new)
+
+ returnValue(result)
+
+
+ @inlineCallbacks
+ def unshareWith(self, shareeHome):
+ """
+ Remove the shared version of this (owned) L{CommonHomeChild} from the
+ referenced L{CommonHome}.
+
+ @see: L{CommonHomeChild.shareWith}
+
+ @param shareeHome: The home with which this L{CommonHomeChild} was
+ previously shared.
+
+ @return: a L{Deferred} which will fire with the previous shareUID
+ """
+ sharedAddressBook = yield shareeHome.addressbookWithName(self.shareeAddressBookName())
+ if sharedAddressBook:
+
+ acceptedBindCount = 1 if sharedAddressBook.fullyShared() else 0
+ acceptedBindCount += len((yield AddressBookObject._acceptedBindForHomeIDAndAddressBookID.on(
+ self._txn, homeID=shareeHome._resourceID, addressbookID=sharedAddressBook._resourceID
+ )))
+ if acceptedBindCount == 1:
+ sharedAddressBook._deletedSyncToken(sharedRemoval=True)
+ shareeHome._children.pop(sharedAddressBook.name(), None)
+ shareeHome._children.pop(sharedAddressBook._resourceID, None)
+ elif not sharedAddressBook.fullyShared():
+ #FIXME: remove objects for this group only using self.removeObjectResource
+ self._objectNames = None
+
+ # Must send notification to ensure cache invalidation occurs
+ yield self.notifyChanged()
+
+ # delete binds including invites
+ deletedBindNameRows = yield self._deleteBindForResourceIDAndHomeID.on(self._txn, resourceID=self._resourceID,
+ homeID=shareeHome._resourceID
+ )
+ if deletedBindNameRows:
+ deletedBindName = deletedBindNameRows[0][0]
+ queryCacher = self._txn._queryCacher
+ if queryCacher:
+ cacheKey = queryCacher.keyForObjectWithName(shareeHome._resourceID, self.shareeAddressBookName())
+ queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+ else:
+ deletedBindName = None
+
+ returnValue(deletedBindName)
+
+
+
+class AddressBookObject(CommonObjectResource, SharingMixIn):
+
implements(IAddressBookObject)
- _objectTable = ADDRESSBOOK_OBJECT_TABLE
_objectSchema = schema.ADDRESSBOOK_OBJECT
+ _bindSchema = schema.SHARED_GROUP_BIND
- def __init__(self, addressbook, name, uid, resourceID=None, options=None):
+ # used by CommonHomeChild._childrenAndMetadataForHomeID() only
+ #_homeChildSchema = schema.ADDRESSBOOK_OBJECT
+ #_homeChildMetaDataSchema = schema.ADDRESSBOOK_OBJECT
- super(AddressBookObject, self).__init__(addressbook, name, uid, resourceID)
- # Component caching
- self._cachedComponent = None
+ def __init__(self, addressbook, name, uid, resourceID=None, options=None): #@UnusedVariable
+ self._kind = None
+ self._ownerAddressBookResourceID = None
+ # _self._component is the cached, current component
+ # super._objectText now contains the text as read of the database only,
+ # not including group member text
+ self._component = None
+ self._bindMode = None
+ self._bindStatus = None
+ self._bindMessage = None
+ self._bindName = None
+ super(AddressBookObject, self).__init__(addressbook, name, uid, resourceID, options)
+
+ def __repr__(self):
+ return '<%s: %s("%s")>' % (self.__class__.__name__, self._resourceID, self.name())
+
+
@property
def _addressbook(self):
return self._parentCollection
@@ -227,6 +1339,325 @@
return self._addressbook
+ def kind(self):
+ return self._kind
+
+
+ @classmethod
+ def _deleteMembersWithMemberIDAndGroupIDsQuery(cls, memberID, groupIDs):
+ aboMembers = schema.ABO_MEMBERS
+ return Delete(
+ aboMembers,
+ Where=(aboMembers.MEMBER_ID == memberID).And(
+ aboMembers.GROUP_ID.In(Parameter("groupIDs", len(groupIDs)))))
+
+
+ @inlineCallbacks
+ def remove(self):
+
+ if self.owned():
+ # storebridge should already have done this
+ yield self.unshare()
+ else:
+ # Can't delete a share here with notification so raise.
+ if self._resourceID == self._addressbook._resourceID:
+ raise GroupForSharedAddressBookDeleteNotAllowedError
+ elif self.shareUID():
+ raise SharedGroupDeleteNotAllowedError
+
+ if not self.owned() and not self._addressbook.fullyShared():
+ # convert delete in sharee shared group address book to remove of memberships
+ # that make this object visible to the sharee
+
+ readWriteGroupIDs = yield self._addressbook.readWriteGroupIDs()
+ if readWriteGroupIDs:
+ objectsIDs = yield self._addressbook.expandGroupIDs(self._txn, readWriteGroupIDs)
+ yield self._deleteMembersWithMemberIDAndGroupIDsQuery(self._resourceID, objectsIDs).on(
+ self._txn, groupIDs=objectsIDs
+ )
+
+ yield self._changeAddressBookRevision(self.ownerHome().addressbook())
+
+ else:
+ # delete members table rows for this object,...
+ aboMembers = schema.ABO_MEMBERS
+ aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
+
+ groupIDRows = yield Delete(
+ aboMembers,
+ Where=aboMembers.MEMBER_ID == self._resourceID,
+ Return=aboMembers.GROUP_ID
+ ).on(self._txn)
+
+ # add to foreign member table row by UID
+ memberAddress = "urn:uuid:" + self._uid
+ for groupID in [groupIDRow[0] for groupIDRow in groupIDRows]:
+ if groupID != self._ownerAddressBookResourceID: # no aboForeignMembers on address books
+ yield Insert(
+ {aboForeignMembers.GROUP_ID: groupID,
+ aboForeignMembers.ADDRESSBOOK_ID: self._ownerAddressBookResourceID,
+ aboForeignMembers.MEMBER_ADDRESS: memberAddress, }
+ ).on(self._txn)
+
+ yield super(AddressBookObject, self).remove()
+ self._kind = None
+ self._ownerAddressBookResourceID = None
+ self._component = None
+
+
+ @inlineCallbacks
+ def readWriteAccess(self):
+ assert not self.owned(), "Don't call items in owned address book"
+
+ # if fully shared and rw, must be RW since sharing group read-only has no affect
+ if self._addressbook.fullyShared() and self._addressbook.shareMode() == _BIND_MODE_WRITE:
+ yield None
+ returnValue(True)
+
+ readWriteGroupIDs = yield self._addressbook.readWriteGroupIDs()
+ if self._resourceID in (yield self._addressbook.expandGroupIDs(self._txn, readWriteGroupIDs)):
+ returnValue(True)
+
+ returnValue(False)
+
+
+ @classmethod
+ def _allColumnsWithResourceIDsAnd(cls, resourceIDs, column, paramName):
+ """
+ DAL query for all columns where PARENT_RESOURCE_ID matches a parentID
+ parameter and a given instance column matches a given parameter name.
+ """
+ obj = cls._objectSchema
+ return Select(
+ cls._allColumns, From=obj,
+ Where=(column == Parameter(paramName)).And(
+ obj.RESOURCE_ID.In(Parameter("resourceIDs", len(resourceIDs)))),
+ )
+
+
+ @classmethod
+ def _allColumnsWithResourceIDsAndName(cls, resourceIDs):
+ return cls._allColumnsWithResourceIDsAnd(resourceIDs, cls._objectSchema.RESOURCE_NAME, "name")
+
+
+ @classmethod
+ def _allColumnsWithResourceIDsAndUID(cls, resourceIDs):
+ return cls._allColumnsWithResourceIDsAnd(resourceIDs, cls._objectSchema.UID, "uid")
+
+
+ @classproperty
+ def _allColumnsWithResourceID(cls): #@NoSelf
+ obj = cls._objectSchema
+ return Select(
+ cls._allColumns, From=obj,
+ Where=obj.RESOURCE_ID == Parameter("resourceID"),)
+
+
+ @inlineCallbacks
+ def _init_isShared(self):
+ """
+ Temporary hack to set isShared on the owner group
+ 1) This is not up to spec because an group can be shared even without invitations
+ """
+ if not hasattr(self, "_isShared_inited"):
+ isShared = bool((yield self.asShared())) or bool((yield self.asInvited()))
+ yield self.setShared(isShared)
+ self._isShared_inited = True
+ else:
+ yield None
+
+
+ @inlineCallbacks
+ def initFromStore(self):
+ """
+ Initialise this object from the store. We read in and cache all the
+ extra metadata from the DB to avoid having to do DB queries for those
+ individually later. Either the name or uid is present, so we have to
+ tweak the query accordingly.
+
+ @return: L{self} if object exists in the DB, else C{None}
+ """
+ rows = None
+ if self.owned() or self._addressbook.fullyShared(): # owned or fully shared
+ if self._name:
+ rows = yield self._allColumnsWithParentAndName.on(
+ self._txn, name=self._name,
+ parentID=self._parentCollection._resourceID
+ )
+ elif self._uid:
+ rows = yield self._allColumnsWithParentAndUID.on(
+ self._txn, uid=self._uid,
+ parentID=self._parentCollection._resourceID
+ )
+ elif self._resourceID:
+ rows = yield self._allColumnsWithParentAndID.on(
+ self._txn, resourceID=self._resourceID,
+ parentID=self._parentCollection._resourceID
+ )
+
+ if not rows and self._addressbook.fullyShared(): # perhaps add special group
+ if self._name:
+ if self._name == self._addressbook._fullySharedAddressBookGroupName():
+ rows = [self._addressbook._fullySharedAddressBookGroupRow()]
+ elif self._uid:
+ if self._uid == (yield self._addressbook._fullySharedAddressBookGroupUID()):
+ rows = [self._addressbook._fullySharedAddressBookGroupRow()]
+ elif self._resourceID:
+ if self._resourceID == self._addressbook._resourceID:
+ rows = [self._addressbook._fullySharedAddressBookGroupRow()]
+ else:
+ acceptedGroupIDs = yield self._addressbook.acceptedGroupIDs()
+ allowedObjectIDs = yield self._addressbook.expandGroupIDs(self._txn, acceptedGroupIDs)
+ if self._name:
+ if allowedObjectIDs:
+ rows = (yield self._allColumnsWithResourceIDsAndName(allowedObjectIDs).on(
+ self._txn, name=self._name,
+ resourceIDs=allowedObjectIDs,
+ ))
+ elif self._uid:
+ if allowedObjectIDs:
+ rows = (yield self._allColumnsWithResourceIDsAndUID(allowedObjectIDs).on(
+ self._txn, uid=self._uid,
+ resourceIDs=allowedObjectIDs,
+ ))
+ elif self._resourceID:
+ if self._resourceID not in allowedObjectIDs:
+ # allow invited groups
+ allowedObjectIDs = yield self._addressbook.unacceptedGroupIDs()
+ if self._resourceID in allowedObjectIDs:
+ rows = (yield self._allColumnsWithResourceID.on(
+ self._txn, resourceID=self._resourceID,
+ ))
+
+ if rows:
+ self._initFromRow(tuple(rows[0]))
+
+ if self._kind == _ABO_KIND_GROUP:
+ # generate "X-ADDRESSBOOKSERVER-MEMBER" properties
+ # calc md5 and set size
+ componentText = str((yield self.component()))
+ self._md5 = hashlib.md5(componentText).hexdigest()
+ self._size = len(componentText)
+
+ groupBindRows = yield AddressBookObject._bindForResourceIDAndHomeID.on(
+ self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+ )
+
+ if groupBindRows:
+ groupBindRow = groupBindRows[0]
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = groupBindRow[:self.bindColumnCount] #@UnusedVariable
+ self._bindMode = bindMode
+ self._bindStatus = bindStatus
+ self._bindMessage = bindMessage
+ self._bindName = bindName
+
+ if self.owned():
+ yield self._init_isShared()
+
+ yield self._loadPropertyStore()
+
+ returnValue(self)
+ else:
+ returnValue(None)
+
+
+ @classproperty
+ def _allColumns(cls): #@NoSelf
+ """
+ Full set of columns in the object table that need to be loaded to
+ initialize the object resource state.
+ """
+ obj = cls._objectSchema
+ return [
+ obj.ADDRESSBOOK_HOME_RESOURCE_ID,
+ obj.RESOURCE_ID,
+ obj.RESOURCE_NAME,
+ obj.UID,
+ obj.KIND,
+ obj.MD5,
+ Len(obj.TEXT),
+ obj.CREATED,
+ obj.MODIFIED,
+ ]
+
+
+ def _initFromRow(self, row):
+ """
+ Given a select result using the columns from L{_allColumns}, initialize
+ the object resource state.
+ """
+ (self._ownerAddressBookResourceID,
+ self._resourceID,
+ self._name,
+ self._uid,
+ self._kind,
+ self._md5,
+ self._size,
+ self._created,
+ self._modified,) = tuple(row)
+
+
+ @classmethod
+ def _columnsWithResourceIDsQuery(cls, columns, resourceIDs):
+ """
+ DAL statement to retrieve addressbook object rows with given columns.
+ """
+ obj = cls._objectSchema
+ return Select(columns, From=obj,
+ Where=obj.RESOURCE_ID.In(Parameter("resourceIDs", len(resourceIDs))),)
+
+
+ @classmethod
+ @inlineCallbacks
+ def _allColumnsWithParent(cls, addressbook):
+ if addressbook.owned() or addressbook.fullyShared():
+ rows = yield super(AddressBookObject, cls)._allColumnsWithParent(addressbook)
+ if addressbook.fullyShared():
+ rows.append(addressbook._fullySharedAddressBookGroupRow())
+ else:
+ acceptedGroupIDs = yield addressbook.acceptedGroupIDs()
+ allowedObjectIDs = yield addressbook.expandGroupIDs(addressbook._txn, acceptedGroupIDs)
+ rows = yield cls._columnsWithResourceIDsQuery(cls._allColumns, allowedObjectIDs).on(
+ addressbook._txn, resourceIDs=allowedObjectIDs
+ )
+ returnValue(rows)
+
+
+ @classmethod
+ def _allColumnsWithResourceIDsAndNamesQuery(cls, resourceIDs, names):
+ obj = cls._objectSchema
+ return Select(cls._allColumns, From=obj,
+ Where=(obj.RESOURCE_ID.In(Parameter("resourceIDs", len(resourceIDs))).And(
+ obj.RESOURCE_NAME.In(Parameter("names", len(names))))),)
+
+
+ @classmethod
+ @inlineCallbacks
+ def _allColumnsWithParentAndNames(cls, addressbook, names):
+
+ if addressbook.owned() or addressbook.fullyShared():
+ rows = yield super(AddressBookObject, cls)._allColumnsWithParentAndNames(addressbook, names)
+ if addressbook.fullyShared() and addressbook._fullySharedAddressBookGroupName() in names:
+ rows.append(addressbook._fullySharedAddressBookGroupRow())
+ else:
+ acceptedGroupIDs = yield addressbook.acceptedGroupIDs()
+ allowedObjectIDs = yield addressbook.expandGroupIDs(addressbook._txn, acceptedGroupIDs)
+ rows = yield cls._allColumnsWithResourceIDsAndNamesQuery(allowedObjectIDs, names).on(
+ addressbook._txn, resourceIDs=allowedObjectIDs, names=names
+ )
+ returnValue(rows)
+
+
+ @inlineCallbacks
+ def _changeAddressBookRevision(self, addressbook, inserting=False):
+ if inserting:
+ yield addressbook._insertRevision(self._name)
+ else:
+ yield addressbook._updateRevision(self._name)
+
+ yield addressbook.notifyChanged()
+
+
# Stuff from put_addressbook_common
def fullValidation(self, component, inserting):
"""
@@ -245,7 +1676,7 @@
self.validAddressDataCheck(component, inserting)
- def validAddressDataCheck(self, component, inserting):
+ def validAddressDataCheck(self, component, inserting): #@UnusedVariable
"""
Check that the calendar data is valid iCalendar.
@return: tuple: (True/False if the calendar data is valid,
@@ -303,18 +1734,76 @@
yield self._lockUID(component, inserting)
yield self.updateDatabase(component, inserting=inserting)
- if inserting:
- yield self._addressbook._insertRevision(self._name)
+ yield self._changeAddressBookRevision(self._addressbook, inserting)
+
+ if self.owned():
+ # update revision table of the sharee group address book
+ if self._kind == _ABO_KIND_GROUP: # optimization
+ for shareeAddressBook in (yield self.asShared()):
+ yield self._changeAddressBookRevision(shareeAddressBook, inserting)
+ # one is enough because all have the same resourceID
+ break
else:
- yield self._addressbook._updateRevision(self._name)
+ if self._addressbook._resourceID != self._ownerAddressBookResourceID:
+ # update revisions table of shared group's containing address book
+ yield self._changeAddressBookRevision(self.ownerHome().addressbook(), inserting)
- yield self._addressbook.notifyChanged()
-
+ self._component = component
returnValue(self._componentChanged)
+ @classmethod
+ def _resourceIDAndUIDForUIDsAndAddressBookResourceIDQuery(cls, uids):
+ abo = schema.ADDRESSBOOK_OBJECT
+ return Select([abo.RESOURCE_ID, abo.VCARD_UID],
+ From=abo,
+ Where=((abo.ADDRESSBOOK_HOME_RESOURCE_ID == Parameter("addressbookResourceID")
+ ).And(
+ abo.VCARD_UID.In(Parameter("uids", len(uids))))),
+ )
+
+
+ @classmethod
+ def _deleteMembersWithGroupIDAndMemberIDsQuery(cls, groupID, memberIDs):
+ aboMembers = schema.ABO_MEMBERS
+ return Delete(
+ aboMembers,
+ Where=(aboMembers.GROUP_ID == groupID).And(
+ aboMembers.MEMBER_ID.In(Parameter("memberIDs", len(memberIDs)))))
+
+
+ @classmethod
+ def _deleteForeignMembersWithGroupIDAndMembeAddrsQuery(cls, groupID, memberAddrs):
+ aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
+ return Delete(
+ aboForeignMembers,
+ Where=(aboForeignMembers.GROUP_ID == groupID).And(
+ aboForeignMembers.MEMBER_ADDRESS.In(Parameter("memberAddrs", len(memberAddrs)))))
+
+
+ @classproperty
+ def _insertABObject(cls): #@NoSelf
+ """
+ DAL statement to create an addressbook object with all default values.
+ """
+ abo = schema.ADDRESSBOOK_OBJECT
+ return Insert(
+ {abo.RESOURCE_ID: schema.RESOURCE_ID_SEQ,
+ abo.ADDRESSBOOK_HOME_RESOURCE_ID: Parameter("addressbookResourceID"),
+ abo.RESOURCE_NAME: Parameter("name"),
+ abo.VCARD_TEXT: Parameter("text"),
+ abo.VCARD_UID: Parameter("uid"),
+ abo.KIND: Parameter("kind"),
+ abo.MD5: Parameter("md5"),
+ },
+ Return=(abo.RESOURCE_ID,
+ abo.CREATED,
+ abo.MODIFIED))
+
+
@inlineCallbacks
- def updateDatabase(self, component, expand_until=None, reCreate=False, inserting=False):
+ def updateDatabase(self, component, expand_until=None, reCreate=False, #@UnusedVariable
+ inserting=False):
"""
Update the database tables for the new data being written.
@@ -322,42 +1811,186 @@
@type component: L{Component}
"""
- ao = schema.ADDRESSBOOK_OBJECT
+ componentResourceKindToAddressBookObjectKindMap = {
+ "person": _ABO_KIND_PERSON,
+ "group": _ABO_KIND_GROUP,
+ "resource": _ABO_KIND_RESOURCE,
+ "location": _ABO_KIND_LOCATION,
+ }
+ lcResourceKind = component.resourceKind().lower() if component.resourceKind() else component.resourceKind();
+ kind = componentResourceKindToAddressBookObjectKindMap.get(lcResourceKind, _ABO_KIND_PERSON)
+ assert inserting or self._kind == kind # can't change kind. Should be checked in upper layers
+ self._kind = kind
- componentText = str(component)
- self._objectText = componentText
- self._cachedComponent = component
+ # For shared groups: Non owner may NOT add group members not currently in group!
+ # (Or it would be possible to troll for unshared vCard UIDs and make them shared.)
+ if not self._ownerAddressBookResourceID:
+ self._ownerAddressBookResourceID = self.ownerHome().addressbook()._resourceID
- # ADDRESSBOOK_OBJECT table update
- self._md5 = hashlib.md5(componentText).hexdigest()
- self._size = len(componentText)
+ if self._kind == _ABO_KIND_GROUP:
+ # get member ids
+ memberUIDs = []
+ foreignMemberAddrs = []
+ for memberAddr in component.resourceMemberAddresses():
+ if len(memberAddr) > len("urn:uuid:") and memberAddr.startswith("urn:uuid:"):
+ memberUIDs.append(memberAddr[len("urn:uuid:"):])
+ else:
+ foreignMemberAddrs.append(memberAddr)
+
+ memberRows = yield self._resourceIDAndUIDForUIDsAndAddressBookResourceIDQuery(memberUIDs).on(
+ self._txn, addressbookResourceID=self._ownerAddressBookResourceID, uids=memberUIDs
+ ) if memberUIDs else []
+ memberIDs = [memberRow[0] for memberRow in memberRows]
+ foundUIDs = [memberRow[1] for memberRow in memberRows]
+ foreignMemberAddrs.extend(["urn:uuid:" + missingUID for missingUID in set(memberUIDs) - set(foundUIDs)])
+
+ if not self.owned():
+ if not self._addressbook.fullyShared():
+ #in shared ab defined by groups, all members must be inside the shared groups
+
+ #FIXME: does this apply to whole-shared address books too?
+ if foreignMemberAddrs:
+ raise GroupWithUnsharedAddressNotAllowedError
+
+ acceptedGroupIDs = yield self._addressbook.acceptedGroupIDs()
+ allowedObjectIDs = yield self._addressbook.expandGroupIDs(self._txn, acceptedGroupIDs)
+ if set(memberIDs) - set(allowedObjectIDs):
+ raise GroupWithUnsharedAddressNotAllowedError
+
+ # don't store group members in object text
+
+ orginialComponent = str(component)
+ # sort addresses in component text
+ memberAddresses = component.resourceMemberAddresses()
+ component.removeProperties("X-ADDRESSBOOKSERVER-MEMBER")
+ for memberAddress in sorted(memberAddresses):
+ component.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", memberAddress))
+
+ # use sorted test to get size and md5
+ componentText = str(component)
+ self._md5 = hashlib.md5(componentText).hexdigest()
+ self._size = len(componentText)
+ self._componentChanged = componentText != orginialComponent
+
+ # remove members from component get new text
+ component.removeProperties("X-ADDRESSBOOKSERVER-MEMBER")
+ componentText = str(component)
+ self._objectText = componentText
+
+ else:
+ componentText = str(component)
+ self._md5 = hashlib.md5(componentText).hexdigest()
+ self._size = len(componentText)
+ self._objectText = componentText
+
+ uid = component.resourceUID()
+ assert inserting or self._uid == uid # can't change UID. Should be checked in upper layers
+ self._uid = uid
+
# Special - if migrating we need to preserve the original md5
if self._txn._migrating and hasattr(component, "md5"):
self._md5 = component.md5
+ abo = schema.ADDRESSBOOK_OBJECT
+ aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
+ aboMembers = schema.ABO_MEMBERS
+
if inserting:
+
self._resourceID, self._created, self._modified = (
+ yield self._insertABObject.on(
+ self._txn,
+ addressbookResourceID=self._ownerAddressBookResourceID,
+ name=self._name,
+ text=self._objectText,
+ uid=self._uid,
+ md5=self._md5,
+ kind=self._kind,
+ )
+ )[0]
+
+ # delete foreign members table row for this object
+ groupIDRows = yield Delete(
+ aboForeignMembers,
+ # should this be scoped to the owner address book?
+ Where=aboForeignMembers.MEMBER_ADDRESS == "urn:uuid:" + self._uid,
+ Return=aboForeignMembers.GROUP_ID
+ ).on(self._txn)
+ groupIDs = [groupIDRow[0] for groupIDRow in groupIDRows]
+
+ # FIXME: Is this correct? Write test case
+ if not self.owned():
+ if not self._addressbook.fullyShared() or self._addressbook.shareMode() != _BIND_MODE_WRITE:
+ readWriteGroupIDs = yield self._addressbook.readWriteGroupIDs()
+ assert readWriteGroupIDs, "no access"
+ groupIDs.extend(readWriteGroupIDs)
+
+ # add to member table rows
+ for groupID in groupIDs:
yield Insert(
- {ao.ADDRESSBOOK_RESOURCE_ID: self._addressbook._resourceID,
- ao.RESOURCE_NAME: self._name,
- ao.VCARD_TEXT: componentText,
- ao.VCARD_UID: component.resourceUID(),
- ao.MD5: self._md5},
- Return=(ao.RESOURCE_ID,
- ao.CREATED,
- ao.MODIFIED)
- ).on(self._txn))[0]
+ {aboMembers.GROUP_ID: groupID,
+ aboMembers.ADDRESSBOOK_ID: self._ownerAddressBookResourceID,
+ aboMembers.MEMBER_ID: self._resourceID, }
+ ).on(self._txn)
+
else:
self._modified = (yield Update(
- {ao.VCARD_TEXT: componentText,
- ao.VCARD_UID: component.resourceUID(),
- ao.MD5: self._md5,
- ao.MODIFIED: utcNowSQL},
- Where=ao.RESOURCE_ID == self._resourceID,
- Return=ao.MODIFIED).on(self._txn))[0][0]
+ {abo.VCARD_TEXT: self._objectText,
+ abo.MD5: self._md5,
+ abo.MODIFIED: utcNowSQL},
+ Where=abo.RESOURCE_ID == self._resourceID,
+ Return=abo.MODIFIED).on(self._txn))[0][0]
+ if self._kind == _ABO_KIND_GROUP:
+ #get current members
+ currentMemberRows = yield Select([aboMembers.MEMBER_ID],
+ From=aboMembers,
+ Where=aboMembers.GROUP_ID == self._resourceID,).on(self._txn)
+ currentMemberIDs = [currentMemberRow[0] for currentMemberRow in currentMemberRows]
+
+ memberIDsToDelete = set(currentMemberIDs) - set(memberIDs)
+ memberIDsToAdd = set(memberIDs) - set(currentMemberIDs)
+
+ if memberIDsToDelete:
+ yield self._deleteMembersWithGroupIDAndMemberIDsQuery(self._resourceID, memberIDsToDelete).on(
+ self._txn, memberIDs=memberIDsToDelete
+ )
+
+ for memberIDToAdd in memberIDsToAdd:
+ yield Insert(
+ {aboMembers.GROUP_ID: self._resourceID,
+ aboMembers.ADDRESSBOOK_ID: self._ownerAddressBookResourceID,
+ aboMembers.MEMBER_ID: memberIDToAdd, }
+ ).on(self._txn)
+
+ # don't bother with aboForeignMembers on address books
+ if self._resourceID != self._ownerAddressBookResourceID:
+
+ #get current foreign members
+ currentForeignMemberRows = yield Select(
+ [aboForeignMembers.MEMBER_ADDRESS],
+ From=aboForeignMembers,
+ Where=aboForeignMembers.GROUP_ID == self._resourceID,).on(self._txn)
+ currentForeignMemberAddrs = [currentForeignMemberRow[0] for currentForeignMemberRow in currentForeignMemberRows]
+
+ foreignMemberAddrsToDelete = set(currentForeignMemberAddrs) - set(foreignMemberAddrs)
+ foreignMemberAddrsToAdd = set(foreignMemberAddrs) - set(currentForeignMemberAddrs)
+
+ if foreignMemberAddrsToDelete:
+ yield self._deleteForeignMembersWithGroupIDAndMembeAddrsQuery(self._resourceID, foreignMemberAddrsToDelete).on(
+ self._txn, memberAddrs=foreignMemberAddrsToDelete
+ )
+
+ for foreignMemberAddrToAdd in foreignMemberAddrsToAdd:
+ yield Insert(
+ {aboForeignMembers.GROUP_ID: self._resourceID,
+ aboForeignMembers.ADDRESSBOOK_ID: self._ownerAddressBookResourceID,
+ aboForeignMembers.MEMBER_ADDRESS: foreignMemberAddrToAdd, }
+ ).on(self._txn)
+
+
@inlineCallbacks
def component(self):
"""
@@ -366,45 +1999,87 @@
the caller - that is not ideal but in theory we should have checked everything on the way in and
only allowed in good data.
"""
- if self._cachedComponent is None:
- text = yield self._text()
+ if self._component is None:
- try:
- component = VCard.fromString(text)
- except InvalidVCardDataError, e:
- # This is a really bad situation, so do raise
- raise InternalDataStoreError(
- "Data corruption detected (%s) in id: %s"
- % (e, self._resourceID)
- )
+ if not self.owned() and self._resourceID == self._addressbook._resourceID:
+ component = yield self._addressbook._fullySharedAddressBookGroupComponent()
+ else:
+ text = yield self._text()
- # Fix any bogus data we can
- fixed, unfixed = component.validVCardData(doFix=True, doRaise=False)
+ try:
+ component = VCard.fromString(text)
+ except InvalidVCardDataError, e:
+ # This is a really bad situation, so do raise
+ raise InternalDataStoreError(
+ "Data corruption detected (%s) in id: %s"
+ % (e, self._resourceID)
+ )
- if unfixed:
- self.log_error("Address data id=%s had unfixable problems:\n %s" % (self._resourceID, "\n ".join(unfixed),))
+ # Fix any bogus data we can
+ fixed, unfixed = component.validVCardData(doFix=True, doRaise=False)
- if fixed:
- self.log_error("Address data id=%s had fixable problems:\n %s" % (self._resourceID, "\n ".join(fixed),))
+ if unfixed:
+ self.log_error("Address data id=%s had unfixable problems:\n %s" % (self._resourceID, "\n ".join(unfixed),))
- self._cachedComponent = component
+ if fixed:
+ self.log_error("Address data id=%s had fixable problems:\n %s" % (self._resourceID, "\n ".join(fixed),))
- returnValue(self._cachedComponent)
+ if self._kind == _ABO_KIND_GROUP:
+ assert not component.hasProperty("X-ADDRESSBOOKSERVER-MEMBER"), "database group vCard text contains members %s" % (component,)
+ # generate "X-ADDRESSBOOKSERVER-MEMBER" properties
+ # first get member resource ids
+ aboMembers = schema.ABO_MEMBERS
+ memberRows = yield Select(
+ [aboMembers.MEMBER_ID],
+ From=aboMembers,
+ Where=aboMembers.GROUP_ID == self._resourceID,
+ ).on(self._txn)
+ memberIDs = [memberRow[0] for memberRow in memberRows]
+ # then get member UIDs
+ abo = schema.ADDRESSBOOK_OBJECT
+ memberUIDRows = (
+ yield self._columnsWithResourceIDsQuery(
+ [abo.VCARD_UID],
+ memberIDs
+ ).on(self._txn, resourceIDs=memberIDs)
+ ) if memberIDs else []
+ memberUIDs = [memberUIDRow[0] for memberUIDRow in memberUIDRows]
+
+ # add prefix to get property string
+ memberAddresses = ["urn:uuid:" + memberUID for memberUID in memberUIDs]
+
+ # get foreign members
+ aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
+ foreignMemberRows = yield Select(
+ [aboForeignMembers.MEMBER_ADDRESS],
+ From=aboForeignMembers,
+ Where=aboForeignMembers.GROUP_ID == self._resourceID,
+ ).on(self._txn)
+ foreignMembers = [foreignMemberRow[0] for foreignMemberRow in foreignMemberRows]
+
+ # now add the properties to the component
+ for memberAddress in sorted(memberAddresses + foreignMembers):
+ component.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", memberAddress))
+
+ self._component = component
+
+ returnValue(self._component)
+
+
def moveValidation(self, destination, name):
"""
Validate whether a move to the specified collection is allowed.
- @param destination: destination calendar collection
- @type destination: L{CalendarCollection}
+ @param destination: destination address book collection
+ @type destination: L{AddressBookCollection}
@param name: name of new resource
@type name: C{str}
"""
pass
-
# IDataStoreObject
def contentType(self):
"""
@@ -413,5 +2088,423 @@
return MimeType.fromString("text/vcard; charset=utf-8")
+ def owned(self):
+ return self._addressbook.owned()
+
+ def ownerHome(self):
+ return self._addressbook.ownerHome()
+
+
+ def viewerHome(self):
+ return self._addressbook.viewerHome()
+
+
+ def shareUID(self):
+ """
+ @see: L{ICalendar.shareUID}
+ """
+ return self._bindName
+
+ @inlineCallbacks
+ def setShared(self, shared):
+ """
+ Set an owned collection to shared or unshared state. Technically this is not useful as "shared"
+ really means it has invitees, but the current sharing spec supports a notion of a shared collection
+ that has not yet had invitees added. For the time being we will support that option by using a new
+ MESSAGE value to indicate an owned collection that is "shared".
+
+ @param shared: whether or not the owned collection is "shared"
+ @type shared: C{bool}
+ """
+ assert self.owned()
+
+ self._bindMessage = "shared" if shared else None
+
+ ''' FIXME: Make shared persistent: Owned address book does not have a bind table
+ bind = self._bindSchema
+ yield Update(
+ {bind.MESSAGE: self._bindMessage},
+ Where=(bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
+ ).on(self._txn, resourceID=self._resourceID, homeID=self.viewerHome()._resourceID)
+
+ yield self.invalidateQueryCache()
+ yield self.notifyChanged()
+ '''
+ yield None
+
+ @classmethod
+ def metadataColumns(cls):
+ """
+ Return a list of column name for retrieval of metadata. This allows
+ different child classes to have their own type specific data, but still make use of the
+ common base logic.
+ """
+ # Common behavior is to have created and modified
+ return (
+ cls._objectSchema.CREATED,
+ cls._objectSchema.MODIFIED,
+ )
+
+
+ # same as CommonHomeChild._childrenAndMetadataForHomeID() w/o metadata join
+ @classproperty
+ def _childrenAndMetadataForHomeID(cls): #@NoSelf
+ bind = cls._bindSchema
+ child = cls._objectSchema
+ columns = cls.bindColumns() + cls.additionalBindColumns() + cls.metadataColumns()
+ return Select(columns,
+ From=child.join(
+ bind, child.RESOURCE_ID == bind.RESOURCE_ID,
+ 'left outer'),
+ Where=(bind.HOME_RESOURCE_ID == Parameter("homeID")
+ ).And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
+
+
+
+ def notifyChanged(self):
+ return self._addressbook.notifyChanged()
+
+
+ @inlineCallbacks
+ def asShared(self):
+ """
+ Retrieve all the versions of this L{AddressBookObject} as it is shared to
+ everyone.
+
+ @see: L{ICalendarHome.asShared}
+
+ @return: L{AddressBookObject} objects that represent this
+ L{AddressBookObject} as a child of different L{AddressBooks}s
+ in different L{CommonHome}s
+ @rtype: a L{Deferred} which fires with a L{list} of L{AddressBookObject}s.
+ """
+ result = []
+ if self.owned():
+ # get all accepted shared binds
+ groupBindRows = yield self._sharedBindForResourceID.on(
+ self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+ )
+ for groupBindRow in groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = groupBindRow[:self.bindColumnCount] #@UnusedVariable
+ home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+ addressbook = yield home.childWithName(self._home.shareeAddressBookName())
+ new = yield addressbook.objectResourceWithID(resourceID)
+ result.append(new)
+
+ returnValue(result)
+
+
+ @inlineCallbacks
+ def asInvited(self):
+ """
+ Retrieve all the versions of this L{AddressBookObject} as it is shared to
+ everyone.
+
+ @see: L{ICalendarHome.asShared}
+
+ @return: L{AddressBookObject} objects that represent this
+ L{AddressBookObject} as a child of different L{AddressBooks}s
+ in different L{CommonHome}s
+ @rtype: a L{Deferred} which fires with a L{list} of L{AddressBookObject}s.
+ """
+ result = []
+ if self.owned():
+ # get all accepted shared binds
+ groupBindRows = yield self._unacceptedBindForResourceID.on(
+ self._txn, resourceID=self._resourceID
+ )
+ for groupBindRow in groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = groupBindRow[:self.bindColumnCount] #@UnusedVariable
+ home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+ addressbook = yield home.childWithName(self._home.shareeAddressBookName())
+ if not addressbook:
+ addressbook = yield AddressBook.objectWithName(home, self._home.shareeAddressBookName(), accepted=False)
+ new = yield AddressBookObject.objectWithID(addressbook, resourceID) # avoids object cache
+ result.append(new)
+
+ returnValue(result)
+
+
+ @classproperty
+ def _addressbookIDForResourceID(cls): #@NoSelf
+ obj = cls._objectSchema
+ return Select([obj.PARENT_RESOURCE_ID],
+ From=obj,
+ Where=obj.RESOURCE_ID == Parameter("resourceID")
+ )
+
+
+ @classmethod
+ @inlineCallbacks
+ def ownerAddressBookFromGroupID(cls, txn, resourceID):
+ ownerAddressBookIDRows = yield cls._addressbookIDForResourceID.on(txn, resourceID=resourceID)
+ returnValue(ownerAddressBookIDRows[0][0])
+
+
+ @inlineCallbacks
+ def unshare(self):
+ """
+ Unshares a group, regardless of which "direction" it was shared.
+ """
+ if self._kind == _ABO_KIND_GROUP:
+ if self.owned():
+ # This collection may be shared to others
+ for sharedToHome in [x.viewerHome() for x in (yield self.asShared())]:
+ yield self.unshareWith(sharedToHome)
+ else:
+ # This collection is shared to me
+ ownerAddressBook = self._addressbook.ownerHome().addressbook()
+ ownerGroup = yield ownerAddressBook.objectResourceWithID(self._resourceID)
+ if ownerGroup:
+ yield ownerGroup.unshareWith(self._home)
+
+
+ @inlineCallbacks
+ def unshareWith(self, shareeHome):
+ """
+ Remove the shared version of this (owned) L{CommonHomeChild} from the
+ referenced L{CommonHome}.
+
+ @see: L{CommonHomeChild.shareWith}
+
+ @param shareeHome: The home with which this L{CommonHomeChild} was
+ previously shared.
+
+ @return: a L{Deferred} which will fire with the previously-used name.
+ """
+ sharedAddressBook = yield shareeHome.addressbookWithName(self._addressbook.shareeAddressBookName())
+ if sharedAddressBook:
+
+ acceptedBindCount = 1 if sharedAddressBook.fullyShared() else 0
+ acceptedBindCount += len((
+ yield AddressBookObject._acceptedBindForHomeIDAndAddressBookID.on(
+ self._txn, homeID=shareeHome._resourceID, addressbookID=sharedAddressBook._resourceID
+ )
+ ))
+
+ if acceptedBindCount == 1:
+ sharedAddressBook._deletedSyncToken(sharedRemoval=True)
+ shareeHome._children.pop(self._addressbook.shareeAddressBookName(), None)
+ shareeHome._children.pop(self._addressbook._resourceID, None)
+
+ # Must send notification to ensure cache invalidation occurs
+ yield self.notifyChanged()
+
+ # delete binds including invites
+ deletedBindNameRows = yield self._deleteBindForResourceIDAndHomeID.on(
+ self._txn, resourceID=self._resourceID,
+ homeID=shareeHome._resourceID
+ )
+ if deletedBindNameRows:
+ deletedBindName = deletedBindNameRows[0][0]
+ queryCacher = self._txn._queryCacher
+ if queryCacher:
+ cacheKey = queryCacher.keyForObjectWithName(shareeHome._resourceID, self._addressbook.shareeAddressBookName())
+ queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+ else:
+ deletedBindName = None
+
+ returnValue(deletedBindName)
+
+
+ @inlineCallbacks
+ def shareWith(self, shareeHome, mode, status=None, message=None):
+ """
+ Share this (owned) L{AddressBookObject} with another home.
+
+ @param shareeHome: The home of the sharee.
+ @type shareeHome: L{CommonHome}
+
+ @param mode: The sharing mode; L{_BIND_MODE_READ} or
+ L{_BIND_MODE_WRITE} or L{_BIND_MODE_DIRECT}
+ @type mode: L{str}
+
+ @param status: The sharing status; L{_BIND_STATUS_INVITED} or
+ L{_BIND_STATUS_ACCEPTED}
+ @type mode: L{str}
+
+ @param message: The proposed message to go along with the share, which
+ will be used as the default display name.
+ @type mode: L{str}
+
+ @return: the name of the shared group in the sharee home.
+ @rtype: L{str}
+ """
+
+ if status is None:
+ status = _BIND_STATUS_ACCEPTED
+
+ @inlineCallbacks
+ def doInsert(subt):
+ newName = str(uuid4())
+ yield self._bindInsertQuery.on(
+ subt, homeID=shareeHome._resourceID,
+ resourceID=self._resourceID, name=newName,
+ mode=mode, bindStatus=status, message=message
+ )
+ returnValue(newName)
+ try:
+ bindName = yield self._txn.subtransaction(doInsert)
+ except AllRetriesFailed:
+ # FIXME: catch more specific exception
+ groupBindRows = yield self._bindForResourceIDAndHomeID.on(
+ self._txn, resourceID=self._resourceID, homeID=shareeHome._resourceID
+ )
+ groupBindRow = groupBindRows[0]
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = groupBindRow[:self.bindColumnCount] #@UnusedVariable
+ if bindStatus == _BIND_STATUS_ACCEPTED:
+ group = yield shareeHome.objectWithShareUID(bindName)
+ else:
+ group = yield shareeHome.invitedObjectWithShareUID(bindName)
+ bindName = yield self.updateShare(
+ group, mode=mode, status=status,
+ message=message
+ )
+ else:
+ if status == _BIND_STATUS_ACCEPTED:
+ shareeView = yield shareeHome.objectWithShareUID(bindName)
+ yield shareeView._initSyncToken()
+ yield shareeView._initBindRevision()
+
+
+ # Must send notification to ensure cache invalidation occurs
+ yield self.notifyChanged()
+
+ returnValue(bindName)
+
+ @inlineCallbacks
+ #TODO: This is almost the same as AddressBook.updateShare(): combine
+ def updateShare(self, shareeView, mode=None, status=None, message=None, name=None):
+ """
+ Update share mode, status, and message for a home child shared with
+ this (owned) L{CommonHomeChild}.
+
+ @param shareeView: The sharee home child that shares this.
+ @type shareeView: L{CommonHomeChild}
+
+ @param mode: The sharing mode; L{_BIND_MODE_READ} or
+ L{_BIND_MODE_WRITE} or None to not update
+ @type mode: L{str}
+
+ @param status: The sharing status; L{_BIND_STATUS_INVITED} or
+ L{_BIND_STATUS_ACCEPTED} or L{_BIND_STATUS_DECLINED} or
+ L{_BIND_STATUS_INVALID} or None to not update
+ @type status: L{str}
+
+ @param message: The proposed message to go along with the share, which
+ will be used as the default display name, or None to not update
+ @type message: L{str}
+
+ @param name: The bind resource name or None to not update
+ @type message: L{str}
+
+ @return: the name of the shared item in the sharee's home.
+ @rtype: a L{Deferred} which fires with a L{str}
+ """
+ # TODO: raise a nice exception if shareeView is not, in fact, a shared
+ # version of this same L{CommonHomeChild}
+
+
+ #remove None parameters, and substitute None for empty string
+ bind = self._bindSchema
+ columnMap = dict([(k, v if v else None)
+ for k, v in {bind.BIND_MODE:mode,
+ bind.BIND_STATUS:status,
+ bind.MESSAGE:message,
+ bind.RESOURCE_NAME:name}.iteritems() if v is not None])
+
+ if len(columnMap):
+
+ # count accepted
+ if status is not None:
+ previouslyAcceptedBindCount = 1 if shareeView._addressbook.fullyShared() else 0
+ previouslyAcceptedBindCount += len((
+ yield AddressBookObject._acceptedBindForHomeIDAndAddressBookID.on(
+ self._txn, homeID=shareeView._home._resourceID, addressbookID=self._addressbook._resourceID
+ )
+ ))
+
+ sharedname = yield self._updateBindColumnsQuery(columnMap).on(
+ self._txn,
+ resourceID=self._resourceID, homeID=shareeView._home._resourceID
+ )
+
+ #update affected attributes
+ if mode is not None:
+ shareeView._bindMode = columnMap[bind.BIND_MODE]
+
+ if status is not None:
+ shareeView._bindStatus = columnMap[bind.BIND_STATUS]
+ if shareeView._bindStatus == _BIND_STATUS_ACCEPTED:
+ if 0 == previouslyAcceptedBindCount:
+ yield shareeView._addressbook._initSyncToken()
+ yield shareeView._addressbook._initBindRevision()
+ shareeView._home._children[shareeView._addressbook._name] = shareeView._addressbook
+ shareeView._home._children[shareeView._addressbook._resourceID] = shareeView._addressbook
+ elif shareeView._bindStatus != _BIND_STATUS_INVITED:
+ if 1 == previouslyAcceptedBindCount:
+ shareeView._addressbook._deletedSyncToken(sharedRemoval=True)
+ shareeView._home._children.pop(shareeView._addressbook._name, None)
+ shareeView._home._children.pop(shareeView._addressbook._resourceID, None)
+
+ if message is not None:
+ shareeView._bindMessage = columnMap[bind.MESSAGE]
+
+ # safer to just invalidate in all cases rather than calculate when to invalidate
+ queryCacher = self._txn._queryCacher
+ if queryCacher:
+ cacheKey = queryCacher.keyForObjectWithName(shareeView._home._resourceID, shareeView._addressbook._name)
+ queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+
+ shareeView._name = sharedname[0][0]
+
+ # Must send notification to ensure cache invalidation occurs
+ yield self.notifyChanged()
+
+ returnValue(shareeView._name)
+
+
+ @classproperty
+ def _acceptedBindForHomeIDAndAddressBookID(cls): #@NoSelf
+ bind = cls._bindSchema
+ abo = cls._objectSchema
+ return Select(
+ cls.bindColumns() + cls.additionalBindColumns(),
+ From=bind.join(abo),
+ Where=(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+ .And(bind.RESOURCE_ID == abo.RESOURCE_ID)
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ .And(abo.ADDRESSBOOK_HOME_RESOURCE_ID == Parameter("addressbookID"))
+ )
+
+
+ @classproperty
+ def _unacceptedBindForHomeIDAndAddressBookID(cls): #@NoSelf
+ bind = cls._bindSchema
+ abo = cls._objectSchema
+ return Select(
+ cls.bindColumns() + cls.additionalBindColumns(),
+ From=bind.join(abo),
+ Where=(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+ .And(bind.RESOURCE_ID == abo.RESOURCE_ID)
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ .And(abo.ADDRESSBOOK_HOME_RESOURCE_ID == Parameter("addressbookID"))
+ )
+
+
+ @classproperty
+ def _bindForHomeIDAndAddressBookID(cls): #@NoSelf
+ bind = cls._bindSchema
+ abo = cls._objectSchema
+ return Select(
+ cls.bindColumns() + cls.additionalBindColumns(),
+ From=bind.join(abo),
+ Where=(bind.RESOURCE_ID == abo.RESOURCE_ID)
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ .And(abo.ADDRESSBOOK_HOME_RESOURCE_ID == Parameter("addressbookID"))
+ )
+
+
AddressBook._objectResourceClass = AddressBookObject
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/1.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/1.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/1.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,12 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Thompson;Default;;;
-FN:Default Thompson
-EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
-TEL;type=WORK;type=pref:1-555-555-5555
-TEL;type=CELL:1-444-444-4444
-item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
-item1.X-ABADR:us
-UID:uid1
-NOTE:CardDAV protocol updates
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/1.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/1.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/1.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/1.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-444-444-4444
+item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
+item1.X-ABADR:us
+UID:uid1
+NOTE:CardDAV protocol updates
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/2.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/2.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/2.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,17 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Contact;Mulberry;;;
-FN:Mulberry Contact
-NICKNAME:mulberry
-ORG:Apple Inc.;
-EMAIL;type=INTERNET;type=WORK;type=pref:mulberry at example.com
-TEL;type=HOME;type=pref:777-777-7777
-TEL;type=WORK:8888888888
-TEL;type=WORK;type=FAX:5555555555
-item1.ADR;type=WORK;type=pref:;;1234 Infinite Circle;Exampletino\, CA 99999;USA;;
-item1.X-ABADR:us
-NOTE:This is a contact created in Mulberry.
-item2.URL;type=pref:http://www.example.com/~magic
-item2.X-ABLabel:_$!<HomePage>!$_
-UID:uid2
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/2.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/2.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/2.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/2.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,17 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Contact;Mulberry;;;
+FN:Mulberry Contact
+NICKNAME:mulberry
+ORG:Apple Inc.;
+EMAIL;type=INTERNET;type=WORK;type=pref:mulberry at example.com
+TEL;type=HOME;type=pref:777-777-7777
+TEL;type=WORK:8888888888
+TEL;type=WORK;type=FAX:5555555555
+item1.ADR;type=WORK;type=pref:;;1234 Infinite Circle;Exampletino\, CA 99999;USA;;
+item1.X-ABADR:us
+NOTE:This is a contact created in Mulberry.
+item2.URL;type=pref:http://www.example.com/~magic
+item2.X-ABLabel:_$!<HomePage>!$_
+UID:uid2
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/3.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/3.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/3.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,12 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Kawado;Saeko;;;
-FN:Snow Leopard
-ORG:Snow Leopard;
-EMAIL;type=INTERNET;type=WORK;type=pref:snowleopard at example.com
-TEL;type=WORK;type=pref:777-777-7777
-item1.ADR;type=WORK;type=pref:;;1 Fidel Ave. Suite 100;Mountain Top;CA;99999;USA
-item1.X-ABADR:us
-X-ABShowAs:COMPANY
-UID:uid3
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/3.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/3.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/3.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/3.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Kawado;Saeko;;;
+FN:Snow Leopard
+ORG:Snow Leopard;
+EMAIL;type=INTERNET;type=WORK;type=pref:snowleopard at example.com
+TEL;type=WORK;type=pref:777-777-7777
+item1.ADR;type=WORK;type=pref:;;1 Fidel Ave. Suite 100;Mountain Top;CA;99999;USA
+item1.X-ABADR:us
+X-ABShowAs:COMPANY
+UID:uid3
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/3765A955-1B96-41EA-994D-335192BEDCCD.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/3765A955-1B96-41EA-994D-335192BEDCCD.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/3765A955-1B96-41EA-994D-335192BEDCCD.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,18 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:InfoIn;All;;;
-FN:All InfoIn
-ORG:allinfo Company;
-EMAIL;type=INTERNET;type=WORK;type=pref:allinfomationin at example.com
-TEL;type=WORK;type=pref:777-777-7777
-TEL;type=CELL:8888888888
-item1.ADR;type=WORK;type=pref:;;1 Gally Street Apt #2;Mountain Top;CA;99999;USA
-item1.X-ABADR:us
-X-YAHOO;type=WORK;type=pref:saeko.where at example.com
-X-YAHOO-ID;type=WORK;type=pref:saeko.where at example.com
-item2.X-ABRELATEDNAMES;type=pref:Mayumi Yan
-item2.X-ABLabel:_$!<Friend>!$_
-item3.X-ABRELATEDNAMES:Shane
-item3.X-ABLabel:_$!<Assistant>!$_
-UID:3765A955-1B96-41EA-994D-335192BEDCCD
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/3765A955-1B96-41EA-994D-335192BEDCCD.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/3765A955-1B96-41EA-994D-335192BEDCCD.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/3765A955-1B96-41EA-994D-335192BEDCCD.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/3765A955-1B96-41EA-994D-335192BEDCCD.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,18 @@
+BEGIN:VCARD
+VERSION:3.0
+N:InfoIn;All;;;
+FN:All InfoIn
+ORG:allinfo Company;
+EMAIL;type=INTERNET;type=WORK;type=pref:allinfomationin at example.com
+TEL;type=WORK;type=pref:777-777-7777
+TEL;type=CELL:8888888888
+item1.ADR;type=WORK;type=pref:;;1 Gally Street Apt #2;Mountain Top;CA;99999;USA
+item1.X-ABADR:us
+X-YAHOO;type=WORK;type=pref:saeko.where at example.com
+X-YAHOO-ID;type=WORK;type=pref:saeko.where at example.com
+item2.X-ABRELATEDNAMES;type=pref:Mayumi Yan
+item2.X-ABLabel:_$!<Friend>!$_
+item3.X-ABRELATEDNAMES:Shane
+item3.X-ABLabel:_$!<Assistant>!$_
+UID:3765A955-1B96-41EA-994D-335192BEDCCD
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44745975-AE6D-4FB0-80A6-A298427E047A.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44745975-AE6D-4FB0-80A6-A298427E047A.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44745975-AE6D-4FB0-80A6-A298427E047A.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,12 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Mariotte;WithNote;;;
-FN:WithNote Mariotte
-EMAIL;type=INTERNET;type=WORK;type=pref:withnmariotte at example.com
-TEL;type=WORK;type=pref:1-777-777-7777
-TEL;type=CELL:1-8888888888
-item1.ADR;type=WORK;type=pref:;;1 North Blvd;Cupertino;CA;99999;United States
-item1.X-ABADR:us
-NOTE: Address book server test contact that hsa note field filled in.
-UID:44745975-AE6D-4FB0-80A6-A298427E047A
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44745975-AE6D-4FB0-80A6-A298427E047A.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44745975-AE6D-4FB0-80A6-A298427E047A.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44745975-AE6D-4FB0-80A6-A298427E047A.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44745975-AE6D-4FB0-80A6-A298427E047A.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Mariotte;WithNote;;;
+FN:WithNote Mariotte
+EMAIL;type=INTERNET;type=WORK;type=pref:withnmariotte at example.com
+TEL;type=WORK;type=pref:1-777-777-7777
+TEL;type=CELL:1-8888888888
+item1.ADR;type=WORK;type=pref:;;1 North Blvd;Cupertino;CA;99999;United States
+item1.X-ABADR:us
+NOTE: Address book server test contact that hsa note field filled in.
+UID:44745975-AE6D-4FB0-80A6-A298427E047A
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44EE78BF-8814-4471-899C-92280CEFB098.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44EE78BF-8814-4471-899C-92280CEFB098.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44EE78BF-8814-4471-899C-92280CEFB098.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,11 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Śuterry;HiAscii;;;
-FN:HiAscii Śuterry
-EMAIL;type=INTERNET;type=WORK;type=pref:hiascii at example.com
-TEL;type=WORK;type=pref:777-777-7777
-TEL;type=CELL:8888888888
-item1.ADR;type=WORK;type=pref:;;1 ïlena;Paris;Paris;77777;France
-item1.X-ABADR:us
-UID:44EE78BF-8814-4471-899C-92280CEFB098
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44EE78BF-8814-4471-899C-92280CEFB098.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44EE78BF-8814-4471-899C-92280CEFB098.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44EE78BF-8814-4471-899C-92280CEFB098.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44EE78BF-8814-4471-899C-92280CEFB098.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Śuterry;HiAscii;;;
+FN:HiAscii Śuterry
+EMAIL;type=INTERNET;type=WORK;type=pref:hiascii at example.com
+TEL;type=WORK;type=pref:777-777-7777
+TEL;type=CELL:8888888888
+item1.ADR;type=WORK;type=pref:;;1 ïlena;Paris;Paris;77777;France
+item1.X-ABADR:us
+UID:44EE78BF-8814-4471-899C-92280CEFB098
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,12 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:バイト;ダブル;;;
-FN:ダブル バイト
-EMAIL;type=INTERNET;type=WORK;type=pref:doublebytes at example.com
-TEL;type=WORK;type=pref:777-777-7777
-TEL;type=CELL:8888888888
-item1.ADR;type=WORK;type=pref:;;1-23-4 Irohacho #2;Tokyo;Japan;33-3333;Japan
-item1.X-ABADR:us
-NOTE:日本ですよ。
-UID:8424B7F0-C878-4722-B522-EBB07CF48AD7
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+VERSION:3.0
+N:バイト;ダブル;;;
+FN:ダブル バイト
+EMAIL;type=INTERNET;type=WORK;type=pref:doublebytes at example.com
+TEL;type=WORK;type=pref:777-777-7777
+TEL;type=CELL:8888888888
+item1.ADR;type=WORK;type=pref:;;1-23-4 Irohacho #2;Tokyo;Japan;33-3333;Japan
+item1.X-ABADR:us
+NOTE:日本ですよ。
+UID:8424B7F0-C878-4722-B522-EBB07CF48AD7
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/934731C6-1C95-4C40-BE1F-FA4215B2307B.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/934731C6-1C95-4C40-BE1F-FA4215B2307B.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/934731C6-1C95-4C40-BE1F-FA4215B2307B.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,993 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Picture;With;;;
-FN:With Picture
-EMAIL;type=INTERNET;type=WORK;type=pref:withpicture at example.com
-TEL;type=WORK;type=pref:777-777-7777
-TEL;type=CELL:8888888888
-item1.ADR;type=WORK;type=pref:;;1234 Golly Street;Sunnyside;CA;99999;USA
-item1.X-ABADR:us
-PHOTO;BASE64:
- /9j/4AAQSkZJRgABAQAAAQABAAD/7QA8UGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAB8cAVoAAx
- sl RxwCAAACAAIcAhkAC1Bob3RvIEJvb3RoAP/iG6hJQ0NfUFJPRklMRQABAQAAG5hhcHBsAgA
- AAG1u dHJSR0IgWFlaIAfaAAEAEwAJADEABGFjc3BBUFBMAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAD2 1gABAAAAANMtYXBwbFYcEOZVYuhIRg5LwLIi62wAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAA AAAAEXJYWVoAAAFQAAAAFGdYWVoAAAFkAAAAFGJYWVoAAAF4AAAAFHd0cHQAAA
- GMAAAAFGNoYWQA AAGgAAAALHJUUkMAAAHMAAAIDGdUUkMAAAnYAAAIDGJUUkMAABHkAAAIDGF
- hcmcAABnwAAAAIGFh Z2cAABoQAAAAIGFhYmcAABowAAAAIHZjZ3QAABpQAAAAMG5kaW4AABqA
- AAAAOGRlc2MAABq4AAAA ZGRzY20AABscAAAALm1tb2QAABtMAAAAKGNwcnQAABt0AAAAJFhZW
- iAAAAAAAAB7vQAAQXsAAAJL WFlaIAAAAAAAAFYqAACp0AAAFF9YWVogAAAAAAAAJO8AABS1AA
- C8glhZWiAAAAAAAADz2AABAAAA ARYIc2YzMgAAAAAAAQu3AAAFlv//81cAAAcpAAD91///+7f
- ///2mAAAD2gAAwPZjdXJ2AAAAAAAA BAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUA
- SgBPAFQAWQBeAGMAaABtAHIAdwB8AIEA hgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0
- ADVANoA4ADlAOoA8AD1APsBAQEHAQwBEgEY AR4BJQErATEBOAE+AUUBSwFSAVkBYAFmAW0BdQ
- F8AYMBigGSAZkBoQGoAbABuAHAAcgB0AHYAeAB 6QHxAfoCAgILAhQCHAIlAi4CNwJAAkoCUwJ
- cAmYCcAJ5AoMCjQKXAqECqwK1Ar8CygLUAt8C6gL0 Av8DCgMVAyADKwM3A0IDTQNZA2UDcAN8
- A4gDlAOgA6wDuQPFA9ID3gPrA/gEBAQRBB4ELAQ5BEYE VARhBG8EfASKBJgEpgS0BMIE0QTfB
- O4E/AULBRoFKAU3BUcFVgVlBXQFhAWTBaMFswXDBdMF4wXz BgMGFAYkBjUGRQZWBmcGeAaJBp
- oGqwa9Bs4G4AbyBwMHFQcnBzkHTAdeB3AHgweWB6gHuwfOB+EH 9AgICBsILwhCCFYIagh+CJI
- Ipgi6CM4I4wj3CQwJIQk2CUsJYAl1CYoJoAm1CcsJ4An2CgwKIgo5 Ck8KZQp8CpIKqQrACtcK
- 7gsFCx0LNAtLC2MLewuTC6sLwwvbC/MMDAwkDD0MVgxuDIcMoQy6DNMM 7Q0GDSANOg1UDW4Ni
- A2iDbwN1w3xDgwOJw5CDl0OeA6TDq8Oyg7mDwIPHg86D1YPcg+OD6sPyA/k EAEQHhA7EFgQdh
- CTELEQzhDsEQoRKBFGEWQRgxGhEcAR3xH+Eh0SPBJbEnoSmhK5EtkS+RMZEzkT WRN6E5oTuxP
- bE/wUHRQ+FF8UgRSiFMQU5RUHFSkVSxVtFZAVshXVFfcWGhY9FmAWgxanFsoW7hcS FzUXWRd9
- F6IXxhfqGA8YNBhZGH0YoxjIGO0ZExk4GV4ZhBmqGdAZ9hodGkMaahqQGrca3hsGGy0b VBt8G
- 6MbyxvzHBscQxxsHJQcvRzmHQ4dNx1gHYodsx3dHgYeMB5aHoQerh7YHwMfLR9YH4Mfrh/Z IA
- QgMCBbIIcgsyDeIQohNyFjIY8hvCHpIhUiQiJwIp0iyiL4IyUjUyOBI68j3SQMJDokaSSXJMYk
- 9SUkJVQlgyWzJeImEiZCJnImoybTJwMnNCdlJ5Ynxyf4KCooWyiNKL4o8CkiKVUphym5KewqHy
- pS KoUquCrrKx4rUiuGK7or7iwiLFYsiiy/LPQtKS1eLZMtyC39LjMuaS6eLtQvCy9BL3cvri/
- kMBsw UjCJMMEw+DEwMWcxnzHXMg8ySDKAMrgy8TMqM2MznDPVNA80SDSCNLw09jUwNWo1pTXf
- Nho2VTaQ Nss3BjdCN343uTf1ODE4bTiqOOY5IzlgOZ052joXOlQ6kjrPOw07SzuJO8c8BjxEP
- IM8wj0BPUA9 fz2/Pf4+Pj5+Pr4+/j8/P38/wEAAQEFAgkDEQQVBR0GIQcpCDEJOQpFC00MWQ1
- hDm0PeRCFEZUSo ROxFMEV0RbhF/EZARoVGykcOR1NHmUfeSCNIaUivSPVJO0mBScdKDkpVSpt
- K4ksqS3FLuEwATEhM kEzYTSBNaE2xTfpOQk6MTtVPHk9nT7FP+1BFUI9Q2VEkUW5RuVIEUk9S
- mlLlUzFTfFPIVBRUYFSt VPlVRlWSVd9WLFZ6VsdXFFdiV7BX/lhMWJpY6Vk4WYZZ1VokWnRaw
- 1sTW2NbslwDXFNco1z0XURd lV3mXjdeiV7aXyxffl/QYCJgdGDHYRlhbGG/YhJiZWK5YwxjYG
- O0ZAhkXGSxZQVlWmWvZgRmWWav ZwRnWmewaAZoXGiyaQlpX2m2ag1qZGq8axNra2vDbBtsc2z
- LbSNtfG3Vbi5uh27gbzpvk2/tcEdw oXD7cVZxsHILcmZywXMcc3hz03QvdIt053VDdaB1/HZZ
- drZ3E3dwd854K3iJeOd5RXmjegJ6YHq/ ex57fXvcfDx8m3z7fVt9u34bfnx+3H89f55//4Bgg
- MKBI4GFgeeCSYKrgw6DcIPThDaEmYT8hWCF w4YnhouG74dUh7iIHYiBiOaJTImxihaKfIrii0
- iLrowUjHuM4o1Ija+OF45+juWPTY+1kB2QhZDu kVaRv5IokpGS+pNkk82UN5ShlQuVdZXglkq
- WtZcgl4uX95himM6ZOpmmmhKafprrm1ebxJwxnJ+d DJ15neeeVZ7DnzGfoKAPoH2g7KFbocui
- OqKqoxqjiqP6pGqk26VMpbymLqafpxCngqf0qGWo2KlK qbyqL6qiqxWriKv7rG+s461WrcuuP
- 66zryivnbARsIew/LFxseeyXbLTs0mzv7Q2tK21JLWbthK2 ibcBt3m38bhpuOG5WrnSuku6xL
- s+u7e8MLyqvSS9nr4ZvpO/Dr+JwATAf8D6wXbB8cJtwunDZsPi xF/E3MVZxdbGU8bRx07HzMh
- KyMnJR8nGykXKxMtDy8LMQszBzUHNwc5CzsLPQ8/D0ETQxtFH0cjS StLM007T0NRT1NbVWNXb
- 1l7W4tdl1+nYbdjx2XXZ+tp/2wPbiNwO3JPdGd2e3iTeqt8x37fgPuDF 4Uzh0+Ja4uLjauPy5
- HrlAuWL5hPmnOcl56/oOOjC6Uzp1upg6urrdev/7IrtFu2h7izuuO9E79Dw XPDp8XXyAvKP8x
- zzqvQ39MX1U/Xh9m/2/veM+Bv4qvk5+cn6Wfro+3j8CPyZ/Sn9uv5L/tz/bmN1 cnYAAAAAAAA
- EAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0A cgB3AHwA
- gQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2gDgAOUA6gDwAPUA+wEB AQcBD
- AESARgBHgElASsBMQE4AT4BRQFLAVIBWQFgAWYBbQF1AXwBgwGKAZIBmQGhAagBsAG4AcAB yA
- HQAdgB4AHpAfEB+gICAgsCFAIcAiUCLgI3AkACSgJTAlwCZgJwAnkCgwKNApcCoQKrArUCvwLK
- AtQC3wLqAvQC/wMKAxUDIAMrAzcDQgNNA1kDZQNwA3wDiAOUA6ADrAO5A8UD0gPeA+sD+AQEBB
- EE HgQsBDkERgRUBGEEbwR8BIoEmASmBLQEwgTRBN8E7gT8BQsFGgUoBTcFRwVWBWUFdAWEBZM
- FowWz BcMF0wXjBfMGAwYUBiQGNQZFBlYGZwZ4BokGmgarBr0GzgbgBvIHAwcVBycHOQdMB14H
- cAeDB5YH qAe7B84H4Qf0CAgIGwgvCEIIVghqCH4IkgimCLoIzgjjCPcJDAkhCTYJSwlgCXUJi
- gmgCbUJywng CfYKDAoiCjkKTwplCnwKkgqpCsAK1wruCwULHQs0C0sLYwt7C5MLqwvDC9sL8w
- wMDCQMPQxWDG4M hwyhDLoM0wztDQYNIA06DVQNbg2IDaINvA3XDfEODA4nDkIOXQ54DpMOrw7
- KDuYPAg8eDzoPVg9y D44Pqw/ID+QQARAeEDsQWBB2EJMQsRDOEOwRChEoEUYRZBGDEaERwBHf
- Ef4SHRI8ElsSehKaErkS 2RL5ExkTORNZE3oTmhO7E9sT/BQdFD4UXxSBFKIUxBTlFQcVKRVLF
- W0VkBWyFdUV9xYaFj0WYBaD FqcWyhbuFxIXNRdZF30XohfGF+oYDxg0GFkYfRijGMgY7RkTGT
- gZXhmEGaoZ0Bn2Gh0aQxpqGpAa txreGwYbLRtUG3wboxvLG/McGxxDHGwclBy9HOYdDh03HWA
- dih2zHd0eBh4wHloehB6uHtgfAx8t H1gfgx+uH9kgBCAwIFsghyCzIN4hCiE3IWMhjyG8Ieki
- FSJCInAinSLKIvgjJSNTI4EjryPdJAwk OiRpJJckxiT1JSQlVCWDJbMl4iYSJkImciajJtMnA
- yc0J2UnlifHJ/goKihbKI0ovijwKSIpVSmH Kbkp7CofKlIqhSq4KusrHitSK4YruivuLCIsVi
- yKLL8s9C0pLV4tky3ILf0uMy5pLp4u1C8LL0Ev dy+uL+QwGzBSMIkwwTD4MTAxZzGfMdcyDzJ
- IMoAyuDLxMyozYzOcM9U0DzRINII0vDT2NTA1ajWl Nd82GjZVNpA2yzcGN0I3fje5N/U4MTht
- OKo45jkjOWA5nTnaOhc6VDqSOs87DTtLO4k7xzwGPEQ8 gzzCPQE9QD1/Pb89/j4+Pn4+vj7+P
- z8/fz/AQABAQUCCQMRBBUFHQYhBykIMQk5CkULTQxZDWEOb Q95EIURlRKhE7EUwRXRFuEX8Rk
- BGhUbKRw5HU0eZR95II0hpSK9I9Uk7SYFJx0oOSlVKm0riSypL cUu4TABMSEyQTNhNIE1oTbF
- N+k5CToxO1U8eT2dPsU/7UEVQj1DZUSRRblG5UgRST1KaUuVTMVN8 U8hUFFRgVK1U+VVGVZJV
- 31YsVnpWx1cUV2JXsFf+WExYmljpWThZhlnVWiRadFrDWxNbY1uyXANc U1yjXPRdRF2VXeZeN
- 16JXtpfLF9+X9BgImB0YMdhGWFsYb9iEmJlYrljDGNgY7RkCGRcZLFlBWVa Za9mBGZZZq9nBG
- daZ7BoBmhcaLJpCWlfabZqDWpkarxrE2tra8NsG2xzbMttI218bdVuLm6HbuBv Om+Tb+1wR3C
- hcPtxVnGwcgtyZnLBcxxzeHPTdC90i3TndUN1oHX8dll2tncTd3B3zngreIl453lF eaN6Anpg
- er97Hnt9e9x8PHybfPt9W327fht+fH7cfz1/nn//gGCAwoEjgYWB54JJgquDDoNwg9OE NoSZh
- PyFYIXDhieGi4bvh1SHuIgdiIGI5olMibGKFop8iuKLSIuujBSMe4zijUiNr44Xjn6O5Y9N j7
- WQHZCFkO6RVpG/kiiSkZL6k2STzZQ3lKGVC5V1leCWSpa1lyCXi5f3mGKYzpk6maaaEpp+muub
- V5vEnDGcn50MnXmd555VnsOfMZ+goA+gfaDsoVuhy6I6oqqjGqOKo/qkaqTbpUylvKYupp+nEK
- eC p/SoZajYqUqpvKovqqKrFauIq/usb6zjrVaty64/rrOvKK+dsBGwh7D8sXGx57JdstOzSbO
- /tDa0 rbUktZu2EraJtwG3ebfxuGm44blaudK6S7rEuz67t7wwvKq9JL2evhm+k78Ov4nABMB/
- wPrBdsHx wm3C6cNmw+LEX8TcxVnF1sZTxtHHTsfMyErIyclHycbKRcrEy0PLwsxCzMHNQc3Bz
- kLOws9Dz8PQ RNDG0UfRyNJK0szTTtPQ1FPU1tVY1dvWXtbi12XX6dht2PHZddn62n/bA9uI3A
- 7ck90Z3Z7eJN6q 3zHft+A+4MXhTOHT4lri4uNq4/LkeuUC5YvmE+ac5yXnr+g46MLpTOnW6mD
- q6ut16//siu0W7aHu LO6470Tv0PBc8OnxdfIC8o/zHPOq9Df0xfVT9eH2b/b+94z4G/iq+Tn5
- yfpZ+uj7ePwI/Jn9Kf26 /kv+3P9uY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAoAC0AM
- gA3ADsAQABFAEoATwBUAFkA XgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAKQAqQCuALIAtw
- C8AMEAxgDLANAA1QDaAOAA5QDq APAA9QD7AQEBBwEMARIBGAEeASUBKwExATgBPgFFAUsBUgF
- ZAWABZgFtAXUBfAGDAYoBkgGZAaEB qAGwAbgBwAHIAdAB2AHgAekB8QH6AgICCwIUAhwCJQIu
- AjcCQAJKAlMCXAJmAnACeQKDAo0ClwKh AqsCtQK/AsoC1ALfAuoC9AL/AwoDFQMgAysDNwNCA
- 00DWQNlA3ADfAOIA5QDoAOsA7kDxQPSA94D 6wP4BAQEEQQeBCwEOQRGBFQEYQRvBHwEigSYBK
- YEtATCBNEE3wTuBPwFCwUaBSgFNwVHBVYFZQV0 BYQFkwWjBbMFwwXTBeMF8wYDBhQGJAY1BkU
- GVgZnBngGiQaaBqsGvQbOBuAG8gcDBxUHJwc5B0wH XgdwB4MHlgeoB7sHzgfhB/QICAgbCC8I
- QghWCGoIfgiSCKYIugjOCOMI9wkMCSEJNglLCWAJdQmK CaAJtQnLCeAJ9goMCiIKOQpPCmUKf
- AqSCqkKwArXCu4LBQsdCzQLSwtjC3sLkwurC8ML2wvzDAwM JAw9DFYMbgyHDKEMugzTDO0NBg
- 0gDToNVA1uDYgNog28DdcN8Q4MDicOQg5dDngOkw6vDsoO5g8C Dx4POg9WD3IPjg+rD8gP5BA
- BEB4QOxBYEHYQkxCxEM4Q7BEKESgRRhFkEYMRoRHAEd8R/hIdEjwS WxJ6EpoSuRLZEvkTGRM5
- E1kTehOaE7sT2xP8FB0UPhRfFIEUohTEFOUVBxUpFUsVbRWQFbIV1RX3 FhoWPRZgFoMWpxbKF
- u4XEhc1F1kXfReiF8YX6hgPGDQYWRh9GKMYyBjtGRMZOBleGYQZqhnQGfYa HRpDGmoakBq3Gt
- 4bBhstG1QbfBujG8sb8xwbHEMcbByUHL0c5h0OHTcdYB2KHbMd3R4GHjAeWh6E Hq4e2B8DHy0
- fWB+DH64f2SAEIDAgWyCHILMg3iEKITchYyGPIbwh6SIVIkIicCKdIsoi+CMlI1Mj gSOvI90k
- DCQ6JGkklyTGJPUlJCVUJYMlsyXiJhImQiZyJqMm0ycDJzQnZSeWJ8cn+CgqKFsojSi+ KPApI
- ilVKYcpuSnsKh8qUiqFKrgq6yseK1Irhiu6K+4sIixWLIosvyz0LSktXi2TLcgt/S4zLmku ni
- 7ULwsvQS93L64v5DAbMFIwiTDBMPgxMDFnMZ8x1zIPMkgygDK4MvEzKjNjM5wz1TQPNEg0gjS8
- NPY1MDVqNaU13zYaNlU2kDbLNwY3Qjd+N7k39TgxOG04qjjmOSM5YDmdOdo6FzpUOpI6zzsNO0
- s7 iTvHPAY8RDyDPMI9AT1APX89vz3+Pj4+fj6+Pv4/Pz9/P8BAAEBBQIJAxEEFQUdBiEHKQgx
- CTkKR QtNDFkNYQ5tD3kQhRGVEqETsRTBFdEW4RfxGQEaFRspHDkdTR5lH3kgjSGlIr0j1STtJ
- gUnHSg5K VUqbSuJLKktxS7hMAExITJBM2E0gTWhNsU36TkJOjE7VTx5PZ0+xT/tQRVCPUNlRJ
- FFuUblSBFJP UppS5VMxU3xTyFQUVGBUrVT5VUZVklXfVixWelbHVxRXYlewV/5YTFiaWOlZOF
- mGWdVaJFp0WsNb E1tjW7JcA1xTXKNc9F1EXZVd5l43Xole2l8sX35f0GAiYHRgx2EZYWxhv2I
- SYmViuWMMY2BjtGQI ZFxksWUFZVplr2YEZllmr2cEZ1pnsGgGaFxosmkJaV9ptmoNamRqvGsT
- a2trw2wbbHNsy20jbXxt 1W4ubodu4G86b5Nv7XBHcKFw+3FWcbByC3JmcsFzHHN4c9N0L3SLd
- Od1Q3Wgdfx2WXa2dxN3cHfO eCt4iXjneUV5o3oCemB6v3see3173Hw8fJt8+31bfbt+G358ft
- x/PX+ef/+AYIDCgSOBhYHngkmC q4MOg3CD04Q2hJmE/IVghcOGJ4aLhu+HVIe4iB2IgYjmiUy
- JsYoWinyK4otIi66MFIx7jOKNSI2v jheOfo7lj02PtZAdkIWQ7pFWkb+SKJKRkvqTZJPNlDeU
- oZULlXWV4JZKlrWXIJeLl/eYYpjOmTqZ ppoSmn6a65tXm8ScMZyfnQydeZ3nnlWew58xn6CgD
- 6B9oOyhW6HLojqiqqMao4qj+qRqpNulTKW8 pi6mn6cQp4Kn9KhlqNipSqm8qi+qoqsVq4ir+6
- xvrOOtVq3Lrj+us68or52wEbCHsPyxcbHnsl2y 07NJs7+0NrSttSS1m7YStom3Abd5t/G4abj
- huVq50rpLusS7Pru3vDC8qr0kvZ6+Gb6Tvw6/icAE wH/A+sF2wfHCbcLpw2bD4sRfxNzFWcXW
- xlPG0cdOx8zISsjJyUfJxspFysTLQ8vCzELMwc1BzcHO Qs7Cz0PPw9BE0MbRR9HI0krSzNNO0
- 9DUU9TW1VjV29Ze1uLXZdfp2G3Y8dl12fraf9sD24jcDtyT 3Rndnt4k3qrfMd+34D7gxeFM4d
- PiWuLi42rj8uR65QLli+YT5pznJeev6DjowulM6dbqYOrq63Xr /+yK7Rbtoe4s7rjvRO/Q8Fz
- w6fF18gLyj/Mc86r0N/TF9VP14fZv9v73jPgb+Kr5OfnJ+ln66Pt4 /Aj8mf0p/br+S/7c/25w
- YXJhAAAAAAADAAAAAmZmAADypwAADVkAABPQAAALA3BhcmEAAAAAAAMA AAACZmYAAPKnAAANW
- QAAE9AAAAsDcGFyYQAAAAAAAwAAAAJmZgAA8qcAAA1ZAAAT0AAACwN2Y2d0 AAAAAAAAAAEAAQ
- AAAAAAAAABAAAAAQAAAAAAAAABAAAAAQAAAAAAAAABAABuZGluAAAAAAAAADAA AKPAAABXwAA
- ASsAAAJ5AAAAlQAAAEwAAAFBAAABUQAACMzMAAjMzAAIzM2Rlc2MAAAAAAAAACkNp bmVtYSBI
- RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAABIAAAAc AE
- MAaQBuAGUAbQBhACAASABEAABtbW9kAAAAAAAABhAAAJIjAgAqqcBCT4AAAAAAAAAAAAAAAAAA
- AAAAdGV4dAAAAABDb3B5cmlnaHQgQXBwbGUsIEluYy4sIDIwMTAA/+EAQEV4aWYAAE1NACoAAA
- AI AAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAAoCgAwAEAAAAAQAAAeAAAAAA/9sAQwA
- CAgIC AgECAgICAgICAwMGBAMDAwMHBQUEBggHCAgIBwgICQoNCwkJDAoICAsPCwwNDg4ODgkL
- EBEPDhEN Dg4O/9sAQwECAgIDAwMGBAQGDgkICQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4OD
- g4ODg4ODg4O Dg4ODg4ODg4ODg4ODg4O/8AAEQgB4AKAAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQ
- EBAAAAAAAAAAAB AgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhN
- RYQcicRQygZGhCCNC scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RV
- VldYWVpjZGVmZ2hpanN0 dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4u
- brCw8TFxsfIycrS09TV1tfY 2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQ
- EAAAAAAAABAgMEBQYHCAkKC//E ALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXE
- TIjKBCBRCkaGxwQkjM1LwFWJy0QoW JDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZX
- WFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWG h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5u
- sLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp 6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A+To438
- n5HVipGCR1q/Em6JiwOc9PrUEKbY8KCd3SrsUZ UfNk7sZA9ayje2jCbjHboWoh5gIJCsp71PH
- ErQltrDcfXrTQvz4I4zwAeasLE8bcA4HTNNU07u+o oKLd0yaJFEWQCGwCD6CtJBFsOCSx6nNV
- wuxE+Q5HC59KsxxuACNufUjpWjp33ZLm0TwpsdgnO3HG fWrSjEnG7nr+VQRIWYqQ3J4q7GMNn
- OCTilaNxzaT1Y+NWSJQw6Lipo13RM3pgfjUa5RzuO5asxKi kEkYA6VqtI+pLaWhZZRJFGDlyM
- kY71MgUIecgjn61HbguCjoyg9+lSxoVbDHbnkkjpWaj0fQldri g52+4yaFj2y8AqvbmlCls4O
- DnAJ9Ksqylxxz0Fa81mrIt3jHTqKkW/DZ5PJxUgQhmByXBz+lAAUA k9D2qcbAFZTuPcntUOUm
- 7Iq17SYigNGoYbiF7UhGJfQAZz2zUiliduRwdtTkYQhSFXd1NDk927lR Scit85kG3gnHFLhwA
- FHOc/Wp4wNuVHHc1IACxB7D16VE2+a6QX3uiEJlD8pyTkj0p2394QQSQMYF SnOSMhe3Sm7Cjq
- mecck1fNeOpMoprRgFOCOetOcMSrHg9elPAxIN2MHkcdqcRltuDg85rG0m9EFu zI/LRWwAScZ
- Jz1qdYQ6EkYZe1KiFnG0qPXNPwSQpJI7Y705yfRltSe5XdHLbu2enpT1HzorHOBjH tUmxhkkP
- j+VTJGwYFgNp6k9qXncIzTViAxgAjsPU0Kn4euas+WcOx4GaBHk7sL1GM96q65Xd3KjF W0ZFj
- aSQQ425NSrGSARwTkA9s0qRqCSenQVZCrsO0MOelRKSTSSM3q9Csy5Us3LnH51IYyYs5zg8 U4
- JyTtJwanCsEwMHDZxjkD3q4JNle8rscgySOM/xe9O2sMdTjJx9KmSJt7FgASevtT1j3MCucg9/
- SpcnfVGcVGz1K5A3K5545+tChshh1PUmrYjUxlQCy57elBSQPwowDjmm9VuNP3WV+EYEhsZwD7
- 1J 5J8hPmBPU+9WFBEhLAcgHkd6MFQvTI45PQVV9dUOzbuiqy7QY14wc59qV41LYHJz61Oqqck
- 5Ck55 70BAH3N+B9aXMloWm4+RD5fBU8Z70/CGIIRkgCpH+UZYZUd6REClRz64PUVUWum5Ls3e
- 40KOWPJJ ySO1O2ARk7SecjHrUx4G7aCuc1IIt5G3PqwpXfVA1FSRXXPkruO3PApArlxhgFAw1
- WOA4UgLzyT/ ACppUuu3B2selWvd3RDTTd1Yr/OZM54PU+1QqDu5OwDocdauldockfTNQAttBl
- AKdiB1pdW2i3Hm V0tCA9HwDgNjFVHAM24Da2CRn0q80eWPGFIz9DVdo+u75h0yKiN4PRgrRV7
- 3KgDbl24B5xnvUbB9 x2jAH86uBBgsM5XvnpUBDEE7lJ7itLoEkiIKwO5Dgn1HWlbywxDk5HQ+
- 9TE7odqDaucjPUVGw+Ut wxPYCsVBbBy8xG65jcHJycDHeq4j3LuHAA+6fX1q9jeMgDJ6HFQbS
- YsZ6frXRBNJ3JbtuisBiTK8 8jj3pXZyjsOCCOoqfaDKCo+975pxVhHtwAMYJNZ631FzK+xS2h
- gxYcqvr1qIYDbiCMj86uGPDBWH TuO9Q+UCgC/fz1NaXhs2a+0SVkQBR5me5/Wo2CkMGyvHU/W
- rRTM23DZzyewprKwKbgSMdMVlzLWx GiaZWZjgncMdAKh2MZPu4wME5qw6cL8v3RSNteQqnUD5
- qSduhUndaFJ0zDg9R1xUBjDJtwdpXIIq 4yb3L7H9wTTHXbBtTHzdCaq/K77icVoomeYiybHO0
- d6rSJt6EEdiexrTKtxsXLY5Paq7RMJgSAV9 AO9aRloxwhzbsoup2LzkHjFV5EJCg4Cgg5J71o
- vHvZQT8oyenJqJok3spy2RkUmna19yNFKyZmkF Qp77TkfWmYAUKwK854rQ8tGiBLLnuPU01kX
- G/cCc8nHFRey1KbVrWM4oPvAhWB4J7etV2RfkUckN lauunm4JAHJOMVXlj2gEHoM5qKcYq/mV
- Dkdmys20naecZGRVcqQAduATyPStJAB8q7Xz6dxULsm0 gRk49T1pTcl0M5rXRGaYwqAschhgj
- pz2pohVSH5DAYPPerk4Aj2k8KPkJqMqhVsjA+8aykoyV1qy KrbdmcPbIxtyuVDk8fnU6rIGwd
- ofkdO3rTIInVztB4HrV6AMW3Pznnnr9K0Ti/e6lxS2JI0Cpuxu I6Cre1WXBIyM8jtUaBWcFM4
- PcnirO35gvOSMgY61cZrZjcHGWwi7iuCcj+Ee1X9hXaW4GOcnvUSq DtAIYDgEVbRCBubJwcVS
- kk77EX5unyFQnapVjwfWrigjkHDcHJ5qFVIjD4G0jgkd6srGGm5IU4ye a05+idg93axKCN6kr
- vBPIFWU2iR8grn7opIIwTtDAgc4qYRESj5DhelJVOgRkh6K5X5uFHT3NWM5 D56ds0kSkCMEdu
- hqVEEm4ZAb+lNpLV7DhK716CAgAZIXb6ipCSUYfx54I9KcEGdzfMO3vUwUsQdp 9zUOSvciDs7
- iRhfJAI3AEDOeasEqVZQhB3YzTFXksFOMAjPQ1KuWl5GOetOUrlNSXoBQHaOjcfnU ka5U8YHb
- PenlOeDnjipowcruCliMAAVkqivoTKWtyNFwrZHy+3rTRlnYpww9RVlk25yehAxTdv8A dGQD0
- qlO+xoprls9xrMCB8wyf0pCuWHfHenCPMuzGOeuKmSM7kBIZTyfX6VF9GPVOxCvLZPOD27V KE
- bIJypB4PtTyquWCgkcdOtSohG35WbB4FKLk7hLyIwrGU7umck461OqnIBABxxgUoV15QBhyRxU
- 6eYeoyMfLxRe1rpBza3bsQZQjcfu9TUygsrkKewB7U7CBcbcZOOaeyB9wG4ZYdDilLlRLV43aI
- TG uPmJ6cD0p21sBODjgcdqnxmPIU8cD6UuTtw2D6cYzQ46FySk1cjCfu8MMgHjFAQlNoGVz1q
- 4qghS VyT2oC4QYVjk5JHalC9rijOMVpoVkUhyQC4x0FWQB5bYG3d1Y/yp+z+JAct/KpnX5Azj
- bz0NNTaY k4vcr7ZNoyQwHT61NtO44OM/p7U5doVdx5IPSpgCEAGCTxWmluxUdFqyMAhcHO3GK
- cSfJORkAjp6 U9cFgMH/AGs96fszGV2n1xUzXSwKdyIE7GUjjqPWmMMjoTk8+9TjG7ZyzY5FLt
- 3KNwwR29KXw9Ac bNELITCVOGbsQKaAxkI6AdzVkgliFU7R3pdqm4YlSoOMZp82gcyk7EGNyjc
- QwxggU0A+aXCYY+tW lTO3b3PXFKEKJwCcVSfvWsVztIgbe23cPy70/Y2CBnPXr0qVfmBVl4Jy
- MU9IwAR0HbJ6Ucz6IzTa 1kyLYMDncWHTHU0NkAKFxjjOOlP2Ethn4HpSAbnz144BPNNy1CMdd
- dSsWy43jdj26UhH948jsBUp QtIwxtIPT0pWX94GUHO386huI3Ho0UXjV3ZS5Uk5AzTRGFkJOc
- dvarGBvxgk7eD6VHs3RKTuDZwc 96J3ve5bTatcpMSrPgD73PFJJHnHG47cjjvVh4w82GO3NN2
- lmbkbRwvrRGpZak8qbK4RdoPc56U1 Yssc8Lj8an2FWA2kDrmjaSJF7Acgd6qE2nZAoroVzkRh
- MHryR601lLK/RecdKsbVQhs5BOMZppUD LDoWyM/zpuUn5lUuVN6FFDhsgcKecUOQVODhifu1b
- KjcSBt9TUJQqRlcE8Z60m1fUUpq2xAQxG4Y yM5yKiY8jcV6YOBirexgvIyvUkVXKhotuNp7E+
- 9J27ExlddyJkzGqA8g4+opgQ+YTuyoOfc1MQm/ axIIXtSIqHDchgp4zS5ujJcXazKnl43NnIL
- fjTCWBJ+UZzxire0OMgYXnPNRMpZQNpx9KtSuh3Kp QH0BA4Gar/NuJVlK5wAfSr5HAJwQOw6i
- oiBsJI2nODx1pqL6FOS27lRlj3ZUnntmogqtuyCBwTV4 qBDwPusB7moggxgMApOSKz5o3sDir
- XKJiGAD/A3B9cVG4zCCAADkZx61oFi2F2NtyeSKg6wfKowD 0I6+9a03fWRn71ym0YEW3AyOp9
- aq7Au4ckdh6f8A160Xj/dDdnPbNQeSCDuJIz69TVWuro0VmUHC 7AuGG3pVfyQ1xt3YBB4NaDQ
- 7Mt1LHHNRybWK7mULjhhwBUPmbuiZtRdkzLwF2quA5GR9KrvG29lY ckdfStJkJj3BVYLxkVCV
- dUBxuycnik5a3BN82hQ2c/N8317VAY2JZuMY45q+6b0Jyc+npVRl2Abu F6hu2ayjPmlpv6BNy
- scWkR3jy2LAnB9quLjesZZX+nGDTY1jLkYZT6E9asDHnMccqeKelryZTjL1 FjYKFB7cYq2u1S
- u70xn29KYqLlTtPIz06VONznDHCYHUd61cby00RKcXezJgQASANuMgDrU6FimE yVwBmmIMbVy
- B2JI4qwmVOM454GOoqXZIlOUVoTJhjtY8A4/GrCqC+FPze/NV0CEMNxGfSrKAL8oy W65PaiKT
- WzE27WluWgxVtnG4kc46+1Wgrn7o4zwT2qqh+QO3UNjOPWrhP7kBWUELzSu001oRy20S J0VVG
- 7JYHoKkjAAdz8pNNjKsFVVZiF69qVmDBAM5x2rSMeZe87lXT0JFXmMs4GB/KnLkRhgxyR2/ Wl
- 2guoxyeeakj27UGQp64PaovJO6Qk3HbUWP7/Xv8ue9TkOzPtA4PpQEBnDg8Dr6GpSPkLA8Yxij
- nTZq7qwJnYA+SSOwxzUwVlkG44OM/SowMptTjB6mpwoZSTnI7Z7VTb6iWj2H5wDlctjIPpTRyw
- zn 3xT1RSRklcdc1IFCsGzjI9O9ZxUNbAnbWxXCKThSR3GT0zU5XaVXOWPp3pwX93uCk/NyalR
- RyWyp BOM9jROS66E8zvoNU4I+Vl55JqULnc/IYniiMeZHuHQHk9jT1x5mARzzjHIp8umxq3ro
- PXBVQMgj v2qQLu3jBUfWpPLOVw67SvI9akXaRxlm74PWnLTUjpdkIiHnsDkgHIqdFYxFmVcjv
- ilCsMSLxz1N SspDc4xjJFQotyuLV69CGMkPyOnftineWwkIC5FPKDY69SDSKjFzjKgf3jRbRt
- sbgl5Cbdy4YEYA BqTaCjIOdvB9alVG8xsLlcYA9akCYIAOecDNPmu97FJx7kYwD042kcdqVc7
- djfMAOB3p3zbgOPfj rUobLDK9tpx2pRi7aohNX1GgKAoIB9Tj9Kbty6gZHGf/AK1WNoQhscA0
- 9VHILA5746VVkXGViEr8 4VO1WAFADt0xg+1TBQCCRnjOaDGrx/KOSOM9KhN3DmVyodyvlRkg5
- 6cmnsN8gYqykjBx61N5W5lH LEccdTStGQQAhD9GJqrpyDroQfO0ez15/AUpOTt2HINSiLPAzu
- we9PIIBADZI4/xofI1sNMhKYkB /g6/So1VPMU/MCw/vVcyWhIBDY4IqIgAqMHjP+RUwV2xvfc
- RP9Y3QkYwaXG+ZW3Acf8A6qGUlAFw CD940Z287d+ey0cvYjldrpjH+/k/dJzSIcHd/CR8pqZQ
- Cxdl3Hdzjpmoir8jrk4A9PWtFcE00MIA BLN8xP6VEdwZW4wPxqc4Uj5fl7Z7VEyjcSu7BPU9A
- aUtgcrtXehCQxcE460wuRKqEdRgVOR84Bx0 /P3prYAUYDY6kVCk7lOGlyFolCbm5btUBBVs42
- qvT6mpMNwwbryBUwAywyCSfyrR3jZkxauVAoK4 bOM8HNC4yybfmPUipNuUAYZOfzoCsZAOAev
- /ANamo33L+FXW5WZFEhHX0BpxXzHcgDdx19BUzEbi WXBJPHeo0UtJvCsgHBU+lTL4dTOfe5Xd
- B5pZuMHIUd6iYZbvgkVbkG1TznHf0qFkzI46D+92qeZ7 iSRWcZn2nIbODzTCpGSMHB61YZf3b
- ZGAO+eTVd4yA2MnPvQk927DVlKxG6jBJwcnk+lQmMFTjJA7 9KlkBWLnO3pinEfIQpHT8qpNtI
- NU79Cru2odvA6NSMjcBTkY61JtJhDNjlhkAdKeU+UgOFbPJP8A KrejuOL10RVK7IyGI64B9Kj
- 2Ah9wPTKk1O0bFgjnbu6d6btAdhtLc4P+NLRa9yb62bKm3EQDA4xk ketMaM43Y/i6Y5FW2UHG
- Bmo34PAy9KU7i1asirIGKY7kjgVEQSp3HbjjPqKsSKQTj0BNMPzbsYLd 89Kq+qsVfuQk5YFun
- QAjioyp2KQDyc1aZThkG3JHSo/4FTBOD8xH6UlG6egnLQolN2dvQDnNVGBC 4AUg9citd1YLjK
- nJxgcVUkiUQMG4YccU4ya06Cg0tWZ3lLu+X7uM4BqrInzttcH6VpHcG/2T271W aMoF55Kk+9S
- k3rsaK6bszPkiITczAFuQPQVUMSlPmOQvH1rSePMALZLH37VWkiXJ2HaOvNVzWRPN b1OQ4YLt
- VTjrxU8cQMiylcDrnHenIvzljjcTgAd6nXIjYN0B5XuKxTd9URHR3S3ARE5wAARmpo1Q hiQ2R
- j5T1BpQF25DfLwQfapFXDuFBwTz64rW11ZsfM7bCoMHOCTjn61OpUv8yjJ6EdqbyoI5JPPW pl
- GG46EdamMW90Wo6PUkCAN/CBnJOKsKp2fKC7dGqNYgmCT1NXIwPIC9VPP4+lVTcWmupM5K2jJI
- 1O1QBwTnj6VZjj2jcWyccj3qJUwqYJXnvVlVUBSCBk9D2qV7quZubY5RkEDIAHGKlVeMbSpzzU
- aq AQc4GOBVhAH4JwelP3+UpxaW+g+NldSDw+MEU5QWlBAx2xjrTEVftDY5I61Nyr5IJPt0pcj
- TLj7z 0JkY45IBI6YqQr8gHUDpxUaIABtB5PP1q7tGPccYNS0oscFyvQYnzH5cZPTFTKORwRxw
- PWkC5BOM g8DFSrncFPUcim1bUUnfW4g+VMhSc9c1IY8y7ucA9DQY9/GTz3HSplAEOQDknvT3W
- gruyY1FyhLn AHIx61LtBjDf7XNNCtySMZ6gU5cnae/92okubqNJLYkCbVIGMY605OeSAPl60r
- DYM9MYxzTwMvgH APX0ojZ7scZN6MlVCyKXGAv4VKFUSsSQBnK+4qJA7Bg2Qo6L6fWrqrGdxUb
- l449KblyqzYWdvIjV RvwPnDcn8KmweODgccinEYlAwMdqUoTIoLdOabWt2Jt3syHbmTcOucED
- uaVtoVQ3BPGTUxjIz6hs 5qTblG+Xjd+lU5K1xrTV7FYJljlzgHOe1TbeSVVs49e9O4JcsMKT0
- FSKQrjB4789awblbRAoys2Q KSrD5Tk8gnpVhUAKkLuGCTShN69yw6Uqn5ioBU9+atJuzsN2+H
- uC5VyzggehqVETaBtzz69RTkiM krPj5SvQ84qRlOQxI2jsKeknbqNWTsmO2AH3HamfMpXcBnG
- Tx0qTkwED0zn0pu3OCRnjinFa6kNN qzDsc8DI5pwB35Jy3b3p3BTIBA6nNAQl+CM96hrW76By
- WtYjA+YKpw3XB600LIsvIOO4P6VM0Yxu AO49TT8HA7GqUU3ce22hCMkDPDdzSYUjef8AgIqXy
- y2Rnae9DR7EHoOopJR72BRs1Z7kecJxt56i onGEOB8zDtUyoAvBOKQ7BKvXJAzzTh1sCa2K4f
- BVf4R0A/nTF5OC+M9qtMIyWO3B6A1CF3bcA8Lx xThNrQJLaxExHmE9RxgetM25cAErg8ZqfGE
- IYYbFRH5SgK5yOPXNTzeYN3diEjAOBnLcYprIRIVY YGOtT7S67sYYjcaZ5TYJIOc4BpJWepLT
- tbYYRmIKFI3dKhIw6jnuM9quKH/dgjgc5xUG3Mm/rk/d x0q0+bQtVJR0RFyGVSQcDgUMAXkJU
- gk5OP5VPtDOcckHtUcyEoSAVJPA9Kq8X6kc3NIr7cyAMDgj jHtRkrICSAT7VMuPkJyG757Gkb
- PJK5J6YpO70YSd20VHUvHu3AnPboajbCOFOArHBq2w27VAHTp6 UEApjAPf6VU2r2HotEUnU7m
- Kjfnt6VGwcnbt2kDnjp71aIDMVOdxOQe2Ka6kZ+916VLp3KXLzLuZ +Nr84Y+9H7sx4XhzyRVn
- y9z/ACglsY3f1qLYBDjGCT1o91oLK+4xwTGGjAbPUCoMZi+YgOOntUxy nVie4x2pzKu7jJDHG
- aHZLREu97FSSNmdVLDdnAIFMbchCEAsBzVqRS0eSOfT+tRTZMTv6kA4pqVk KMddSmR8wDZwR8
- xqPgP0zxx71ZCKpyQcBe571AB1yRuHFVKSauXBLUjI5BK4Lc4PVaj2neVcbV6H AqVVLMcfNxy
- TTSDuBJ68GpgrPUma7kZCMDjIG7hqgWT5dp5OCOP51aZVdODx6VF5ahSxI3H5sY7V cWr+YrNL
- QiK8DeOT0AqHY2/Zt4znJqwSx9MY4JFRYYHrhRyfrR7NpPQUm7FKdRvHXKjk+tVH+b7o IbsfQ
- VpMv7sBgOhzkVAy/IW4AwO1EZpoqLcUrGbJBjb1YdiOlVJUGG2Ho2AOta7BQW6nB5qjKWZA Rh
- cHJOOvvSjNteRK35n+Jx2zLkFgB1x3qwvlvCSDknuPT3pkKctv+ZmH5VbWFfKP8K+1S3Hlu0VT
- UktBiKcxqMHaMfWpxuMhJGMcYNBVdyYyScZ9qlCjJOfl3Zya0m9UiHT1fMJ/GyhSnOSakRQck5
- JH 8IPSnCIhiSmSGxmpYgysWABOemKlRvKyKUktiVUVlIySOuM81NHGpmj+96gg96EXeylDjHH
- Tp9au Ip3cYP0p8zQRu9ESAHY2SBhh19KeFbaVHzKCOlNwjxkMD8w5we9Tqu3Z8hPfg011E2kt
- h3lg4JyA Dz7VKuQcfLkHPPYUKMyZJ2jqM96kCq4BAZiTyajTVMvVR1YKpbBHIz27VaWMKvJye
- 3vUIiKybRke v+NWgCFBPJxzTlJP4SVGSSdxIwjOWyRnselWE+Y8fNkcUxAxVTtB+g6Va8sYIT
- txnNRdKSTKbYCJ ieMrgjgVKsZYNjIG7IzzRGDu4BG08GpVXMiu+evABpzk2LXdkUauHOCMHqK
- mUbZguCR0JPalYEKw PUdcCnxgNEzEYI9TWU00hWd7oQJ8mCc4HBqQIqKpzu29/Q0oBOFwATzU
- xBCMduOeRUtONrlNydk7 EcQDIykEtnj29qmaPJXAK4680KOFbBJI7elPCbo1wduFJwfSq91dC
- rPo7Eq/eUBflxxUwABOcgf1 pqACFN5UsecipkAMg3Hg88UoyVr2JVm7Dgm9t3UEZFP2hFBJxu
- 55pFB3gKrFgOlPKMV3N3PB7VTv a7GoJvYRow+5lYDP5mlXIZOp4pdjBFUtlRnGKkERBBIbnt3
- FO91ua83LFJ7BtT5jwBnFO2jPsB19 KkCkgLtO3GfrSgEvgkAEdMcmkrcy0FGzW+gxQCoKgtzj
- ilwROARySefapgm04UfNnnFKfvqSvXpU 3voTe70/EWNZd3P44qRwfOAAHPUYpEVmkYDpnjH6i
- pwrB9nU4x9KmWjJu1Ig8vLAFTg9DninKCV2 gd+CalUk8A/MTmpFIbKt1rbm01RTjK9yAAyOfu
- qRwB604ghAuMMcGpU6kDGD3I5FIqfMWJwVOMno aj3t0hTjeRCsZXJbGPrSYPmYP3SMZqcbiow
- uQvf8aUhCVycEH7o61oovqGlyAwhFzye3JpPvNjnb jg1Ic/eLA59+lIMeaG2nG39ahxa3KbaV
- 2RqpPzbhjBycVEUxGoI5PB561YOzgdCOvvTijMSy8qDk AGs3U5CFzXuykw7DnHQe1NHCHjBzz
- U+MlQwwCOPemMm98DGM9a1TuhtQZAdzEuudpOee1K8ZIjA4 GcZqVdzPtBG0j06CkMTAbVy2Dk
- k0ot37F1IrS7IGDrnHQjFOKtt4BJH8qs+WPLKnOexzTFVlQKCc k9x0FJz0uZOloVlGZc5xx0P
- WmlNrLkH1B9qteWeD0JGaULx1DN2HpVRWliZR5VdbFXauQAOvJwaJ NocgDdnpk/pVp4gTkgjn
- gd6Ro2YLhQB6nnmnyor3U1YoFPn5ZeuAaYYzgAjLDg81om3KgMSOpxgV EFBfKc84PPSn7ttAU
- le5RcEsdq/IMc1AEZpGypxnj3960XSQEkqcZwABTGDIuSuG7E96b006im2m upRMYDE49vrTcE
- 5bBzjvVzbwCwJpCpCBQMjHQ1jJNNXHvdGeRj5lznOPlqNVUMhUqX27SDVpk53Y YAVDJEzSDkK
- DVJSW5KtaxTkwBgEE9+KjI4AwTkVZljjyfm+YDGPemmPKKB/31VruXzqBUGCp2ggA bagkTajD
- kAt69/SrTnAcFW4P51WkHAbady9vWkpMKl3a5G2DHs7tzioZFbzNoAHPYfrUrhjhlO1Q e9MZR
- 5rLuJY9MdqqTWmolFpX6EGMZAYDuD60MCVBf0z9aTB3KpHzECjDAEMQCtJQ1LuyMhsZUcdO el
- JsUplWAYDGPUVKcHpjgcj1NLjMK7gFbkkdOKpS+8ht21Kzrh/7xxx6YpOAuOhz0xUuR5YGRkcH
- im7kGSfWhQbQlq7MpFSZNxOBjvUbkBdxGQTzV0puk44P9KqyREbSMYBPXvWnkJK7V9ikwwrDac
- no KoyRjA7FupNarRsAxIJdT+BqnIoHJwxNYqd37o2r2OSVAH4GTjC+9SiIlP4hgYPPWiNd77O
- hJzU6 AeYcnkeveiEWndijKXzGoCHGep5H0qdAAEfHBHBqRFH3mU4fJ4pUA2hdp5Hr0q/djqhR
- ldXGkjyj jOSct7VYgwfmZl4OD6Gh1Uop2MrVaSNBGcDHPU9DRNqMdQ91LUBh5o3UjgnIq0oKH
- LL8nG0+ntUK Bvk3LtYrk8dCKuqSQC/3OpBpJ6aIbTi7t7iCE+XkcEHOB6VNGgx0ZVbqSc0Ko8
- xtpLcYODVlVxDw 2OOQR0qm77j1T1ZGisFYZQgcDAqzHt2lMYx/OnIMrx2qxGAJMbcEc896xem
- w48sVdoYqc8DIIx15 pQgXDEcHg896kMbs8gzhQePpUmzKkcsMnJPrVQlpZDjo9BYlcxsqgZHT
- PcetWUXy4+oJzSxx4hQn IYggCp0T5cBSXHOaiSbIkuXYYiK7cH5icnBqQja4KA4VtuMVKNq4b
- GWyMYqRkPmAg9fmxVySSByf qVwuGJbI78+lPXaTtwMZ/KnbSzgYYnOfrTRw6sw+XoR3xWerRV
- lF3e5MFKjOw4HJz1p+A8oySccq PX60IPlDBWwTzk9KaquFJXnBwPU1Lbej0Jv5jWB8racx5xg
- +gqeMkZx82FI3evtTQvmJgttbpzTx Gylg2CMYAFOyvqbuCfUkiX92rZGO6+lW1TIwQduetQxD
- 5WVvbOfSreAm0cgYzyaOfo2TNxi9NRMv t447fWpduIvusefu55FQ5YMDj3z1Bq0qsTubPsBVq
- KWz0Ks762EjjBwwPc5zUvJcAggAZ3HtQPvk 8BfSpQrllHXNS7bszlve43nb6+9TKp2EgBsDOA
- OaRYz9OM4zV+9vZb65SaZY1YRqg8pNowPp396i bk9LaepajzPRmfg5BKnlue1TMmZcAHJ5APp
- T+NoCdz370pG1x/Hx2pqLbuK1t9xgRkXeCCCecVN5 b+Q/UH1oQMEVWUk54o2s0yqrMuBg5PU1
- pZ6CteWoKo3biMBTyaVTmMhyFOPSgxs0PzffHWpApxyM Y4FTy8q3KlFNakQiJYdQQeT/ACqRB
- hQuQMg4BGakAyoyOB3po5OSmMjr7VTTb1Rnz31vcRQNmRyp 600xqJ+clgORnmpAMoB1Q8ijaD
- 8zHH+16099UNR1uV2QbuhHp/jQFXaC/BwenFWFUFJG5PHY1Hsd WBbgEdetZ7p3ZUrIiCEZC9y
- MsfaoWOZCMhc9fSrbgEsGVjxke9QDbnLAL8vfvRG27VxKz2IlTOD0 471GUUkHIABq0QGTABPP
- H+FIsW4LkHimhQ5lqyExlV29s5yKcFcENwDg9qlGPPK5G0E4HrQYyeit nPXNXSWqvsZ2VyFjn
- eo4bIIzT1jTbvY4PYetTGIh8hRtH51IqEE5TaeM0pRXQ1bKeHIPy5xx0p6R F2Bx1HDdqvqik5
- cbDg/Q0rRhIDg4GOtQ5JWJk/spbmf5Q3Hb3PGaaqDewPYY/Grvl7lDZAyMA4pp UGfnhh7VUUK
- a7lVe7MM7fWqzrlchcAHJxWg0YGdoJWhYSVK4ySMnPtWqilqNNJ7FBl+fAzzVdoix GQSoHb1r
- U8k5Axs5PXtUHlPg8fMvUe9C0d0yYyd7GcIct3z6VE8e5dwyW9PSr5+7u2kjdULJzuCk HJyPW
- p13Zo7bGcVLSsM/MePpUEifeHBx1NX3Tjbzu/vYqCQARAEEsfQ1knF7MUU07FCRG3AhR24x z7
- 1BJGBvYZX6mtArlivO4HNUpPvsCOR3q1JPboHNLmKkoUx7sbiRyAagkGYgeSw4xVvZhRgZbHT2
- qsy7mIH8XQ0Jx7g+V9SEgDkc+tRBSCHHHPGe9Tsq5ywO7HrUHP8AF8wWko3ZCiloiJgGdjkfSg
- nI baARxjingMYCP4euMc0mEIB3gY+8K1lBRHzJ6kIUs2NuHz29aCrdcZI4/OnHGVfJPGBj+dO
- KEqVA IyecnvTSW9ynOzTSGPGViAwCOnHWoXTbg5Hr9atlGVCHXPriq7cI2MZDDnqKE3bUUOaW
- xHtJTBHI NV5CMgEgHkirjcy/eBJ64qPYm8qCG5y2am9tQta6KbqcbsZz1xWdKFXLMpJA4wa0Z
- G/dfM2FJzmq L7TMSGAX0PUirjFv3rCglbU5gI4j4252nGBT448oqgdfzpVJVmABGehNTopfGC
- MjP41Ki0op7E87 WiSBFILqc8HP41Oqh2OGAOMn61AgKguMlu/vVqMAptcYz07YFU6cbrW4NRX
- QkWPFxgkMAD+NTeSS BlwOfTpTWXaVyCX3Yx7VaUOzZUcZwKlT00exMVZjfKZ12hup/MVaUMAd
- zKADjBFLs4I6joAvUmpo 1fG35ST1z0xVJprc0cm9LhkqAFAzj045qZIzu5OSq80KAQC4LKRzg
- 4xU6D98Aepx1pN8q0H7vKHl k7XBwAatJy24gknoaiWMMw56enSrMarGuQ3bvzUWctLi0+YBVz
- xn73Q9c1LHDlgTnGfyqeJN5DYA 559qkCncBjAPT3odrWW5MXK46OPERJIJAyfzqXy2EkpJxkZ
- XHepY9oX58cHp6VJtVwMkjBznPWiD aRUpcysiDYcAYIPoamcr5XzIyYbrUwUljkg5GcntTfvb
- gAGX3qGtSoK2+xERgccseSSOBTNi7Mry QclR71Y45DEc+1Q+VsACFsk561UU+4rx6gpIifeQA
- TwKQ7vOKFW2Zxu9Klk+cfLjrxxSkseA3XkV KvLYPdWohUxlVGNucZqXbk5GB3570iYYDJyOuK
- lUZJwQDnafapd47sFG7HwuGcHIIJqYrtUEjLHr UIj+f3x0FWAm2QJnIA7mhRb1iNQSJljUgFs
- 57c1Y2ttByB/eqCIh5VHXvVlQFOfU80Wa3KkmtEOw fLCLHjA9OvNSiP7rbjkjkUcHAwSMcVYV
- Ay7gu0k8Amna7uhX8hnlqNp5zjBz0zT/AC+eF6DvUywn eRn5QevvTzFzuAI7EUdRwik73KqJw
- OwBxzUm3EXylQcd6mCOFYcD5snPenhVVtxIJJ5HoablO+hT ty2GBGf72MZyGFBDbUyoGfQVaA
- O3gAY60hVyCSFDdv8AGjfcmMYy1IgvGADnPfvUvlZbHY5PFAUF l3blyM9elLsbJJyOMGs5pqV
- 0LlTVrkBQNnnDdMZpWGCB9457DrUoQE4OOBTdjbeBuOeNv86pK8bi Sa0uR45XgAE8CkIBf7wH
- J4x0q0wIAUqOnJxTAozyRhTx70lrrsDepDtG0IWGc9cU0g+bjBbH86nO 3eSRnB4pAp39MN/Oh
- WauKz2ZAc4XbjJ5INQFQxOEJIHGKuH74yVB9cVGw67APbFXDUFHl1KoG+P7 rEg9qeiHYeMHPe
- pwhRctyp7U8gKv3TkcDjrmhtDjdvQhaLMZKDcQc5pyIVZOOCMkGpEVs9CFxyB6 1KxJcFQMdia
- SvYSp3umRffBKr3wMVIsMjElmGSMkY6elShQsauDkk8gdKlCKWGCSV6gd6Iu2liL8 qsVvLDqF
- 79/rR5DNK2WBAGDnpVsR8YwQcdaapYAZIPvjrT1GpaalIoVwB0757U7ZldxXqcVa2jyv xxz3p
- AoVsO6sMZzVSiujLeq0KjRfMQAVPoaaAWHVSPbg1awAz91PWo9i7cdT1wKztzego766FYqd 2W
- bPrxUZRSd24sOTnNWNowzFSOw5poT5cDA7E1qlrvYTSKDoVL7cbcA59feqzLuwWyfpxmr5DZIT
- BUdPpUUiZB2kYbr7VMnfdjaa3RmvtbHynHtVSRFwDtJwOMelakiquFIKkjqaqSg+Ruxls4z2xU
- cz a0KppddTKnD4QqOW6VVmQguA3zZwR71pN0wc5zwKqug2sfmOTkVV7eQNqKM6XIjBHBIxVdg
- Rkg5I 4Aq267gcsCR0A71Ds3SMWXaCRn61T1WoorS7Km1uMjGBTTwhJXBPXjrUroVbuU3du9I+
- Fl6qeMjN Du3ZA4EDDahYnAI6U0xlWOFGcDPvT8HY2c7u2akWMeXnlznrmqlLRGclGG/UrBAXY
- N6jgdqD8vQE 89TUmAXYchup96UHjdkYA446U1d9DW15e9sNyfNAxkE/pUPAOBjGcgYqdchieK
- YynfkjOWolG8bh F2TRXIJyAueM8VAAAzNnDn9assA4OzcSc57Ux1VoY/UDqO1EWuVXFdJGfKo
- LfN2GMVVdQI/ubsdV xzV+VSCwAPzEduaqyZIZsFfqaqN09xt30RzGAJMLjG3gVLGEEMW/qD1F
- RjcAHI/H1qYHLsevoPT1 p662MG4t2JT8+CFIUHjijZnag5GOfpUwLBlxjaVwvFCEHIzyp61nG
- pNPRF35rpIlJbJPbjFWowRG Cx6dPU1WBLI2Msc1OoHkDJI9vSnyXVy46R2LCKwk4X5BjBqym4
- Lk/Xiod6MwyG4461OAw5ByB2NK K0ZEo/zDtuUKg7geRg1ZjU+WeMgcD1piA+YdwGVHHFTRjbt
- ZeMjBz70NN2Vxuy2JwihcNkEdcd81 OBGG+ZgMdSKjjyVxtYe5HWrJVMJ0PsOtTfQbtzWHqFWJ
- eCDmrCK0sakcbT0oVB5TKcbhknNWYubf BOCcEKOopw1iDVtLD0QmIsANucY71Kik4yuec0kSF
- pHboB2p20E919M1K6hyXYIvzcZYHoe30pyx gBU+73P0qZFORtIyD0ppVmlbAANKTb6g1LoyB+
- 5Tpu7imMjYJzyeRgdqtDhcFc4HT0ppHHHzZ6Yq nIlS0sQlSqk8YA/Ko/KbKMCPKUZNWCreWpz
- kEcj3pVLbSqr94c8dKhKUXdMcFf0GgDfgsPy6VIqj YAx9/rS7dibQCQeckU5fvBQBnPU1HNdm
- junoPCrvycBck4FTKrFchhgnqeabG2VZTjgYB9aspGdg A9OnaiLktBx3HJGFB44z1xViNCbgF
- VO0DAz2poBOAAcdqtqTvUMM5AB7Uc0ktyLvcUJ83TcAOcVM qAzEnK46Aninhf3hO3p39akZN8
- vPyj1p01Lc0i9fUaqkZ6lieBUyBgpyj+1SxodqrjBweT3qVIiQ OowepqrX1sZyiQ4byk2jnHc
- U5YlLtvGT2IqYxsYiFOSDg0oRliA4PPPrTXky3tqRIMlh2xT3Rtqc YGOM09FDOF6Lg80/6AkA
- 49aOV7ia1uV9u9tv3mI5pAjE/N0I5qwvysTlVOeQe9GwBiOpxnFG2iJc tdNCHywGIJGDxkd6Z
- tZQWC7WHBH1qyCAjAcjOeabyMbs5I5JrJxaditdSEqdoUDH071GinkjDDIz kdasBVY/KrA4OM
- 96Ty+VxnC9MGr5rKxMo2SZAIyMgDqeSe1OdSBwuQDwKslQfYAdD1pgjxyTwOAK FZopR01Kyod
- 58wbe3P8AOoWAVioBGF5Iq+yhYMN14yfemsmC3HOaIvleocz3K+C2FI4zmnYJjAIz /M1KEIVe
- Rzxn0p6ALJubOBkCqnZvTUGVwu1WDKQM+vNIFO8hmG32FW3BHJwf6UhwULdeelLmsiYu T6EeB
- nIDA+hFCBstg/NiplT5iMb365BqTO2MkDDg5YU4zsu4KWpCBzywGCM5qUL83IBUDjFOdV3D 5h
- 83r2qMKu9s8jtg0KSlqx8rlqgKl5QUX5TyM1HtGWPAOec1OMoMZIA6AdqaQoRjz9aLvoK1tyP5
- JeGwvFQuqqgIP3jx7VPgHAPOB2ppTn5iMKck4qnZE31K7Rgjbn5aidh5RIyGLVaPKjjqQTgVA4
- GT gYPai19Ane5WkwUO3GSvPvVUjEOHDZP3jVzcykEKHGeRUEjP8oIzlc5os27Ar7dDPlUBDyT
- gd6qh Q4DE5GOlaLKpBBbnghu2KpOGbG3AwcYx1pabLc1im42RVZQMAfMQccVRdWBPB4/WtHcC
- zYwMYxkV UcNhgSFPv1NRJyi1clU0tDPkj+QsoxjoRVKUtvywAbPKitBowoIfIBHFQSKu7JUlg
- vBFVfTVaj52 ml0KZA8rHUkVWdNx4OCSO1XnRwm47QPYVHngYUgjgn6UczW24Nte8iu0P7/ZnO
- By3bNI5bdtVtuD gD2qVl3KnUk54B5qEI7H5R8o4IPWq1t7zH5takYBUMAQ3PIApuTsG5SOMmp
- 2iCsSScDrTCcp9OmK 0g7aolct9iONgQoZSM8g4psgCjG8D0OamyA2DgAdD601gwTGwnjk1Upa
- 3JUnFpWKyjM2Mjj0HFQs NpUNkGrMqb4s459qrEMgALDnnkVKSfW7E3e8iGQ5Dbhxk45qkcM+5
- RkYzzVxtxJBxVSRvLj27eB2 xzTUWjVL3fM5bdu5cnGOmasjBb5Qc/xH0qoqhQyuQ4H3CKsJIq
- hVJwT61PNFrTc5X8PmTqHDFj8w xxjvUy/eUkblzVbcywkEgNnj3qdJGdQw2/THH1ocnbUtO9r
- lsMoBKgc9DntU0aYLfOOeTxVdFVnC qdwPX2q2VUZ/hI6AnNSk0xNJK1ydAqbSRxyOKmjznAO5
- umPSqy8sMg7Satp/ruy55zitG0tLjUep MnDHnBJwc1aViCxwuMDjFVwvPykEnnpVmI/MOMA9c
- 9jUTit3qhuS5kmizHubO4AAHGMVJ5W6bI4x 1zTVA8zkkDA6dc1PuYBduGDdRilG0dEaJuOqWp
- biIZUyMnGAR3FWlCrKMc5HNQxJt5bk9QasY3Ho cHr60Kd2Qvi2FRMLnc3XkZqwi55JyAM9OlM
- wwwCNzZxVpcKi5BII5NJspxaIwGCAhSvzCkO4NIcY GR19anZQ0eAxGeQKiAwzNznPSmttUSo6
- 7jDhkI54HNR5CDBU4PerI3BMHBweOKMA4LY9MGlJ8ysy tnsVuSS33jjj0pVA8oZBJ6ilB2DC4
- INOB/eqTzgHJ7VlPRWG4ybsNwwXJztqVI1eQnngc+9NJY8h SwUZwKmjBUHaDu6Gm9tB8slG1h
- 8cYAVlIPHI9KsqpUsRjnqPSkAywBG0Hmp40Y4YDA60r31Y7skT HIPHNWSmTnBOaIugAUk44Pr
- VgKCRnuOT2FF1zaISs2EasEAYc/xfWrKAZGcHmnImX5yVx2qcLjrg 8gCtZVL6Gb3uMjAMmATk
- dasAMFORwMjNKoDBmA4AxkCngcKAwx1JxUX1vsauOl0AjcL1JJ9KFG0Y bIXvkVJltz5I+Xoe2
- KeD8/zY2gdxQrtXHPoQhQWODz2o34l+bgjqcdak48wgKeRUY5yx6elVGCl8 RUrdxMKzNn74pp
- B5ZSCdv+RUu1g7BsEY5I44p4iw5wGOzGMd6TcY7shuKGbRtweh6cUzZuBxk461 OVBUNyAOcUg
- VA+TwGHOegqVKz0E3G2pA0Z8xSMgEYBpmwGIBQwYnAFWvLyowR14B707YWkDKBn17 VV0yeezv
- cg8vJUhcr60YViQcepx2qTBE2F+YL05qdkUpv4B6ips2y29SiYmfaoOR700pubGCSPvE VcyNm
- Rgtn8hQyhWyMHjPHen72w9ehRUMp4AGBzTtpJZccfSrZ2luAWyM8DrUQD4JOeveq3VxWSaZ Bz
- zuXk80pUByGyAeKsnHA3AknnjimOiqAyEhQO/NRe+yFomRB9qrtBye9OC7lc8nJAFLwpC53ev1
- qVscgpgZ7etVDcmWm5HgkHLKoPHIpiqozk5Iz0p2wZY88nIBpM7fw4OKculgcLIUlQvUMM8Uxs
- bQ B0J6UhHXdxj7tHCt8x68jntUR0eg9JdAfaCSDjB/OmMOuDkdzUoG5GJI44qDJDY4xyTQr7d
- Qcbaj PmKEH2PSmO373joD1p5kyDzk9uKiOdhGCxYZAHatNiZJW0KsknynYnUHr2qEhfKcsSTg
- Cp8DhQck dRUDhxk4BBIzipUo27AovRFaR1wV2NtJ49qruy4wePWrxUkglehPJPBqiVLMpdG+b
- 7px6U5W0sSr NWuVSueR8ueSTVaVSJDjGR2PXFWn+8wY8fyqq4ypK5OTyc9qvlu9TXZ3KjKTzz
- z0qu4ZigVSMAZP rVp0G9gAwBxwarMWG0cHA/GsrXbS/EpQbTdyuyHYp2tg9vaoVAOBwT3qSQM
- yr1X09qjbakxIBAzx n9avl7mKg2vQYygTIRkgdcetN2/OCGUDrjH60/c+8k4BPI96coACse+d
- wqm31HV5lYjZSWzncoFQ uA+8N8oB6nip+fLZsgI3AJpjnEm3cuTgn2qU+wlK1m27orMCFUBSx
- x+VNbMkZDvhQw6cVZbAcAq3 3aikAyApHyjn1NUpN6JWDmTXvIrOjAMVO4KePeo5DuAyMjPQda
- mLAqSoJBODz+tVmz5WBx6moa7h K60KrszHgcjrVd0weeHHUE9amcMMAAnjPFR7gG3OTuz3rdt
- pJi5mk9NDjY1Ckclhk4qXc2NyqDt9 qrhpRMWG0fUVKoLBN5Kk4wKiCVtWh6W1ZIrSyFQw9uB6
- 1cVNiYPHTr61WCDBJfkn5cfrVtGVsDna RkUpaPRFqXRLQtRYCAMRz3FTRsr8569/Wq4XbsBwy
- Afw9asqMOjDHoBRrvuQ5R5diYKckndhTxir kYJfBPbA9qpBf3ipuIx6981eiwG69u9DslqSk7
- E8ZXcSf4atxIoB5OOvTvVVQQdv97HarUZ+RgCB kd6Tu9i7K9rFkDKqGJyeQfWrUa4b1I6jv9a
- rK24qehA/KrW3d1ID4AIHem22yox0szSiI81iFBIG M468VYRfnXBHIyQfWqUHAByx46DrV5cG
- 3yMdce9Q6coshLWxajUAZHJx6Ui8rypIJp4+VVLNjIwf rSlHVSgOQeh9Kuj5lJ20FH3nIxnPH
- HQU+OMAgbx170mweuOak2bHBYnJPWsp2u9SddiCQAyqOCQM getRyBW4UFcdfxq2RkhsDHqKjc
- BztIyM8047JNGvw6opjG3aMEr0p467SAwJ6etTCNR04zR067Sf aiatr1BSSV+hCissnB6jlT1
- xVuLcVCYBJ6eppoXBUgdanjC5zv29xU3VtiZrm1QqowYHGOO4zVmM MiNkYAIH1qOMLvwWOSep
- q2MK23IDDgZp8y2aKtZEkZBwRkgdhU678BAvPeo1Q7hhGUnnHtWiqsij GDgUKTWwJxWlhY0Uq
- ufl9asKijhQTzknPFRhTjnk+1Tx8NnaQQO1G+7EpNdAC4fKjqeRTzy7FlAz 0FSMoDhiflJ5FI
- yoZFzk4HUVSSkwbjfmeg4YECqy+5NOIBU4GfWgKwiOG3YNOLED5lJ4OQDUcqWy CPLuiLYdvA2
- +uaCoD9Rn0xUm7jHQ459qYUYliGUn2PJptoq4m1TgnJLdvSpNrA5UbgBg4pyYwO2R wTQEGeG3
- AHHB70tGzPnSViHJdQudqmjywAOSeOD2qUtiYkqRxT02lVyeAMe5qrS3aNZaLyGKpEee G7ChE
- lckMdo7YFTortIG424x0p4HBA7fr7VHMldEvV6WINiqAARuxz7+9KBxlVJI7VYSIPg9Oxpw T5
- SF7HiiTRL1ZXEZZCSoUHpTNjM53AD+oq0uPKAz17UeUcdOn6ZpN2dmVJJPVFOOPapY7d2etMZN
- x6g55NWyCpyB8gqJl3AsMD1HcVUVuwk9SuF8sZUA7h82e1MJAZQG3ADk4q75bmMg7QD047VWZd
- pb ONhPFQnd2QWTYwEmMFgHOeMDt60jH5G2jvnHvTmXLjnGeDjvRsweOctiqtswirDQDu+cgHr
- UDKPM IU85qUgrGAw7kdaXaSm4FQT7d6ak4vUhy1uRKocc5ODUe07sEEkH5cmpTGynIdeOuPWm
- kqOW6ZOM VUXqW72uMDsuflBye3Smg5U9h796kC/IvB55qJicjAx6ZqHHrbUl6sj2YZm3A/3eK
- h+UPnIyM5NT uGB7HsDjrUL8IitsPckU0iZOxXZ/vBRlgM8dSarNllBww4yee9Wn3NI23A4yOK
- idiJFBHUdaFo9E XIqtln28mPqaqPvxkk+w7c1eGwyDaedvIzUMoIySc5I6DpTcrbg5JOyM9lG
- 7aMbcYyahZG3ZwVxV mYMQfmG44NVnL7MZ4GOPem17oc7lqyo4PlhmPJPTvUG0AvjnuAetWJFb
- eCQWAOKrudr5b5cjj6UO zVjRp21e5AyDb5jbunK1FIC8KnGORnI6VZO10DFiD2FRE7l2nqR0q
- rS00MG0upVIyhZM5AOc0pGY 9+04IyamG0M3XpyMd6Yy/uxgNucDPoKTTk7GvM7bkW0AxlsgDj
- BNI4ILYVSfUjpVoRAHghiOlMyN r7sY5FVdOWphKzd2yg24yE5zkYxUbxnJIzx0NWnQhAcgnHG
- B1FNO4xkk4XGF9aG23p0HzRVuUqMC FIGM9yRxWczvgkD25H51fdWWQ5yQx6elQOVKkAAkrkjH
- elGV9C9tTPJJU/KzkH17VCwBRhkjPTNX MAnBBGRyAarSZ2hgQMcEYpxbb1By10RxAR2DHaw2n
- vU4wEDclx0FRZPnbVHB65NSr/q/mwSPSnaa 3WhnGMpOxIkYcqSSM9BVpOAAgyqnGfWokRTJye
- /SrUaFM9CSc1LlZ2RUn/Kx6D5k3E46H1q2QTMv zDnt6UyPY0jZHfr6U9UbILevH0rSTbI5dUi
- wIxuDHd+BqyobrjPNQxbVcjdk+/NTICrBdrgE5JJr K8upspa7k6glsAkHHFXUXDIQM4B/Gq0b
- KNvRmHJx9atBQNrBjgHOParcrWZLm5aNXLShCFYkg55A q6FGdzHn+9VWMANuySAMgetXI+Y8k
- YO4Yz6U7q17ii2mWkAVVbgn1FX0j4Udx6iqaj7gHJ3VeiBc 5OSOq4qJau6HfXUsIw2gn5yemO
- lWUzk4Xgd6gj4QYUdenpVgYJYsTszwB1py2JaSe4w/cGfv/Snq uSpY8gZ5HWpAAyBipCA85PW
- m8Ky7eR79qhtWdhJdLDFUsxIZcdcYoCnBJUkAcU/bmQtwVHXbQwBD Ku7pwM1Tir6s0TuiLAJw
- x6DnFRNwTwc9qsBMQvkEnIwaTaRJkjGBSja9nqJct9AHysw4J7HHFSIm HHTBHFNXAycZOOpNW
- YwrsgByMZIrOTsrlNW+YRhUm5G8Hgn3qxg7iDgcYyajYbQchWXqNvepskjb jt8opxSdmPVsmj
- JyAWB9eOlaKKTlgRgcEVSjGcHaScfSr6qCPQEZNXNx6E3k1ZE4BXBYZHQU7LC4 BYZBPUUiqRG
- AgOc5INToEIGckg4UZ6VKskNNpa7j2GSBjjGQaYNocEhvb3pyZUYLAH3puO+B6del LZgiTIEn
- Q7j2NJ87yMT0xmmgsOh4A5yOTTgrErjOP50k3uUoqIMGRiw+6Rkk01sja5xu64p0mTEQ 3AzTC
- 6tHySCOo9adkyYRfVCnJ6nnPrT14kBBAznioYwc7gc46A1KhJcswBXODijW+5vbSyQ/hijb Xb
- Pp2qVVTzM+vWmqpUZ3LjPSpgqFxjj+9k03boZbxtIMLtAyQc+tSIAYzn5cdz3pCwLYHJ7Yp4AL
- bW4XPPNZuPViau0mRgMsxKsGHoKmCEkYU8ZIHpT9pU7sYXPFNAdZyVILMc/hVKTa3LsmtBCpOF
- AA 9OKWVBv2jPIyTmpI4280biAR2oCKfvE49aUY31bM07S1ICi8ZyQOvNQ7EycffPUE9KsnAfB
- ySTz7 VGUVXbB3MT070WaepSVr3ZWdWCbGJwOgqJjgJ3HHFWnDOw5xyOMUwqMtjHDdT60NpbkS
- baRX24wQ jYJORTXIwoIwR0+vensjEAjPShozgFCpwDmnyxHBJdSAoG+YZb0GajcELjcAMdKsY
- /dsCME4Ix2p N2YBjacdeOarm122G073IQqrGzFWwegJpjBSwYKcE8CrBi/dAksuB0NDLk9cY6
- ij3G7CUnzXuVDu EgBztHTimEDByxBPSrRGXwrDH8xVXYJGAPU84pytYaW5HJneMsCOPzqFhuY
- p1OcD6VaaLGOMAdjT HCBgWIBApSfREN32Kflny8HOcYB71DJEzHjqBz9atOPnznGDnk9KgYP5
- Xy/Mfapemty48zXmUplI A2qzNjGRVd1eNRvUirrABn6g8d6pS7i+SSf5E04663G7oqspI3EHn
- mqzFVG4DGD3qydwbaPSoJSu SvGT2xVySJnLVXKxJLKvzZ5JNV2A8vjax28DFWJOm3BJPTFV8f
- vOeBSslcE7FfgpknbjtSAF5c4y CPpxVna2SdoIz3FRHaGyM5zx70k09A50lfYiKBo/pwDTQCG
- yvOGxx2qQ7NuQrZDcinMP3jHGMnkV TSSVyXKzSRE2M7h1PXHemeWrAF+GI4FSbQhAOPahm4x0
- JPGe1OVraAo2d7laSNsIy8YHQiq0iHLs WAK4wParxU8gsT61CwBWQMM/Lx70SlqiXOy5Uigy7
- pGLbj0JPaqjhWkbI2kdavHeocYx04NUyjA8 nODyfU04xS2ZTs7vqUnwp3AgfhVaQFXzjapGST
- V+URhlGeRnI9OKpH51XJ4C8+1XGTetxKz1OGRH XcDx9asx7gCQBuxk8UkSs7Efe+lWYlZRtI3
- Ang+tSut3sZ36WEVC0W98KCQRjirKFgQMlhu5zTNp Jz2z8q5596sRxEfJyxJyOcmlLk5WaWtH
- XYcrMJNvUHjA7VaUoyqSTlSAfc1GigTjIx681ZQASKcZ BGcinFWjYVknZDgpzvZhjdgECrfBA
- ywztzjHeokUgbsrgcnI71IpJVeV3d+KUWzRt3LUWBGDxuPT /CrKhmlIJGR6DqKgQgkbcZA54q
- ypDMrEgHGc1lZpkJ66Muop2oCQCO/Y1cQfKpPfpz2qpGcBQCNn bPfNaMIUJn5S49appvcce7L
- MKhSGHIJAq3GoTGc/n0qpHxKp6gnIFX41LMGOMHnFJvuOTV7lvomF GQCSakKkrljnIzxUXcbT
- nd2FS4G1T/CB07inTTRCg1G6Q4DCZVlYDOOKcf3sYIHJ75oiXfvDEKM8 U4K2xQqkjtVcqva+o
- S27jUTG49e4pxUKvuRUyjLnbkAg5yKaDlScZGCOnNZ2uaJ63IGTjklh/CV7 077rDb1I5BpzKT
- EqnjIwKbtZVGeDuwM85qVDogatuAWNwDnHHSnLgElTtBPODTiCGXJUIO+KcQuM cHb7VUlbR7C
- +1zE6BSGGak27skZHGefamAEFdoABGcVJEH5LE4PAzUpMaSaumWYlZpc89KuqSpxg A9PpVeKN
- hGfmJz6VOi5JwNpB6k048vQNd2WflKhs8qe3enqh3lhwe5ojAEahirDHHvQFY4YHK45q k7PQN
- 3qSMVyCoJbvzQ5yFDEKew70oAIBIPB4pCSc5HIPU0nFNXQknsMD4O1OWxRhiAd4JHtSqB5i j2
- 60joAcp1+vWqtdGrS5rCgk5JwfrSkArzgE0iqQ5I5AGKcuHwOgrFtqW4SsnoMUjzAVOTnpUyqG
- JwCPX61EmFbI5yOanVVZCyMc5zyf0qpRd7kys3cVIyRyGGeetTlcgEYz1I9qSPlQ3HTgCpQPl4
- wW 6fhQpS26GbkubXoL1YN1xx0p2wALngE8jv8AWm/MHx3qwqq0ZKZLdDROTXU21vZAflwFcNg
- 88dKV hsdWxkbevvSbEaIspJYHOD3FO/e+YMKOnSiLu9EDbuG0GNmw27sD3poG3g5IzkAU8OPL
- Kty9O2bc EDBxnk1V7XQa21GsmSrE4JPP0qDy/wB4SMjHUntU+zd1O0DjOaTYFLMx9MUrPl3Mp
- S7MpucDLDq2 aaykJkcgmp9mVbODgcH2qEAhMA9+/an00NY2IAJGyCpOc5x2oZWBOVJ+Xip1yM
- jIBPrTWLAgsCeM ZqVo7ESqW2RXwfLz91elRONuBjIq0yfNkg8DpTCAxUbWHGDRfUV0lcjHCjq
- fQGmhOehJY1JJuWba vX0IzTdpI3Ecn+VDWgOOt9rkBB5JGDjBqLBRzgEsB1q2R8nIO4+1NbJb
- aCuc8gindsV1LS5TzkkS McgVE8fI+Uk9B6GrLIxkZuFxycimFQYyRnccY5q7NLRjjZ7FNlLFt
- q4GOaruDtUc5A4Aq0V4JAY5 zxUcnyxqXAXAqLaA+XoUXHOTgMB0qjJkSABgcDpjmtGQ5XcF5I
- wapgNuycZHBJq1dxLc5LqUmH38 kBic1E5LNkgA1cypUsu0MQeTVNwBGScnPIqJxu1czTUpabl
- BlIkKkcN055qHC72KqST2PNWySGJ6 ZHGRUJQEHBye+PSteW6syp9rkZHyg7wdvHHeowu5VB+X
- 6npUhIJxyF7+xpm3EuQS6Zx71PK72bJj OVmhNuEO5gR600xksfm3dKlUAsVwCucj3oCBo22sR
- g0c043JipRd0MCoVBAbKnp61CoBlJ6kt0qx 5alzgkY5+tMkTanyDJ3ZOPXFOD08hyV3vqViWD
- MMADtUAAMbnDcNzV4gBFU/ewMmq7HAYdM0SfMy HorWKTJukZ+QO/1qlInPJBbqeKuurByM4H8
- 6glRfMwW249aXO47Mr2fZmcY/nbcpJbuKptxPg4K4 xj3rSk3IWwQwHT2qhIrlCRg554HSrU0x
- p6WbOTRcKu0jp2p4R3dQWGcZwBjFNRW81t3HHIFW/LO1 WBz+FVCavqzBSEKuBlyBsOOPepVGE
- B3HjgGlBA2ZXI6kZ61MFOSI+M8gHtUxkn0L1vqCLgjcCy9R irMbbhnAwTUfV1Gff6VMgJjOSM
- 54IpuF1sXZrccBhsn0xU6hWCtnPHWmqNxIALHpx3qVFAAUgg9R T0tpuVa7J9gRMqu7ng1cjBf
- kId+MYqBcjb0VcdxVpEODIWAHQYqOawrW1ZcjRvKAPQfdJFXIlKx9 MYPaq0R/dBScqOM/yq6u
- 4qQDjP3ie1SnKXkTF9WW4wjELnHynbmrUKu6Zx04OPWqgTJ3dyOFFWEY jOcnHUDvRGBV7rQux
- qI5h1IFSnIQHI46+hqDkhSowD1zUysFbOM9unQ1ST1ZKvfclU7HyTtB7GpT kP8AKcHGc9qiLo
- 8Y5B569Kk+UF9z5AXFZ6PdGkeZvTQAoZSQ3OOMVKoHA+YZ96jXbs4buB0p+AFT HT1zV811a5k
- m0mMdVDKc5YcAf1pz7gABjOeR60qjdIWOGbOOBUgHO0927dai7RbnZLuQqp8ojg5P GR0qRVzk
- cYByPWgrmRuRweacOH9QAMkUpO6Ls2rdRyZaQEHoOKurlmxjKkn8KrxjlvlYgAbWHcVO AQ27J
- UEZxUyV3oQ4q+hOmAo6lhxyasCNkbkbh0z6VXADMVGMjn61bRSF+6SDxgdacUoaopavUkVf lD
- EEAHGKtqPkLbhtHU4qFVygKhgw65OalQ7WOcFcYx6Vo5NqyCK0EB+Qb+mc8Gnkcnn60KMLuJVu
- OlPADkAg5xSaT6FNkZjxFuORnktTGyd+CBg8Va2g5zzjpzUAYBSpPKjAx3rNNvVgm5q1iMbg+5
- iM GnjY0nJxx60vCg7uv8vakCZBCg9eM9vam2xqKd7jesgUY+tSqm0gZKkN/OmquJV5+cE1MQS
- MBWIB 5x3o5ul7FbpxFO8QFRjcDgEDFTAd8980i8QscHr370oYttIwfUY6VUddzLWyViQEuwcL
- x0x71MIg sg3NhvQVAMEDBBqYN+93MpB6VN0ti32RIVO9FXovBNOZk8rvjOajDHL4VmPfnpQAo
- CyNknqc0Nu+ hDTtqA2vIxHy9+e9SM7PGGQY9vaoWc7vkA2njHpT2J4weh4IpN6mjSVhCwNtzk
- c8imhwW5yaeXV0 wfvHgimAgwbOMnnPpSdiXqtRjfMSNw44ppXBIII4AP1p3zFCSm0n1poAdwV
- JIHv1pxTfUUpRURjf MgGCec5HpTOOOScHpUw+U9Rnp9aiI+bB45qvIhNNJiEjzCOCc81XIJGS
- cKDxVlgmCCGwTkmmEHYT jgnkGpSHpazI2PAZjls5pnU4XIyM89qlbaoye3603PzBR6Von0BbX
- IzGVjB3fMcd6a6Ig3KCSelS KzZG5lJ9AKYzPvIUA49qmfNcabvZkRVmPrxVQgnGTsA447fWrW
- 87sdW9B6VC5UA9s9c1pG6bVimn flRXO7zc8kAdKjdQ/BwQRwakKbpAobnvzUZyCNvPH5Vb1ZF
- 7PzKpxxuBHWqMwMaHaR16H0q6yZbh sZHWqskZLbWHzMRg1DXW44pLR9ShKm0jZjOOAPTvUGxV
- XGc8cZPNaJUeaQB8o79aqsuCx2nJOR/9 al7Rtb6jnJJ2RU2ZTpxVTb5bHGSxIAJq6cknquByP
- eoTBlGG4jnijp7zMltuVCoZs45BxkHFMZSk m3ORjmrAjw4Qk8rwfemiP5sSAkY4x60pWS3NFN
- dWRk7uCNvYkDpQFMbcuNwbn3pxXClgSQH55qRg JFXbg85xRaL3FvsiJRuGQcDviggAHoV60rB
- vNwcbc9vamlDjCnIIyfarml1JnFt3RWLF5gwUehpr Iw+7gZ7kVO+PLHzDcBjAqEqWAUsQuKUo
- p67B73QpNgxnI46E1TYARu4+bB6E81fZFIAzuJ549qqS EFCF7cHjpVJLboS+YzphnG4jBPQCq
- sh4I5znn/CtB9rjGMcdfWqZCGFjyR156k0TjJx2L9pFnGxq fMyh3DoWzmr6HcQQQFAwR3Bquh
- CgkJtbPSrCcHOzAPIFOfvPbQlwdlbQWPltpzkDPPerQ2uQO55x moFyowV+dhj6CrMZBTGVz6i
- m77obTTv1HoFHyqMnv3qUR9DuBA6rimffjXt1JPSpVQqc57c81DXN G97DSVrtEyMQqEkKu3nj
- vUyguQeD6moE6fPkZXFW40AT7/A7DvUyShHmsTzpeoLndllZgep9Kuxf fycBTxj1qJcCIY6Ed
- KtoFKHbhmBHAosmjWUls0WQAYuAQc4q8v8Aqxz04J/CqcI2yNuGVbnirMfz L8wwrGny+RC3Vn
- oWoyAkec/1FWdzcEDI6Zx0quNm8YVsgY61ZjdmBjYqFz6cmla3vA9XsWBtaPqd 3bmgEp83U1G
- pAZeQewFKchGJKjFXzW6jhF7E4O0DcAR6YpxfdI+evrUIztyD9OetPjIYnOBjrxWc 5ajhuy4j
- qVPTcKC/Izg8c4qsjEYHr1yKnj3CbgruPXNTFxTuE421uSGTbGxOcZwR0pQ7bgzfIoGe e9MRC
- 7fMAFJ5Bp7YRxhhwMYNXzK7FzReg7ftckc5OPrTxnhR/EC2KRM8Zwdwz0xUyBAoAB3j37VL 5V
- uipTfzHxgkK2GxjHWrKLulYMCcjiohyAEBwD1qZQwAOwnI5GeRSbbegJ29SzHtwOhHtU652lhk
- A8CoUVi+1Qx4GKsxAlCjL3wKm7QNO5KNyE4yccE1MBhF4OGODxzSLtzhfQk89TU6nCrlcccE0+
- Zl uOl7CkDYAuOOB60zHzgsCMDGalx3GOCOaNoJ6d+lUpaWIWzGlQ2WRgcDr6VAIv3zn7pz909
- asNhV AAw3tSEjILAsfSqvJBzS2uQgLyGbBznrSgENkfTmnhwWOFGW9qMZbcSOOwqeWW7NNle4
- nzHqvfqK lBwSCc5NICVQkkFhxSkAkEDnpUu7Rj1JFEag4ySQD1oJONvyqTzigY243DGfTrSg5
- 5OA3ao6XLjo rpEgwgCPtIJzkdqewPOc7ycDPtURIJyMA+lAJ2A9fTmjVoTpteQ9tyq2Dg/zpU
- IOM8nv6Co2bCqN wIHWmFsSkLycVbV1YqK5r3JgMHJ4BPp1pWkUbcMMDrxUCsW65GKU/KNhIPv
- ik4rqDi21Zkm8M5bg c0ib/M3ZGMYxTVwEw2cdqeWOMEZHqO1K6UtBuTfxEZb5iSdvfB70hJ3c
- MOOOO9KQpTK85PNLwW2j gHkE0732I0TuxXOFUNgjPaowuG9QelBY7SFBLHoKZLuZRs3Z6U1Cx
- UJ3W+4b2LfMDjPHsKc2S3yq eOtKuSfmUjaMGmM4XLhjz0FK6bIabdyPq3HU8nNBC4BwST6dqX
- n5W9RSbcgNjJIwMHGKvbUf2tQY plQDxVc56qeTxxU7ECPbtwRxn1qAqWIw23mnF9w212GFSkY
- cDJ796iZg7AYI7kVLkrGCxJOcYNVn G2HGCSD97NKMXJtsnrfqRsjLKCpGMdahYAZ67/6VZcFz
- klRxjmomAyOo9CD1q4yktFuaOStoVZFz GTg9MjHpVcjMmCSvy4BNWWO5sjdjoQDVeQMMEqxI4
- Jq0/PYmWjViswKqRkMw64qiwyuOcZ4z3q8c FsqGI/izUEqKHXnk9ABWMnrsTblVmUjtV+Qy54
- PNV2V/KbBHtVtwTKOhUHHAqux2uu4jGeKuyd+4 4SkVfmyoztz1zUhB8wc4UDNPZVKlgcYH5VA
- MqMhs/XuKHZ2Ha6GFS0yqxAXGSR3NIwJlBQYOMmpZ FJxnpmkUjadoOQehqua2qKsnoiMKqRtu
- 3EgcEGmFxJz82QMHFTgATkHJ7gE9qCdqA4C4PTFDehjz cujK2Ar9Dnjj1qOUhRgnqRyKsSAZI
- zyevtUDpiQK/OSM1EprqDty6FcqfNyD7/SqEjYkPOT0IFXZ AVZtp5J69uKrv5bFixPJ5x61p0
- 7jgktbGcyAuD0x0xVZowzlOq+1XziOTP3htwRjoaqSkHkcYGM1 HLK4ubojkPvFSdoBOSas7AE
- G0hhnINVQyliuGzjqDxU68lAXA44AFaJPe47qysTocN84wvYmpgBt +XrVc5zgncegx61OmTwS
- OmD9aSuVyJa3LKKWVWI9gRUirhMkr1PB54qJcLgAE+ozTxh2ySAc0byu LVq0noSInO7D8HFXc
- qrKuDuyfxqvgg4JHJ4xUi/NIm48jk570NXd29hP3tyyhOzcAF6EAjpV2I5l VhwCpJB61VjIyM
- 9CfzFXEJyWGBk4A9KzS966QnGz9S4p3Jwd3Ye1PQlY2DfezkVXjOG5DAjjd2q2 CDyPmboT2NU
- 48m5TdtCZJMKWB3ZGPpUgXMI2MRjjr1NV4353KoAqRcsSobGTnPvUweumg7u9yzuV IVJznNPV
- wR94bD0JFVSdu0EhlBwaeJPkZgv0HYVnpzXKUmuhYXJlYKSBjIzUqs3mKmVAI5qgJDuL Drjmn
- 7jhXJwCPTkVcXd2Bxv1NNJCi4Cgj37UAsxP971FUxk42tz2FWQcsDnaaizT0Iah0ZaB3oWd WJ
- xnIPFSId4XYhZsc+xzVRSuOjYX361ZR/3gI4B9KqT8tRtcsdUWN37wg/fLZAP8qnwS2SSv4VWU
- rHPl+hGAT0qwHYkuMYGOKrXroVzNapElvn5vfnPrVwN0KnnuPSq6BQ4Byccn2q0CPlLcA5/Cp5
- rv QiW5OobOQTz29KtRYHBP3ujZqCLDtlQ2QOM1MgOz5x0PGKe+5SldpFsBTtwCOevapgmcr19
- ahjIZ eFbC9h3qbpJ0OSPzqW+g1fqxBncV56/ypwIJUknOaQGTaQVBJ6cUuMR5wOOM4qXbqH2h
- 8h/djODg 4x3pmSX6hR6kcUobcSCp68e9DcnJ4wO9XDXQE9NXqMCFSem007arjKsowOlCnEXBy
- e3eg7SQccjj IqZKT6h7smOHC4PBPOaRi20fIVGOtPx8qgkHFBVi2T09qmLSdw5etyJC4TcQcZ
- qYAFjgZPUUDqVw fpSjIO3+8OvrRJ3Fa6GthGVQNxx1FNb50IB255Apejlt2frScoMDBOemKd0
- hpW1AYCjcDzySaXHz LkjIprPztJwAOKRQTk8nPr3pNuw3orpbgN3mfMOvHBoBfcegUHAzRk7t
- vUA8HFRKWyQScn1quYnV u5M0jgHBBPXpTEOF+Y9cjFMwBwTlh70pY5zlcAdMUou1mSmuxIvTq
- SM9u1OWQZIYYOOCahVwEzkf 7VIXDBmAyQcGm3HZlpq6uWc5XaSBgdqrlmLDaQe5UCm4IkHzA8
- c0xxhmBb5s8e1NJb7mkZa+RYZm DYztOO9J95sFlA+lRo+Y8MAcjJ9qRc7gwzjHc9KOVcphysn
- C4TBIJ6cVH0bdznpjNGcNjB/wppKs oKsAwoW4SWgz5wzEnoKbzuwSAByD9aduycAn+lNwfIO5
- TnGAattpotJ7MhcsPQ9jx0ph3NCM7Tg4 HvTmHOPmI9B2NM+QykANjHek3Ym12J8ipuY5YdR61
- XOCQcgDv7VY6jrtB65qu+ORxzyKT9NQd9iB yGZhk5A4A9ar7vMxnltozU7DJ3Y4Ze3aoSAIsj
- vxmqjazuVFt6FR2YSbVBIIzxUBVjggexBFWzgI eRnHBqrsJhUcjPOfWiTe6DmuyqyEKxbJOeB
- 3qFsHB2MMHknuasOSM5Ukg4TmoWGGIySOhyetOXMt yNempWPO5cYBppXC7QOVP5VI3DAAdev4
- U1wGHOVLfeOajV69DRu6sR43HGfb6UwoVcZBwB1FThcM No3etRF3MhJVuTz9K0jonZkp6asGJ
- 6gD61Ccs5DKT6e1WAGw2VyQeKaWGSp6gVN0tLApLsVnBZkI IL4IpoX5NxYFyp21MQS3GMdc1A
- WLnHAYfnSvpfYznC+xA5xGobBJGRxVR24G5So7/Wr5Q7SrMAcd COao/el28HgHPrTg9BK1io4
- VmByCx5J7VUkVckHOPbvV9ioUjgLyBntVNvv4PHcVd3fmKsrHCs4A JzgZ/WrMeUAYENniqabV
- y+dw6gVZQltwyFOKpT1aREoO1uxZGS2cFsnp6VaHXd2FV0w0KnOCDzip kxkgnPpUxipFddSwv
- LbtrKNufxqwpRh3BPP1NV494Qcg/hUi4Dlic44wDTabauO/ctIMoRjkdR70 DktuBJ2kU2Mkjd
- jaAck+9ShxtJ2nGaiKd9iabd9CaD5XxlSFOBmrkZUzAnIxyeaqJgK2whcc5Izi rS+WyI/8Q4I
- FTK6Zc1zKz3L4KKp3MuC1OQpuPPHb1NVlEXKHnHfPalVUMm4E+mKrlb6kq0VroW1K hyACMjgV
- JvZSMkZA9Kq4c5JcZB5x3qfefLBGCp7YqOZCV97DkcEAPkjrkU7IIJw3QnGagLjACgk9 8elER
- z8vTHB5qancqK5ndE8TAncrY453U9STMy9eeKqqymTAbkA4GamRmEgUZ6c+1S79zVxu9S+j EA
- MNp4yTUyliqsDwRVRGJj3YwmfwqxG6s+3BCf1pRm9yHpsifB3evParablTIxgjBz2qoGw+CDx3
- NTxk4OMkHsa0c+rFzXLgctDtYAkdxU6nJJ45HPtVRFQg5OCe2atg7WPBA71CcFsOL5XoWULMdp
- Gc 9cHrVtSTyV9s+lUo5GVCzHHt6VajYSBSSVHrn3rSLb2QSve7LaEqCBkHpmrqBnChuD1qivM
- pI5bv zVlM7QxbDZwTUyfUvR77l0ElxnoBjjvSsZQpyQAvbFQopwDv5I4HpVgIOm73+tVFRQnK
- 2lwDOQu4 HI6gdxT+DyuWA5poOMNuDMBgAVIMNICflUjpWc22tQe1xSR8u0Y96XaQVx827nFRq
- ylM5LY6c9KA SGJXp/DSSsKy3Q8d/lxzxgUhQEv/AHjjimCbkECpl4O853N29KPeiXyu2ogwSM
- UpyJNrEEegphwT nawPQDNPUuGDHAOeuOtCVtSLu+40BSm3BGCSDSZO7g5OOfanNnftA3c9R0o
- OMt8vQYzVPcL3XcEC 9W4PrjioyzHKtnAPBFPCj7rHr71ExypAPvRC8gTtLVXHMGCbmXcN/FRj
- 7/3sAngUMSyKCTtHPB61 GrfvcnIB9fWlumXyt6Cl8ZCgkg4HvQCGIDDoeTmmM2COmF60ze2d4
- 6UPVE8rS1JSwK8Yz3JoJ2jI PamEfPnIwByaVFCpkHdgnrTjZLUNtRCyliBkg9hT1wApXHI5qM
- AGZmORTcAcjI9OetVdNBKVlZD2 bDdB1496UMG6kEDvQHyvPODzx2pnmDAIHOKSetlqTZtbD94
- 4BXHbPrTgxZsggKBgjFV925+AQONw PWpMp3DdOvrVyaTVg9nJLUkZcg5fIJ4+lIGb5sLxnGaY
- 7sQMD5T3xSKxZckMOefShXaHeyuLnEpU jk8k0g3k/eGMU0yKxwMjPIJqHe3lY/DP8qOVvoFlL
- R6ExJD5TaOMHioWIDLgjOMU4EBipbf6ketR yKu4NtIbriohDUGmpWSGEkqVZgSOtQORuAU4PY
- VK23ZuIYHBzUJx5anBGRyaq73CU2RFzu29s8kd 6rktjpgZqd3BO0YA3Yz61DKWCAYAI5px7Eq
- pJ+RHKoVMnG4DkVUkOIQR261MzfvWOC2Tk88VH+7U 53cEcjvTk+hUYpLUiYq0obepxwBVZ2Bc
- hlzj0qaTBwwBHQAmoHUMc9+MAGs7q7uJWIcrszg49M00 kH72eRz7VMyAOFHT161C3DgkgjIAq
- opJ3KcvdtEQBOmcHd601lRZGwe2BmnkHeTzuBz9aQkSOR1G 0+1PmSepOuxGM5x3HvUL5DtgDI
- +YHHWrGQkJbGD71Fu3tvAbrg47U4xdr20HKKWr0IZMiMltxBPH PIpgUKpZc8HP1FPk3FVCklS
- agAMjKORj360ON1uRb3dxj/MCWIAJ4XviqzIFlPUMOOv6VYZguAyM AD96q5ZndiQpHUcc+9Uk
- 76E3sUpN2/bwRnioZVxl3bPGAF71ZfiWQH5cEYPYmqsvzYK9O496HC5b fVs84R2AYbcYOFwOt
- XI2yyMM4Ixu9aqLtL71O4dMmrkbjcowvfpTSM38VlqWo/uBSWUE8GrUYVYz 13AcelVY8BWx85
- x8oqePJwSu0AHH0qlrpcat1LYHyqADgHjmphjaQeR3xwahRlEOcHOelPicknO3 g4pxTWpa12R
- cGQcDC80qsFnJwORxTIySoB6E8kdqmVdvyfKMEjLd6ykv5jO6UtSRPM2nbgKfUVMv yocHAzjJ
- FQJ8seSx9zUyNubJ5XPSqjF9Byk2ix0ZmXG3PrVpWROSBheCfU1XQuWZSVUDse9SDIJY gHIII
- Hb0rKXM3YrSyvuKwypKZVsjK+tSOSFyGyR1wOlKq/KRnnHBoEacqWJPpnpU86e41JOOpHuV UG
- 0Zz0yakRgRjODnJHemupOdowMcH3pEG6QgZB6YNNxTSuyNL7kvfK4BHUkVYiO5m3lcD8KhWPLg
- kZ9hVlQHKlcHPUd6hJPRG0dOpImAdgJXsQasxjawAGMnkGq6lVnJxnnH0q3zkjPfGarpsRK6aT
- ZN jhufoT0p6SNtwe3GcVCqknaCCAM4qYcKwzuz0AoXK99y5rSxbUq8jZbGDkVYT98nU7emapR
- D5iww uF6N3q3CwEG0NnDU5abGMrpouZIk6ggdqtRsocgkbQetU+d+TgjHFW1I2ZI4OM02rW7F
- u76FtHUZ AxgHHH86tR4xk8gjNUozk/KeM81YXk/Id3baPSlyrqLmaL4KhAnDDqMVIpz8wByD6
- 1TUsspzjHGB irHKwBjkY5PpSa6I1cLJXe5L0bOQAO38qcSdyjrtPJxUR8tlC5OCMHB704AZXL
- EgHnnvT6ahovUc NoZiCMN93NOVy0Q2j5sc0HhBgZOO3egHK4zjNRZ9NQUtbsXy1IOVx2z2Bpx
- YiM45IOKZvJbB4GOD mlj5AJbJx0Bq9be8TNO97kjcw5CkECpVKeWrMGJpMAZIIwRSbcBiTkbe
- 3SpWqNJO6sKANrMemaib 3O0HvmnAtnnOBxStngEgVPK76C5bakIyvzDP3T15pBhgMEBunNLkg
- YKlU7saGIVc8Z6gVdnuydLX IwSHbcQRTWcA4bkAce9O6zcDJpSMYbIwexHUVOtx8sXKxGCDtI
- AzjPPvTGxtH97HSrG1WTnqTyem KgUDcSwJYHr2qU3dg1Faobt/dkK2455poyJFye3SnbSJSRy
- SM8dKMDhwwIwQRWkX3JlorDRsaQBm IGOcGmlSAQvOemKGCbG2LknjOaQBgpGeBjH+FCknqNKy
- 0Yi/LhS3Q8GpG7kYAHQ0w5CnC5oPmEjI CjuSOKaSbuym2noxQABnrntUaSFUwcjnBzSkgnCk4
- xnPpSAkldwHQ9qclbSxMpRa11JztI+U9+/r TWwS3BHPTPeoySytIBkdsUwlSmWbIx196m7urF
- RejfQA2JFO0/WnbhkgLgYz7ZpOkQbjpjJ70xiG CjPA5JrR8vVC01Y8bcBdrHb6Hk1GTtbC88c
- k9qeCQTg9fX1qNmEfmF1znHA71mnYzbTZE+OVyTnt moWYlAQOg4FSN9/c+cnOMdqhyuOWyQO1
- XZNjjdvQY3IC7MN14qFiRIBgZxzUhwW3Bvm9PWoiSykA c5wKlvUbkra7EGQf4TkDFQE4dhlcH
- n8KmLDldrKCeCTVZnLYLHg8VTTew4yitRsg+UbTu9PYmo3A DKBj1OKexAcEHPXP0pGZnjGAAo
- GCSOtDctmRyIiJXlSDuzzjtSPFkDq2R1HSl5ySwJHTI/lQ27dw VAz0PahSl00HGTjezIG/1QQ
- NkmmbFVjyW7A1Lg7MdRnP0qPYCHCkqpbrnpTcrIUX2InG6Tg4cdc9 KEyqjcCpPB96kbAcgr0H
- B9aYR+7BwxGM4pSldFtXepAWKv1xlc4qAtnayDDemanckS/dzjp9KiZQ qgMTg+ntVJkVHFWTd
- iuQxQn5iOpx2qB8/MAwBY9D1/CpnPyl92Ez09aquTztb/cNJe90DlS1uR5U qM5J7+1Z5YbiGB
- 9jVuRm5jUZ+YZPr61TZAFDbScngD0pyavYSTtc87ixsQKeec1bGFkAABHXFVVE eGVD1PAHarE
- IXzVdcjj5iTVuV7a3Q4zsrXL0ZGwFR0PHtVhRluCc5yQD2qqpyfkOBnknvVuJwpAB DNmjmdrk
- pxT0JwvzblBOexqwuSuCAORg1GxYxZACkHrUiBccg8UuZ213CKb1J4wc7WPy+pHWpesi gnAx3
- 7mqyHMyhmyAMfWrAwYgwHI9KLNOzHLe5MpZiFA2/L0I6VMpfy92Ax74qFEK3GSTyKl2soAG QW
- Hc0khtxvYsfwDOemCfepg42luhJxk1AjbSdxUknke9TKA2A3A5ODWeq0Y07bCgsfunJ9RUqFto
- wQSSckimxhAxxuAx1oVgZAT8v8PNOydgt0SFCfMRlyoGSe1SAbWUg7gOtOU5+RjjJ/SpG3kHao
- Ax 6VEm7ibb0sEe5pl9WP6VPG6rMAOQM9KbhgDgcjgZFS42MQMZzSdt0OmlLRk6KNnbGD1qfLG
- PCkHA HBqBAzIvb1qwF4AXk45xTstFcTjrrqSKuCOeCcilCsJFJI46cdRSD7ucccZqQuCOCMk9
- xT1T0Qcz Ww/7pJDAsTVoEBME8DgEVAGAO9zyFySasRhfL6gA9aTk1rYuMu5YTaxXBx3ye9Wt2
- EUDOD1NVkOY 0Cge9WAm9VVux4NTz2SbBSu0pFuNj5pXv296mVtrj5s8cYqpGnIOcsTwAasoGO
- 1gvfJ47VpHlLdk X42/ixn6mp9w5YHPYiqiq52v0XH51KuTwpyAMfWhW2M5RVxYx84fIwRwDVl
- eFAAzk5qNUBReMEDF OG7ewOQc5z2oqT1Vyp3k7IcMSDAzx+pp5RgrOoBbHI9cVEnXjIXNWTnp
- 0PbNEk4kt9GRkBsDjjqO 9TZ4Hy9+/eoVADswyTmrC/NtJBA7kdqzfmXJJWHgfJ0Aye/anAMmV
- fBBHQd6a2FOSS3vS9cAKWAH WoSuHKnsxrcIOABngnvTAGLDPzZPb0qXAaPAwwz1xSqsm8sF2g
- DtWnoKM+UY4zDuOcg4AqJgzDJA Crz05qwpyQGIHHpUZ3BieAOmCKIprcIbtkeDuBxgdeRTScg
- 579KmGSF/rTHUjAGCR6UpJXHFvqQy sVxgY4wajA3YBOPpUx5cAjnsKT58j5Rj6U0tBOViA/cA
- 2sB2+lLtJ3K65QnjHepmXbGV5bPSohu2 YY5XOFIq17y2Ji7bETDkAYVccEimlWEYCjJBqT5WB
- G7GTwaQ/e8vuO9Zv3XsU5PsNziIE5zmo9+S 3JxnkUuG3AE5UnimswHyMMA9CKtJkpxTIyq/L8
- 56dzTkILfN8x6AU18bhyO/5Uwbig5ByOaJ2a3N LpbEzPhBheD61EwJwSvy5xigMxIUMoXqCaY
- pVW+ZiRjjB604NWtYjl0JQ5CFcj5egIpuAYznAx2P Wm5J3E8YOM0EER5B+b0qWS7XGFxtLc4J
- xj0puQckndmlCtyTnHVhTAp2sBjHqa0TQ1roGVMuVJK+ lQyJG+4rzxzg0YAPI4J4NNYDeckjn
- J96lysEbt77ERDBVJ2kN7VAygMfmIbPNSSBmjyT3zxUZXA4 OeRyfemtdWJu6K8pG3uSeeDUWc
- lQpUkL1x0qRvlySRuP3jUBKHAGAGPrUt23GrdCJmcPuK9BgDFO WQNER8qjOeaR/vZznj0/Wq+
- D5oKk4xkVbUXZFOKepIW+YgnHtTCW3HjoKUDdzjnuKQLiQYbBXjBo uuUTmrWGniMdeTk+9MJ4
- OMnNSjHkr8pHXgnkVEWO7GKaV9h0+wmNqKW6kdTTONjYJAx1PQU4McKv 3hg5FI20dTgHsam7u
- ZXalZlUsSm3BbnOc9qZIpB2McjBqVyQ3TAH3ahYhw5LY+tDjLmukO22hA4A jC5DA8darZzCVU
- g4qZ/kUMMEHggVBjO48DPFVLSxMdXcpyttQ8nPt+tVXBK5ByoH61ckC7diqSPX PaqTDGRk4z0
- 9qLrSxS+E873DDLjkHr61ZBAZTn0yBVNPMSLLkMw68VbQLnewbLeh9KttWeu5MlFL YtxZMf8A
- cye9XE27lLEDA7VWAX95huBg/jVhcmXPDLu6+lZX1Ha6si+CGfIzsPr61KhYgchWxjFV k++Cc
- jP6VYUETbu2Oc09X1M9k0TbNhwPvZ/Onpy5Cgpz0NMT95yxAAGOalj25JXcwzyaqTdrGu6e pY
- yWPXHTBqQAsm7dkZOKQGP+LIAqQhfLYLu3LgVClZp2JtrqIiuYyM5I6mpSVZGL5OBxikBwxUL1
- pGJUggZBGD35pNu+ptT31LDBBIGbcvy9/wCVOxmJeCfm5FNAKSGRnVs44IqcDLqVOBu5FHM1pc
- mT UXYWJW8ggkZB+WpxH8oIz7/X0pvUlcEYPapVA3kFuOg96h3uKKbTuKu8ybenPBqyPmZecHG
- fwFRK p8sgDBLcH1qwEIwTwONpppsG0x6lQOCORkj0qVeUBGTnsOtIEyoUDgdDUu0cc7ferc4/
- ChSn1uOU MMhuB6HqKcqgHBJPNCr8ud2cjJPvUrR4iXJ5HXFTKdnbuNSkxVCiFSTu9vSpxgfNn
- BBweKhjDNE4 4GSCPcVJgBSCQ+DzSTsF3HZlhJdhK5VgQSMCpkyQobrgc+9VyoI3cg8AAVYi++
- RgMq9xSvFJ2RSU Wty4vEn38EDr71bUs6hQSQOpqmoBw4PzA4YZq0GGFVSPT/8AXTitBa6WLPI
- UnPBqwDsKFSpK9cVX TOFB5wKlVl8s4GT0U+9PltoNp2SLOTuPoTjpRywPPfrUKu2BgEjOalU/
- Jg/LzjFTblKcZfMmxggE fMOTin7v3hAy2T+VIuGVW3bh6ipo1IBLAZxwacprRii0tGhgzgjHO
- 4U8u+WG3cM/dWl24+Y04ZKc MBkVDs9UFpIcqqFBLKWPYnpinDIbbuyG9KaFyvBUHGfpT0IT5g
- u4nsaNWOT6CEqVA6Y7CmsHLDaa njjDOcgHnkCmvHj5lO0981UJpj92/L37jX5iwAcetMVJATu
- +nSnlmA5KrkdMdabglQRyP4setONl qOV4dhpyOMd/yphA5K8MDx78VO5UJnPzMckZqA8rnBAP
- SktRNcqIlU4GcjnrT2+UsecZ4NLtHmIr HaOetOCsVyQdopylsTe0tSPBJAOGGDUDcr2AHarB7
- YOc9hUfJcgEKO5I71PNbcSTTuQNjaNqkf7W KjOBOSzAqR+dSSKVLbRkgjimsOWPdTjGKZUOVO
- 7GMdx+XqOeahLDOD97vmpNoL8sOnzVD97cMDOe TVWSiHKlsN35KnaRtGMnpTc8sScZ6cVL90f
- ezngccVFsHkkNnJPrUc0dWyelkIfkUMRz0znpUZ3Z P8QJ7dqe2ApVidh6+1R4USPubGcc1am7
- rqSko6XBV+TLHgHtQeMlckgfMc0mVDE8njof0pSNifK2 T/EAaTlc0vZaiFiQo6Meuab8vz8+m
- OafuUkZ4brVZztAJHQYFCvs0TFJ6j5JFEeGXnOD61DLJhQM Yz09hTmysW7GTjnio2BJBOMnnG
- OlOLsEbbkLMyhj2A/WomJIU4PQcVLksXyNvOCCKrmTpubsCcUW bb6icbIhD/vgS2QTnHrUTcS
- c4Ck8EipJGDSbeAP61AVyqqwPc7aqST0M5JrXYhYsVJYgYPXFKxOz jGGFMJCyDP3M8j09ajZg
- pDLz754FG0i0uVXHKF3jduyDliDTiwMvUDPTNR5bJLDHYUAZTLYyD0FW pNi57eg4l/MHQL61E
- 5bIAHyjnipC22M54FBcCQggEgUlUaaVgTTVkMVnk5VMHPTHNMfJX7w3HrxT s/6QCFJ9SDS9mA
- AIzxmolP3hSdtCsC7Lt28k5we1QSMPL5UlurAVJJncSAxHIAHeoDgDoTxVx01K dmiLg78gjJy
- BVNiRJlgd3UDPSrbLsUEA8jpmqLuASwDHI70Xv0IptJtdCCRz5uw4UpyWHQ1TkGSC HBLA5C+l
- XsgIzMADjvWax3YUIw56miM0nsXDV3jsefgsdyqA2CMmrYIJBQ9OoPrVE8bemDx8tWou GYEHn
- APtVSXKm0ZO+7Lkb87cjsT71fUdSCAx5wRVJFXaB/FjrVuHzDArEZOMKfWlOF2pJmr6P8y/ CM
- k5G4ntUw7gg5OKrRsGbK/fU5zVsllJOMZpRSvqZuVxdoB2qee2R1q1Fnapwc96gQ9CQeCfxqVS
- ehO3PSrUtGW4uSLIO1/mUN6CpF3NMyg7ecmokGIyZDnI5PvU+R5KgZzt59aye+w3Lp3H4AgHyN
- vI 496OhRcEHoc+tIUyuDkDqM9qfGr/ADcBiT37U6clcUb8trljaXkYsjEHgVJGCMEABc8imAk
- 8dV9q mCfLwGU+9EovUHK2iJV2gSEg5zzzUyqiDPUkcVCnO5SQRjJqUZDoPLPy8DIrNRaZpfrc
- kxu43fLn irURJTDjPcCmooDcYbdzUyFVHGS2cE0m76WJVncevy52thsd6kT5W5xkjqaAuHI6g
- 9falLELgYLd qqEuZWQpaj8YQ/KRxgUuFCjG4kfeye9NXeXxnJ6gEdalDqwwQWOMDFDlYfNdWF
- QcKSpBPGc0+NC6 ttZeeo9KaC2wK3GetKMK+A4I9Kh33Qoxdrkq7gy57DOfWrKoFAIJBPqaqDI
- GMHaauhFIyT8w6iql JrdFyjH0J02qSeemTzVuL7o+6Sc4/wAKpKMsArAnuvtVwMoIO3kdqfK7
- DUL6J2LYKiNQCUYdQak4 bIVl3dsVCq7hllKn1PvU8S+UVbaWAGMUaJeZLvF6EyAiLYzADvx3q
- RQ5Vdy7sDkAVBltxYLu5B9a urnduHLEdBScrPUavFkijg49cY9KeciPackn3pi7mXGw89frUy
- 5ITIPHU0l7u4pNSWgg2hQvJ5pP 48EEc5Ap5X5/lIOeRUjACIc8HuaTbsKLaV7jVXqcc5wBU2H
- BALIGbtiq4DBCSAQORzT18wgMWXP0 5FO19bml2KU2S7MnB64NOHQgAbS2eaaH/eZyC+O/ak3M
- 2FwPU4FJvUqbskrgAPNy2ScVLujSMdTn oO31qJQyynOCMc5605l6HJOeAPaok13M5STdhPmbI
- KgDPWmncI8feHsKk3nagTHTkmo3yF3D8QKa auJybeoE7iWyDTSV8gZbOcZA9akDAgnYQ2PmNR
- Md6gEr1p7ly9NBhUFyfmGcVWJAdN3G5Sx9varT kAnad1QO6nICgYwCTVQeu1xOV9LXRA25lDt
- yQe1RcKflbLHn1qct+76dT2qry78HC4xnFO7e+xSl aOpICokwcEc9BUPl7W4PGM5zS5AJCtjt
- zSFl3lmPTr2FKO9kzNq5Ex2oFTO71J4NRlgX5baQ2SKl b7vp+FRyDcAcgYHJIpy8h82uhG+Sv
- Xv+dIMrIQenFOJPlhQM49RmmseORgk5B9KTTaDV3EO7Chuu MZHalAKklRnHQ0jOhHIYkYyaaA
- AM5LZGeDxT3uNu0dR2CS2c5x26VAyjJGCRwMelTDduy+BG1RBR v45GeTnpSunsRGdncQ4VQoB
- LBehNQMWdQVG3Pb0qRwDyxII6EVC5XYBuG4ngU0+ZBZXuyJziY9el VpCpi3A855qeRT5hySST
- 1qCQgDYwwM9cVUddAT8yFyoj3kc54yeoqq0iAfezj3qZshcHHI4qux3D sW6dKpIm1yLPRTkA5
- xmlfDRDhT601gUTaTvXoAOpNRD/AFIYqwGfm56VN0nqU+e+iHdQGyMU9Xyh ABHPU1CcrMQeRn
- IPajcxK7gADyMd6q/NuOUko7DiwAAI5I70mSI0zxnjB60qYxjGD15pA+ZMMVPH 5UOavawlG+o
- 8sBCdqncO/vTH3gglgvHUU1nGNwJb6Um/12kHqTWV12FJtLRaCZOAVB5PXqKrswGA e/A4qRid
- pAHocCq8m4nkAHvmtORNh53IflDFdxyF71Ucose7nkcVO/31BBBJqCVVI2Kc+nvRdpak ucb7l
- Vy5baBkd8VRlYHhvlIORirjMSwAypA6mqLsvmY43E8H0pWQk9Tz8KpjJDFgO3pVqHAtx8pL E5
- BzUChIpujONw4FW12F8E4I4rZWWjRKqPlS3LaffXH3ic5q1HzGrfN16dhVKHkxkZy3I5rSjc4J
- I4J5A7VHLJbMq6jqSqQANox6+1XomDIN3JAPPUVUTmRQoAJHQirCLhlGCAOtFr+opJPUlBUqrD
- Ab r7VYXPDsASTnj2qCM/OwwAM8ZGashQ5BcgqAfu+tN8yfkaaLUdGHkUZxnGasqo2jLbiQcKO
- tRKmR hRgYJ68inqSsiY+7twKE+bWxklfW5YjJ+VcEt/dNTKMIG3Luzk8dPaoVBV+Dn196lUDa
- 3t/D9KV0 nojWy2JMDbyQzHONtTooG4knHHNQJ83JUDPIOKtpvEI3Lyeg/pR0stxxajoJySxwT
- zjIq1FxKuQe mMGoUwQepOMfSnqCZPXuSKmWq1Y3YljO6VVIKnGB9KtooE45xkY57VXUkyLkj7
- tWgcle+BzUXtsT JvZDt+JTnJGe1TrzGVAJXvnqKrZ6dAOpzT45SBuyDn06VVna6C2mhOA20FT
- vA9OopSxVidnBHGO9 RlnKrg4PAp+T0JyAODjrSk4p6iV7oAflUkdD3NTHbkA9AB0FRBXJUYYn
- HFSP9xF3Ddijmje472ej JshpAoI2jgipRu3KVyQDzVSMb1O1stnJJqzGxKk5xxwaUk7jcGti0
- rLn7uCOM1ZyXG48jPFUlYlF Lde4Aq2kgEcfqRyKIxafcIt3ukWs7Y8iTI3DrVtQfmzzz1qih4
- AwMdR71dDkNwcelKo5dR2luiwM LwBxjgk1OnyKQoJPc5qIEFACBjP409VyMgj3oik9bDb93sX
- EwARzxwOaUfK5xkIetRxklxjr+hqT d8w6An1ovyuxLbt5D9+F6cdD9KVgNw3nGRkc05mwoPyk
- 49Ka+PL+YZ44OKEwjN20QDiU+XkjPc9a d8y5bB3E0ijcvAKnGeOhoEjPnkL+FQm3ctvqG1DI2
- 44yOMUb1BAGSSOQO1DGMg8nIOevWmgHYflx 82QfarUrIIO6Ji29BjAwcc+lDEeQCOe4qBR+/w
- C4X1p+cuMlR7VD3FyNvUXdhSPvetB3CPkYY8ke lIWZlzlR+HWmM2VGQSc4x7U1eW5Suh7PkAA
- 84wfeo88KBgtio2YuxXBPTBpWxwOVApyVlqLlVtRj MzEHG1c1G2OR8pB/SnM/zYbkED8KjYnb
- kcjuaq7W+hU1MhLgkgnA7ZFRMyD937Zp8o7gYOM4JppC qSxxnGckcVNnYhxttqRA5k6gEdc0O
- +EVtpIPX2prHKliQD14FIZCUyFHsDVKydxxetxh6sXIOeQB 2pn8POQemeooOGl3g4bFMBONzZ
- HfHpmktdWKT5XYT5WRc5B9QakPEHPXvTHIkIKnnoP60gLNuwVJ zTTuKb2YnO3HGO9KcKByOBk
- H1qPc3CjB5546UbS7ZzznI+lVJdxTaaJWc/LyvTn2qsTjncCM9hUj KB909ByM1GwG5iAC23JW
- iDgtCIciegh5UAj+HOf8arSKoZT0zz9KezNtzjaCBkU1pQFJzyOoHaqb lH4TTkb0WxGzNhQAC
- MZ5qkfkQ5+YZ4PrU5kZyw+ZT6mqrnaFUnJ5zU6MXLb1GM5zlVLehqEswTgd uuOKeS6ttGCeB0
- qs7Yf7rZ579az0voC0VmhpYEEpyAc47ioeWYgA46nmnOxDKyjjZ27mmBSGyCCc c4q5WWw7voR
- lHKgHAyN2acmQoO7JOce1NO5txPUnJA9qe7jyVClSx7DtTdSTtZD57jix8tS5AJOS MUpaPYxC
- nkY96rjO5QQWJ/KkYsEyeB3I70pQ6tEQsP6SgjB5GRS5bzmGR6jiogf3bHIB/XFMZ2ST KsOec
- EVad2kiUkk2JJuaYOHGc9qa7Ycg84OCKc+DEoCkAdvX3qq0owxwPcGh2Za1WiB2ONxB3AcE 9q
- ol9wH8QBzuFTOTI20KykcnP8qqMCAQflwOhppxvZkxtfXcYSqtnJYEdfT0qhNuMrbQCoHX1qy7
- rsIRh1/Sq0j7V27i2eeB0NCdpbWEna7OBjLrcgyqT34q1GvKNtYk8cGq0QO/5zyw5J9Par8ZKQ
- 4O OeFNaKKixSUlui1Ep+UYPX8h6VdiQjoG5PQ1SjOUwuR6k96vh2CrgjJ65FJyadkEd9CdOHH
- zZPoO 1WFKYBBye9V1XEoKsGJ9quRgA7SoBx19aXNd6blOcbk65CBSQT16danwR8qg5POagVm2
- qrLjaMA1 bQqqhiRzwKcrp6oIpLzQ7bv27Th8/NS/MzgNkbR9MilC7SCp5H86k2tkM4JyP1oTX
- cjn7f8ABJUK mJwGABHyk09B8rBcnA596ZCRtA6sOOKl5Ac7eSeah26LUpSbRYiZSNjIV2jjNT
- DhVPU44HpVYOS3 KHgdh14qbBaMGs0rajknFpskTJkPG0A9+9T4POM7SaroMRbG5HHNT7hyw3d
- fWolZsaqST10JsgKN 3UcVKpCSYBPoc1WDYOeWBxUpbc20AMc9/Wrd4vTQcnZ2ROhyWx90HmhW
- B42j1BHpTchF54Oe5pqn bHzwTVpXQ7LcslsJk5G09RSo75IBAye4qBWIX5sjihWxkEgqTkGs7
- LZ7iastNS3ucyZJyMYGKAxW VlCsx3dahYgIdvXsKlUkrgHBbrSdkitbX2LEfJ+VgpI6Y61MgH
- mEBlyBwPWqu4hl4yvX3qWJjjad pbGOByKLahHa5cQncp64HfvVxVBTIK4Pas9XPC5B9asoWUA
- 44oS0ugvZdjQUgyEggLwB7VaQlgwO Ce+KqIyBgRk9yD0NWFbdHlQQSMginH3mRz3diynKEnJJ
- 6j0qwvRMZyOoHeqiHG7nBzzmp0fadwPT pnvUSUraGlu7Lqv84HAOQcCpFTPLNli35VSUBRuOd
- zcA5zVkNgYzk5GTWlraoU79CT+IqzAk+lOG DjPJHUCoULeYN3DE9COtSBwDsIAbqTRPunqTKo
- 3uPBZQT37Ugww+Vc8cgUxm+fgHavSkLYOTgYqI pmlpJXH7gCFw24npSbgVIJOOn1phb5g4PX7
- xNIpBlZ/4c4ApuKWqTJfw3bJozxtY5WkYgHK5Oema YDjIU8Z545oYFkUYJwucipi7SuxqUn6D
- 95Em08EHnjv6Um853bScnr6U0H58nrjvSFvlBwVB7Vcm mKKtqOBbcCMNgc0yXnaPmzu9aQnK7
- kYEHoaYzhXGWww6A0t3oHQa7EggjAA4Pf6UxORxuzt6mnkk RAZU46Co2ZSSQ4HajWzByfLYgl
- B6McA9aYPvYGcEkYNSO4XGQSe1QNJlkHXvn1oTk42Y76CEcjJI I9aYx+ckEnjIx6U44bkHnJx
- moJTtAABxkHNS7kryEcsWLAjoBjvSlMKScn3qMsN5zxk9D2pu5t5x 86YzxTk5dNAVO7JFPy9V
- zt49qUYCYHPTkVAhJhztOfbtS5AMgXOd2atxSbQSbegrsAMLxzxmgFsj CnkZyD0PpTfTuBjJp
- ruTFlfuk4oa6WFKAfMcsx9M8UwkdCc9uO9Mzt+UHqcZ9qiB2uTtNEvImEls h7FtoA5UdCB1qA
- suWGC307VI0hOcjAYZzmq2TlyF6EfjSd+U1jGUU7sVmLP2UDnJFVnALYIJ460r 5KjqSfQVCzA
- uCxGSOMdqmDa0Iv1GEnc2OhqBlHzbvl9z2pzOvGC27GDVc5GSx3Y4xVxWlx2k1dDM qBvHHPy8
- 00u2SMKG3dMdKRSGB9M5xUJIOCTknk+xqFHmTZTk0tR2SsuQMAr1NIULOjA/MwzxUTZV 9ucZ7
- ntR5gV9xJwea0SaWhE6bvpuSMWWTHLEelM8xS6gZzjBz3o85TICSMAHFRNIPLD8ccAYqEm9 ZI
- E7rRakm4lmXCnnrURxj5/vZqMFcsTkEnkZxikkC79yt823nPNN6MnlvuSNJk8YHHB9aqM20tuO
- 4Me3YCpN/wA7AgAYyc1XLsycYwy9SKuF9hW5XqhrFN+QTtHU5qvM3ICjJbgnOcUjEH5FPINRMQ
- xA OVLcYB5qrK97jvHQgZPk7YI7dAaqsCsjgHB75q1ICq8ZfmqTjc53EqCKOfm0voEXdO7OOUj
- zF+cE dh9KvoWZo2ypXb0xWdGSQPfjNXot4QKE4J3DNae0bCSdrMuwhS6hsEYyAK0Yvmj2kEkd
- CKpxkM46 YI5AFXEUmIEMN4GM1EbvYybu9CULmJeAFBwR0NXN5BH8LDgk1XjVSSVyST8wzU0RG
- 4koTim02+Yt O/QskZB2LtVj1z1qyhOeQox61XRsDplQcfn3qyAQxkwS3AI/rSumrMWpOQxLbg
- Cc4BoX7+WcD19q i39CPqQaeOHPQkgcVlGLvfsEJ6PsTL94lTjI6irEbkPh0bb3NU1CrErZIP8
- AFz3q0h3x8sc7uRVS lfRAn1LC8KDnHf6UsbjyyRwM/eqKM8HJOOQOakT5QCOVzihrqUlH5lkN
- lV6EYORilUkgbSD9KgDB 3AY4bGB71LnfGAg24GBUxTiU5cr0Jy6CNskAjoM0oBOSGHTg1CcEB
- iMPtAyacSQgZSG5xTdltcLt 6LQduywyS+DnOaejfvgx5zke1V1ZuQBk+1OVgHJUcAHNNyfUuN
- +m5cJJZRjnufpSYJCsB823oKgD 5YkkA4596AxKHJwAO1TTk73YlK3Uubl8vkbGyAMmpI+ZgDk
- ADHJqmADLw+H9D3qRXy4HIyOppyin 1J3TLSkh/vcY71KrfviRnnrz1qupDfNnvU6fMVGPmB7C
- lJdy+ZblxXQsDjCscD2q4gG1MsDxjGf0 rOU4IBx1/KrcQIj5OBUPR2XUlzvHVl5MmTDcY6GrU
- U3zFTngZGKoxv8Au++OhA61ZR8OuVx7049g 1toaMUihQzKST61JGCy7eAR0zVIM2Bt+bnGM1Y
- DAxnIII75oQ4rtoXg2FI9B19KkjI8xx3H61VQq eTnb9alXaXwThQM5HehWdkNJJWJvNcxgsrA
- 5wD6CnqGWQh+gXvUcZDKFB/E05WzknIIPQ1T0dloR a6FBUgDPvTyxzkABQOtQh1VjgcHOBSKw
- 8woT9PpQrvVjlAnRlCHHzHdTSPkLcjB4/CmsF8vjOAOv rQFQIM7sEHPNZ8yvuCjyq7GrIS2Oz
- HJp5kCH5mHFRLsU4zyBwfamsCAG3AnFaJxbsXzJsl+8MFgx BHSnbsSAEEjHGahRv3OSQWzk4p
- u4MSec9AM1m1d3uNkiyElRwo7DFMO4jAIZsZBo6qG4zSAZdWJH XnFXzaaEuKirsRuyngk5zUT
- OhdCFIwMZ9akdzvPTj261AwO08HcOnHFKyW+j9SkrLcj5YAqRjFMw pXcGAYHAqQ8n5QNpHFQk
- FkBQAE8nNCm0gspDWUFm5xnmomBO7d0B59qlwA5Qg9Ofr7VCTtRiSfoe 9SpXVkyXroMccEHHT
- J4pmQY1XcFwMk0u0MysTheuKiPRiULHGMA1XLrqxqSTSaAyeXFxjrT92Y2X bgdSR2qDBO4MNo
- B4pwZmwQQvrx1FVaSsyZWtckLZTtx6VE4PlkZwueBipN4VT0AHTPpVZiruMucd cE4pRm7jWm4
- 0nbCQxIPIFNZgB8xzwKQMecjg9CaiLDCknGOufSm5N9NAlKLsx+4spG4Edj6VE7bl U5LAc5X6
- 0jN8+ARsx1A601G29BgHORUpNq4p8rSbImIR2AYgHqPSoWJ3YAPrT3YEMRjrmoCQS+GI JpXuh
- +VyNiS/ODt4+tRZwgxktnk1IwYsF3Dbjiq0nB2c4BBq4S3QOXQa/CnjC54yOajI/d5AP5VI ZC
- FcfeUtkH6VBJJIXDBTt9BUpyetiOW+vRDB8wCk5HXIppAMTBSODhaQvmQj7vFQOcgqeBjPHHPp
- VR10RXs5Rt9485wSBgg85/nR5gORj5VqKNS0LKTgHpzSNjIXJVfX6UNO+opqO7HeYfMACk57+t
- IW QuScHA7U3eABxyehqsTlAAGxuzk+lOe3mRTS5idpBtDYZc9agbhz1Cg8Uudm4daiZgAoYdO
- BikuZ 7lp+RDkl8bSoHrUL7V2u2ckZ4PepGV+X5yemKruchQykHr7YrX7VhcuuhHIwzlTgexql
- Ix2Nhhz0 Bq2xBBGRuPI4qhKxDk4yB2p00kyVHXU5WIPgA/Kd3TFacbHYM9CeMCscvm4AVmZFP
- PbNaceMgsTg t096cIppSe4oQdveZfhU+YeeM8CrUf3mYfdPvVeIncdw4Pp2qyqho9xOPl49qa
- 31B1d7F2LiIgkZ xjHerYOVAY4XntyKpL9xVzweCcd6tDccLwAG5JqJKzUuwKVtbEqn5gUxgcc
- +lWI/u5LZ5yBnrVcB t+Bjk849KsIACUK4zycGkpNsi2t7DwckqMktzmnD5hnkc4564qLJLjgh
- exFPBbaMnopyfeqcXpct Su/dHsSzsNwx64qxESyBcgKO4qqB8vUcDp3qdXAI4KkfeqbJ+Zb8y
- yrNsYgfP7VOrYUBmJY/rVJW RQ5JIG4Y96lWQPGNnDdBnvUTve2we0didWywC7SM5b2NWFbMi/
- 3vSqQLo42kBe4I5NO4JZt25uow ad76kc3NKzLgIIO7JK/ewabuwMgg5GcHtVbAC5IIGRg5608
- Hk4H+9mk7l1Hd9hxyuMnGTz9alU4P tnJNV0O1/mDHJyfapI2UrlclT696mV2hy12J94BYYLEn
- I9qkJTyzhtxJ6f1qtyZSHODnqKdgAk5z 7UJx0voJSTdkWS6hyQcfhT4h+9y2eDwKpqGExYsCM
- 8CrCtgEEng9fU1F7PRluLtYthgpcjIOe9Tx bsh0OCfWqZYspPXBH4VYVzs+8oDD8jWqatohpO
- yRfUlQTkAk4GatRnIznORgVnIExgszccc1Yhbk FidvQKDWTjzEWT2NKNmO4NxgdRVgHLrwTn0
- qipWRv3bDGOc1aTy9u1m556U3ZO1hve5cUtuKqOCc VbVSAehPQ1TiK+UD2xVuMk9hgqKcm3r0
- QStLoTJklSwzxjC1Lg7lAIVQOM1ArFMsMdOB7VIrgxqS ec8j0qk29hWcWTpkKMMB6e9SEneDk
- HnBqEFdoK9hkCnZLLlVbJGcmm2+oJXWmhPG+ZmIC8c8iohg yjcBk9KcG2Rg8ZxyPSkDqcDgMe
- pFTFNXaCKiODYO1jgLwR60KN8h+b5cZ+tMYswXaBz0NMLFc5Bc AYODilyaaGyjpZMmZflxwoH
- eoxjaf4mB4pT+8AIOBtzg1AASCoO0g9SaairE+9Lcn2gcgH5l7dBT VZApbhiDjg0zls5bjouO
- KamDn5WH9fepkronybJfMAk5+Yd81FuYEkHPPbpQW/esAMHbQMFkG5Sc Z4pOKaG1FbiYfYGYk
- U08qPmKgDn2pWJVflHbpmoHLAAjPv71XvSe4K+iYhOGyOw6CkyMhiMEjqPW lXOct1DcZpjDL9
- T1zUpp+odbXGM2wl1OXPvUBILIT09aectk4/D0prAbQOrY6elKLj1FfR3ISylT jJCjFRMGVXJ
- OB1B9amcEJtUbsjJA9fSmHLR/Mp+lOUtdBR03GphHLHJZhjFNdnyNoAH0pGKonck/ 3jSO7Lyg
- GAvI9qbb0E0ubUiZ8SHcSQTgYHFNJBBUsu7AIGKc3zbWUnGM/SqxY88jIPHHJzTSG7dx zNghi
- eAOMDrUTsrSA/eHTA707dmM7uD0AqEKxXIXAB60PVXvYmLsrLccVUIpOc9jnioyYtuBk8fN z3
- pxb5twO4jjHamEfeIGB/OhOyTuDhciZsqQoBNMJznO0euRTyPnycAZ60xuWAJGAfSnv0KurWKs
- jFcYPA4zTGwTubn/ABqdii43Ju5/CoGBEXHXGcelSlfQr2t0QSMVGMAsB0qEO5UnIz6YqTlosD
- rx zUMshUkDH9aqTSurERtuiOTb5YycMDjNV9xwTkccHFSuysfm7rkc4qH5TDwCCPyoVt2Cm3o
- MGQD1 BPIJody7M2cLn86YzKYs8l88AGneYwjw6YHvROVlexXNqMZkYKqdcVG+WTb368GgqPu5
- wB3qMD94 R3xkGtoqDs0wtZWuPATGMtk9CTTC43MAR+NGAB7fyqJt2PlGQeR71D1l7pDV72Gqj
- LIdxyR0qJ2O MLgt/EfSnklfvZHrmoyDypXhl7VMoO+pm5JNMrsMxkrgtjvWZNkQspPzAf5NXi
- eOAwYDnFUJs5Zc 5OevrW9JvpsXFOMrtHNwKAFBYMScjHetCF87Wbam0YOfSstFO7cSPp6VfVs
- NgDdu5OPSs4qLd0Ja q5qxvldxwUzzVhY2Mqsp3DHOKrQqRlScjsPWrilhGQN3J/Orje/MiG0r
- 8rLqgbQeQccg9jUiFjuG CTuAxUMZwuHwSefepkJDll4c0ScloKCstSVMA8ghgeecUoblMZwR6
- 9aiAORgFjnluxp5faQGG054 PrSUXzaDdtEiZT8uPm5PQ9qkz8uN25h1+tRIMyckZzjJp7IpkL
- Ek5ORipvFsttbk5kAx90NSugd9 24rzwPUU0FQG3dB1NM3dGB+mO9KnJ3skCT3uTO2U2EfKp6m
- pgVUgJ1B4J71W3YOMFjn9KlKn76hv qe1Nyv5BBPUsB3Eg+RmKipN4+V8HHt2qDLBSQQSOpp4I
- P8SjPNRFue5UoqLLDOcKu0AkdaaNzcEg rjFMUEDcpL8/L3NOyrEhmAA6g0pNJ3QLmXmKWY5+Y
- eoxTg4C9Qfp61CVBG9enYCpDgKTtx9fypXY udOKDzB5I5781OHEjEoM88VWiKbyB+JNTK+0n5
- MDoDVW622CKS0sS+ZsfdkYPQd6nV2JGcdPTqaq 7htUnle/t7ipVQkKwJ2rkY96W+5bk3HYvq3
- yqdw3Z5WrMcnzdm4x0qjGNoBYjGeo71bDDIUfpURm m7WEloWlbDYxwO9SIwyrAH3qBSNp3ckH
- oPWrMZ3rgYJBzVRnZbBbsi3HgkscYPAAq2iN8wAHHVjV FFZl5YDvirIBwu3K/Ng5NEn5iXxWu
- aSsoVFBwvcCrKEAtnP0qggJjKnbkDOcdasoDsUg9PWnN3Wj HZbEjt/CDwecjtVlSBncPmA5NQ
- BcFQVOegp4Y43ngHr7Uoy7FxkraEylcHHBzyDVne7TFVIA61VB woB4PBI9alz1ZelEo66slyb
- RNht+5iMY4wKe+1o9xPscDqarA7WQYzxzz3pzEhwGUnjnFFpJlXF3 7DtByMjHrim7ShJHIJzz
- 3oY7WG7oB6UhfAIyNmeDTadrIcJauw7cDxtJUDk/0qPy24xnceoPamBg rHJy3UUquTIxJx7+t
- JOUdkEnLuOG3zfmDeoxSfLuY/NjPODTfMCyHnIIwaY2GYkZLEYIBoctrkPV 6inAYsMkAcjPNI
- rKr+uO9NHQEEbv4hmgFsDcoGGyaHJNWKkiRmQrnkccGmE/KAOVApCQCoYgZ7Zq PI3YXcDnj2p
- uy3Jd2tGDZGC2cHrn1pgYgZPrn1pc8sXwwzjHpUXykswOc9qS5Wxy0Qrk7QFYMSOv qaiJUD+8
- 3c04hD1JJzxg9KRVz0IwTyPSiVSCTfYhy2ZDIu3ocE8ioy2EAY4APX3qRvl2AfMp61Vc HcB94
- fw+1SrSdmXGLkxjjdIkhODjilIOCScHOPanHBAOctTWweeDx+taXb2JmrvcR8KjBcg9OarF WB
- 5wf73tUzMSncc9fWoGJJIUEnHBPem/dVib2dxkpbegUAn1HekYZbkbexx0p45kUlh6sMVHklWO
- Cc96zUrrQtSXYa0ZTJUg4681EWcOA3TsfWnO+IgT1xyKaSdv3SCeMU+l5BJNIRmAYgjd6H1phK
- rG ASMAdCacQPN5YEY4xUUgHBIJA6e9OEbbmfuN2sV3zv4OVJPJ7Uxcqwyy7duQcdanLNvZSpw
- AOKrn DBsrsGOAaOddTXV+hXZgcYYFgckAdagchs7Rk9Qo61OxCyA8MT1qttOeCO+D60JrbuDV
- newwg7SQ Ac8cjpUBkJypAU55OKldiqbXHU5qqQGlY5znGMd6laXRiovqIwKuwIwAfvAVCPMAI
- fLMTkGldynG QADgmohvZevGOfrWkNVdm0bN3X/DjxzGcMAT3Peo844OSxHPtS7ioIABY8gYpA
- Bt3Akdcj3ppva+ gOpaLQ0BgAOdw6/jSO+F2hTkcDmlLsY1XK/722ojlZgQMjj5vU1XNd3fQzu
- t2DszSnI2gDkY61Dy Mj+NutWS+ZCRjOOpqgWBdwFJOeTQouXQatezRC5LHpgDg8VSc7Fz6nqa
- tyA/Pk5x29aoykkHd8oL fLQuW2oSbscvEXB3N0HUHvWhEAATjHGV5rNgceUzltwPQetXomAUM
- Qxz94U3F3aasT8PwmxGSU3b vmOMe9XEfaoHKjOBjnis+3G4ggjYq45/lV5CCwyvy579qFCysh
- Xu7dS6Dld2R14NS5CEHIJJ4qoA d3UYHBFWVIbjac4x9fehwT3ZK0JFdgeOFzyalCKTnDH0qDG
- Fznv0qSMFgRg8HjNVL+6Va71Jd7KR 8wJPQVKWAYAdCcE+hqujqJRwNygjPapAGweMemai10KS
- 8rEgQK2c8Hkg+tKPuEkY5qNVwCS3U5NS bCBgklQeRUu17FRaHn5lxzn+I+tSoSFIBwB6+tVVf
- ORjBzhfcd6njUM5xuwf1pTWlnsOcblnduxu UghsfWkOBM67h97oBSKTGCf4u+ecUiBmf5uAe9
- EYJq/RCT0vHYsLuIBJKrgjPYGmtIwTG0DI5OKX DDojAY6noTTWfcF44OaElo0aQemmogB24BO
- Ac/SpWHDBWzznB71Dvw5wCASMj3p7EOcjIYcnHpV2 bJcFLqSEKZAo4HU49KcBtAcE4xzk0wMh
- JxnJ64peUCYO5AORWEZu9gndLyLOAxwMFs8VLGWwvXB6 1SXesi844I5qaORiegwBjNU4y5bvY
- bskncuq245XO0Hmrsajdy3zHkc9KooPlJ6BQB9TU8LZ5IJI bn3FTvpHYpu0dy6rkoqjBz6CrM
- YbaT3PcVVTZ1Ugk9u9TI58xQcL/e9qpXtYWltGaEO5lJIG7PQd atKAY1bsRwKqL9xQA/Xr61Z
- ickfwlQeKXJLdMSRbT5ARnag6GrAJLp/e9+9VUfeCcHnpxU5diBu5 7Ad6qFuZ33HFSUtiz5jb
- 23HhjwKeoVQwLfMBjGelVjzjJwOwqUMdw45NJJLbQNVt1LQZWIODtI5N P3oMYI56k9BVNZOgJ
- z3x61MAShYY+hokrEyunqywHUD5myCeo705STjHQAgfWq2/quDjscUuS020 EjA5Oe9EdtirW2
- Jzgq28YYjjPpTcbcDdxjkVG0mTg8sMA+1EcqLMSQxAPr1os+XQlybdkOZwJPmX K5GPpTGYLJx
- 1I9aN5KjcFVevNMbeu45UjORx+lCkirJhkiHaMZ9x1pCMMmWGTyCO1RF22MxTPWgP iE8AEf5x
- R1KvfdKw7euCcMMDFMySmwsGJ6GoSSAOhXv7GgsxYlfl9eKTTuHLtaxMSWy5IJHA9qYC dzHID
- DpxUO7Oed3c4oDgxkkgMBjFVJMlwWo9m3AABgAevqaZtYMTn5c8UEqDhSffmoncbM5AGMcV F7
- 6WFboPXBlHOcGkLnO3BxUGSGU5Bx0AphdnYnjj0qlRT2Y4au9ywx+U8/w9PxqNiDEW6cimLKS4
- LbdvUkd6Vj5iuSAVJ7UJNOwnF3SYwcg/UEVGzH94QdpzgDFPHTYDt96TehfO5cdTQ3dkR0ukVi
- Qs Pynvj3pN/wC5YL1zg56ipyEaL1btioXVgzbSvXoKlyj3EktmyAqythTzjmkYsiK2Rk4PSpM
- KEOSd x/Wq5yHAAyB0qU5PU2u7DmZc5wCfWo+THubnBwMUH+7kDI4yKR2xGAOfWr5Laoydo2Eb
- arBiSCeM VCzFmQHsMfWpc8c9e2KjfcTkOARV3TKtdDcgjdzkngVUk28lsgnoKmztnbecY+6Kj
- b5n3EcEcmpb irNAlZ67FVmUM7gDBHeqzE+XnrjJwPrVqZx8uQSuB+VU2fdJgKetJy5TS7b22K
- 7kc43FTzzVd5dq Y4Ge+OtTSBQ4CnHt61C5VtpAwAeAeorRxW7J5o3vYPl3hB+vvULZIC7Tx1N
- K2dmWyQDmkVkZujZ6 4rNcqRN1zXEEny8DvlcjtURkG4b/AJVPb0pzkYK5yWGQF7VCS0jbSR26
- itb2d7D5Fa6HEkMSD26e ntTS+dwB2kcn2PpTG2iUjOPm7/zpp/iLE57+5qtRJXsmSFsBGP3jz
- VRzk+hxyfWpBvaLocVE5UPG OhBxTp3TEmkRuwE2Wxg+lULggN1wMA81ckZQxU4K5+UiqExOeR
- uQjrjrQtdNrgpdzlLcLt2nue/r V5CDcKT17g1TVmEYBKqSCcEdKnjyp6goRxn1pxmpRV9xcrR
- sqSIwFwcHnFWY2YcBwQKzF/eR9Tw2 G9quptC5Vvm4xnuB1qFbW7ErPQ1g4OC3c4qZJcSbkPAH
- f+VUIwSmVPfuasglUzgjjOe1WlGWjMuV bssmYmFRgcYzxzUivuIXlXHBqHLBjnAA6kipQqgoc
- 8k4J9aJuNti+aNuxOFUHO3cR90jvUse0yY2 sGAHWq4DKxDAlQ3B9KkQcr13Dk1k0mm2UpO2g5
- QDPySd2fyoO7eu4nBFI3EhOcL0zT2zxyDjnFCY 7dmPGDjAO5epqQf3s8YxioEJ8tTzyOR3zUg
- OUwzYHXP0qbu9rijpLQnX7xLHginKwMeXGCTUKA7Q Mg7jU552pj5geBim7LSxd3fcUM28bySN
- pwBSfOCAD25GKjLOW4+THHI6ikjU/OfmLA8VUYpapgpv XUnBAj+YZYnj2pW2FxtIA24z60Fw2
- Mqxz/FTCVYZA2gHPX9KNXrYyTe9iRGRdxYEgDjFODqUyAWV uuOxqH5ZGbAIBHTPenKxCJzg9R
- 7Vnyxi79S0kt1qyePGdrA5xjJqWNV285GTjmojk5crtxUqkG2Y k7z14FP2lxxeti4BmE4557V
- ZR8EYZeOnpioIyFOBgAjBz3qUDg8AjHbtWSnG9jaLi4l8EBV6MT/d 71YABbI45qjCFb7pIGOR
- 6VawAB97d654q+ZNkpR2vY0oxmHk8dRnvU0WDJllwM96pRD5gCe3HPtV 5WXCBlOSOue1Jc1tD
- Nx6LUn8shixb5cZODUytmIdMDoTVZDuBwdwJzipWKiLGCCCCaHZ9Q12LHmf N8oUEAcmpFLlmx
- jAPp0quDuUkDL5FTLkPgZG73pylG4XdrJC5AHzcMD1/pUqOcDLDkflUDZMzIeA uDk96RDgtxw
- OgzV8nPqXJpKzJiWLAnB9cVIZG3HLA9s1AN23Bz/hSY2p3Yk5Yil7t0Q5XsiZD++D MwPHPvSg
- nBGB1yCahyHwRkDHQinA/MduSDyD6CqcmU273uSbsyKcbgTSOxy2eFx61Hu3IMHJA59q iJBY5
- BIPIJrJJp3C33Em4mDryp549aZuA/2Wx0Paos4yM9emKXdn+JQQOBjvTkne4pX7A0uZXB5R ue
- D0pA2EBDHA61Az5IIQ5Jwab0Hy/Pxzmh9UEGm9SYuBk5xjj61BG4JI7Z/E0zcMckEn17VCXKue
- wzwR0rS9o2YOyLJkG4rjn69KYGCtlhnnj0quXbeSB8vGfembgWVhnJPc1HvdGOfTm1sWgyqAc5
- 5z SkqVDD5SeeKr72YLhcADoKRSzsRnr93j86Ol7hJR6FjLAAgDIyMAU3ewjQFSF7ketRlmwOm
- WPIpy ksm0YUA5we9Ta24003ddBWcA5/p0NIrAKC4UkjsKQkLxtLHdwR6U6QgQBgCAOORVwu1a
- xKvIYGHz Y5HsaiJcyZCkc80rn5xkgITkgdqjLeYCoODn8aU421Y5JSkrobI53YZCee1QgrwcN
- 05Ge9PYqsIU /M/cUw5ZAQRVr3V6kPYYxAm7n1wcUEgRMU4U+v8AOgsMKWIzjkVE6kng4Hfnis
- 5PYbswZioBOHx3 FR7gz4Gdx7D2okKiJuTnoTUAbEhAPAAJwOa2i9DSUdE0xzk7y2OAeMjp9aq
- vuZAM9QMAVYEm5Sg6 EZqAgeVgj5T3704zsmmjL3272sRHgnLDaowc1VdiR8hHP3j3xUrqC2GY
- sSc9euO1VmYZZh8ox0NZ JXC+mpAzjaFK98Bqru2A5XGCcZxxUhy0o+7jGM9qiYbot3Bwegq52
- SL1lZCMvzjJ+UDmoCxzkrgA 8mlYtglgctyfbFJIVXf8w3HHFZp9EJaaDfNydwPU56U1RmZstt
- PPXvTQSFHzDI6D1p24hgGGTtNW 9CXGw1SAdg5XPJpPlDFEJPuaa20LlGPH60Fj8zgj3x2oe+r
- G72uMbgkk5QnjFR5DjAPQ9+tBYHcx Ofl4AqM+oPPc+tW5XVzJS11K8u3e/GFU9aoyktje6g5/
- MetWJGYI2RuGc/Sq0pVTlFJ479jVOTlG yZautf8AI5SMtKRwR6A96uIMRkvztzgVQi3ZJzkMc
- DHarS+aCfYDGRSg76tk2cn2NGDLg46Edv4q tIWBIUFRjlj/ACrOjkOGz94A4CjGKtJlgNxIXP
- AzTs7astrlgaSEh1O4qDyCatpuEqh2Jfb09az0 KeV3yDgjPSraksDI5Jx6U4prXoRFrYuId0o
- BJDHOM96srgJt5z3HrVIK7Mr5AYcirEeTnuTgDAqb LdBbXcsB2aZfmO2p1yIjtOXzwB1NVeQw
- QnA5O4jgVMpwwYn5QOtHu9LBp3JlbABCtjHPFNLfJtJy yjkAc89KGZxvAPyjHNIoOZGLBvXFV
- G6V7jSVtCdSuxcNtcgcmn/dIUAMevFVQ5WLOFHapFLBtzDg 8E9vrWbpu92aOF47FknCphfwBp
- 4bMYf5s98/yqJPvbicANjrSNIFyAOjc0lByZMVJqyROwVlO0nr gUAKrhQ2GJyMmo8hWYtnO7j
- 3pw+djgEknjFTy9wimtCQFi/JGAccjrSgkvkfdB6VF1YAnjvz0pFP +kDdwo6Z7Vak0i5OKehI
- h/dEcbi3GO9Skny2+XjcMYqsXCttB6HginjcioSCV7+9Z1IpPzGnqtCy WDMx3deasBsY2jO0Y
- PvVPzE3jIyuKmhYs+Typ9qhpJik4vVFoHJ4ywPbNXkPyYbIU/mazyMNuALD 2PWrYKkDkqfQ+l
- Obi2mNSfQvRHPygMBmrCu+/DLuAbg/1qou/goRluoNWkIWXG8EDgiiKT95jcW0 y7ESQSPvdDV
- xQUVQysR0+maoQPjb1GRmrMbnbnJGPXmh/F5Ecr6F4Hy4Tzk9x3pUJfGSMDqMVEGx uZj6dafv
- XaQrAgcHHWk0gu7WJsjzRtJI9qN37veu4E9aqpIN2Oq59amG5WY7sqT0rT4dRqNupYST OflJx
- xUhZVjU4JzwKqxHI3MduTkink/u2wQcdDU/MTUWyRmZioDdjg0FyBjBJI7VArDcCM7s4p4J bB
- bIbg1EnYNVp0LGW2bgdxxzx3pAxL9QGPXiq4O0sOeT60iFlLbs4/h9abcXqg0ZMZSIsdTjBIHF
- DkeXGD90Dj3quzjeQVYgjpS5XYDg5B6Z6Umr6hyajzIWITjIYYNM5MjAnoRzTC5eY7SMk/Lx+V
- Re Zg8tznJq3toilFW0JJCGIAb5hy3tVdnKMGwfmPTPanMAZHYA5LDAFQOT5uCc4PGaFq7MqPY
- eSDnI ZQOBk1A7nkxlQMdSP1p5ZjGSRk96hZ9q/Njbjn1xTjduxKuhWcsgBK9QRjvSbgH6Ajoc
- DvUGcqCO gPSlyhcBj3zwalvoyZJvRonZgAAThgeSPWlVgp6E88c1XEuG+ccnue9CnccqRgdhT
- vrqwTsixE37 3kEHOeTU/mZyEA39c1TEkaz7gWz2p6kFgUYBei+tDjZ3a0CUepbA+QkMCB3xUR
- J3krx7Z4qNiyFl PcY49aUMhUZ4yPWnDmtcLisQVLEdeMmmvnawXHHem4DHhjjPAph8wgYyfXF
- S9VqNOMhJCSEPAzxU OSHb+HnPPSpSNpyPTjPrUEj/ACsAOeBTbVhJdENdhtTZtb+8RUO4AlSe
- e1K4ZITk44qDqSw+4OAe tVpYdl0ZKzA5yTioy2NwyMjofam9X5yQR096iZmUsTjavAoTjazHK
- 0WrClhuwOucZHpTHD7Gw459 ulIz/ug2BuIOAOtQblRck/Nt6ZqeRPYUY3I2l+ZdpUgDP4VXMg
- MZAUnBJBpAzCViFyOhpu/94eR0 xjFXyRWlhcq16jH24Vty4B6Adc1UkkI3JhQAe4709w/PKbB
- 3xVZ93m/Ng88E0RjHVFQ31FILxgZA 44GKrF1D/Nz1GfU1K+4jeO3FRsBtAce+aatorkyu3zDQ
- Dx37kU0LtZiSSccc08ZUqOQDn/8AVTXO 11BGPX/ClOWtgc3JaC7gykg59qiB4yWUKRnn0pec4
- 4A6moZWG0EAYB5I6CiGl0jPmauhQY1QYPP6 VGZG344A9xTSf3TBCAcdD2pj/KQcj0OPWnNt6W
- uNxtqROWxhsbjxnHBqnL5iySE8j+H2qVjtUt82 BkcnpVZyzEnO0gZwTUrnirrcqk3FnMoFZSM
- nIPPsam3MqZyc5G6qyFDtByB61KSwK7fulT1Nb02p PkbFCfOXBOD1YZ+nXFXbeUmND/F/Ks1N
- vm4PzY4AFWomKjA4IGeaThFaW1JaSdjTjZSCFHG45zzj 61MjgySDJOOlZsMrgeUFwauI24ggB
- eOR60rSStYIxcXroaCy5QY5bp+FWklGAOQV61nAbnyCQe5q VQiyHcwI4ORRypPbUtST3NMN8h
- JU5wM5qRJS3yMPlAwDjrVNGBJ35H49qkRwQevqvtVciT0Kv5bF osQNucZ7U9WY4I645I7mq6k
- EAntyc08PlvMAxyciqTSexE2nsSxmQjgKTnk4qT5sNuPfp61WL/IM kkjsKkTax3fMWHbNZOLS
- ci2tidB90BiQRkg1YVhjoMZ9KqAgAqM5wATUwRRCGLcdeKzlNaLqTKLW o/zMR53oVye3NPDNs
- 4YAbutV2UeWQAVwRtzTztb5NxY5HT+VaqXLG44vlSaHnaYiQQW3cnPFCnbJ nIJ9xTPlRDkHIy
- eaQujfN944zgVF27dhqzW1yQyq2xM5OetOUzSOSBhe31qDzNpBMZweoxzVjcfL BQrzyBUybto
- S5vsSA4ZiSd2fwqyPmiYAhXBqiCS+Xz6nHaplY4CgEg1EU76Cv1ZfRxsIZieRg1bj dTM2RgDu
- azI5CJAxPy9GJHQ1c3Hy02+mC2M5ob63K5tDQibDgEH5hn6VZjI6Lwcck1RR+FUN8xGc elWVY
- 7h3GODRF2K23Reib94MOMhcgYq6shBIY8HI+tZiY3jHLY5x2qwrbiRnqauotnuKW2rLgkYf KC
- ckdDVhjj5Mc7dwqisgG2Rh16D+dTGTc6nhvQ09biU1cs+YDtBHG3kjvThKMb9rECqxZhHy6g/T
- ofSnBm8plbkg8epNFkDkm7ItiRWdgSMgYwO9GflxkYYVAM7gDwSckgU7cAcFx0NZKLvfcXXQlO
- 0K Q3zD245pDNu2kcHOPoKrmRQwRiXGM8HrTy2JMAqAOuacoq1maKyWo9WZXBYgnHSpeDzkjnH
- Xiq6u zA4BJHT3pWkURnggZ5FKdrabmUtWmTl03D+Jj+mKiZsPkKykng9qg3MjoY1Zwe4/lQST
- FvOd3YZp xSTsy2rInQZJzjI6c1FvVAey+4/Wog5zvORk460oCnJORgc+/NUopJpkKbUrsVpAE
- 65weTUb8kk4 B64PWlDYBPBXd0qu7MA2GXI6Aj9KlRUmXFtrQC7MeCMY4pCcsSQ3A7UbiAASOn
- YUxuFBJ4H605WS CU76XGNjgYO3tUeflyGUYPzE9qCQyEbu361BuInA5IAzz3qqabjdFNN2J8/
- KOdx7VIoB+YEe1VlI LKd2MHjPepuTu4ycZPNQp3eo5/DclHI5OR1z/SnoQuGGNpORVeMHAJwC
- vT2pzMwj3ZJx6Cq5r3I2 67lnfucjIzjOD3pPMbLJ8u/OR/hUO5XjQ888/WlDK7Es2DnPPYYo0
- S1JSTeqJTy69jjioSSzHk4z g4pxfMTHjp8opm44APB6kd6Oa6uO3RBIQGGM4Ax1qBypJy4Az0
- 70rP8AJ1yQ3PtUZfJwAMepHein a9hra41i+0Asufeo9xMJXIUDBzimtJkAnp1J9aY7Mq4JB7c
- d6bTfQGlLqIznLZ7ntwTUDOC3cknI 9qldm8oAKC3fFVVYb2JIyetSo21auIWORTKQWzkHmoWw
- ASGzx1NTOyiM44B6MB0qoVAlJzv+Xrmq VrdhOXYQsHQ4wr+lQH5lY5A5HSib5ckZBGDTVfgsS
- o6np1qpNdCYySdrETAFT83IPrVZidzNkHtj FTtIARhSQc81A58uMOgJJ4ORRdtFvfyItwYspB
- OB2prL/o4LHljnGeKU4YnjBx9KgYqI+pLA560J pNJEtdEDsfl5AGaRtvmMfmPI6GmuS6rgZwc
- emTSrw4O5cE/NmrltZEpaNtjQ5MZPJB7Y5qFlxGzI cHuD3pWYtKcDJPSq7FgwQsGIB6Ci2uhX
- PZWHO+bfI4yO45FRO2QQx4OMmnsy8YOFPXNRMwwU424y OKm7a02Jb6WK7kqzBsHBwM96rvgxb
- jnrxUhO6Rh94YBzmqUhbywp+bk4Naq0ZJX1Hfn0OaVmBw2O OelSCUNtKHcvIqrHiQ78nKnnnr
- VxDhfkwPTIpKKb5uoc0bNrqTq+VYDO4kfjVrBJzzjg7qrKSrkM ue4x2qwjbshc4PJJ9aG1cSl
- ZbFtWCyEg5weoqyGBjHXLHNUlZFBAYccEVZRiHxjgD07VD91Dbk1c vrgOBndyCMVZYgMB1GDt
- OKpoTgBCCMfL/jVgblxlgSDyxHFCfVCk3uWkYr8p5JGcjoanJwPTjnmq qEgKQRycCnqxySxUj
- 2FUtWJa6l778RAYcenehThixIK5waqKQV3Ipz9aCxymDjHUUkpWZcWnp0L2 7AZGxjtx1oBHlk
- LgHpzVXeTtZ+BgYAp4kB+bgc85ocJLYOVK6SLqkbwrNyVxxSkjYOcDIyKqiQ7g WxwMcDvS7+j
- jle4qfZtvUtKz3LIYgkHLAHpUuWRC4AA3DHvVQElcHC89TR5hGd2WA5FW7WaQra/o WncswLDA
- waiB+fPPHpQZAzEHAGR/+qotxwAMH09qhb6ExbtZqxM8hwzbScfrSJJ1G5Rxx7VXL/Ju H5e1K
- N4fGzI7nFTy2+I2SsXQxfcSdw3DO2pEdhls/TFU1fYjKDwx9KsIxchPup9OtTNSvqZKbitC 5F
- Io2jgluevFXRKTIEJwO2Ky4yAcKQVBJJx0qzC28lyDg5/Cl7jfMLmcmaQbCb8jhueeatLIzHrw
- elZqksSCpVeM81ZSQKMD5gXz9KSSvoyoq2xphwp8wn5c4wOoqZWbPDDJ5OOlZccn77BG5Tzx7V
- dV wMEcZGTU8/Ky57abl9GUjG7d7elPWTqvJJ6Gs9HbqBxg4zU0LuwUEEgLkt6GtL2V2yaitZp
- F4N9z JJyccVMCobnkY79RVIvhVPTj73anKxKgnJ5GeetO8rXuKMVqjQV/lPzDJqMygwg7SWHB
- qMSKof5c 5OMelJhd+7kDvRdaihZbkhZty52gZ9Ke0gyeRjFQAOJSeo4xn0ppYYAP0pWTVjRS1
- 0LBmIfCHHAJ JoeXEhLdevHvVbdjnHQflSblKN1YD35NDjGJPLbct7yqqPfJpTKM4PUHt3quGV
- iOchvSmJgH7rHa MHmp5Y31E9XqtiXeS5JXqeMUrKzSAbdox92oXZnU+x4pu5mdxnGDketXEpw
- 2bH7nLjO3AFNdSpPB L9aYWGGJPWo5pG2BOcj86Uua+hV76iuRvBz0HamBizNwRt9+tBx8rbXA
- 2VGwKsPmOxuQauLurDbW 0RJCBIpz82OcUAEHhgVNMBO4MT14z6VG2clFDDkEZqeS79A5+ZrXY
- mfgLjv+lSEEREr8pz371CCu SGBwB0qMj90x5GW4PahxStYlSu73LasScMw47Cl8zJTuuccGqw
- bDh8hmyQRinq6iNhkKO+exqGnb QN3ZFkkLEMck9famkgEvkF81XD8rn1/KpGkVkJKkDuaTi1o
- Db2JCB5YGTu6ioncHaeQT1/wpuT5K tzwcnJqMOzBtykKTnPvVJcruhRl+A5mC8DJz3pm9lG11
- IZumaU4AJYhR1x3qJ2BbeMgD5sH071Sd 9LCnNRFYKVCg9Bgiq7MFlIc4HT6Uu9ch+vHTvUBYt
- IzldyZArWF0rkpNK4M5KEg9DnH0qENmDpli Tx60skp35UYUcEe1RO4weOMYX1qJPsK1la2orE
- BNmd2R3/hqvwAVB4xkihpBkDn0YUw4ZGyMccYq oRvuNq71GHexJHzY9aiJf5m4PTIpzMyOCAW
- Ug/yqPK+WE2NnBwc0QulsU7Kz6EW0+SwLZ9R+NRs3 y4ZsnPBFOH3/AJQRxyDURwM78Ar2pv3m
- J2bI3I3MAQA3vyKiLHJC8sODTz87EEHnmo1IBw3IzQ2k tR8sVqwHACBucc+1Rs23O0n3zTcru
- Y5O4DkZpnmbc56+9K2l0Q5/IduZW+XHGSeKruQWDZySOR6V MMKBkj3NVzlpCSyZI+UAdKFbuV
- HRa7jG27cLxnrk1CThWHJwOQKkcbtuMFfb3qu0qguFU5HynFXL
- l5dTOd1qxgYfaS4U4KY4NUJA23byzdMDrVl2D2+5c9gT71Rk++cB85yMmiEXF2Jb5ndH/9k=
-UID:934731C6-1C95-4C40-BE1F-FA4215B2307B
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/934731C6-1C95-4C40-BE1F-FA4215B2307B.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/934731C6-1C95-4C40-BE1F-FA4215B2307B.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/934731C6-1C95-4C40-BE1F-FA4215B2307B.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/934731C6-1C95-4C40-BE1F-FA4215B2307B.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,993 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Picture;With;;;
+FN:With Picture
+EMAIL;type=INTERNET;type=WORK;type=pref:withpicture at example.com
+TEL;type=WORK;type=pref:777-777-7777
+TEL;type=CELL:8888888888
+item1.ADR;type=WORK;type=pref:;;1234 Golly Street;Sunnyside;CA;99999;USA
+item1.X-ABADR:us
+PHOTO;BASE64:
+ /9j/4AAQSkZJRgABAQAAAQABAAD/7QA8UGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAB8cAVoAAx
+ sl RxwCAAACAAIcAhkAC1Bob3RvIEJvb3RoAP/iG6hJQ0NfUFJPRklMRQABAQAAG5hhcHBsAgA
+ AAG1u dHJSR0IgWFlaIAfaAAEAEwAJADEABGFjc3BBUFBMAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAD2 1gABAAAAANMtYXBwbFYcEOZVYuhIRg5LwLIi62wAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAA AAAAEXJYWVoAAAFQAAAAFGdYWVoAAAFkAAAAFGJYWVoAAAF4AAAAFHd0cHQAAA
+ GMAAAAFGNoYWQA AAGgAAAALHJUUkMAAAHMAAAIDGdUUkMAAAnYAAAIDGJUUkMAABHkAAAIDGF
+ hcmcAABnwAAAAIGFh Z2cAABoQAAAAIGFhYmcAABowAAAAIHZjZ3QAABpQAAAAMG5kaW4AABqA
+ AAAAOGRlc2MAABq4AAAA ZGRzY20AABscAAAALm1tb2QAABtMAAAAKGNwcnQAABt0AAAAJFhZW
+ iAAAAAAAAB7vQAAQXsAAAJL WFlaIAAAAAAAAFYqAACp0AAAFF9YWVogAAAAAAAAJO8AABS1AA
+ C8glhZWiAAAAAAAADz2AABAAAA ARYIc2YzMgAAAAAAAQu3AAAFlv//81cAAAcpAAD91///+7f
+ ///2mAAAD2gAAwPZjdXJ2AAAAAAAA BAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUA
+ SgBPAFQAWQBeAGMAaABtAHIAdwB8AIEA hgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0
+ ADVANoA4ADlAOoA8AD1APsBAQEHAQwBEgEY AR4BJQErATEBOAE+AUUBSwFSAVkBYAFmAW0BdQ
+ F8AYMBigGSAZkBoQGoAbABuAHAAcgB0AHYAeAB 6QHxAfoCAgILAhQCHAIlAi4CNwJAAkoCUwJ
+ cAmYCcAJ5AoMCjQKXAqECqwK1Ar8CygLUAt8C6gL0 Av8DCgMVAyADKwM3A0IDTQNZA2UDcAN8
+ A4gDlAOgA6wDuQPFA9ID3gPrA/gEBAQRBB4ELAQ5BEYE VARhBG8EfASKBJgEpgS0BMIE0QTfB
+ O4E/AULBRoFKAU3BUcFVgVlBXQFhAWTBaMFswXDBdMF4wXz BgMGFAYkBjUGRQZWBmcGeAaJBp
+ oGqwa9Bs4G4AbyBwMHFQcnBzkHTAdeB3AHgweWB6gHuwfOB+EH 9AgICBsILwhCCFYIagh+CJI
+ Ipgi6CM4I4wj3CQwJIQk2CUsJYAl1CYoJoAm1CcsJ4An2CgwKIgo5 Ck8KZQp8CpIKqQrACtcK
+ 7gsFCx0LNAtLC2MLewuTC6sLwwvbC/MMDAwkDD0MVgxuDIcMoQy6DNMM 7Q0GDSANOg1UDW4Ni
+ A2iDbwN1w3xDgwOJw5CDl0OeA6TDq8Oyg7mDwIPHg86D1YPcg+OD6sPyA/k EAEQHhA7EFgQdh
+ CTELEQzhDsEQoRKBFGEWQRgxGhEcAR3xH+Eh0SPBJbEnoSmhK5EtkS+RMZEzkT WRN6E5oTuxP
+ bE/wUHRQ+FF8UgRSiFMQU5RUHFSkVSxVtFZAVshXVFfcWGhY9FmAWgxanFsoW7hcS FzUXWRd9
+ F6IXxhfqGA8YNBhZGH0YoxjIGO0ZExk4GV4ZhBmqGdAZ9hodGkMaahqQGrca3hsGGy0b VBt8G
+ 6MbyxvzHBscQxxsHJQcvRzmHQ4dNx1gHYodsx3dHgYeMB5aHoQerh7YHwMfLR9YH4Mfrh/Z IA
+ QgMCBbIIcgsyDeIQohNyFjIY8hvCHpIhUiQiJwIp0iyiL4IyUjUyOBI68j3SQMJDokaSSXJMYk
+ 9SUkJVQlgyWzJeImEiZCJnImoybTJwMnNCdlJ5Ynxyf4KCooWyiNKL4o8CkiKVUphym5KewqHy
+ pS KoUquCrrKx4rUiuGK7or7iwiLFYsiiy/LPQtKS1eLZMtyC39LjMuaS6eLtQvCy9BL3cvri/
+ kMBsw UjCJMMEw+DEwMWcxnzHXMg8ySDKAMrgy8TMqM2MznDPVNA80SDSCNLw09jUwNWo1pTXf
+ Nho2VTaQ Nss3BjdCN343uTf1ODE4bTiqOOY5IzlgOZ052joXOlQ6kjrPOw07SzuJO8c8BjxEP
+ IM8wj0BPUA9 fz2/Pf4+Pj5+Pr4+/j8/P38/wEAAQEFAgkDEQQVBR0GIQcpCDEJOQpFC00MWQ1
+ hDm0PeRCFEZUSo ROxFMEV0RbhF/EZARoVGykcOR1NHmUfeSCNIaUivSPVJO0mBScdKDkpVSpt
+ K4ksqS3FLuEwATEhM kEzYTSBNaE2xTfpOQk6MTtVPHk9nT7FP+1BFUI9Q2VEkUW5RuVIEUk9S
+ mlLlUzFTfFPIVBRUYFSt VPlVRlWSVd9WLFZ6VsdXFFdiV7BX/lhMWJpY6Vk4WYZZ1VokWnRaw
+ 1sTW2NbslwDXFNco1z0XURd lV3mXjdeiV7aXyxffl/QYCJgdGDHYRlhbGG/YhJiZWK5YwxjYG
+ O0ZAhkXGSxZQVlWmWvZgRmWWav ZwRnWmewaAZoXGiyaQlpX2m2ag1qZGq8axNra2vDbBtsc2z
+ LbSNtfG3Vbi5uh27gbzpvk2/tcEdw oXD7cVZxsHILcmZywXMcc3hz03QvdIt053VDdaB1/HZZ
+ drZ3E3dwd854K3iJeOd5RXmjegJ6YHq/ ex57fXvcfDx8m3z7fVt9u34bfnx+3H89f55//4Bgg
+ MKBI4GFgeeCSYKrgw6DcIPThDaEmYT8hWCF w4YnhouG74dUh7iIHYiBiOaJTImxihaKfIrii0
+ iLrowUjHuM4o1Ija+OF45+juWPTY+1kB2QhZDu kVaRv5IokpGS+pNkk82UN5ShlQuVdZXglkq
+ WtZcgl4uX95himM6ZOpmmmhKafprrm1ebxJwxnJ+d DJ15neeeVZ7DnzGfoKAPoH2g7KFbocui
+ OqKqoxqjiqP6pGqk26VMpbymLqafpxCngqf0qGWo2KlK qbyqL6qiqxWriKv7rG+s461WrcuuP
+ 66zryivnbARsIew/LFxseeyXbLTs0mzv7Q2tK21JLWbthK2 ibcBt3m38bhpuOG5WrnSuku6xL
+ s+u7e8MLyqvSS9nr4ZvpO/Dr+JwATAf8D6wXbB8cJtwunDZsPi xF/E3MVZxdbGU8bRx07HzMh
+ KyMnJR8nGykXKxMtDy8LMQszBzUHNwc5CzsLPQ8/D0ETQxtFH0cjS StLM007T0NRT1NbVWNXb
+ 1l7W4tdl1+nYbdjx2XXZ+tp/2wPbiNwO3JPdGd2e3iTeqt8x37fgPuDF 4Uzh0+Ja4uLjauPy5
+ HrlAuWL5hPmnOcl56/oOOjC6Uzp1upg6urrdev/7IrtFu2h7izuuO9E79Dw XPDp8XXyAvKP8x
+ zzqvQ39MX1U/Xh9m/2/veM+Bv4qvk5+cn6Wfro+3j8CPyZ/Sn9uv5L/tz/bmN1 cnYAAAAAAAA
+ EAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0A cgB3AHwA
+ gQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2gDgAOUA6gDwAPUA+wEB AQcBD
+ AESARgBHgElASsBMQE4AT4BRQFLAVIBWQFgAWYBbQF1AXwBgwGKAZIBmQGhAagBsAG4AcAB yA
+ HQAdgB4AHpAfEB+gICAgsCFAIcAiUCLgI3AkACSgJTAlwCZgJwAnkCgwKNApcCoQKrArUCvwLK
+ AtQC3wLqAvQC/wMKAxUDIAMrAzcDQgNNA1kDZQNwA3wDiAOUA6ADrAO5A8UD0gPeA+sD+AQEBB
+ EE HgQsBDkERgRUBGEEbwR8BIoEmASmBLQEwgTRBN8E7gT8BQsFGgUoBTcFRwVWBWUFdAWEBZM
+ FowWz BcMF0wXjBfMGAwYUBiQGNQZFBlYGZwZ4BokGmgarBr0GzgbgBvIHAwcVBycHOQdMB14H
+ cAeDB5YH qAe7B84H4Qf0CAgIGwgvCEIIVghqCH4IkgimCLoIzgjjCPcJDAkhCTYJSwlgCXUJi
+ gmgCbUJywng CfYKDAoiCjkKTwplCnwKkgqpCsAK1wruCwULHQs0C0sLYwt7C5MLqwvDC9sL8w
+ wMDCQMPQxWDG4M hwyhDLoM0wztDQYNIA06DVQNbg2IDaINvA3XDfEODA4nDkIOXQ54DpMOrw7
+ KDuYPAg8eDzoPVg9y D44Pqw/ID+QQARAeEDsQWBB2EJMQsRDOEOwRChEoEUYRZBGDEaERwBHf
+ Ef4SHRI8ElsSehKaErkS 2RL5ExkTORNZE3oTmhO7E9sT/BQdFD4UXxSBFKIUxBTlFQcVKRVLF
+ W0VkBWyFdUV9xYaFj0WYBaD FqcWyhbuFxIXNRdZF30XohfGF+oYDxg0GFkYfRijGMgY7RkTGT
+ gZXhmEGaoZ0Bn2Gh0aQxpqGpAa txreGwYbLRtUG3wboxvLG/McGxxDHGwclBy9HOYdDh03HWA
+ dih2zHd0eBh4wHloehB6uHtgfAx8t H1gfgx+uH9kgBCAwIFsghyCzIN4hCiE3IWMhjyG8Ieki
+ FSJCInAinSLKIvgjJSNTI4EjryPdJAwk OiRpJJckxiT1JSQlVCWDJbMl4iYSJkImciajJtMnA
+ yc0J2UnlifHJ/goKihbKI0ovijwKSIpVSmH Kbkp7CofKlIqhSq4KusrHitSK4YruivuLCIsVi
+ yKLL8s9C0pLV4tky3ILf0uMy5pLp4u1C8LL0Ev dy+uL+QwGzBSMIkwwTD4MTAxZzGfMdcyDzJ
+ IMoAyuDLxMyozYzOcM9U0DzRINII0vDT2NTA1ajWl Nd82GjZVNpA2yzcGN0I3fje5N/U4MTht
+ OKo45jkjOWA5nTnaOhc6VDqSOs87DTtLO4k7xzwGPEQ8 gzzCPQE9QD1/Pb89/j4+Pn4+vj7+P
+ z8/fz/AQABAQUCCQMRBBUFHQYhBykIMQk5CkULTQxZDWEOb Q95EIURlRKhE7EUwRXRFuEX8Rk
+ BGhUbKRw5HU0eZR95II0hpSK9I9Uk7SYFJx0oOSlVKm0riSypL cUu4TABMSEyQTNhNIE1oTbF
+ N+k5CToxO1U8eT2dPsU/7UEVQj1DZUSRRblG5UgRST1KaUuVTMVN8 U8hUFFRgVK1U+VVGVZJV
+ 31YsVnpWx1cUV2JXsFf+WExYmljpWThZhlnVWiRadFrDWxNbY1uyXANc U1yjXPRdRF2VXeZeN
+ 16JXtpfLF9+X9BgImB0YMdhGWFsYb9iEmJlYrljDGNgY7RkCGRcZLFlBWVa Za9mBGZZZq9nBG
+ daZ7BoBmhcaLJpCWlfabZqDWpkarxrE2tra8NsG2xzbMttI218bdVuLm6HbuBv Om+Tb+1wR3C
+ hcPtxVnGwcgtyZnLBcxxzeHPTdC90i3TndUN1oHX8dll2tncTd3B3zngreIl453lF eaN6Anpg
+ er97Hnt9e9x8PHybfPt9W327fht+fH7cfz1/nn//gGCAwoEjgYWB54JJgquDDoNwg9OE NoSZh
+ PyFYIXDhieGi4bvh1SHuIgdiIGI5olMibGKFop8iuKLSIuujBSMe4zijUiNr44Xjn6O5Y9N j7
+ WQHZCFkO6RVpG/kiiSkZL6k2STzZQ3lKGVC5V1leCWSpa1lyCXi5f3mGKYzpk6maaaEpp+muub
+ V5vEnDGcn50MnXmd555VnsOfMZ+goA+gfaDsoVuhy6I6oqqjGqOKo/qkaqTbpUylvKYupp+nEK
+ eC p/SoZajYqUqpvKovqqKrFauIq/usb6zjrVaty64/rrOvKK+dsBGwh7D8sXGx57JdstOzSbO
+ /tDa0 rbUktZu2EraJtwG3ebfxuGm44blaudK6S7rEuz67t7wwvKq9JL2evhm+k78Ov4nABMB/
+ wPrBdsHx wm3C6cNmw+LEX8TcxVnF1sZTxtHHTsfMyErIyclHycbKRcrEy0PLwsxCzMHNQc3Bz
+ kLOws9Dz8PQ RNDG0UfRyNJK0szTTtPQ1FPU1tVY1dvWXtbi12XX6dht2PHZddn62n/bA9uI3A
+ 7ck90Z3Z7eJN6q 3zHft+A+4MXhTOHT4lri4uNq4/LkeuUC5YvmE+ac5yXnr+g46MLpTOnW6mD
+ q6ut16//siu0W7aHu LO6470Tv0PBc8OnxdfIC8o/zHPOq9Df0xfVT9eH2b/b+94z4G/iq+Tn5
+ yfpZ+uj7ePwI/Jn9Kf26 /kv+3P9uY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAoAC0AM
+ gA3ADsAQABFAEoATwBUAFkA XgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAKQAqQCuALIAtw
+ C8AMEAxgDLANAA1QDaAOAA5QDq APAA9QD7AQEBBwEMARIBGAEeASUBKwExATgBPgFFAUsBUgF
+ ZAWABZgFtAXUBfAGDAYoBkgGZAaEB qAGwAbgBwAHIAdAB2AHgAekB8QH6AgICCwIUAhwCJQIu
+ AjcCQAJKAlMCXAJmAnACeQKDAo0ClwKh AqsCtQK/AsoC1ALfAuoC9AL/AwoDFQMgAysDNwNCA
+ 00DWQNlA3ADfAOIA5QDoAOsA7kDxQPSA94D 6wP4BAQEEQQeBCwEOQRGBFQEYQRvBHwEigSYBK
+ YEtATCBNEE3wTuBPwFCwUaBSgFNwVHBVYFZQV0 BYQFkwWjBbMFwwXTBeMF8wYDBhQGJAY1BkU
+ GVgZnBngGiQaaBqsGvQbOBuAG8gcDBxUHJwc5B0wH XgdwB4MHlgeoB7sHzgfhB/QICAgbCC8I
+ QghWCGoIfgiSCKYIugjOCOMI9wkMCSEJNglLCWAJdQmK CaAJtQnLCeAJ9goMCiIKOQpPCmUKf
+ AqSCqkKwArXCu4LBQsdCzQLSwtjC3sLkwurC8ML2wvzDAwM JAw9DFYMbgyHDKEMugzTDO0NBg
+ 0gDToNVA1uDYgNog28DdcN8Q4MDicOQg5dDngOkw6vDsoO5g8C Dx4POg9WD3IPjg+rD8gP5BA
+ BEB4QOxBYEHYQkxCxEM4Q7BEKESgRRhFkEYMRoRHAEd8R/hIdEjwS WxJ6EpoSuRLZEvkTGRM5
+ E1kTehOaE7sT2xP8FB0UPhRfFIEUohTEFOUVBxUpFUsVbRWQFbIV1RX3 FhoWPRZgFoMWpxbKF
+ u4XEhc1F1kXfReiF8YX6hgPGDQYWRh9GKMYyBjtGRMZOBleGYQZqhnQGfYa HRpDGmoakBq3Gt
+ 4bBhstG1QbfBujG8sb8xwbHEMcbByUHL0c5h0OHTcdYB2KHbMd3R4GHjAeWh6E Hq4e2B8DHy0
+ fWB+DH64f2SAEIDAgWyCHILMg3iEKITchYyGPIbwh6SIVIkIicCKdIsoi+CMlI1Mj gSOvI90k
+ DCQ6JGkklyTGJPUlJCVUJYMlsyXiJhImQiZyJqMm0ycDJzQnZSeWJ8cn+CgqKFsojSi+ KPApI
+ ilVKYcpuSnsKh8qUiqFKrgq6yseK1Irhiu6K+4sIixWLIosvyz0LSktXi2TLcgt/S4zLmku ni
+ 7ULwsvQS93L64v5DAbMFIwiTDBMPgxMDFnMZ8x1zIPMkgygDK4MvEzKjNjM5wz1TQPNEg0gjS8
+ NPY1MDVqNaU13zYaNlU2kDbLNwY3Qjd+N7k39TgxOG04qjjmOSM5YDmdOdo6FzpUOpI6zzsNO0
+ s7 iTvHPAY8RDyDPMI9AT1APX89vz3+Pj4+fj6+Pv4/Pz9/P8BAAEBBQIJAxEEFQUdBiEHKQgx
+ CTkKR QtNDFkNYQ5tD3kQhRGVEqETsRTBFdEW4RfxGQEaFRspHDkdTR5lH3kgjSGlIr0j1STtJ
+ gUnHSg5K VUqbSuJLKktxS7hMAExITJBM2E0gTWhNsU36TkJOjE7VTx5PZ0+xT/tQRVCPUNlRJ
+ FFuUblSBFJP UppS5VMxU3xTyFQUVGBUrVT5VUZVklXfVixWelbHVxRXYlewV/5YTFiaWOlZOF
+ mGWdVaJFp0WsNb E1tjW7JcA1xTXKNc9F1EXZVd5l43Xole2l8sX35f0GAiYHRgx2EZYWxhv2I
+ SYmViuWMMY2BjtGQI ZFxksWUFZVplr2YEZllmr2cEZ1pnsGgGaFxosmkJaV9ptmoNamRqvGsT
+ a2trw2wbbHNsy20jbXxt 1W4ubodu4G86b5Nv7XBHcKFw+3FWcbByC3JmcsFzHHN4c9N0L3SLd
+ Od1Q3Wgdfx2WXa2dxN3cHfO eCt4iXjneUV5o3oCemB6v3see3173Hw8fJt8+31bfbt+G358ft
+ x/PX+ef/+AYIDCgSOBhYHngkmC q4MOg3CD04Q2hJmE/IVghcOGJ4aLhu+HVIe4iB2IgYjmiUy
+ JsYoWinyK4otIi66MFIx7jOKNSI2v jheOfo7lj02PtZAdkIWQ7pFWkb+SKJKRkvqTZJPNlDeU
+ oZULlXWV4JZKlrWXIJeLl/eYYpjOmTqZ ppoSmn6a65tXm8ScMZyfnQydeZ3nnlWew58xn6CgD
+ 6B9oOyhW6HLojqiqqMao4qj+qRqpNulTKW8 pi6mn6cQp4Kn9KhlqNipSqm8qi+qoqsVq4ir+6
+ xvrOOtVq3Lrj+us68or52wEbCHsPyxcbHnsl2y 07NJs7+0NrSttSS1m7YStom3Abd5t/G4abj
+ huVq50rpLusS7Pru3vDC8qr0kvZ6+Gb6Tvw6/icAE wH/A+sF2wfHCbcLpw2bD4sRfxNzFWcXW
+ xlPG0cdOx8zISsjJyUfJxspFysTLQ8vCzELMwc1BzcHO Qs7Cz0PPw9BE0MbRR9HI0krSzNNO0
+ 9DUU9TW1VjV29Ze1uLXZdfp2G3Y8dl12fraf9sD24jcDtyT 3Rndnt4k3qrfMd+34D7gxeFM4d
+ PiWuLi42rj8uR65QLli+YT5pznJeev6DjowulM6dbqYOrq63Xr /+yK7Rbtoe4s7rjvRO/Q8Fz
+ w6fF18gLyj/Mc86r0N/TF9VP14fZv9v73jPgb+Kr5OfnJ+ln66Pt4 /Aj8mf0p/br+S/7c/25w
+ YXJhAAAAAAADAAAAAmZmAADypwAADVkAABPQAAALA3BhcmEAAAAAAAMA AAACZmYAAPKnAAANW
+ QAAE9AAAAsDcGFyYQAAAAAAAwAAAAJmZgAA8qcAAA1ZAAAT0AAACwN2Y2d0 AAAAAAAAAAEAAQ
+ AAAAAAAAABAAAAAQAAAAAAAAABAAAAAQAAAAAAAAABAABuZGluAAAAAAAAADAA AKPAAABXwAA
+ ASsAAAJ5AAAAlQAAAEwAAAFBAAABUQAACMzMAAjMzAAIzM2Rlc2MAAAAAAAAACkNp bmVtYSBI
+ RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAABIAAAAc AE
+ MAaQBuAGUAbQBhACAASABEAABtbW9kAAAAAAAABhAAAJIjAgAqqcBCT4AAAAAAAAAAAAAAAAAA
+ AAAAdGV4dAAAAABDb3B5cmlnaHQgQXBwbGUsIEluYy4sIDIwMTAA/+EAQEV4aWYAAE1NACoAAA
+ AI AAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAAoCgAwAEAAAAAQAAAeAAAAAA/9sAQwA
+ CAgIC AgECAgICAgICAwMGBAMDAwMHBQUEBggHCAgIBwgICQoNCwkJDAoICAsPCwwNDg4ODgkL
+ EBEPDhEN Dg4O/9sAQwECAgIDAwMGBAQGDgkICQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4OD
+ g4ODg4ODg4O Dg4ODg4ODg4ODg4ODg4O/8AAEQgB4AKAAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQ
+ EBAAAAAAAAAAAB AgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhN
+ RYQcicRQygZGhCCNC scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RV
+ VldYWVpjZGVmZ2hpanN0 dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4u
+ brCw8TFxsfIycrS09TV1tfY 2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQ
+ EAAAAAAAABAgMEBQYHCAkKC//E ALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXE
+ TIjKBCBRCkaGxwQkjM1LwFWJy0QoW JDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZX
+ WFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWG h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5u
+ sLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp 6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A+To438
+ n5HVipGCR1q/Em6JiwOc9PrUEKbY8KCd3SrsUZ UfNk7sZA9ayje2jCbjHboWoh5gIJCsp71PH
+ ErQltrDcfXrTQvz4I4zwAeasLE8bcA4HTNNU07u+o oKLd0yaJFEWQCGwCD6CtJBFsOCSx6nNV
+ wuxE+Q5HC59KsxxuACNufUjpWjp33ZLm0TwpsdgnO3HG fWrSjEnG7nr+VQRIWYqQ3J4q7GMNn
+ OCTilaNxzaT1Y+NWSJQw6Lipo13RM3pgfjUa5RzuO5asxKi kEkYA6VqtI+pLaWhZZRJFGDlyM
+ kY71MgUIecgjn61HbguCjoyg9+lSxoVbDHbnkkjpWaj0fQldri g52+4yaFj2y8AqvbmlCls4O
+ DnAJ9Ksqylxxz0Fa81mrIt3jHTqKkW/DZ5PJxUgQhmByXBz+lAAUA k9D2qcbAFZTuPcntUOUm
+ 7Iq17SYigNGoYbiF7UhGJfQAZz2zUiliduRwdtTkYQhSFXd1NDk927lR Scit85kG3gnHFLhwA
+ FHOc/Wp4wNuVHHc1IACxB7D16VE2+a6QX3uiEJlD8pyTkj0p2394QQSQMYF SnOSMhe3Sm7Cjq
+ mecck1fNeOpMoprRgFOCOetOcMSrHg9elPAxIN2MHkcdqcRltuDg85rG0m9EFu zI/LRWwAScZ
+ Jz1qdYQ6EkYZe1KiFnG0qPXNPwSQpJI7Y705yfRltSe5XdHLbu2enpT1HzorHOBjH tUmxhkkP
+ j+VTJGwYFgNp6k9qXncIzTViAxgAjsPU0Kn4euas+WcOx4GaBHk7sL1GM96q65Xd3KjF W0ZFj
+ aSQQ425NSrGSARwTkA9s0qRqCSenQVZCrsO0MOelRKSTSSM3q9Csy5Us3LnH51IYyYs5zg8 U4
+ JyTtJwanCsEwMHDZxjkD3q4JNle8rscgySOM/xe9O2sMdTjJx9KmSJt7FgASevtT1j3MCucg9/
+ SpcnfVGcVGz1K5A3K5545+tChshh1PUmrYjUxlQCy57elBSQPwowDjmm9VuNP3WV+EYEhsZwD7
+ 1J 5J8hPmBPU+9WFBEhLAcgHkd6MFQvTI45PQVV9dUOzbuiqy7QY14wc59qV41LYHJz61Oqqck
+ 5Ck55 70BAH3N+B9aXMloWm4+RD5fBU8Z70/CGIIRkgCpH+UZYZUd6REClRz64PUVUWum5Ls3e
+ 40KOWPJJ ySO1O2ARk7SecjHrUx4G7aCuc1IIt5G3PqwpXfVA1FSRXXPkruO3PApArlxhgFAw1
+ WOA4UgLzyT/ ACppUuu3B2selWvd3RDTTd1Yr/OZM54PU+1QqDu5OwDocdauldockfTNQAttBl
+ AKdiB1pdW2i3Hm V0tCA9HwDgNjFVHAM24Da2CRn0q80eWPGFIz9DVdo+u75h0yKiN4PRgrRV7
+ 3KgDbl24B5xnvUbB9 x2jAH86uBBgsM5XvnpUBDEE7lJ7itLoEkiIKwO5Dgn1HWlbywxDk5HQ+
+ 9TE7odqDaucjPUVGw+Ut wxPYCsVBbBy8xG65jcHJycDHeq4j3LuHAA+6fX1q9jeMgDJ6HFQbS
+ YsZ6frXRBNJ3JbtuisBiTK8 8jj3pXZyjsOCCOoqfaDKCo+975pxVhHtwAMYJNZ631FzK+xS2h
+ gxYcqvr1qIYDbiCMj86uGPDBWH TuO9Q+UCgC/fz1NaXhs2a+0SVkQBR5me5/Wo2CkMGyvHU/W
+ rRTM23DZzyewprKwKbgSMdMVlzLWx GiaZWZjgncMdAKh2MZPu4wME5qw6cL8v3RSNteQqnUD5
+ qSduhUndaFJ0zDg9R1xUBjDJtwdpXIIq 4yb3L7H9wTTHXbBtTHzdCaq/K77icVoomeYiybHO0
+ d6rSJt6EEdiexrTKtxsXLY5Paq7RMJgSAV9 AO9aRloxwhzbsoup2LzkHjFV5EJCg4Cgg5J71o
+ vHvZQT8oyenJqJok3spy2RkUmna19yNFKyZmkF Qp77TkfWmYAUKwK854rQ8tGiBLLnuPU01kX
+ G/cCc8nHFRey1KbVrWM4oPvAhWB4J7etV2RfkUckN lauunm4JAHJOMVXlj2gEHoM5qKcYq/mV
+ Dkdmys20naecZGRVcqQAduATyPStJAB8q7Xz6dxULsm0 gRk49T1pTcl0M5rXRGaYwqAschhgj
+ pz2pohVSH5DAYPPerk4Aj2k8KPkJqMqhVsjA+8aykoyV1qy KrbdmcPbIxtyuVDk8fnU6rIGwd
+ ofkdO3rTIInVztB4HrV6AMW3Pznnnr9K0Ti/e6lxS2JI0Cpuxu I6Cre1WXBIyM8jtUaBWcFM4
+ PcnirO35gvOSMgY61cZrZjcHGWwi7iuCcj+Ee1X9hXaW4GOcnvUSq DtAIYDgEVbRCBubJwcVS
+ kk77EX5unyFQnapVjwfWrigjkHDcHJ5qFVIjD4G0jgkd6srGGm5IU4ye a05+idg93axKCN6kr
+ vBPIFWU2iR8grn7opIIwTtDAgc4qYRESj5DhelJVOgRkh6K5X5uFHT3NWM5 D56ds0kSkCMEdu
+ hqVEEm4ZAb+lNpLV7DhK716CAgAZIXb6ipCSUYfx54I9KcEGdzfMO3vUwUsQdp 9zUOSvciDs7
+ iRhfJAI3AEDOeasEqVZQhB3YzTFXksFOMAjPQ1KuWl5GOetOUrlNSXoBQHaOjcfnU ka5U8YHb
+ PenlOeDnjipowcruCliMAAVkqivoTKWtyNFwrZHy+3rTRlnYpww9RVlk25yehAxTdv8A dGQD0
+ qlO+xoprls9xrMCB8wyf0pCuWHfHenCPMuzGOeuKmSM7kBIZTyfX6VF9GPVOxCvLZPOD27V KE
+ bIJypB4PtTyquWCgkcdOtSohG35WbB4FKLk7hLyIwrGU7umck461OqnIBABxxgUoV15QBhyRxU
+ 6eYeoyMfLxRe1rpBza3bsQZQjcfu9TUygsrkKewB7U7CBcbcZOOaeyB9wG4ZYdDilLlRLV43aI
+ TG uPmJ6cD0p21sBODjgcdqnxmPIU8cD6UuTtw2D6cYzQ46FySk1cjCfu8MMgHjFAQlNoGVz1q
+ 4qghS VyT2oC4QYVjk5JHalC9rijOMVpoVkUhyQC4x0FWQB5bYG3d1Y/yp+z+JAct/KpnX5Azj
+ bz0NNTaY k4vcr7ZNoyQwHT61NtO44OM/p7U5doVdx5IPSpgCEAGCTxWmluxUdFqyMAhcHO3GK
+ cSfJORkAjp6 U9cFgMH/AGs96fszGV2n1xUzXSwKdyIE7GUjjqPWmMMjoTk8+9TjG7ZyzY5FLt
+ 3KNwwR29KXw9Ac bNELITCVOGbsQKaAxkI6AdzVkgliFU7R3pdqm4YlSoOMZp82gcyk7EGNyjc
+ QwxggU0A+aXCYY+tW lTO3b3PXFKEKJwCcVSfvWsVztIgbe23cPy70/Y2CBnPXr0qVfmBVl4Jy
+ MU9IwAR0HbJ6Ucz6IzTa 1kyLYMDncWHTHU0NkAKFxjjOOlP2Ethn4HpSAbnz144BPNNy1CMdd
+ dSsWy43jdj26UhH948jsBUp QtIwxtIPT0pWX94GUHO386huI3Ho0UXjV3ZS5Uk5AzTRGFkJOc
+ dvarGBvxgk7eD6VHs3RKTuDZwc 96J3ve5bTatcpMSrPgD73PFJJHnHG47cjjvVh4w82GO3NN2
+ lmbkbRwvrRGpZak8qbK4RdoPc56U1 Yssc8Lj8an2FWA2kDrmjaSJF7Acgd6qE2nZAoroVzkRh
+ MHryR601lLK/RecdKsbVQhs5BOMZppUD LDoWyM/zpuUn5lUuVN6FFDhsgcKecUOQVODhifu1b
+ KjcSBt9TUJQqRlcE8Z60m1fUUpq2xAQxG4Y yM5yKiY8jcV6YOBirexgvIyvUkVXKhotuNp7E+
+ 9J27ExlddyJkzGqA8g4+opgQ+YTuyoOfc1MQm/ axIIXtSIqHDchgp4zS5ujJcXazKnl43NnIL
+ fjTCWBJ+UZzxire0OMgYXnPNRMpZQNpx9KtSuh3Kp QH0BA4Gar/NuJVlK5wAfSr5HAJwQOw6i
+ oiBsJI2nODx1pqL6FOS27lRlj3ZUnntmogqtuyCBwTV4 qBDwPusB7moggxgMApOSKz5o3sDir
+ XKJiGAD/A3B9cVG4zCCAADkZx61oFi2F2NtyeSKg6wfKowD 0I6+9a03fWRn71ym0YEW3AyOp9
+ aq7Au4ckdh6f8A160Xj/dDdnPbNQeSCDuJIz69TVWuro0VmUHC 7AuGG3pVfyQ1xt3YBB4NaDQ
+ 7Mt1LHHNRybWK7mULjhhwBUPmbuiZtRdkzLwF2quA5GR9KrvG29lY ckdfStJkJj3BVYLxkVCV
+ dUBxuycnik5a3BN82hQ2c/N8317VAY2JZuMY45q+6b0Jyc+npVRl2Abu F6hu2ayjPmlpv6BNy
+ scWkR3jy2LAnB9quLjesZZX+nGDTY1jLkYZT6E9asDHnMccqeKelryZTjL1 FjYKFB7cYq2u1S
+ u70xn29KYqLlTtPIz06VONznDHCYHUd61cby00RKcXezJgQASANuMgDrU6FimE yVwBmmIMbVy
+ B2JI4qwmVOM454GOoqXZIlOUVoTJhjtY8A4/GrCqC+FPze/NV0CEMNxGfSrKAL8oy W65PaiKT
+ WzE27WluWgxVtnG4kc46+1Wgrn7o4zwT2qqh+QO3UNjOPWrhP7kBWUELzSu001oRy20S J0VVG
+ 7JYHoKkjAAdz8pNNjKsFVVZiF69qVmDBAM5x2rSMeZe87lXT0JFXmMs4GB/KnLkRhgxyR2/ Wl
+ 2guoxyeeakj27UGQp64PaovJO6Qk3HbUWP7/Xv8ue9TkOzPtA4PpQEBnDg8Dr6GpSPkLA8Yxij
+ nTZq7qwJnYA+SSOwxzUwVlkG44OM/SowMptTjB6mpwoZSTnI7Z7VTb6iWj2H5wDlctjIPpTRyw
+ zn 3xT1RSRklcdc1IFCsGzjI9O9ZxUNbAnbWxXCKThSR3GT0zU5XaVXOWPp3pwX93uCk/NyalR
+ RyWyp BOM9jROS66E8zvoNU4I+Vl55JqULnc/IYniiMeZHuHQHk9jT1x5mARzzjHIp8umxq3ro
+ PXBVQMgj v2qQLu3jBUfWpPLOVw67SvI9akXaRxlm74PWnLTUjpdkIiHnsDkgHIqdFYxFmVcjv
+ ilCsMSLxz1N SspDc4xjJFQotyuLV69CGMkPyOnftineWwkIC5FPKDY69SDSKjFzjKgf3jRbRt
+ sbgl5Cbdy4YEYA BqTaCjIOdvB9alVG8xsLlcYA9akCYIAOecDNPmu97FJx7kYwD042kcdqVc7
+ djfMAOB3p3zbgOPfj rUobLDK9tpx2pRi7aohNX1GgKAoIB9Tj9Kbty6gZHGf/AK1WNoQhscA0
+ 9VHILA5746VVkXGViEr8 4VO1WAFADt0xg+1TBQCCRnjOaDGrx/KOSOM9KhN3DmVyodyvlRkg5
+ 6cmnsN8gYqykjBx61N5W5lH LEccdTStGQQAhD9GJqrpyDroQfO0ez15/AUpOTt2HINSiLPAzu
+ we9PIIBADZI4/xofI1sNMhKYkB /g6/So1VPMU/MCw/vVcyWhIBDY4IqIgAqMHjP+RUwV2xvfc
+ RP9Y3QkYwaXG+ZW3Acf8A6qGUlAFw CD940Z287d+ey0cvYjldrpjH+/k/dJzSIcHd/CR8pqZQ
+ Cxdl3Hdzjpmoir8jrk4A9PWtFcE00MIA BLN8xP6VEdwZW4wPxqc4Uj5fl7Z7VEyjcSu7BPU9A
+ aUtgcrtXehCQxcE460wuRKqEdRgVOR84Bx0 /P3prYAUYDY6kVCk7lOGlyFolCbm5btUBBVs42
+ qvT6mpMNwwbryBUwAywyCSfyrR3jZkxauVAoK4 bOM8HNC4yybfmPUipNuUAYZOfzoCsZAOAev
+ /ANamo33L+FXW5WZFEhHX0BpxXzHcgDdx19BUzEbi WXBJPHeo0UtJvCsgHBU+lTL4dTOfe5Xd
+ B5pZuMHIUd6iYZbvgkVbkG1TznHf0qFkzI46D+92qeZ7 iSRWcZn2nIbODzTCpGSMHB61YZf3b
+ ZGAO+eTVd4yA2MnPvQk927DVlKxG6jBJwcnk+lQmMFTjJA7 9KlkBWLnO3pinEfIQpHT8qpNtI
+ NU79Cru2odvA6NSMjcBTkY61JtJhDNjlhkAdKeU+UgOFbPJP8A KrejuOL10RVK7IyGI64B9Kj
+ 2Ah9wPTKk1O0bFgjnbu6d6btAdhtLc4P+NLRa9yb62bKm3EQDA4xk ketMaM43Y/i6Y5FW2UHG
+ Bmo34PAy9KU7i1asirIGKY7kjgVEQSp3HbjjPqKsSKQTj0BNMPzbsYLd 89Kq+qsVfuQk5YFun
+ QAjioyp2KQDyc1aZThkG3JHSo/4FTBOD8xH6UlG6egnLQolN2dvQDnNVGBC 4AUg9citd1YLjK
+ nJxgcVUkiUQMG4YccU4ya06Cg0tWZ3lLu+X7uM4BqrInzttcH6VpHcG/2T271W aMoF55Kk+9S
+ k3rsaK6bszPkiITczAFuQPQVUMSlPmOQvH1rSePMALZLH37VWkiXJ2HaOvNVzWRPN b1OQ4YLt
+ VTjrxU8cQMiylcDrnHenIvzljjcTgAd6nXIjYN0B5XuKxTd9URHR3S3ARE5wAARmpo1Q hiQ2R
+ j5T1BpQF25DfLwQfapFXDuFBwTz64rW11ZsfM7bCoMHOCTjn61OpUv8yjJ6EdqbyoI5JPPW pl
+ GG46EdamMW90Wo6PUkCAN/CBnJOKsKp2fKC7dGqNYgmCT1NXIwPIC9VPP4+lVTcWmupM5K2jJI
+ 1O1QBwTnj6VZjj2jcWyccj3qJUwqYJXnvVlVUBSCBk9D2qV7quZubY5RkEDIAHGKlVeMbSpzzU
+ aq AQc4GOBVhAH4JwelP3+UpxaW+g+NldSDw+MEU5QWlBAx2xjrTEVftDY5I61Nyr5IJPt0pcj
+ TLj7z 0JkY45IBI6YqQr8gHUDpxUaIABtB5PP1q7tGPccYNS0oscFyvQYnzH5cZPTFTKORwRxw
+ PWkC5BOM g8DFSrncFPUcim1bUUnfW4g+VMhSc9c1IY8y7ucA9DQY9/GTz3HSplAEOQDknvT3W
+ gruyY1FyhLn AHIx61LtBjDf7XNNCtySMZ6gU5cnae/92okubqNJLYkCbVIGMY605OeSAPl60r
+ DYM9MYxzTwMvgH APX0ojZ7scZN6MlVCyKXGAv4VKFUSsSQBnK+4qJA7Bg2Qo6L6fWrqrGdxUb
+ l449KblyqzYWdvIjV RvwPnDcn8KmweODgccinEYlAwMdqUoTIoLdOabWt2Jt3syHbmTcOucED
+ uaVtoVQ3BPGTUxjIz6hs 5qTblG+Xjd+lU5K1xrTV7FYJljlzgHOe1TbeSVVs49e9O4JcsMKT0
+ FSKQrjB4789awblbRAoys2Q KSrD5Tk8gnpVhUAKkLuGCTShN69yw6Uqn5ioBU9+atJuzsN2+H
+ uC5VyzggehqVETaBtzz69RTkiM krPj5SvQ84qRlOQxI2jsKeknbqNWTsmO2AH3HamfMpXcBnG
+ Tx0qTkwED0zn0pu3OCRnjinFa6kNN qzDsc8DI5pwB35Jy3b3p3BTIBA6nNAQl+CM96hrW76By
+ WtYjA+YKpw3XB600LIsvIOO4P6VM0Yxu AO49TT8HA7GqUU3ce22hCMkDPDdzSYUjef8AgIqXy
+ y2Rnae9DR7EHoOopJR72BRs1Z7kecJxt56i onGEOB8zDtUyoAvBOKQ7BKvXJAzzTh1sCa2K4f
+ BVf4R0A/nTF5OC+M9qtMIyWO3B6A1CF3bcA8Lx xThNrQJLaxExHmE9RxgetM25cAErg8ZqfGE
+ IYYbFRH5SgK5yOPXNTzeYN3diEjAOBnLcYprIRIVY YGOtT7S67sYYjcaZ5TYJIOc4BpJWepLT
+ tbYYRmIKFI3dKhIw6jnuM9quKH/dgjgc5xUG3Mm/rk/d x0q0+bQtVJR0RFyGVSQcDgUMAXkJU
+ gk5OP5VPtDOcckHtUcyEoSAVJPA9Kq8X6kc3NIr7cyAMDgj jHtRkrICSAT7VMuPkJyG757Gkb
+ PJK5J6YpO70YSd20VHUvHu3AnPboajbCOFOArHBq2w27VAHTp6 UEApjAPf6VU2r2HotEUnU7m
+ Kjfnt6VGwcnbt2kDnjp71aIDMVOdxOQe2Ka6kZ+916VLp3KXLzLuZ +Nr84Y+9H7sx4XhzyRVn
+ y9z/ACglsY3f1qLYBDjGCT1o91oLK+4xwTGGjAbPUCoMZi+YgOOntUxy nVie4x2pzKu7jJDHG
+ aHZLREu97FSSNmdVLDdnAIFMbchCEAsBzVqRS0eSOfT+tRTZMTv6kA4pqVk KMddSmR8wDZwR8
+ xqPgP0zxx71ZCKpyQcBe571AB1yRuHFVKSauXBLUjI5BK4Lc4PVaj2neVcbV6H AqVVLMcfNxy
+ TTSDuBJ68GpgrPUma7kZCMDjIG7hqgWT5dp5OCOP51aZVdODx6VF5ahSxI3H5sY7V cWr+YrNL
+ QiK8DeOT0AqHY2/Zt4znJqwSx9MY4JFRYYHrhRyfrR7NpPQUm7FKdRvHXKjk+tVH+b7o IbsfQ
+ VpMv7sBgOhzkVAy/IW4AwO1EZpoqLcUrGbJBjb1YdiOlVJUGG2Ho2AOta7BQW6nB5qjKWZA Rh
+ cHJOOvvSjNteRK35n+Jx2zLkFgB1x3qwvlvCSDknuPT3pkKctv+ZmH5VbWFfKP8K+1S3Hlu0VT
+ UktBiKcxqMHaMfWpxuMhJGMcYNBVdyYyScZ9qlCjJOfl3Zya0m9UiHT1fMJ/GyhSnOSakRQck5
+ JH 8IPSnCIhiSmSGxmpYgysWABOemKlRvKyKUktiVUVlIySOuM81NHGpmj+96gg96EXeylDjHH
+ Tp9au Ip3cYP0p8zQRu9ESAHY2SBhh19KeFbaVHzKCOlNwjxkMD8w5we9Tqu3Z8hPfg011E2kt
+ h3lg4JyA Dz7VKuQcfLkHPPYUKMyZJ2jqM96kCq4BAZiTyajTVMvVR1YKpbBHIz27VaWMKvJye
+ 3vUIiKybRke v+NWgCFBPJxzTlJP4SVGSSdxIwjOWyRnselWE+Y8fNkcUxAxVTtB+g6Va8sYIT
+ txnNRdKSTKbYCJ ieMrgjgVKsZYNjIG7IzzRGDu4BG08GpVXMiu+evABpzk2LXdkUauHOCMHqK
+ mUbZguCR0JPalYEKw PUdcCnxgNEzEYI9TWU00hWd7oQJ8mCc4HBqQIqKpzu29/Q0oBOFwATzU
+ xBCMduOeRUtONrlNydk7 EcQDIykEtnj29qmaPJXAK4680KOFbBJI7elPCbo1wduFJwfSq91dC
+ rPo7Eq/eUBflxxUwABOcgf1 pqACFN5UsecipkAMg3Hg88UoyVr2JVm7Dgm9t3UEZFP2hFBJxu
+ 55pFB3gKrFgOlPKMV3N3PB7VTv a7GoJvYRow+5lYDP5mlXIZOp4pdjBFUtlRnGKkERBBIbnt3
+ FO91ua83LFJ7BtT5jwBnFO2jPsB19 KkCkgLtO3GfrSgEvgkAEdMcmkrcy0FGzW+gxQCoKgtzj
+ ilwROARySefapgm04UfNnnFKfvqSvXpU 3voTe70/EWNZd3P44qRwfOAAHPUYpEVmkYDpnjH6i
+ pwrB9nU4x9KmWjJu1Ig8vLAFTg9DninKCV2 gd+CalUk8A/MTmpFIbKt1rbm01RTjK9yAAyOfu
+ qRwB604ghAuMMcGpU6kDGD3I5FIqfMWJwVOMno aj3t0hTjeRCsZXJbGPrSYPmYP3SMZqcbiow
+ uQvf8aUhCVycEH7o61oovqGlyAwhFzye3JpPvNjnb jg1Ic/eLA59+lIMeaG2nG39ahxa3KbaV
+ 2RqpPzbhjBycVEUxGoI5PB561YOzgdCOvvTijMSy8qDk AGs3U5CFzXuykw7DnHQe1NHCHjBzz
+ U+MlQwwCOPemMm98DGM9a1TuhtQZAdzEuudpOee1K8ZIjA4 GcZqVdzPtBG0j06CkMTAbVy2Dk
+ k0ot37F1IrS7IGDrnHQjFOKtt4BJH8qs+WPLKnOexzTFVlQKCc k9x0FJz0uZOloVlGZc5xx0P
+ WmlNrLkH1B9qteWeD0JGaULx1DN2HpVRWliZR5VdbFXauQAOvJwaJ NocgDdnpk/pVp4gTkgjn
+ gd6Ro2YLhQB6nnmnyor3U1YoFPn5ZeuAaYYzgAjLDg81om3KgMSOpxgV EFBfKc84PPSn7ttAU
+ le5RcEsdq/IMc1AEZpGypxnj3960XSQEkqcZwABTGDIuSuG7E96b006im2m upRMYDE49vrTcE
+ 5bBzjvVzbwCwJpCpCBQMjHQ1jJNNXHvdGeRj5lznOPlqNVUMhUqX27SDVpk53Y YAVDJEzSDkK
+ DVJSW5KtaxTkwBgEE9+KjI4AwTkVZljjyfm+YDGPemmPKKB/31VruXzqBUGCp2ggA bagkTajD
+ kAt69/SrTnAcFW4P51WkHAbady9vWkpMKl3a5G2DHs7tzioZFbzNoAHPYfrUrhjhlO1Q e9MZR
+ 5rLuJY9MdqqTWmolFpX6EGMZAYDuD60MCVBf0z9aTB3KpHzECjDAEMQCtJQ1LuyMhsZUcdO el
+ JsUplWAYDGPUVKcHpjgcj1NLjMK7gFbkkdOKpS+8ht21Kzrh/7xxx6YpOAuOhz0xUuR5YGRkcH
+ im7kGSfWhQbQlq7MpFSZNxOBjvUbkBdxGQTzV0puk44P9KqyREbSMYBPXvWnkJK7V9ikwwrDac
+ no KoyRjA7FupNarRsAxIJdT+BqnIoHJwxNYqd37o2r2OSVAH4GTjC+9SiIlP4hgYPPWiNd77O
+ hJzU6 AeYcnkeveiEWndijKXzGoCHGep5H0qdAAEfHBHBqRFH3mU4fJ4pUA2hdp5Hr0q/djqhR
+ ldXGkjyj jOSct7VYgwfmZl4OD6Gh1Uop2MrVaSNBGcDHPU9DRNqMdQ91LUBh5o3UjgnIq0oKH
+ LL8nG0+ntUK Bvk3LtYrk8dCKuqSQC/3OpBpJ6aIbTi7t7iCE+XkcEHOB6VNGgx0ZVbqSc0Ko8
+ xtpLcYODVlVxDw 2OOQR0qm77j1T1ZGisFYZQgcDAqzHt2lMYx/OnIMrx2qxGAJMbcEc896xem
+ w48sVdoYqc8DIIx15 pQgXDEcHg896kMbs8gzhQePpUmzKkcsMnJPrVQlpZDjo9BYlcxsqgZHT
+ PcetWUXy4+oJzSxx4hQn IYggCp0T5cBSXHOaiSbIkuXYYiK7cH5icnBqQja4KA4VtuMVKNq4b
+ GWyMYqRkPmAg9fmxVySSByf qVwuGJbI78+lPXaTtwMZ/KnbSzgYYnOfrTRw6sw+XoR3xWerRV
+ lF3e5MFKjOw4HJz1p+A8oySccq PX60IPlDBWwTzk9KaquFJXnBwPU1Lbej0Jv5jWB8racx5xg
+ +gqeMkZx82FI3evtTQvmJgttbpzTx Gylg2CMYAFOyvqbuCfUkiX92rZGO6+lW1TIwQduetQxD
+ 5WVvbOfSreAm0cgYzyaOfo2TNxi9NRMv t447fWpduIvusefu55FQ5YMDj3z1Bq0qsTubPsBVq
+ KWz0Ks762EjjBwwPc5zUvJcAggAZ3HtQPvk 8BfSpQrllHXNS7bszlve43nb6+9TKp2EgBsDOA
+ OaRYz9OM4zV+9vZb65SaZY1YRqg8pNowPp396i bk9LaepajzPRmfg5BKnlue1TMmZcAHJ5APp
+ T+NoCdz370pG1x/Hx2pqLbuK1t9xgRkXeCCCecVN5 b+Q/UH1oQMEVWUk54o2s0yqrMuBg5PU1
+ pZ6CteWoKo3biMBTyaVTmMhyFOPSgxs0PzffHWpApxyM Y4FTy8q3KlFNakQiJYdQQeT/ACqRB
+ hQuQMg4BGakAyoyOB3po5OSmMjr7VTTb1Rnz31vcRQNmRyp 600xqJ+clgORnmpAMoB1Q8ijaD
+ 8zHH+16099UNR1uV2QbuhHp/jQFXaC/BwenFWFUFJG5PHY1Hsd WBbgEdetZ7p3ZUrIiCEZC9y
+ MsfaoWOZCMhc9fSrbgEsGVjxke9QDbnLAL8vfvRG27VxKz2IlTOD0 471GUUkHIABq0QGTABPP
+ H+FIsW4LkHimhQ5lqyExlV29s5yKcFcENwDg9qlGPPK5G0E4HrQYyeit nPXNXSWqvsZ2VyFjn
+ eo4bIIzT1jTbvY4PYetTGIh8hRtH51IqEE5TaeM0pRXQ1bKeHIPy5xx0p6R F2Bx1HDdqvqik5
+ cbDg/Q0rRhIDg4GOtQ5JWJk/spbmf5Q3Hb3PGaaqDewPYY/Grvl7lDZAyMA4pp UGfnhh7VUUK
+ a7lVe7MM7fWqzrlchcAHJxWg0YGdoJWhYSVK4ySMnPtWqilqNNJ7FBl+fAzzVdoix GQSoHb1r
+ U8k5Axs5PXtUHlPg8fMvUe9C0d0yYyd7GcIct3z6VE8e5dwyW9PSr5+7u2kjdULJzuCk HJyPW
+ p13Zo7bGcVLSsM/MePpUEifeHBx1NX3Tjbzu/vYqCQARAEEsfQ1knF7MUU07FCRG3AhR24x z7
+ 1BJGBvYZX6mtArlivO4HNUpPvsCOR3q1JPboHNLmKkoUx7sbiRyAagkGYgeSw4xVvZhRgZbHT2
+ qsy7mIH8XQ0Jx7g+V9SEgDkc+tRBSCHHHPGe9Tsq5ywO7HrUHP8AF8wWko3ZCiloiJgGdjkfSg
+ nI baARxjingMYCP4euMc0mEIB3gY+8K1lBRHzJ6kIUs2NuHz29aCrdcZI4/OnHGVfJPGBj+dO
+ KEqVA IyecnvTSW9ynOzTSGPGViAwCOnHWoXTbg5Hr9atlGVCHXPriq7cI2MZDDnqKE3bUUOaW
+ xHtJTBHI NV5CMgEgHkirjcy/eBJ64qPYm8qCG5y2am9tQta6KbqcbsZz1xWdKFXLMpJA4wa0Z
+ G/dfM2FJzmq L7TMSGAX0PUirjFv3rCglbU5gI4j4252nGBT448oqgdfzpVJVmABGehNTopfGC
+ MjP41Ki0op7E87 WiSBFILqc8HP41Oqh2OGAOMn61AgKguMlu/vVqMAptcYz07YFU6cbrW4NRX
+ QkWPFxgkMAD+NTeSS BlwOfTpTWXaVyCX3Yx7VaUOzZUcZwKlT00exMVZjfKZ12hup/MVaUMAd
+ zKADjBFLs4I6joAvUmpo 1fG35ST1z0xVJprc0cm9LhkqAFAzj045qZIzu5OSq80KAQC4LKRzg
+ 4xU6D98Aepx1pN8q0H7vKHl k7XBwAatJy24gknoaiWMMw56enSrMarGuQ3bvzUWctLi0+YBVz
+ xn73Q9c1LHDlgTnGfyqeJN5DYA 559qkCncBjAPT3odrWW5MXK46OPERJIJAyfzqXy2EkpJxkZ
+ XHepY9oX58cHp6VJtVwMkjBznPWiD aRUpcysiDYcAYIPoamcr5XzIyYbrUwUljkg5GcntTfvb
+ gAGX3qGtSoK2+xERgccseSSOBTNi7Mry QclR71Y45DEc+1Q+VsACFsk561UU+4rx6gpIifeQA
+ TwKQ7vOKFW2Zxu9Klk+cfLjrxxSkseA3XkV KvLYPdWohUxlVGNucZqXbk5GB3570iYYDJyOuK
+ lUZJwQDnafapd47sFG7HwuGcHIIJqYrtUEjLHr UIj+f3x0FWAm2QJnIA7mhRb1iNQSJljUgFs
+ 57c1Y2ttByB/eqCIh5VHXvVlQFOfU80Wa3KkmtEOw fLCLHjA9OvNSiP7rbjkjkUcHAwSMcVYV
+ Ay7gu0k8Amna7uhX8hnlqNp5zjBz0zT/AC+eF6DvUywn eRn5QevvTzFzuAI7EUdRwik73KqJw
+ OwBxzUm3EXylQcd6mCOFYcD5snPenhVVtxIJJ5HoablO+hT ty2GBGf72MZyGFBDbUyoGfQVaA
+ O3gAY60hVyCSFDdv8AGjfcmMYy1IgvGADnPfvUvlZbHY5PFAUF l3blyM9elLsbJJyOMGs5pqV
+ 0LlTVrkBQNnnDdMZpWGCB9457DrUoQE4OOBTdjbeBuOeNv86pK8bi Sa0uR45XgAE8CkIBf7wH
+ J4x0q0wIAUqOnJxTAozyRhTx70lrrsDepDtG0IWGc9cU0g+bjBbH86nO 3eSRnB4pAp39MN/Oh
+ WauKz2ZAc4XbjJ5INQFQxOEJIHGKuH74yVB9cVGw67APbFXDUFHl1KoG+P7 rEg9qeiHYeMHPe
+ pwhRctyp7U8gKv3TkcDjrmhtDjdvQhaLMZKDcQc5pyIVZOOCMkGpEVs9CFxyB6 1KxJcFQMdia
+ SvYSp3umRffBKr3wMVIsMjElmGSMkY6elShQsauDkk8gdKlCKWGCSV6gd6Iu2liL8 qsVvLDqF
+ 79/rR5DNK2WBAGDnpVsR8YwQcdaapYAZIPvjrT1GpaalIoVwB0757U7ZldxXqcVa2jyv xxz3p
+ AoVsO6sMZzVSiujLeq0KjRfMQAVPoaaAWHVSPbg1awAz91PWo9i7cdT1wKztzego766FYqd 2W
+ bPrxUZRSd24sOTnNWNowzFSOw5poT5cDA7E1qlrvYTSKDoVL7cbcA59feqzLuwWyfpxmr5DZIT
+ BUdPpUUiZB2kYbr7VMnfdjaa3RmvtbHynHtVSRFwDtJwOMelakiquFIKkjqaqSg+Ruxls4z2xU
+ cz a0KppddTKnD4QqOW6VVmQguA3zZwR71pN0wc5zwKqug2sfmOTkVV7eQNqKM6XIjBHBIxVdg
+ Rkg5I 4Aq267gcsCR0A71Ds3SMWXaCRn61T1WoorS7Km1uMjGBTTwhJXBPXjrUroVbuU3du9I+
+ Fl6qeMjN Du3ZA4EDDahYnAI6U0xlWOFGcDPvT8HY2c7u2akWMeXnlznrmqlLRGclGG/UrBAXY
+ N6jgdqD8vQE 89TUmAXYchup96UHjdkYA446U1d9DW15e9sNyfNAxkE/pUPAOBjGcgYqdchieK
+ YynfkjOWolG8bh F2TRXIJyAueM8VAAAzNnDn9assA4OzcSc57Ux1VoY/UDqO1EWuVXFdJGfKo
+ LfN2GMVVdQI/ubsdV xzV+VSCwAPzEduaqyZIZsFfqaqN09xt30RzGAJMLjG3gVLGEEMW/qD1F
+ RjcAHI/H1qYHLsevoPT1 p662MG4t2JT8+CFIUHjijZnag5GOfpUwLBlxjaVwvFCEHIzyp61nG
+ pNPRF35rpIlJbJPbjFWowRG Cx6dPU1WBLI2Msc1OoHkDJI9vSnyXVy46R2LCKwk4X5BjBqym4
+ Lk/Xiod6MwyG4461OAw5ByB2NK K0ZEo/zDtuUKg7geRg1ZjU+WeMgcD1piA+YdwGVHHFTRjbt
+ ZeMjBz70NN2Vxuy2JwihcNkEdcd81 OBGG+ZgMdSKjjyVxtYe5HWrJVMJ0PsOtTfQbtzWHqFWJ
+ eCDmrCK0sakcbT0oVB5TKcbhknNWYubf BOCcEKOopw1iDVtLD0QmIsANucY71Kik4yuec0kSF
+ pHboB2p20E919M1K6hyXYIvzcZYHoe30pyx gBU+73P0qZFORtIyD0ppVmlbAANKTb6g1LoyB+
+ 5Tpu7imMjYJzyeRgdqtDhcFc4HT0ppHHHzZ6Yq nIlS0sQlSqk8YA/Ko/KbKMCPKUZNWCreWpz
+ kEcj3pVLbSqr94c8dKhKUXdMcFf0GgDfgsPy6VIqj YAx9/rS7dibQCQeckU5fvBQBnPU1HNdm
+ junoPCrvycBck4FTKrFchhgnqeabG2VZTjgYB9aspGdg A9OnaiLktBx3HJGFB44z1xViNCbgF
+ VO0DAz2poBOAAcdqtqTvUMM5AB7Uc0ktyLvcUJ83TcAOcVM qAzEnK46Aninhf3hO3p39akZN8
+ vPyj1p01Lc0i9fUaqkZ6lieBUyBgpyj+1SxodqrjBweT3qVIiQ OowepqrX1sZyiQ4byk2jnHc
+ U5YlLtvGT2IqYxsYiFOSDg0oRliA4PPPrTXky3tqRIMlh2xT3Rtqc YGOM09FDOF6Lg80/6AkA
+ 49aOV7ia1uV9u9tv3mI5pAjE/N0I5qwvysTlVOeQe9GwBiOpxnFG2iJc tdNCHywGIJGDxkd6Z
+ tZQWC7WHBH1qyCAjAcjOeabyMbs5I5JrJxaditdSEqdoUDH071GinkjDDIz kdasBVY/KrA4OM
+ 96Ty+VxnC9MGr5rKxMo2SZAIyMgDqeSe1OdSBwuQDwKslQfYAdD1pgjxyTwOAK FZopR01Kyod
+ 58wbe3P8AOoWAVioBGF5Iq+yhYMN14yfemsmC3HOaIvleocz3K+C2FI4zmnYJjAIz /M1KEIVe
+ Rzxn0p6ALJubOBkCqnZvTUGVwu1WDKQM+vNIFO8hmG32FW3BHJwf6UhwULdeelLmsiYu T6EeB
+ nIDA+hFCBstg/NiplT5iMb365BqTO2MkDDg5YU4zsu4KWpCBzywGCM5qUL83IBUDjFOdV3D 5h
+ 83r2qMKu9s8jtg0KSlqx8rlqgKl5QUX5TyM1HtGWPAOec1OMoMZIA6AdqaQoRjz9aLvoK1tyP5
+ JeGwvFQuqqgIP3jx7VPgHAPOB2ppTn5iMKck4qnZE31K7Rgjbn5aidh5RIyGLVaPKjjqQTgVA4
+ GT gYPai19Ane5WkwUO3GSvPvVUjEOHDZP3jVzcykEKHGeRUEjP8oIzlc5os27Ar7dDPlUBDyT
+ gd6qh Q4DE5GOlaLKpBBbnghu2KpOGbG3AwcYx1pabLc1im42RVZQMAfMQccVRdWBPB4/WtHcC
+ zYwMYxkV UcNhgSFPv1NRJyi1clU0tDPkj+QsoxjoRVKUtvywAbPKitBowoIfIBHFQSKu7JUlg
+ vBFVfTVaj52 ml0KZA8rHUkVWdNx4OCSO1XnRwm47QPYVHngYUgjgn6UczW24Nte8iu0P7/ZnO
+ By3bNI5bdtVtuD gD2qVl3KnUk54B5qEI7H5R8o4IPWq1t7zH5takYBUMAQ3PIApuTsG5SOMmp
+ 2iCsSScDrTCcp9OmK 0g7aolct9iONgQoZSM8g4psgCjG8D0OamyA2DgAdD601gwTGwnjk1Upa
+ 3JUnFpWKyjM2Mjj0HFQs NpUNkGrMqb4s459qrEMgALDnnkVKSfW7E3e8iGQ5Dbhxk45qkcM+5
+ RkYzzVxtxJBxVSRvLj27eB2 xzTUWjVL3fM5bdu5cnGOmasjBb5Qc/xH0qoqhQyuQ4H3CKsJIq
+ hVJwT61PNFrTc5X8PmTqHDFj8w xxjvUy/eUkblzVbcywkEgNnj3qdJGdQw2/THH1ocnbUtO9r
+ lsMoBKgc9DntU0aYLfOOeTxVdFVnC qdwPX2q2VUZ/hI6AnNSk0xNJK1ydAqbSRxyOKmjznAO5
+ umPSqy8sMg7Satp/ruy55zitG0tLjUep MnDHnBJwc1aViCxwuMDjFVwvPykEnnpVmI/MOMA9c
+ 9jUTit3qhuS5kmizHubO4AAHGMVJ5W6bI4x 1zTVA8zkkDA6dc1PuYBduGDdRilG0dEaJuOqWp
+ biIZUyMnGAR3FWlCrKMc5HNQxJt5bk9QasY3Ho cHr60Kd2Qvi2FRMLnc3XkZqwi55JyAM9OlM
+ wwwCNzZxVpcKi5BII5NJspxaIwGCAhSvzCkO4NIcY GR19anZQ0eAxGeQKiAwzNznPSmttUSo6
+ 7jDhkI54HNR5CDBU4PerI3BMHBweOKMA4LY9MGlJ8ysy tnsVuSS33jjj0pVA8oZBJ6ilB2DC4
+ INOB/eqTzgHJ7VlPRWG4ybsNwwXJztqVI1eQnngc+9NJY8h SwUZwKmjBUHaDu6Gm9tB8slG1h
+ 8cYAVlIPHI9KsqpUsRjnqPSkAywBG0Hmp40Y4YDA60r31Y7skT HIPHNWSmTnBOaIugAUk44Pr
+ VgKCRnuOT2FF1zaISs2EasEAYc/xfWrKAZGcHmnImX5yVx2qcLjrg 8gCtZVL6Gb3uMjAMmATk
+ dasAMFORwMjNKoDBmA4AxkCngcKAwx1JxUX1vsauOl0AjcL1JJ9KFG0Y bIXvkVJltz5I+Xoe2
+ KeD8/zY2gdxQrtXHPoQhQWODz2o34l+bgjqcdak48wgKeRUY5yx6elVGCl8 RUrdxMKzNn74pp
+ B5ZSCdv+RUu1g7BsEY5I44p4iw5wGOzGMd6TcY7shuKGbRtweh6cUzZuBxk461 OVBUNyAOcUg
+ VA+TwGHOegqVKz0E3G2pA0Z8xSMgEYBpmwGIBQwYnAFWvLyowR14B707YWkDKBn17 VV0yeezv
+ cg8vJUhcr60YViQcepx2qTBE2F+YL05qdkUpv4B6ips2y29SiYmfaoOR700pubGCSPvE VcyNm
+ Rgtn8hQyhWyMHjPHen72w9ehRUMp4AGBzTtpJZccfSrZ2luAWyM8DrUQD4JOeveq3VxWSaZ Bz
+ zuXk80pUByGyAeKsnHA3AknnjimOiqAyEhQO/NRe+yFomRB9qrtBye9OC7lc8nJAFLwpC53ev1
+ qVscgpgZ7etVDcmWm5HgkHLKoPHIpiqozk5Iz0p2wZY88nIBpM7fw4OKculgcLIUlQvUMM8Uxs
+ bQ B0J6UhHXdxj7tHCt8x68jntUR0eg9JdAfaCSDjB/OmMOuDkdzUoG5GJI44qDJDY4xyTQr7d
+ Qcbaj PmKEH2PSmO373joD1p5kyDzk9uKiOdhGCxYZAHatNiZJW0KsknynYnUHr2qEhfKcsSTg
+ Cp8DhQck dRUDhxk4BBIzipUo27AovRFaR1wV2NtJ49qruy4wePWrxUkglehPJPBqiVLMpdG+b
+ 7px6U5W0sSr NWuVSueR8ueSTVaVSJDjGR2PXFWn+8wY8fyqq4ypK5OTyc9qvlu9TXZ3KjKTzz
+ z0qu4ZigVSMAZP rVp0G9gAwBxwarMWG0cHA/GsrXbS/EpQbTdyuyHYp2tg9vaoVAOBwT3qSQM
+ yr1X09qjbakxIBAzx n9avl7mKg2vQYygTIRkgdcetN2/OCGUDrjH60/c+8k4BPI96coACse+d
+ wqm31HV5lYjZSWzncoFQ uA+8N8oB6nip+fLZsgI3AJpjnEm3cuTgn2qU+wlK1m27orMCFUBSx
+ x+VNbMkZDvhQw6cVZbAcAq3 3aikAyApHyjn1NUpN6JWDmTXvIrOjAMVO4KePeo5DuAyMjPQda
+ mLAqSoJBODz+tVmz5WBx6moa7h K60KrszHgcjrVd0weeHHUE9amcMMAAnjPFR7gG3OTuz3rdt
+ pJi5mk9NDjY1Ckclhk4qXc2NyqDt9 qrhpRMWG0fUVKoLBN5Kk4wKiCVtWh6W1ZIrSyFQw9uB6
+ 1cVNiYPHTr61WCDBJfkn5cfrVtGVsDna RkUpaPRFqXRLQtRYCAMRz3FTRsr8569/Wq4XbsBwy
+ Afw9asqMOjDHoBRrvuQ5R5diYKckndhTxir kYJfBPbA9qpBf3ipuIx6981eiwG69u9DslqSk7
+ E8ZXcSf4atxIoB5OOvTvVVQQdv97HarUZ+RgCB kd6Tu9i7K9rFkDKqGJyeQfWrUa4b1I6jv9a
+ rK24qehA/KrW3d1ID4AIHem22yox0szSiI81iFBIG M468VYRfnXBHIyQfWqUHAByx46DrV5cG
+ 3yMdce9Q6coshLWxajUAZHJx6Ui8rypIJp4+VVLNjIwf rSlHVSgOQeh9Kuj5lJ20FH3nIxnPH
+ HQU+OMAgbx170mweuOak2bHBYnJPWsp2u9SddiCQAyqOCQM getRyBW4UFcdfxq2RkhsDHqKjc
+ BztIyM8047JNGvw6opjG3aMEr0p467SAwJ6etTCNR04zR067Sf aiatr1BSSV+hCissnB6jlT1
+ xVuLcVCYBJ6eppoXBUgdanjC5zv29xU3VtiZrm1QqowYHGOO4zVmM MiNkYAIH1qOMLvwWOSep
+ q2MK23IDDgZp8y2aKtZEkZBwRkgdhU678BAvPeo1Q7hhGUnnHtWiqsij GDgUKTWwJxWlhY0Uq
+ ufl9asKijhQTzknPFRhTjnk+1Tx8NnaQQO1G+7EpNdAC4fKjqeRTzy7FlAz 0FSMoDhiflJ5FI
+ yoZFzk4HUVSSkwbjfmeg4YECqy+5NOIBU4GfWgKwiOG3YNOLED5lJ4OQDUcqWy CPLuiLYdvA2
+ +uaCoD9Rn0xUm7jHQ459qYUYliGUn2PJptoq4m1TgnJLdvSpNrA5UbgBg4pyYwO2R wTQEGeG3
+ AHHB70tGzPnSViHJdQudqmjywAOSeOD2qUtiYkqRxT02lVyeAMe5qrS3aNZaLyGKpEee G7ChE
+ lckMdo7YFTortIG424x0p4HBA7fr7VHMldEvV6WINiqAARuxz7+9KBxlVJI7VYSIPg9Oxpw T5
+ SF7HiiTRL1ZXEZZCSoUHpTNjM53AD+oq0uPKAz17UeUcdOn6ZpN2dmVJJPVFOOPapY7d2etMZN
+ x6g55NWyCpyB8gqJl3AsMD1HcVUVuwk9SuF8sZUA7h82e1MJAZQG3ADk4q75bmMg7QD047VWZd
+ pb ONhPFQnd2QWTYwEmMFgHOeMDt60jH5G2jvnHvTmXLjnGeDjvRsweOctiqtswirDQDu+cgHr
+ UDKPM IU85qUgrGAw7kdaXaSm4FQT7d6ak4vUhy1uRKocc5ODUe07sEEkH5cmpTGynIdeOuPWm
+ kqOW6ZOM VUXqW72uMDsuflBye3Smg5U9h796kC/IvB55qJicjAx6ZqHHrbUl6sj2YZm3A/3eK
+ h+UPnIyM5NT uGB7HsDjrUL8IitsPckU0iZOxXZ/vBRlgM8dSarNllBww4yee9Wn3NI23A4yOK
+ idiJFBHUdaFo9E XIqtln28mPqaqPvxkk+w7c1eGwyDaedvIzUMoIySc5I6DpTcrbg5JOyM9lG
+ 7aMbcYyahZG3ZwVxV mYMQfmG44NVnL7MZ4GOPem17oc7lqyo4PlhmPJPTvUG0AvjnuAetWJFb
+ eCQWAOKrudr5b5cjj6UO zVjRp21e5AyDb5jbunK1FIC8KnGORnI6VZO10DFiD2FRE7l2nqR0q
+ rS00MG0upVIyhZM5AOc0pGY 9+04IyamG0M3XpyMd6Yy/uxgNucDPoKTTk7GvM7bkW0AxlsgDj
+ BNI4ILYVSfUjpVoRAHghiOlMyN r7sY5FVdOWphKzd2yg24yE5zkYxUbxnJIzx0NWnQhAcgnHG
+ B1FNO4xkk4XGF9aG23p0HzRVuUqMC FIGM9yRxWczvgkD25H51fdWWQ5yQx6elQOVKkAAkrkjH
+ elGV9C9tTPJJU/KzkH17VCwBRhkjPTNX MAnBBGRyAarSZ2hgQMcEYpxbb1By10RxAR2DHaw2n
+ vU4wEDclx0FRZPnbVHB65NSr/q/mwSPSnaa 3WhnGMpOxIkYcqSSM9BVpOAAgyqnGfWokRTJye
+ /SrUaFM9CSc1LlZ2RUn/Kx6D5k3E46H1q2QTMv zDnt6UyPY0jZHfr6U9UbILevH0rSTbI5dUi
+ wIxuDHd+BqyobrjPNQxbVcjdk+/NTICrBdrgE5JJr K8upspa7k6glsAkHHFXUXDIQM4B/Gq0b
+ KNvRmHJx9atBQNrBjgHOParcrWZLm5aNXLShCFYkg55A q6FGdzHn+9VWMANuySAMgetXI+Y8k
+ YO4Yz6U7q17ii2mWkAVVbgn1FX0j4Udx6iqaj7gHJ3VeiBc 5OSOq4qJau6HfXUsIw2gn5yemO
+ lWUzk4Xgd6gj4QYUdenpVgYJYsTszwB1py2JaSe4w/cGfv/Snq uSpY8gZ5HWpAAyBipCA85PW
+ m8Ky7eR79qhtWdhJdLDFUsxIZcdcYoCnBJUkAcU/bmQtwVHXbQwBD Ku7pwM1Tir6s0TuiLAJw
+ x6DnFRNwTwc9qsBMQvkEnIwaTaRJkjGBSja9nqJct9AHysw4J7HHFSIm HHTBHFNXAycZOOpNW
+ YwrsgByMZIrOTsrlNW+YRhUm5G8Hgn3qxg7iDgcYyajYbQchWXqNvepskjb jt8opxSdmPVsmj
+ JyAWB9eOlaKKTlgRgcEVSjGcHaScfSr6qCPQEZNXNx6E3k1ZE4BXBYZHQU7LC4 BYZBPUUiqRG
+ AgOc5INToEIGckg4UZ6VKskNNpa7j2GSBjjGQaYNocEhvb3pyZUYLAH3puO+B6del LZgiTIEn
+ Q7j2NJ87yMT0xmmgsOh4A5yOTTgrErjOP50k3uUoqIMGRiw+6Rkk01sja5xu64p0mTEQ 3AzTC
+ 6tHySCOo9adkyYRfVCnJ6nnPrT14kBBAznioYwc7gc46A1KhJcswBXODijW+5vbSyQ/hijb Xb
+ Pp2qVVTzM+vWmqpUZ3LjPSpgqFxjj+9k03boZbxtIMLtAyQc+tSIAYzn5cdz3pCwLYHJ7Yp4AL
+ bW4XPPNZuPViau0mRgMsxKsGHoKmCEkYU8ZIHpT9pU7sYXPFNAdZyVILMc/hVKTa3LsmtBCpOF
+ AA 9OKWVBv2jPIyTmpI4280biAR2oCKfvE49aUY31bM07S1ICi8ZyQOvNQ7EycffPUE9KsnAfB
+ ySTz7 VGUVXbB3MT070WaepSVr3ZWdWCbGJwOgqJjgJ3HHFWnDOw5xyOMUwqMtjHDdT60NpbkS
+ baRX24wQ jYJORTXIwoIwR0+vensjEAjPShozgFCpwDmnyxHBJdSAoG+YZb0GajcELjcAMdKsY
+ /dsCME4Ix2p N2YBjacdeOarm122G073IQqrGzFWwegJpjBSwYKcE8CrBi/dAksuB0NDLk9cY6
+ ij3G7CUnzXuVDu EgBztHTimEDByxBPSrRGXwrDH8xVXYJGAPU84pytYaW5HJneMsCOPzqFhuY
+ p1OcD6VaaLGOMAdjT HCBgWIBApSfREN32Kflny8HOcYB71DJEzHjqBz9atOPnznGDnk9KgYP5
+ Xy/Mfapemty48zXmUplI A2qzNjGRVd1eNRvUirrABn6g8d6pS7i+SSf5E04663G7oqspI3EHn
+ mqzFVG4DGD3qydwbaPSoJSu SvGT2xVySJnLVXKxJLKvzZ5JNV2A8vjax28DFWJOm3BJPTFV8f
+ vOeBSslcE7FfgpknbjtSAF5c4y CPpxVna2SdoIz3FRHaGyM5zx70k09A50lfYiKBo/pwDTQCG
+ yvOGxx2qQ7NuQrZDcinMP3jHGMnkV TSSVyXKzSRE2M7h1PXHemeWrAF+GI4FSbQhAOPahm4x0
+ JPGe1OVraAo2d7laSNsIy8YHQiq0iHLs WAK4wParxU8gsT61CwBWQMM/Lx70SlqiXOy5Uigy7
+ pGLbj0JPaqjhWkbI2kdavHeocYx04NUyjA8 nODyfU04xS2ZTs7vqUnwp3AgfhVaQFXzjapGST
+ V+URhlGeRnI9OKpH51XJ4C8+1XGTetxKz1OGRH XcDx9asx7gCQBuxk8UkSs7Efe+lWYlZRtI3
+ Ang+tSut3sZ36WEVC0W98KCQRjirKFgQMlhu5zTNp Jz2z8q5596sRxEfJyxJyOcmlLk5WaWtH
+ XYcrMJNvUHjA7VaUoyqSTlSAfc1GigTjIx681ZQASKcZ BGcinFWjYVknZDgpzvZhjdgECrfBA
+ ywztzjHeokUgbsrgcnI71IpJVeV3d+KUWzRt3LUWBGDxuPT /CrKhmlIJGR6DqKgQgkbcZA54q
+ ypDMrEgHGc1lZpkJ66Muop2oCQCO/Y1cQfKpPfpz2qpGcBQCNn bPfNaMIUJn5S49appvcce7L
+ MKhSGHIJAq3GoTGc/n0qpHxKp6gnIFX41LMGOMHnFJvuOTV7lvomF GQCSakKkrljnIzxUXcbT
+ nd2FS4G1T/CB07inTTRCg1G6Q4DCZVlYDOOKcf3sYIHJ75oiXfvDEKM8 U4K2xQqkjtVcqva+o
+ S27jUTG49e4pxUKvuRUyjLnbkAg5yKaDlScZGCOnNZ2uaJ63IGTjklh/CV7 077rDb1I5BpzKT
+ EqnjIwKbtZVGeDuwM85qVDogatuAWNwDnHHSnLgElTtBPODTiCGXJUIO+KcQuM cHb7VUlbR7C
+ +1zE6BSGGak27skZHGefamAEFdoABGcVJEH5LE4PAzUpMaSaumWYlZpc89KuqSpxg A9PpVeKN
+ hGfmJz6VOi5JwNpB6k048vQNd2WflKhs8qe3enqh3lhwe5ojAEahirDHHvQFY4YHK45q k7PQN
+ 3qSMVyCoJbvzQ5yFDEKew70oAIBIPB4pCSc5HIPU0nFNXQknsMD4O1OWxRhiAd4JHtSqB5i j2
+ 60joAcp1+vWqtdGrS5rCgk5JwfrSkArzgE0iqQ5I5AGKcuHwOgrFtqW4SsnoMUjzAVOTnpUyqG
+ JwCPX61EmFbI5yOanVVZCyMc5zyf0qpRd7kys3cVIyRyGGeetTlcgEYz1I9qSPlQ3HTgCpQPl4
+ wW 6fhQpS26GbkubXoL1YN1xx0p2wALngE8jv8AWm/MHx3qwqq0ZKZLdDROTXU21vZAflwFcNg
+ 88dKV hsdWxkbevvSbEaIspJYHOD3FO/e+YMKOnSiLu9EDbuG0GNmw27sD3poG3g5IzkAU8OPL
+ Kty9O2bc EDBxnk1V7XQa21GsmSrE4JPP0qDy/wB4SMjHUntU+zd1O0DjOaTYFLMx9MUrPl3Mp
+ S7MpucDLDq2 aaykJkcgmp9mVbODgcH2qEAhMA9+/an00NY2IAJGyCpOc5x2oZWBOVJ+Xip1yM
+ jIBPrTWLAgsCeM ZqVo7ESqW2RXwfLz91elRONuBjIq0yfNkg8DpTCAxUbWHGDRfUV0lcjHCjq
+ fQGmhOehJY1JJuWba vX0IzTdpI3Ecn+VDWgOOt9rkBB5JGDjBqLBRzgEsB1q2R8nIO4+1NbJb
+ aCuc8gindsV1LS5TzkkS McgVE8fI+Uk9B6GrLIxkZuFxycimFQYyRnccY5q7NLRjjZ7FNlLFt
+ q4GOaruDtUc5A4Aq0V4JAY5 zxUcnyxqXAXAqLaA+XoUXHOTgMB0qjJkSABgcDpjmtGQ5XcF5I
+ wapgNuycZHBJq1dxLc5LqUmH38 kBic1E5LNkgA1cypUsu0MQeTVNwBGScnPIqJxu1czTUpabl
+ BlIkKkcN055qHC72KqST2PNWySGJ6 ZHGRUJQEHBye+PSteW6syp9rkZHyg7wdvHHeowu5VB+X
+ 6npUhIJxyF7+xpm3EuQS6Zx71PK72bJj OVmhNuEO5gR600xksfm3dKlUAsVwCucj3oCBo22sR
+ g0c043JipRd0MCoVBAbKnp61CoBlJ6kt0qx 5alzgkY5+tMkTanyDJ3ZOPXFOD08hyV3vqViWD
+ MMADtUAAMbnDcNzV4gBFU/ewMmq7HAYdM0SfMy HorWKTJukZ+QO/1qlInPJBbqeKuurByM4H8
+ 6glRfMwW249aXO47Mr2fZmcY/nbcpJbuKptxPg4K4 xj3rSk3IWwQwHT2qhIrlCRg554HSrU0x
+ p6WbOTRcKu0jp2p4R3dQWGcZwBjFNRW81t3HHIFW/LO1 WBz+FVCavqzBSEKuBlyBsOOPepVGE
+ B3HjgGlBA2ZXI6kZ61MFOSI+M8gHtUxkn0L1vqCLgjcCy9R irMbbhnAwTUfV1Gff6VMgJjOSM
+ 54IpuF1sXZrccBhsn0xU6hWCtnPHWmqNxIALHpx3qVFAAUgg9R T0tpuVa7J9gRMqu7ng1cjBf
+ kId+MYqBcjb0VcdxVpEODIWAHQYqOawrW1ZcjRvKAPQfdJFXIlKx9 MYPaq0R/dBScqOM/yq6u
+ 4qQDjP3ie1SnKXkTF9WW4wjELnHynbmrUKu6Zx04OPWqgTJ3dyOFFWEY jOcnHUDvRGBV7rQux
+ qI5h1IFSnIQHI46+hqDkhSowD1zUysFbOM9unQ1ST1ZKvfclU7HyTtB7GpT kP8AKcHGc9qiLo
+ 8Y5B569Kk+UF9z5AXFZ6PdGkeZvTQAoZSQ3OOMVKoHA+YZ96jXbs4buB0p+AFT HT1zV811a5k
+ m0mMdVDKc5YcAf1pz7gABjOeR60qjdIWOGbOOBUgHO0927dai7RbnZLuQqp8ojg5P GR0qRVzk
+ cYByPWgrmRuRweacOH9QAMkUpO6Ls2rdRyZaQEHoOKurlmxjKkn8KrxjlvlYgAbWHcVO AQ27J
+ UEZxUyV3oQ4q+hOmAo6lhxyasCNkbkbh0z6VXADMVGMjn61bRSF+6SDxgdacUoaopavUkVf lD
+ EEAHGKtqPkLbhtHU4qFVygKhgw65OalQ7WOcFcYx6Vo5NqyCK0EB+Qb+mc8Gnkcnn60KMLuJVu
+ OlPADkAg5xSaT6FNkZjxFuORnktTGyd+CBg8Va2g5zzjpzUAYBSpPKjAx3rNNvVgm5q1iMbg+5
+ iM GnjY0nJxx60vCg7uv8vakCZBCg9eM9vam2xqKd7jesgUY+tSqm0gZKkN/OmquJV5+cE1MQS
+ MBWIB 5x3o5ul7FbpxFO8QFRjcDgEDFTAd8980i8QscHr370oYttIwfUY6VUddzLWyViQEuwcL
+ x0x71MIg sg3NhvQVAMEDBBqYN+93MpB6VN0ti32RIVO9FXovBNOZk8rvjOajDHL4VmPfnpQAo
+ CyNknqc0Nu+ hDTtqA2vIxHy9+e9SM7PGGQY9vaoWc7vkA2njHpT2J4weh4IpN6mjSVhCwNtzk
+ c8imhwW5yaeXV0 wfvHgimAgwbOMnnPpSdiXqtRjfMSNw44ppXBIII4AP1p3zFCSm0n1poAdwV
+ JIHv1pxTfUUpRURjf MgGCec5HpTOOOScHpUw+U9Rnp9aiI+bB45qvIhNNJiEjzCOCc81XIJGS
+ cKDxVlgmCCGwTkmmEHYT jgnkGpSHpazI2PAZjls5pnU4XIyM89qlbaoye3603PzBR6Von0BbX
+ IzGVjB3fMcd6a6Ig3KCSelS KzZG5lJ9AKYzPvIUA49qmfNcabvZkRVmPrxVQgnGTsA447fWrW
+ 87sdW9B6VC5UA9s9c1pG6bVimn flRXO7zc8kAdKjdQ/BwQRwakKbpAobnvzUZyCNvPH5Vb1ZF
+ 7PzKpxxuBHWqMwMaHaR16H0q6yZbh sZHWqskZLbWHzMRg1DXW44pLR9ShKm0jZjOOAPTvUGxV
+ XGc8cZPNaJUeaQB8o79aqsuCx2nJOR/9 al7Rtb6jnJJ2RU2ZTpxVTb5bHGSxIAJq6cknquByP
+ eoTBlGG4jnijp7zMltuVCoZs45BxkHFMZSk m3ORjmrAjw4Qk8rwfemiP5sSAkY4x60pWS3NFN
+ dWRk7uCNvYkDpQFMbcuNwbn3pxXClgSQH55qRg JFXbg85xRaL3FvsiJRuGQcDviggAHoV60rB
+ vNwcbc9vamlDjCnIIyfarml1JnFt3RWLF5gwUehpr Iw+7gZ7kVO+PLHzDcBjAqEqWAUsQuKUo
+ p67B73QpNgxnI46E1TYARu4+bB6E81fZFIAzuJ549qqS EFCF7cHjpVJLboS+YzphnG4jBPQCq
+ sh4I5znn/CtB9rjGMcdfWqZCGFjyR156k0TjJx2L9pFnGxq fMyh3DoWzmr6HcQQQFAwR3Bquh
+ CgkJtbPSrCcHOzAPIFOfvPbQlwdlbQWPltpzkDPPerQ2uQO55x moFyowV+dhj6CrMZBTGVz6i
+ m77obTTv1HoFHyqMnv3qUR9DuBA6rimffjXt1JPSpVQqc57c81DXN G97DSVrtEyMQqEkKu3nj
+ vUyguQeD6moE6fPkZXFW40AT7/A7DvUyShHmsTzpeoLndllZgep9Kuxf fycBTxj1qJcCIY6Ed
+ KtoFKHbhmBHAosmjWUls0WQAYuAQc4q8v8Aqxz04J/CqcI2yNuGVbnirMfz L8wwrGny+RC3Vn
+ oWoyAkec/1FWdzcEDI6Zx0quNm8YVsgY61ZjdmBjYqFz6cmla3vA9XsWBtaPqd 3bmgEp83U1G
+ pAZeQewFKchGJKjFXzW6jhF7E4O0DcAR6YpxfdI+evrUIztyD9OetPjIYnOBjrxWc 5ajhuy4j
+ qVPTcKC/Izg8c4qsjEYHr1yKnj3CbgruPXNTFxTuE421uSGTbGxOcZwR0pQ7bgzfIoGe e9MRC
+ 7fMAFJ5Bp7YRxhhwMYNXzK7FzReg7ftckc5OPrTxnhR/EC2KRM8Zwdwz0xUyBAoAB3j37VL 5V
+ uipTfzHxgkK2GxjHWrKLulYMCcjiohyAEBwD1qZQwAOwnI5GeRSbbegJ29SzHtwOhHtU652lhk
+ A8CoUVi+1Qx4GKsxAlCjL3wKm7QNO5KNyE4yccE1MBhF4OGODxzSLtzhfQk89TU6nCrlcccE0+
+ Zl uOl7CkDYAuOOB60zHzgsCMDGalx3GOCOaNoJ6d+lUpaWIWzGlQ2WRgcDr6VAIv3zn7pz909
+ asNhV AAw3tSEjILAsfSqvJBzS2uQgLyGbBznrSgENkfTmnhwWOFGW9qMZbcSOOwqeWW7NNle4
+ nzHqvfqK lBwSCc5NICVQkkFhxSkAkEDnpUu7Rj1JFEag4ySQD1oJONvyqTzigY243DGfTrSg5
+ 5OA3ao6XLjo rpEgwgCPtIJzkdqewPOc7ycDPtURIJyMA+lAJ2A9fTmjVoTpteQ9tyq2Dg/zpU
+ IOM8nv6Co2bCqN wIHWmFsSkLycVbV1YqK5r3JgMHJ4BPp1pWkUbcMMDrxUCsW65GKU/KNhIPv
+ ik4rqDi21Zkm8M5bg c0ib/M3ZGMYxTVwEw2cdqeWOMEZHqO1K6UtBuTfxEZb5iSdvfB70hJ3c
+ MOOOO9KQpTK85PNLwW2j gHkE0732I0TuxXOFUNgjPaowuG9QelBY7SFBLHoKZLuZRs3Z6U1Cx
+ UJ3W+4b2LfMDjPHsKc2S3yq eOtKuSfmUjaMGmM4XLhjz0FK6bIabdyPq3HU8nNBC4BwST6dqX
+ n5W9RSbcgNjJIwMHGKvbUf2tQY plQDxVc56qeTxxU7ECPbtwRxn1qAqWIw23mnF9w212GFSkY
+ cDJ796iZg7AYI7kVLkrGCxJOcYNVn G2HGCSD97NKMXJtsnrfqRsjLKCpGMdahYAZ67/6VZcFz
+ klRxjmomAyOo9CD1q4yktFuaOStoVZFz GTg9MjHpVcjMmCSvy4BNWWO5sjdjoQDVeQMMEqxI4
+ Jq0/PYmWjViswKqRkMw64qiwyuOcZ4z3q8c FsqGI/izUEqKHXnk9ABWMnrsTblVmUjtV+Qy54
+ PNV2V/KbBHtVtwTKOhUHHAqux2uu4jGeKuyd+4 4SkVfmyoztz1zUhB8wc4UDNPZVKlgcYH5VA
+ MqMhs/XuKHZ2Ha6GFS0yqxAXGSR3NIwJlBQYOMmpZ FJxnpmkUjadoOQehqua2qKsnoiMKqRtu
+ 3EgcEGmFxJz82QMHFTgATkHJ7gE9qCdqA4C4PTFDehjz cujK2Ar9Dnjj1qOUhRgnqRyKsSAZI
+ zyevtUDpiQK/OSM1EprqDty6FcqfNyD7/SqEjYkPOT0IFXZ AVZtp5J69uKrv5bFixPJ5x61p0
+ 7jgktbGcyAuD0x0xVZowzlOq+1XziOTP3htwRjoaqSkHkcYGM1 HLK4ubojkPvFSdoBOSas7AE
+ G0hhnINVQyliuGzjqDxU68lAXA44AFaJPe47qysTocN84wvYmpgBt +XrVc5zgncegx61OmTwS
+ OmD9aSuVyJa3LKKWVWI9gRUirhMkr1PB54qJcLgAE+ozTxh2ySAc0byu LVq0noSInO7D8HFXc
+ qrKuDuyfxqvgg4JHJ4xUi/NIm48jk570NXd29hP3tyyhOzcAF6EAjpV2I5l VhwCpJB61VjIyM
+ 9CfzFXEJyWGBk4A9KzS966QnGz9S4p3Jwd3Ye1PQlY2DfezkVXjOG5DAjjd2q2 CDyPmboT2NU
+ 48m5TdtCZJMKWB3ZGPpUgXMI2MRjjr1NV4353KoAqRcsSobGTnPvUweumg7u9yzuV IVJznNPV
+ wR94bD0JFVSdu0EhlBwaeJPkZgv0HYVnpzXKUmuhYXJlYKSBjIzUqs3mKmVAI5qgJDuL Drjmn
+ 7jhXJwCPTkVcXd2Bxv1NNJCi4Cgj37UAsxP971FUxk42tz2FWQcsDnaaizT0Iah0ZaB3oWd WJ
+ xnIPFSId4XYhZsc+xzVRSuOjYX361ZR/3gI4B9KqT8tRtcsdUWN37wg/fLZAP8qnwS2SSv4VWU
+ rHPl+hGAT0qwHYkuMYGOKrXroVzNapElvn5vfnPrVwN0KnnuPSq6BQ4Byccn2q0CPlLcA5/Cp5
+ rv QiW5OobOQTz29KtRYHBP3ujZqCLDtlQ2QOM1MgOz5x0PGKe+5SldpFsBTtwCOevapgmcr19
+ ahjIZ eFbC9h3qbpJ0OSPzqW+g1fqxBncV56/ypwIJUknOaQGTaQVBJ6cUuMR5wOOM4qXbqH2h
+ 8h/djODg 4x3pmSX6hR6kcUobcSCp68e9DcnJ4wO9XDXQE9NXqMCFSem007arjKsowOlCnEXBy
+ e3eg7SQccjj IqZKT6h7smOHC4PBPOaRi20fIVGOtPx8qgkHFBVi2T09qmLSdw5etyJC4TcQcZ
+ qYAFjgZPUUDqVw fpSjIO3+8OvrRJ3Fa6GthGVQNxx1FNb50IB255Apejlt2frScoMDBOemKd0
+ hpW1AYCjcDzySaXHz LkjIprPztJwAOKRQTk8nPr3pNuw3orpbgN3mfMOvHBoBfcegUHAzRk7t
+ vUA8HFRKWyQScn1quYnV u5M0jgHBBPXpTEOF+Y9cjFMwBwTlh70pY5zlcAdMUou1mSmuxIvTq
+ SM9u1OWQZIYYOOCahVwEzkf 7VIXDBmAyQcGm3HZlpq6uWc5XaSBgdqrlmLDaQe5UCm4IkHzA8
+ c0xxhmBb5s8e1NJb7mkZa+RYZm DYztOO9J95sFlA+lRo+Y8MAcjJ9qRc7gwzjHc9KOVcphysn
+ C4TBIJ6cVH0bdznpjNGcNjB/wppKs oKsAwoW4SWgz5wzEnoKbzuwSAByD9aduycAn+lNwfIO5
+ TnGAattpotJ7MhcsPQ9jx0ph3NCM7Tg4 HvTmHOPmI9B2NM+QykANjHek3Ym12J8ipuY5YdR61
+ XOCQcgDv7VY6jrtB65qu+ORxzyKT9NQd9iB yGZhk5A4A9ar7vMxnltozU7DJ3Y4Ze3aoSAIsj
+ vxmqjazuVFt6FR2YSbVBIIzxUBVjggexBFWzgI eRnHBqrsJhUcjPOfWiTe6DmuyqyEKxbJOeB
+ 3qFsHB2MMHknuasOSM5Ukg4TmoWGGIySOhyetOXMt yNempWPO5cYBppXC7QOVP5VI3DAAdev4
+ U1wGHOVLfeOajV69DRu6sR43HGfb6UwoVcZBwB1FThcM No3etRF3MhJVuTz9K0jonZkp6asGJ
+ 6gD61Ccs5DKT6e1WAGw2VyQeKaWGSp6gVN0tLApLsVnBZkI IL4IpoX5NxYFyp21MQS3GMdc1A
+ WLnHAYfnSvpfYznC+xA5xGobBJGRxVR24G5So7/Wr5Q7SrMAcd COao/el28HgHPrTg9BK1io4
+ VmByCx5J7VUkVckHOPbvV9ioUjgLyBntVNvv4PHcVd3fmKsrHCs4A JzgZ/WrMeUAYENniqabV
+ y+dw6gVZQltwyFOKpT1aREoO1uxZGS2cFsnp6VaHXd2FV0w0KnOCDzip kxkgnPpUxipFddSwv
+ LbtrKNufxqwpRh3BPP1NV494Qcg/hUi4Dlic44wDTabauO/ctIMoRjkdR70 DktuBJ2kU2Mkjd
+ jaAck+9ShxtJ2nGaiKd9iabd9CaD5XxlSFOBmrkZUzAnIxyeaqJgK2whcc5Izi rS+WyI/8Q4I
+ FTK6Zc1zKz3L4KKp3MuC1OQpuPPHb1NVlEXKHnHfPalVUMm4E+mKrlb6kq0VroW1K hyACMjgV
+ JvZSMkZA9Kq4c5JcZB5x3qfefLBGCp7YqOZCV97DkcEAPkjrkU7IIJw3QnGagLjACgk9 8elER
+ z8vTHB5qancqK5ndE8TAncrY453U9STMy9eeKqqymTAbkA4GamRmEgUZ6c+1S79zVxu9S+j EA
+ MNp4yTUyliqsDwRVRGJj3YwmfwqxG6s+3BCf1pRm9yHpsifB3evParablTIxgjBz2qoGw+CDx3
+ NTxk4OMkHsa0c+rFzXLgctDtYAkdxU6nJJ45HPtVRFQg5OCe2atg7WPBA71CcFsOL5XoWULMdp
+ Gc 9cHrVtSTyV9s+lUo5GVCzHHt6VajYSBSSVHrn3rSLb2QSve7LaEqCBkHpmrqBnChuD1qivM
+ pI5bv zVlM7QxbDZwTUyfUvR77l0ElxnoBjjvSsZQpyQAvbFQopwDv5I4HpVgIOm73+tVFRQnK
+ 2lwDOQu4 HI6gdxT+DyuWA5poOMNuDMBgAVIMNICflUjpWc22tQe1xSR8u0Y96XaQVx827nFRq
+ ylM5LY6c9KA SGJXp/DSSsKy3Q8d/lxzxgUhQEv/AHjjimCbkECpl4O853N29KPeiXyu2ogwSM
+ UpyJNrEEegphwT nawPQDNPUuGDHAOeuOtCVtSLu+40BSm3BGCSDSZO7g5OOfanNnftA3c9R0o
+ OMt8vQYzVPcL3XcEC 9W4PrjioyzHKtnAPBFPCj7rHr71ExypAPvRC8gTtLVXHMGCbmXcN/FRj
+ 7/3sAngUMSyKCTtHPB61 GrfvcnIB9fWlumXyt6Cl8ZCgkg4HvQCGIDDoeTmmM2COmF60ze2d4
+ 6UPVE8rS1JSwK8Yz3JoJ2jI PamEfPnIwByaVFCpkHdgnrTjZLUNtRCyliBkg9hT1wApXHI5qM
+ AGZmORTcAcjI9OetVdNBKVlZD2 bDdB1496UMG6kEDvQHyvPODzx2pnmDAIHOKSetlqTZtbD94
+ 4BXHbPrTgxZsggKBgjFV925+AQONw PWpMp3DdOvrVyaTVg9nJLUkZcg5fIJ4+lIGb5sLxnGaY
+ 7sQMD5T3xSKxZckMOefShXaHeyuLnEpU jk8k0g3k/eGMU0yKxwMjPIJqHe3lY/DP8qOVvoFlL
+ R6ExJD5TaOMHioWIDLgjOMU4EBipbf6ketR yKu4NtIbriohDUGmpWSGEkqVZgSOtQORuAU4PY
+ VK23ZuIYHBzUJx5anBGRyaq73CU2RFzu29s8kd 6rktjpgZqd3BO0YA3Yz61DKWCAYAI5px7Eq
+ pJ+RHKoVMnG4DkVUkOIQR261MzfvWOC2Tk88VH+7U 53cEcjvTk+hUYpLUiYq0obepxwBVZ2Bc
+ hlzj0qaTBwwBHQAmoHUMc9+MAGs7q7uJWIcrszg49M00 kH72eRz7VMyAOFHT161C3DgkgjIAq
+ opJ3KcvdtEQBOmcHd601lRZGwe2BmnkHeTzuBz9aQkSOR1G 0+1PmSepOuxGM5x3HvUL5DtgDI
+ +YHHWrGQkJbGD71Fu3tvAbrg47U4xdr20HKKWr0IZMiMltxBPH PIpgUKpZc8HP1FPk3FVCklS
+ agAMjKORj360ON1uRb3dxj/MCWIAJ4XviqzIFlPUMOOv6VYZguAyM AD96q5ZndiQpHUcc+9Uk
+ 76E3sUpN2/bwRnioZVxl3bPGAF71ZfiWQH5cEYPYmqsvzYK9O496HC5b fVs84R2AYbcYOFwOt
+ XI2yyMM4Ixu9aqLtL71O4dMmrkbjcowvfpTSM38VlqWo/uBSWUE8GrUYVYz 13AcelVY8BWx85
+ x8oqePJwSu0AHH0qlrpcat1LYHyqADgHjmphjaQeR3xwahRlEOcHOelPicknO3 g4pxTWpa12R
+ cGQcDC80qsFnJwORxTIySoB6E8kdqmVdvyfKMEjLd6ykv5jO6UtSRPM2nbgKfUVMv yocHAzjJ
+ FQJ8seSx9zUyNubJ5XPSqjF9Byk2ix0ZmXG3PrVpWROSBheCfU1XQuWZSVUDse9SDIJY gHIII
+ Hb0rKXM3YrSyvuKwypKZVsjK+tSOSFyGyR1wOlKq/KRnnHBoEacqWJPpnpU86e41JOOpHuV UG
+ 0Zz0yakRgRjODnJHemupOdowMcH3pEG6QgZB6YNNxTSuyNL7kvfK4BHUkVYiO5m3lcD8KhWPLg
+ kZ9hVlQHKlcHPUd6hJPRG0dOpImAdgJXsQasxjawAGMnkGq6lVnJxnnH0q3zkjPfGarpsRK6aT
+ ZN jhufoT0p6SNtwe3GcVCqknaCCAM4qYcKwzuz0AoXK99y5rSxbUq8jZbGDkVYT98nU7emapR
+ D5iww uF6N3q3CwEG0NnDU5abGMrpouZIk6ggdqtRsocgkbQetU+d+TgjHFW1I2ZI4OM02rW7F
+ u76FtHUZ AxgHHH86tR4xk8gjNUozk/KeM81YXk/Id3baPSlyrqLmaL4KhAnDDqMVIpz8wByD6
+ 1TUsspzjHGB irHKwBjkY5PpSa6I1cLJXe5L0bOQAO38qcSdyjrtPJxUR8tlC5OCMHB704AZXL
+ EgHnnvT6ahovUc NoZiCMN93NOVy0Q2j5sc0HhBgZOO3egHK4zjNRZ9NQUtbsXy1IOVx2z2Bpx
+ YiM45IOKZvJbB4GOD mlj5AJbJx0Bq9be8TNO97kjcw5CkECpVKeWrMGJpMAZIIwRSbcBiTkbe
+ 3SpWqNJO6sKANrMemaib 3O0HvmnAtnnOBxStngEgVPK76C5bakIyvzDP3T15pBhgMEBunNLkg
+ YKlU7saGIVc8Z6gVdnuydLX IwSHbcQRTWcA4bkAce9O6zcDJpSMYbIwexHUVOtx8sXKxGCDtI
+ AzjPPvTGxtH97HSrG1WTnqTyem KgUDcSwJYHr2qU3dg1Faobt/dkK2455poyJFye3SnbSJSRy
+ SM8dKMDhwwIwQRWkX3JlorDRsaQBm IGOcGmlSAQvOemKGCbG2LknjOaQBgpGeBjH+FCknqNKy
+ 0Yi/LhS3Q8GpG7kYAHQ0w5CnC5oPmEjI CjuSOKaSbuym2noxQABnrntUaSFUwcjnBzSkgnCk4
+ xnPpSAkldwHQ9qclbSxMpRa11JztI+U9+/r TWwS3BHPTPeoySytIBkdsUwlSmWbIx196m7urF
+ RejfQA2JFO0/WnbhkgLgYz7ZpOkQbjpjJ70xiG CjPA5JrR8vVC01Y8bcBdrHb6Hk1GTtbC88c
+ k9qeCQTg9fX1qNmEfmF1znHA71mnYzbTZE+OVyTnt moWYlAQOg4FSN9/c+cnOMdqhyuOWyQO1
+ XZNjjdvQY3IC7MN14qFiRIBgZxzUhwW3Bvm9PWoiSykA c5wKlvUbkra7EGQf4TkDFQE4dhlcH
+ n8KmLDldrKCeCTVZnLYLHg8VTTew4yitRsg+UbTu9PYmo3A DKBj1OKexAcEHPXP0pGZnjGAAo
+ GCSOtDctmRyIiJXlSDuzzjtSPFkDq2R1HSl5ySwJHTI/lQ27dw VAz0PahSl00HGTjezIG/1QQ
+ NkmmbFVjyW7A1Lg7MdRnP0qPYCHCkqpbrnpTcrIUX2InG6Tg4cdc9 KEyqjcCpPB96kbAcgr0H
+ B9aYR+7BwxGM4pSldFtXepAWKv1xlc4qAtnayDDemanckS/dzjp9KiZQ qgMTg+ntVJkVHFWTd
+ iuQxQn5iOpx2qB8/MAwBY9D1/CpnPyl92Ez09aquTztb/cNJe90DlS1uR5U qM5J7+1Z5YbiGB
+ 9jVuRm5jUZ+YZPr61TZAFDbScngD0pyavYSTtc87ixsQKeec1bGFkAABHXFVVE eGVD1PAHarE
+ IXzVdcjj5iTVuV7a3Q4zsrXL0ZGwFR0PHtVhRluCc5yQD2qqpyfkOBnknvVuJwpAB DNmjmdrk
+ pxT0JwvzblBOexqwuSuCAORg1GxYxZACkHrUiBccg8UuZ213CKb1J4wc7WPy+pHWpesi gnAx3
+ 7mqyHMyhmyAMfWrAwYgwHI9KLNOzHLe5MpZiFA2/L0I6VMpfy92Ax74qFEK3GSTyKl2soAG QW
+ Hc0khtxvYsfwDOemCfepg42luhJxk1AjbSdxUknke9TKA2A3A5ODWeq0Y07bCgsfunJ9RUqFto
+ wQSSckimxhAxxuAx1oVgZAT8v8PNOydgt0SFCfMRlyoGSe1SAbWUg7gOtOU5+RjjJ/SpG3kHao
+ Ax 6VEm7ibb0sEe5pl9WP6VPG6rMAOQM9KbhgDgcjgZFS42MQMZzSdt0OmlLRk6KNnbGD1qfLG
+ PCkHA HBqBAzIvb1qwF4AXk45xTstFcTjrrqSKuCOeCcilCsJFJI46cdRSD7ucccZqQuCOCMk9
+ xT1T0Qcz Ww/7pJDAsTVoEBME8DgEVAGAO9zyFySasRhfL6gA9aTk1rYuMu5YTaxXBx3ye9Wt2
+ EUDOD1NVkOY 0Cge9WAm9VVux4NTz2SbBSu0pFuNj5pXv296mVtrj5s8cYqpGnIOcsTwAasoGO
+ 1gvfJ47VpHlLdk X42/ixn6mp9w5YHPYiqiq52v0XH51KuTwpyAMfWhW2M5RVxYx84fIwRwDVl
+ eFAAzk5qNUBReMEDF OG7ewOQc5z2oqT1Vyp3k7IcMSDAzx+pp5RgrOoBbHI9cVEnXjIXNWTnp
+ 0PbNEk4kt9GRkBsDjjqO 9TZ4Hy9+/eoVADswyTmrC/NtJBA7kdqzfmXJJWHgfJ0Aye/anAMmV
+ fBBHQd6a2FOSS3vS9cAKWAH WoSuHKnsxrcIOABngnvTAGLDPzZPb0qXAaPAwwz1xSqsm8sF2g
+ DtWnoKM+UY4zDuOcg4AqJgzDJA Crz05qwpyQGIHHpUZ3BieAOmCKIprcIbtkeDuBxgdeRTScg
+ 579KmGSF/rTHUjAGCR6UpJXHFvqQy sVxgY4wajA3YBOPpUx5cAjnsKT58j5Rj6U0tBOViA/cA
+ 2sB2+lLtJ3K65QnjHepmXbGV5bPSohu2 YY5XOFIq17y2Ji7bETDkAYVccEimlWEYCjJBqT5WB
+ G7GTwaQ/e8vuO9Zv3XsU5PsNziIE5zmo9+S 3JxnkUuG3AE5UnimswHyMMA9CKtJkpxTIyq/L8
+ 56dzTkILfN8x6AU18bhyO/5Uwbig5ByOaJ2a3N LpbEzPhBheD61EwJwSvy5xigMxIUMoXqCaY
+ pVW+ZiRjjB604NWtYjl0JQ5CFcj5egIpuAYznAx2P Wm5J3E8YOM0EER5B+b0qWS7XGFxtLc4J
+ xj0puQckndmlCtyTnHVhTAp2sBjHqa0TQ1roGVMuVJK+ lQyJG+4rzxzg0YAPI4J4NNYDeckjn
+ J96lysEbt77ERDBVJ2kN7VAygMfmIbPNSSBmjyT3zxUZXA4 OeRyfemtdWJu6K8pG3uSeeDUWc
+ lQpUkL1x0qRvlySRuP3jUBKHAGAGPrUt23GrdCJmcPuK9BgDFO WQNER8qjOeaR/vZznj0/Wq+
+ D5oKk4xkVbUXZFOKepIW+YgnHtTCW3HjoKUDdzjnuKQLiQYbBXjBo uuUTmrWGniMdeTk+9MJ4
+ OMnNSjHkr8pHXgnkVEWO7GKaV9h0+wmNqKW6kdTTONjYJAx1PQU4McKv 3hg5FI20dTgHsam7u
+ ZXalZlUsSm3BbnOc9qZIpB2McjBqVyQ3TAH3ahYhw5LY+tDjLmukO22hA4A jC5DA8darZzCVU
+ g4qZ/kUMMEHggVBjO48DPFVLSxMdXcpyttQ8nPt+tVXBK5ByoH61ckC7diqSPX PaqTDGRk4z0
+ 9qLrSxS+E873DDLjkHr61ZBAZTn0yBVNPMSLLkMw68VbQLnewbLeh9KttWeu5MlFL YtxZMf8A
+ cye9XE27lLEDA7VWAX95huBg/jVhcmXPDLu6+lZX1Ha6si+CGfIzsPr61KhYgchWxjFV k++Cc
+ jP6VYUETbu2Oc09X1M9k0TbNhwPvZ/Onpy5Cgpz0NMT95yxAAGOalj25JXcwzyaqTdrGu6e pY
+ yWPXHTBqQAsm7dkZOKQGP+LIAqQhfLYLu3LgVClZp2JtrqIiuYyM5I6mpSVZGL5OBxikBwxUL1
+ pGJUggZBGD35pNu+ptT31LDBBIGbcvy9/wCVOxmJeCfm5FNAKSGRnVs44IqcDLqVOBu5FHM1pc
+ mT UXYWJW8ggkZB+WpxH8oIz7/X0pvUlcEYPapVA3kFuOg96h3uKKbTuKu8ybenPBqyPmZecHG
+ fwFRK p8sgDBLcH1qwEIwTwONpppsG0x6lQOCORkj0qVeUBGTnsOtIEyoUDgdDUu0cc7ferc4/
+ ChSn1uOU MMhuB6HqKcqgHBJPNCr8ud2cjJPvUrR4iXJ5HXFTKdnbuNSkxVCiFSTu9vSpxgfNn
+ BBweKhjDNE4 4GSCPcVJgBSCQ+DzSTsF3HZlhJdhK5VgQSMCpkyQobrgc+9VyoI3cg8AAVYi++
+ RgMq9xSvFJ2RSU Wty4vEn38EDr71bUs6hQSQOpqmoBw4PzA4YZq0GGFVSPT/8AXTitBa6WLPI
+ UnPBqwDsKFSpK9cVX TOFB5wKlVl8s4GT0U+9PltoNp2SLOTuPoTjpRywPPfrUKu2BgEjOalU/
+ Jg/LzjFTblKcZfMmxggE fMOTin7v3hAy2T+VIuGVW3bh6ipo1IBLAZxwacprRii0tGhgzgjHO
+ 4U8u+WG3cM/dWl24+Y04ZKc MBkVDs9UFpIcqqFBLKWPYnpinDIbbuyG9KaFyvBUHGfpT0IT5g
+ u4nsaNWOT6CEqVA6Y7CmsHLDaa njjDOcgHnkCmvHj5lO0981UJpj92/L37jX5iwAcetMVJATu
+ +nSnlmA5KrkdMdabglQRyP4setONl qOV4dhpyOMd/yphA5K8MDx78VO5UJnPzMckZqA8rnBAP
+ SktRNcqIlU4GcjnrT2+UsecZ4NLtHmIr HaOetOCsVyQdopylsTe0tSPBJAOGGDUDcr2AHarB7
+ YOc9hUfJcgEKO5I71PNbcSTTuQNjaNqkf7W KjOBOSzAqR+dSSKVLbRkgjimsOWPdTjGKZUOVO
+ 7GMdx+XqOeahLDOD97vmpNoL8sOnzVD97cMDOe TVWSiHKlsN35KnaRtGMnpTc8sScZ6cVL90f
+ ezngccVFsHkkNnJPrUc0dWyelkIfkUMRz0znpUZ3Z P8QJ7dqe2ApVidh6+1R4USPubGcc1am7
+ rqSko6XBV+TLHgHtQeMlckgfMc0mVDE8njof0pSNifK2 T/EAaTlc0vZaiFiQo6Meuab8vz8+m
+ OafuUkZ4brVZztAJHQYFCvs0TFJ6j5JFEeGXnOD61DLJhQM Yz09hTmysW7GTjnio2BJBOMnnG
+ OlOLsEbbkLMyhj2A/WomJIU4PQcVLksXyNvOCCKrmTpubsCcUW bb6icbIhD/vgS2QTnHrUTcS
+ c4Ck8EipJGDSbeAP61AVyqqwPc7aqST0M5JrXYhYsVJYgYPXFKxOz jGGFMJCyDP3M8j09ajZg
+ pDLz754FG0i0uVXHKF3jduyDliDTiwMvUDPTNR5bJLDHYUAZTLYyD0FW pNi57eg4l/MHQL61E
+ 5bIAHyjnipC22M54FBcCQggEgUlUaaVgTTVkMVnk5VMHPTHNMfJX7w3HrxT s/6QCFJ9SDS9mA
+ AIzxmolP3hSdtCsC7Lt28k5we1QSMPL5UlurAVJJncSAxHIAHeoDgDoTxVx01K dmiLg78gjJy
+ BVNiRJlgd3UDPSrbLsUEA8jpmqLuASwDHI70Xv0IptJtdCCRz5uw4UpyWHQ1TkGSC HBLA5C+l
+ XsgIzMADjvWax3YUIw56miM0nsXDV3jsefgsdyqA2CMmrYIJBQ9OoPrVE8bemDx8tWou GYEHn
+ APtVSXKm0ZO+7Lkb87cjsT71fUdSCAx5wRVJFXaB/FjrVuHzDArEZOMKfWlOF2pJmr6P8y/ CM
+ k5G4ntUw7gg5OKrRsGbK/fU5zVsllJOMZpRSvqZuVxdoB2qee2R1q1Fnapwc96gQ9CQeCfxqVS
+ ehO3PSrUtGW4uSLIO1/mUN6CpF3NMyg7ecmokGIyZDnI5PvU+R5KgZzt59aye+w3Lp3H4AgHyN
+ vI 496OhRcEHoc+tIUyuDkDqM9qfGr/ADcBiT37U6clcUb8trljaXkYsjEHgVJGCMEABc8imAk
+ 8dV9q mCfLwGU+9EovUHK2iJV2gSEg5zzzUyqiDPUkcVCnO5SQRjJqUZDoPLPy8DIrNRaZpfrc
+ kxu43fLn irURJTDjPcCmooDcYbdzUyFVHGS2cE0m76WJVncevy52thsd6kT5W5xkjqaAuHI6g
+ 9falLELgYLd qqEuZWQpaj8YQ/KRxgUuFCjG4kfeye9NXeXxnJ6gEdalDqwwQWOMDFDlYfNdWF
+ QcKSpBPGc0+NC6 ttZeeo9KaC2wK3GetKMK+A4I9Kh33Qoxdrkq7gy57DOfWrKoFAIJBPqaqDI
+ GMHaauhFIyT8w6iql JrdFyjH0J02qSeemTzVuL7o+6Sc4/wAKpKMsArAnuvtVwMoIO3kdqfK7
+ DUL6J2LYKiNQCUYdQak4 bIVl3dsVCq7hllKn1PvU8S+UVbaWAGMUaJeZLvF6EyAiLYzADvx3q
+ RQ5Vdy7sDkAVBltxYLu5B9a urnduHLEdBScrPUavFkijg49cY9KeciPackn3pi7mXGw89frUy
+ 5ITIPHU0l7u4pNSWgg2hQvJ5pP 48EEc5Ap5X5/lIOeRUjACIc8HuaTbsKLaV7jVXqcc5wBU2H
+ BALIGbtiq4DBCSAQORzT18wgMWXP0 5FO19bml2KU2S7MnB64NOHQgAbS2eaaH/eZyC+O/ak3M
+ 2FwPU4FJvUqbskrgAPNy2ScVLujSMdTn oO31qJQyynOCMc5605l6HJOeAPaok13M5STdhPmbI
+ KgDPWmncI8feHsKk3nagTHTkmo3yF3D8QKa auJybeoE7iWyDTSV8gZbOcZA9akDAgnYQ2PmNR
+ Md6gEr1p7ly9NBhUFyfmGcVWJAdN3G5Sx9varT kAnad1QO6nICgYwCTVQeu1xOV9LXRA25lDt
+ yQe1RcKflbLHn1qct+76dT2qry78HC4xnFO7e+xSl aOpICokwcEc9BUPl7W4PGM5zS5AJCtjt
+ zSFl3lmPTr2FKO9kzNq5Ex2oFTO71J4NRlgX5baQ2SKl b7vp+FRyDcAcgYHJIpy8h82uhG+Sv
+ Xv+dIMrIQenFOJPlhQM49RmmseORgk5B9KTTaDV3EO7Chuu MZHalAKklRnHQ0jOhHIYkYyaaA
+ AM5LZGeDxT3uNu0dR2CS2c5x26VAyjJGCRwMelTDduy+BG1RBR v45GeTnpSunsRGdncQ4VQoB
+ LBehNQMWdQVG3Pb0qRwDyxII6EVC5XYBuG4ngU0+ZBZXuyJziY9el VpCpi3A855qeRT5hySST
+ 1qCQgDYwwM9cVUddAT8yFyoj3kc54yeoqq0iAfezj3qZshcHHI4qux3D sW6dKpIm1yLPRTkA5
+ xmlfDRDhT601gUTaTvXoAOpNRD/AFIYqwGfm56VN0nqU+e+iHdQGyMU9Xyh ABHPU1CcrMQeRn
+ IPajcxK7gADyMd6q/NuOUko7DiwAAI5I70mSI0zxnjB60qYxjGD15pA+ZMMVPH 5UOavawlG+o
+ 8sBCdqncO/vTH3gglgvHUU1nGNwJb6Um/12kHqTWV12FJtLRaCZOAVB5PXqKrswGA e/A4qRid
+ pAHocCq8m4nkAHvmtORNh53IflDFdxyF71Ucose7nkcVO/31BBBJqCVVI2Kc+nvRdpak ucb7l
+ Vy5baBkd8VRlYHhvlIORirjMSwAypA6mqLsvmY43E8H0pWQk9Tz8KpjJDFgO3pVqHAtx8pL E5
+ BzUChIpujONw4FW12F8E4I4rZWWjRKqPlS3LaffXH3ic5q1HzGrfN16dhVKHkxkZy3I5rSjc4J
+ I4J5A7VHLJbMq6jqSqQANox6+1XomDIN3JAPPUVUTmRQoAJHQirCLhlGCAOtFr+opJPUlBUqrD
+ Ab r7VYXPDsASTnj2qCM/OwwAM8ZGashQ5BcgqAfu+tN8yfkaaLUdGHkUZxnGasqo2jLbiQcKO
+ tRKmR hRgYJ68inqSsiY+7twKE+bWxklfW5YjJ+VcEt/dNTKMIG3Luzk8dPaoVBV+Dn196lUDa
+ 3t/D9KV0 nojWy2JMDbyQzHONtTooG4knHHNQJ83JUDPIOKtpvEI3Lyeg/pR0stxxajoJySxwT
+ zjIq1FxKuQe mMGoUwQepOMfSnqCZPXuSKmWq1Y3YljO6VVIKnGB9KtooE45xkY57VXUkyLkj7
+ tWgcle+BzUXtsT JvZDt+JTnJGe1TrzGVAJXvnqKrZ6dAOpzT45SBuyDn06VVna6C2mhOA20FT
+ vA9OopSxVidnBHGO9 RlnKrg4PAp+T0JyAODjrSk4p6iV7oAflUkdD3NTHbkA9AB0FRBXJUYYn
+ HFSP9xF3Ddijmje472ej JshpAoI2jgipRu3KVyQDzVSMb1O1stnJJqzGxKk5xxwaUk7jcGti0
+ rLn7uCOM1ZyXG48jPFUlYlF Lde4Aq2kgEcfqRyKIxafcIt3ukWs7Y8iTI3DrVtQfmzzz1qih4
+ AwMdR71dDkNwcelKo5dR2luiwM LwBxjgk1OnyKQoJPc5qIEFACBjP409VyMgj3oik9bDb93sX
+ EwARzxwOaUfK5xkIetRxklxjr+hqT d8w6An1ovyuxLbt5D9+F6cdD9KVgNw3nGRkc05mwoPyk
+ 49Ka+PL+YZ44OKEwjN20QDiU+XkjPc9a d8y5bB3E0ijcvAKnGeOhoEjPnkL+FQm3ctvqG1DI2
+ 44yOMUb1BAGSSOQO1DGMg8nIOevWmgHYflx 82QfarUrIIO6Ji29BjAwcc+lDEeQCOe4qBR+/w
+ C4X1p+cuMlR7VD3FyNvUXdhSPvetB3CPkYY8ke lIWZlzlR+HWmM2VGQSc4x7U1eW5Suh7PkAA
+ 84wfeo88KBgtio2YuxXBPTBpWxwOVApyVlqLlVtRj MzEHG1c1G2OR8pB/SnM/zYbkED8KjYnb
+ kcjuaq7W+hU1MhLgkgnA7ZFRMyD937Zp8o7gYOM4JppC qSxxnGckcVNnYhxttqRA5k6gEdc0O
+ +EVtpIPX2prHKliQD14FIZCUyFHsDVKydxxetxh6sXIOeQB 2pn8POQemeooOGl3g4bFMBONzZ
+ HfHpmktdWKT5XYT5WRc5B9QakPEHPXvTHIkIKnnoP60gLNuwVJ zTTuKb2YnO3HGO9KcKByOBk
+ H1qPc3CjB5546UbS7ZzznI+lVJdxTaaJWc/LyvTn2qsTjncCM9hUj KB909ByM1GwG5iAC23JW
+ iDgtCIciegh5UAj+HOf8arSKoZT0zz9KezNtzjaCBkU1pQFJzyOoHaqb lH4TTkb0WxGzNhQAC
+ MZ5qkfkQ5+YZ4PrU5kZyw+ZT6mqrnaFUnJ5zU6MXLb1GM5zlVLehqEswTgd uuOKeS6ttGCeB0
+ qs7Yf7rZ579az0voC0VmhpYEEpyAc47ioeWYgA46nmnOxDKyjjZ27mmBSGyCCc c4q5WWw7voR
+ lHKgHAyN2acmQoO7JOce1NO5txPUnJA9qe7jyVClSx7DtTdSTtZD57jix8tS5AJOS MUpaPYxC
+ nkY96rjO5QQWJ/KkYsEyeB3I70pQ6tEQsP6SgjB5GRS5bzmGR6jiogf3bHIB/XFMZ2ST KsOec
+ EVad2kiUkk2JJuaYOHGc9qa7Ycg84OCKc+DEoCkAdvX3qq0owxwPcGh2Za1WiB2ONxB3AcE 9q
+ ol9wH8QBzuFTOTI20KykcnP8qqMCAQflwOhppxvZkxtfXcYSqtnJYEdfT0qhNuMrbQCoHX1qy7
+ rsIRh1/Sq0j7V27i2eeB0NCdpbWEna7OBjLrcgyqT34q1GvKNtYk8cGq0QO/5zyw5J9Par8ZKQ
+ 4O OeFNaKKixSUlui1Ep+UYPX8h6VdiQjoG5PQ1SjOUwuR6k96vh2CrgjJ65FJyadkEd9CdOHH
+ zZPoO 1WFKYBBye9V1XEoKsGJ9quRgA7SoBx19aXNd6blOcbk65CBSQT16danwR8qg5POagVm2
+ qrLjaMA1 bQqqhiRzwKcrp6oIpLzQ7bv27Th8/NS/MzgNkbR9MilC7SCp5H86k2tkM4JyP1oTX
+ cjn7f8ABJUK mJwGABHyk09B8rBcnA596ZCRtA6sOOKl5Ac7eSeah26LUpSbRYiZSNjIV2jjNT
+ DhVPU44HpVYOS3 KHgdh14qbBaMGs0rajknFpskTJkPG0A9+9T4POM7SaroMRbG5HHNT7hyw3d
+ fWolZsaqST10JsgKN 3UcVKpCSYBPoc1WDYOeWBxUpbc20AMc9/Wrd4vTQcnZ2ROhyWx90HmhW
+ B42j1BHpTchF54Oe5pqn bHzwTVpXQ7LcslsJk5G09RSo75IBAye4qBWIX5sjihWxkEgqTkGs7
+ LZ7iastNS3ucyZJyMYGKAxW VlCsx3dahYgIdvXsKlUkrgHBbrSdkitbX2LEfJ+VgpI6Y61MgH
+ mEBlyBwPWqu4hl4yvX3qWJjjad pbGOByKLahHa5cQncp64HfvVxVBTIK4Pas9XPC5B9asoWUA
+ 44oS0ugvZdjQUgyEggLwB7VaQlgwO Ce+KqIyBgRk9yD0NWFbdHlQQSMginH3mRz3diynKEnJJ
+ 6j0qwvRMZyOoHeqiHG7nBzzmp0fadwPT pnvUSUraGlu7Lqv84HAOQcCpFTPLNli35VSUBRuOd
+ zcA5zVkNgYzk5GTWlraoU79CT+IqzAk+lOG DjPJHUCoULeYN3DE9COtSBwDsIAbqTRPunqTKo
+ 3uPBZQT37Ugww+Vc8cgUxm+fgHavSkLYOTgYqI pmlpJXH7gCFw24npSbgVIJOOn1phb5g4PX7
+ xNIpBlZ/4c4ApuKWqTJfw3bJozxtY5WkYgHK5Oema YDjIU8Z545oYFkUYJwucipi7SuxqUn6D
+ 95Em08EHnjv6Um853bScnr6U0H58nrjvSFvlBwVB7Vcm mKKtqOBbcCMNgc0yXnaPmzu9aQnK7
+ kYEHoaYzhXGWww6A0t3oHQa7EggjAA4Pf6UxORxuzt6mnkk RAZU46Co2ZSSQ4HajWzByfLYgl
+ B6McA9aYPvYGcEkYNSO4XGQSe1QNJlkHXvn1oTk42Y76CEcjJI I9aYx+ckEnjIx6U44bkHnJx
+ moJTtAABxkHNS7kryEcsWLAjoBjvSlMKScn3qMsN5zxk9D2pu5t5x 86YzxTk5dNAVO7JFPy9V
+ zt49qUYCYHPTkVAhJhztOfbtS5AMgXOd2atxSbQSbegrsAMLxzxmgFsj CnkZyD0PpTfTuBjJp
+ ruTFlfuk4oa6WFKAfMcsx9M8UwkdCc9uO9Mzt+UHqcZ9qiB2uTtNEvImEls h7FtoA5UdCB1qA
+ suWGC307VI0hOcjAYZzmq2TlyF6EfjSd+U1jGUU7sVmLP2UDnJFVnALYIJ460r 5KjqSfQVCzA
+ uCxGSOMdqmDa0Iv1GEnc2OhqBlHzbvl9z2pzOvGC27GDVc5GSx3Y4xVxWlx2k1dDM qBvHHPy8
+ 00u2SMKG3dMdKRSGB9M5xUJIOCTknk+xqFHmTZTk0tR2SsuQMAr1NIULOjA/MwzxUTZV 9ucZ7
+ ntR5gV9xJwea0SaWhE6bvpuSMWWTHLEelM8xS6gZzjBz3o85TICSMAHFRNIPLD8ccAYqEm9 ZI
+ E7rRakm4lmXCnnrURxj5/vZqMFcsTkEnkZxikkC79yt823nPNN6MnlvuSNJk8YHHB9aqM20tuO
+ 4Me3YCpN/wA7AgAYyc1XLsycYwy9SKuF9hW5XqhrFN+QTtHU5qvM3ICjJbgnOcUjEH5FPINRMQ
+ xA OVLcYB5qrK97jvHQgZPk7YI7dAaqsCsjgHB75q1ICq8ZfmqTjc53EqCKOfm0voEXdO7OOUj
+ zF+cE dh9KvoWZo2ypXb0xWdGSQPfjNXot4QKE4J3DNae0bCSdrMuwhS6hsEYyAK0Yvmj2kEkd
+ CKpxkM46 YI5AFXEUmIEMN4GM1EbvYybu9CULmJeAFBwR0NXN5BH8LDgk1XjVSSVyST8wzU0RG
+ 4koTim02+Yt O/QskZB2LtVj1z1qyhOeQox61XRsDplQcfn3qyAQxkwS3AI/rSumrMWpOQxLbg
+ Cc4BoX7+WcD19q i39CPqQaeOHPQkgcVlGLvfsEJ6PsTL94lTjI6irEbkPh0bb3NU1CrErZIP8
+ AFz3q0h3x8sc7uRVS lfRAn1LC8KDnHf6UsbjyyRwM/eqKM8HJOOQOakT5QCOVzihrqUlH5lkN
+ lV6EYORilUkgbSD9KgDB 3AY4bGB71LnfGAg24GBUxTiU5cr0Jy6CNskAjoM0oBOSGHTg1CcEB
+ iMPtAyacSQgZSG5xTdltcLt 6LQduywyS+DnOaejfvgx5zke1V1ZuQBk+1OVgHJUcAHNNyfUuN
+ +m5cJJZRjnufpSYJCsB823oKgD 5YkkA4596AxKHJwAO1TTk73YlK3Uubl8vkbGyAMmpI+ZgDk
+ ADHJqmADLw+H9D3qRXy4HIyOppyin 1J3TLSkh/vcY71KrfviRnnrz1qupDfNnvU6fMVGPmB7C
+ lJdy+ZblxXQsDjCscD2q4gG1MsDxjGf0 rOU4IBx1/KrcQIj5OBUPR2XUlzvHVl5MmTDcY6GrU
+ U3zFTngZGKoxv8Au++OhA61ZR8OuVx7049g 1toaMUihQzKST61JGCy7eAR0zVIM2Bt+bnGM1Y
+ DAxnIII75oQ4rtoXg2FI9B19KkjI8xx3H61VQq eTnb9alXaXwThQM5HehWdkNJJWJvNcxgsrA
+ 5wD6CnqGWQh+gXvUcZDKFB/E05WzknIIPQ1T0dloR a6FBUgDPvTyxzkABQOtQh1VjgcHOBSKw
+ 8woT9PpQrvVjlAnRlCHHzHdTSPkLcjB4/CmsF8vjOAOv rQFQIM7sEHPNZ8yvuCjyq7GrIS2Oz
+ HJp5kCH5mHFRLsU4zyBwfamsCAG3AnFaJxbsXzJsl+8MFgx BHSnbsSAEEjHGahRv3OSQWzk4p
+ u4MSec9AM1m1d3uNkiyElRwo7DFMO4jAIZsZBo6qG4zSAZdWJH XnFXzaaEuKirsRuyngk5zUT
+ OhdCFIwMZ9akdzvPTj261AwO08HcOnHFKyW+j9SkrLcj5YAqRjFMw pXcGAYHAqQ8n5QNpHFQk
+ FkBQAE8nNCm0gspDWUFm5xnmomBO7d0B59qlwA5Qg9Ofr7VCTtRiSfoe 9SpXVkyXroMccEHHT
+ J4pmQY1XcFwMk0u0MysTheuKiPRiULHGMA1XLrqxqSTSaAyeXFxjrT92Y2X bgdSR2qDBO4MNo
+ B4pwZmwQQvrx1FVaSsyZWtckLZTtx6VE4PlkZwueBipN4VT0AHTPpVZiruMucd cE4pRm7jWm4
+ 0nbCQxIPIFNZgB8xzwKQMecjg9CaiLDCknGOufSm5N9NAlKLsx+4spG4Edj6VE7bl U5LAc5X6
+ 0jN8+ARsx1A601G29BgHORUpNq4p8rSbImIR2AYgHqPSoWJ3YAPrT3YEMRjrmoCQS+GI JpXuh
+ +VyNiS/ODt4+tRZwgxktnk1IwYsF3Dbjiq0nB2c4BBq4S3QOXQa/CnjC54yOajI/d5AP5VI ZC
+ FcfeUtkH6VBJJIXDBTt9BUpyetiOW+vRDB8wCk5HXIppAMTBSODhaQvmQj7vFQOcgqeBjPHHPp
+ VR10RXs5Rt9485wSBgg85/nR5gORj5VqKNS0LKTgHpzSNjIXJVfX6UNO+opqO7HeYfMACk57+t
+ IW QuScHA7U3eABxyehqsTlAAGxuzk+lOe3mRTS5idpBtDYZc9agbhz1Cg8Uudm4daiZgAoYdO
+ BikuZ 7lp+RDkl8bSoHrUL7V2u2ckZ4PepGV+X5yemKruchQykHr7YrX7VhcuuhHIwzlTgexql
+ Ix2Nhhz0 Bq2xBBGRuPI4qhKxDk4yB2p00kyVHXU5WIPgA/Kd3TFacbHYM9CeMCscvm4AVmZFP
+ PbNaceMgsTg t096cIppSe4oQdveZfhU+YeeM8CrUf3mYfdPvVeIncdw4Pp2qyqho9xOPl49qa
+ 31B1d7F2LiIgkZ xjHerYOVAY4XntyKpL9xVzweCcd6tDccLwAG5JqJKzUuwKVtbEqn5gUxgcc
+ +lWI/u5LZ5yBnrVcB t+Bjk849KsIACUK4zycGkpNsi2t7DwckqMktzmnD5hnkc4564qLJLjgh
+ exFPBbaMnopyfeqcXpct Su/dHsSzsNwx64qxESyBcgKO4qqB8vUcDp3qdXAI4KkfeqbJ+Zb8y
+ yrNsYgfP7VOrYUBmJY/rVJW RQ5JIG4Y96lWQPGNnDdBnvUTve2we0didWywC7SM5b2NWFbMi/
+ 3vSqQLo42kBe4I5NO4JZt25uow ad76kc3NKzLgIIO7JK/ewabuwMgg5GcHtVbAC5IIGRg5608
+ Hk4H+9mk7l1Hd9hxyuMnGTz9alU4P tnJNV0O1/mDHJyfapI2UrlclT696mV2hy12J94BYYLEn
+ I9qkJTyzhtxJ6f1qtyZSHODnqKdgAk5z 7UJx0voJSTdkWS6hyQcfhT4h+9y2eDwKpqGExYsCM
+ 8CrCtgEEng9fU1F7PRluLtYthgpcjIOe9Tx bsh0OCfWqZYspPXBH4VYVzs+8oDD8jWqatohpO
+ yRfUlQTkAk4GatRnIznORgVnIExgszccc1Yhbk FidvQKDWTjzEWT2NKNmO4NxgdRVgHLrwTn0
+ qipWRv3bDGOc1aTy9u1m556U3ZO1hve5cUtuKqOCc VbVSAehPQ1TiK+UD2xVuMk9hgqKcm3r0
+ QStLoTJklSwzxjC1Lg7lAIVQOM1ArFMsMdOB7VIrgxqS ec8j0qk29hWcWTpkKMMB6e9SEneDk
+ HnBqEFdoK9hkCnZLLlVbJGcmm2+oJXWmhPG+ZmIC8c8iohg yjcBk9KcG2Rg8ZxyPSkDqcDgMe
+ pFTFNXaCKiODYO1jgLwR60KN8h+b5cZ+tMYswXaBz0NMLFc5Bc AYODilyaaGyjpZMmZflxwoH
+ eoxjaf4mB4pT+8AIOBtzg1AASCoO0g9SaairE+9Lcn2gcgH5l7dBT VZApbhiDjg0zls5bjouO
+ KamDn5WH9fepkronybJfMAk5+Yd81FuYEkHPPbpQW/esAMHbQMFkG5Sc Z4pOKaG1FbiYfYGYk
+ U08qPmKgDn2pWJVflHbpmoHLAAjPv71XvSe4K+iYhOGyOw6CkyMhiMEjqPW lXOct1DcZpjDL9
+ T1zUpp+odbXGM2wl1OXPvUBILIT09aectk4/D0prAbQOrY6elKLj1FfR3ISylT jJCjFRMGVXJ
+ OB1B9amcEJtUbsjJA9fSmHLR/Mp+lOUtdBR03GphHLHJZhjFNdnyNoAH0pGKonck/ 3jSO7Lyg
+ GAvI9qbb0E0ubUiZ8SHcSQTgYHFNJBBUsu7AIGKc3zbWUnGM/SqxY88jIPHHJzTSG7dx zNghi
+ eAOMDrUTsrSA/eHTA707dmM7uD0AqEKxXIXAB60PVXvYmLsrLccVUIpOc9jnioyYtuBk8fN z3
+ pxb5twO4jjHamEfeIGB/OhOyTuDhciZsqQoBNMJznO0euRTyPnycAZ60xuWAJGAfSnv0KurWKs
+ jFcYPA4zTGwTubn/ABqdii43Ju5/CoGBEXHXGcelSlfQr2t0QSMVGMAsB0qEO5UnIz6YqTlosD
+ rx zUMshUkDH9aqTSurERtuiOTb5YycMDjNV9xwTkccHFSuysfm7rkc4qH5TDwCCPyoVt2Cm3o
+ MGQD1 BPIJody7M2cLn86YzKYs8l88AGneYwjw6YHvROVlexXNqMZkYKqdcVG+WTb368GgqPu5
+ wB3qMD94 R3xkGtoqDs0wtZWuPATGMtk9CTTC43MAR+NGAB7fyqJt2PlGQeR71D1l7pDV72Gqj
+ LIdxyR0qJ2O MLgt/EfSnklfvZHrmoyDypXhl7VMoO+pm5JNMrsMxkrgtjvWZNkQspPzAf5NXi
+ eOAwYDnFUJs5Zc 5OevrW9JvpsXFOMrtHNwKAFBYMScjHetCF87Wbam0YOfSstFO7cSPp6VfVs
+ NgDdu5OPSs4qLd0Ja q5qxvldxwUzzVhY2Mqsp3DHOKrQqRlScjsPWrilhGQN3J/Orje/MiG0r
+ 8rLqgbQeQccg9jUiFjuG CTuAxUMZwuHwSefepkJDll4c0ScloKCstSVMA8ghgeecUoblMZwR6
+ 9aiAORgFjnluxp5faQGG054 PrSUXzaDdtEiZT8uPm5PQ9qkz8uN25h1+tRIMyckZzjJp7IpkL
+ Ek5ORipvFsttbk5kAx90NSugd9 24rzwPUU0FQG3dB1NM3dGB+mO9KnJ3skCT3uTO2U2EfKp6m
+ pgVUgJ1B4J71W3YOMFjn9KlKn76hv qe1Nyv5BBPUsB3Eg+RmKipN4+V8HHt2qDLBSQQSOpp4I
+ P8SjPNRFue5UoqLLDOcKu0AkdaaNzcEg rjFMUEDcpL8/L3NOyrEhmAA6g0pNJ3QLmXmKWY5+Y
+ eoxTg4C9Qfp61CVBG9enYCpDgKTtx9fypXY udOKDzB5I5781OHEjEoM88VWiKbyB+JNTK+0n5
+ MDoDVW622CKS0sS+ZsfdkYPQd6nV2JGcdPTqaq 7htUnle/t7ipVQkKwJ2rkY96W+5bk3HYvq3
+ yqdw3Z5WrMcnzdm4x0qjGNoBYjGeo71bDDIUfpURm m7WEloWlbDYxwO9SIwyrAH3qBSNp3ckH
+ oPWrMZ3rgYJBzVRnZbBbsi3HgkscYPAAq2iN8wAHHVjV FFZl5YDvirIBwu3K/Ng5NEn5iXxWu
+ aSsoVFBwvcCrKEAtnP0qggJjKnbkDOcdasoDsUg9PWnN3Wj HZbEjt/CDwecjtVlSBncPmA5NQ
+ BcFQVOegp4Y43ngHr7Uoy7FxkraEylcHHBzyDVne7TFVIA61VB woB4PBI9alz1ZelEo66slyb
+ RNht+5iMY4wKe+1o9xPscDqarA7WQYzxzz3pzEhwGUnjnFFpJlXF3 7DtByMjHrim7ShJHIJzz
+ 3oY7WG7oB6UhfAIyNmeDTadrIcJauw7cDxtJUDk/0qPy24xnceoPamBg rHJy3UUquTIxJx7+t
+ JOUdkEnLuOG3zfmDeoxSfLuY/NjPODTfMCyHnIIwaY2GYkZLEYIBoctrkPV 6inAYsMkAcjPNI
+ rKr+uO9NHQEEbv4hmgFsDcoGGyaHJNWKkiRmQrnkccGmE/KAOVApCQCoYgZ7Zq PI3YXcDnj2p
+ uy3Jd2tGDZGC2cHrn1pgYgZPrn1pc8sXwwzjHpUXykswOc9qS5Wxy0Qrk7QFYMSOv qaiJUD+8
+ 3c04hD1JJzxg9KRVz0IwTyPSiVSCTfYhy2ZDIu3ocE8ioy2EAY4APX3qRvl2AfMp61Vc HcB94
+ fw+1SrSdmXGLkxjjdIkhODjilIOCScHOPanHBAOctTWweeDx+taXb2JmrvcR8KjBcg9OarF WB
+ 5wf73tUzMSncc9fWoGJJIUEnHBPem/dVib2dxkpbegUAn1HekYZbkbexx0p45kUlh6sMVHklWO
+ Cc96zUrrQtSXYa0ZTJUg4681EWcOA3TsfWnO+IgT1xyKaSdv3SCeMU+l5BJNIRmAYgjd6H1phK
+ rG ASMAdCacQPN5YEY4xUUgHBIJA6e9OEbbmfuN2sV3zv4OVJPJ7Uxcqwyy7duQcdanLNvZSpw
+ AOKrn DBsrsGOAaOddTXV+hXZgcYYFgckAdagchs7Rk9Qo61OxCyA8MT1qttOeCO+D60JrbuDV
+ newwg7SQ Ac8cjpUBkJypAU55OKldiqbXHU5qqQGlY5znGMd6laXRiovqIwKuwIwAfvAVCPMAI
+ fLMTkGldynG QADgmohvZevGOfrWkNVdm0bN3X/DjxzGcMAT3Peo844OSxHPtS7ioIABY8gYpA
+ Bt3Akdcj3ppva+ gOpaLQ0BgAOdw6/jSO+F2hTkcDmlLsY1XK/722ojlZgQMjj5vU1XNd3fQzu
+ t2DszSnI2gDkY61Dy Mj+NutWS+ZCRjOOpqgWBdwFJOeTQouXQatezRC5LHpgDg8VSc7Fz6nqa
+ tyA/Pk5x29aoykkHd8oL fLQuW2oSbscvEXB3N0HUHvWhEAATjHGV5rNgceUzltwPQetXomAUM
+ Qxz94U3F3aasT8PwmxGSU3b vmOMe9XEfaoHKjOBjnis+3G4ggjYq45/lV5CCwyvy579qFCysh
+ Xu7dS6Dld2R14NS5CEHIJJ4qoA d3UYHBFWVIbjac4x9fehwT3ZK0JFdgeOFzyalCKTnDH0qDG
+ Fznv0qSMFgRg8HjNVL+6Va71Jd7KR 8wJPQVKWAYAdCcE+hqujqJRwNygjPapAGweMemai10KS
+ 8rEgQK2c8Hkg+tKPuEkY5qNVwCS3U5NS bCBgklQeRUu17FRaHn5lxzn+I+tSoSFIBwB6+tVVf
+ ORjBzhfcd6njUM5xuwf1pTWlnsOcblnduxu UghsfWkOBM67h97oBSKTGCf4u+ecUiBmf5uAe9
+ EYJq/RCT0vHYsLuIBJKrgjPYGmtIwTG0DI5OKX DDojAY6noTTWfcF44OaElo0aQemmogB24BO
+ Ac/SpWHDBWzznB71Dvw5wCASMj3p7EOcjIYcnHpV2 bJcFLqSEKZAo4HU49KcBtAcE4xzk0wMh
+ JxnJ64peUCYO5AORWEZu9gndLyLOAxwMFs8VLGWwvXB6 1SXesi844I5qaORiegwBjNU4y5bvY
+ bskncuq245XO0Hmrsajdy3zHkc9KooPlJ6BQB9TU8LZ5IJI bn3FTvpHYpu0dy6rkoqjBz6CrM
+ YbaT3PcVVTZ1Ugk9u9TI58xQcL/e9qpXtYWltGaEO5lJIG7PQd atKAY1bsRwKqL9xQA/Xr61Z
+ ickfwlQeKXJLdMSRbT5ARnag6GrAJLp/e9+9VUfeCcHnpxU5diBu5 7Ad6qFuZ33HFSUtiz5jb
+ 23HhjwKeoVQwLfMBjGelVjzjJwOwqUMdw45NJJLbQNVt1LQZWIODtI5N P3oMYI56k9BVNZOgJ
+ z3x61MAShYY+hokrEyunqywHUD5myCeo705STjHQAgfWq2/quDjscUuS020 EjA5Oe9EdtirW2
+ Jzgq28YYjjPpTcbcDdxjkVG0mTg8sMA+1EcqLMSQxAPr1os+XQlybdkOZwJPmX K5GPpTGYLJx
+ 1I9aN5KjcFVevNMbeu45UjORx+lCkirJhkiHaMZ9x1pCMMmWGTyCO1RF22MxTPWgP iE8AEf5x
+ R1KvfdKw7euCcMMDFMySmwsGJ6GoSSAOhXv7GgsxYlfl9eKTTuHLtaxMSWy5IJHA9qYC dzHID
+ DpxUO7Oed3c4oDgxkkgMBjFVJMlwWo9m3AABgAevqaZtYMTn5c8UEqDhSffmoncbM5AGMcV F7
+ 6WFboPXBlHOcGkLnO3BxUGSGU5Bx0AphdnYnjj0qlRT2Y4au9ywx+U8/w9PxqNiDEW6cimLKS4
+ LbdvUkd6Vj5iuSAVJ7UJNOwnF3SYwcg/UEVGzH94QdpzgDFPHTYDt96TehfO5cdTQ3dkR0ukVi
+ Qs Pynvj3pN/wC5YL1zg56ipyEaL1btioXVgzbSvXoKlyj3EktmyAqythTzjmkYsiK2Rk4PSpM
+ KEOSd x/Wq5yHAAyB0qU5PU2u7DmZc5wCfWo+THubnBwMUH+7kDI4yKR2xGAOfWr5Laoydo2Eb
+ arBiSCeM VCzFmQHsMfWpc8c9e2KjfcTkOARV3TKtdDcgjdzkngVUk28lsgnoKmztnbecY+6Kj
+ b5n3EcEcmpb irNAlZ67FVmUM7gDBHeqzE+XnrjJwPrVqZx8uQSuB+VU2fdJgKetJy5TS7b22K
+ 7kc43FTzzVd5dq Y4Ge+OtTSBQ4CnHt61C5VtpAwAeAeorRxW7J5o3vYPl3hB+vvULZIC7Tx1N
+ K2dmWyQDmkVkZujZ6 4rNcqRN1zXEEny8DvlcjtURkG4b/AJVPb0pzkYK5yWGQF7VCS0jbSR26
+ itb2d7D5Fa6HEkMSD26e ntTS+dwB2kcn2PpTG2iUjOPm7/zpp/iLE57+5qtRJXsmSFsBGP3jz
+ VRzk+hxyfWpBvaLocVE5UPG OhBxTp3TEmkRuwE2Wxg+lULggN1wMA81ckZQxU4K5+UiqExOeR
+ uQjrjrQtdNrgpdzlLcLt2nue/r V5CDcKT17g1TVmEYBKqSCcEdKnjyp6goRxn1pxmpRV9xcrR
+ sqSIwFwcHnFWY2YcBwQKzF/eR9Tw2 G9quptC5Vvm4xnuB1qFbW7ErPQ1g4OC3c4qZJcSbkPAH
+ f+VUIwSmVPfuasglUzgjjOe1WlGWjMuV bssmYmFRgcYzxzUivuIXlXHBqHLBjnAA6kipQqgoc
+ 8k4J9aJuNti+aNuxOFUHO3cR90jvUse0yY2 sGAHWq4DKxDAlQ3B9KkQcr13Dk1k0mm2UpO2g5
+ QDPySd2fyoO7eu4nBFI3EhOcL0zT2zxyDjnFCY 7dmPGDjAO5epqQf3s8YxioEJ8tTzyOR3zUg
+ OUwzYHXP0qbu9rijpLQnX7xLHginKwMeXGCTUKA7Q Mg7jU552pj5geBim7LSxd3fcUM28bySN
+ pwBSfOCAD25GKjLOW4+THHI6ikjU/OfmLA8VUYpapgpv XUnBAj+YZYnj2pW2FxtIA24z60Fw2
+ Mqxz/FTCVYZA2gHPX9KNXrYyTe9iRGRdxYEgDjFODqUyAWV uuOxqH5ZGbAIBHTPenKxCJzg9R
+ 7Vnyxi79S0kt1qyePGdrA5xjJqWNV285GTjmojk5crtxUqkG2Y k7z14FP2lxxeti4BmE4557V
+ ZR8EYZeOnpioIyFOBgAjBz3qUDg8AjHbtWSnG9jaLi4l8EBV6MT/d 71YABbI45qjCFb7pIGOR
+ 6VawAB97d654q+ZNkpR2vY0oxmHk8dRnvU0WDJllwM96pRD5gCe3HPtV 5WXCBlOSOue1Jc1tD
+ Nx6LUn8shixb5cZODUytmIdMDoTVZDuBwdwJzipWKiLGCCCCaHZ9Q12LHmf N8oUEAcmpFLlmx
+ jAPp0quDuUkDL5FTLkPgZG73pylG4XdrJC5AHzcMD1/pUqOcDLDkflUDZMzIeA uDk96RDgtxw
+ OgzV8nPqXJpKzJiWLAnB9cVIZG3HLA9s1AN23Bz/hSY2p3Yk5Yil7t0Q5XsiZD++D MwPHPvSg
+ nBGB1yCahyHwRkDHQinA/MduSDyD6CqcmU273uSbsyKcbgTSOxy2eFx61Hu3IMHJA59q iJBY5
+ BIPIJrJJp3C33Em4mDryp549aZuA/2Wx0Paos4yM9emKXdn+JQQOBjvTkne4pX7A0uZXB5R ue
+ D0pA2EBDHA61Az5IIQ5Jwab0Hy/Pxzmh9UEGm9SYuBk5xjj61BG4JI7Z/E0zcMckEn17VCXKue
+ wzwR0rS9o2YOyLJkG4rjn69KYGCtlhnnj0quXbeSB8vGfembgWVhnJPc1HvdGOfTm1sWgyqAc5
+ 5z SkqVDD5SeeKr72YLhcADoKRSzsRnr93j86Ol7hJR6FjLAAgDIyMAU3ewjQFSF7ketRlmwOm
+ WPIpy ksm0YUA5we9Ta24003ddBWcA5/p0NIrAKC4UkjsKQkLxtLHdwR6U6QgQBgCAOORVwu1a
+ xKvIYGHz Y5HsaiJcyZCkc80rn5xkgITkgdqjLeYCoODn8aU421Y5JSkrobI53YZCee1QgrwcN
+ 05Ge9PYqsIU /M/cUw5ZAQRVr3V6kPYYxAm7n1wcUEgRMU4U+v8AOgsMKWIzjkVE6kng4Hfnis
+ 5PYbswZioBOHx3 FR7gz4Gdx7D2okKiJuTnoTUAbEhAPAAJwOa2i9DSUdE0xzk7y2OAeMjp9aq
+ vuZAM9QMAVYEm5Sg6 EZqAgeVgj5T3704zsmmjL3272sRHgnLDaowc1VdiR8hHP3j3xUrqC2GY
+ sSc9euO1VmYZZh8ox0NZ JXC+mpAzjaFK98Bqru2A5XGCcZxxUhy0o+7jGM9qiYbot3Bwegq52
+ SL1lZCMvzjJ+UDmoCxzkrgA 8mlYtglgctyfbFJIVXf8w3HHFZp9EJaaDfNydwPU56U1RmZstt
+ PPXvTQSFHzDI6D1p24hgGGTtNW 9CXGw1SAdg5XPJpPlDFEJPuaa20LlGPH60Fj8zgj3x2oe+r
+ G72uMbgkk5QnjFR5DjAPQ9+tBYHcx Ofl4AqM+oPPc+tW5XVzJS11K8u3e/GFU9aoyktje6g5/
+ MetWJGYI2RuGc/Sq0pVTlFJ479jVOTlG yZautf8AI5SMtKRwR6A96uIMRkvztzgVQi3ZJzkMc
+ DHarS+aCfYDGRSg76tk2cn2NGDLg46Edv4q tIWBIUFRjlj/ACrOjkOGz94A4CjGKtJlgNxIXP
+ AzTs7astrlgaSEh1O4qDyCatpuEqh2Jfb09az0 KeV3yDgjPSraksDI5Jx6U4prXoRFrYuId0o
+ BJDHOM96srgJt5z3HrVIK7Mr5AYcirEeTnuTgDAqb LdBbXcsB2aZfmO2p1yIjtOXzwB1NVeQw
+ QnA5O4jgVMpwwYn5QOtHu9LBp3JlbABCtjHPFNLfJtJy yjkAc89KGZxvAPyjHNIoOZGLBvXFV
+ G6V7jSVtCdSuxcNtcgcmn/dIUAMevFVQ5WLOFHapFLBtzDg 8E9vrWbpu92aOF47FknCphfwBp
+ 4bMYf5s98/yqJPvbicANjrSNIFyAOjc0lByZMVJqyROwVlO0nr gUAKrhQ2GJyMmo8hWYtnO7j
+ 3pw+djgEknjFTy9wimtCQFi/JGAccjrSgkvkfdB6VF1YAnjvz0pFP +kDdwo6Z7Vak0i5OKehI
+ h/dEcbi3GO9Skny2+XjcMYqsXCttB6HginjcioSCV7+9Z1IpPzGnqtCy WDMx3deasBsY2jO0Y
+ PvVPzE3jIyuKmhYs+Typ9qhpJik4vVFoHJ4ywPbNXkPyYbIU/mazyMNuALD 2PWrYKkDkqfQ+l
+ Obi2mNSfQvRHPygMBmrCu+/DLuAbg/1qou/goRluoNWkIWXG8EDgiiKT95jcW0 y7ESQSPvdDV
+ xQUVQysR0+maoQPjb1GRmrMbnbnJGPXmh/F5Ecr6F4Hy4Tzk9x3pUJfGSMDqMVEGx uZj6dafv
+ XaQrAgcHHWk0gu7WJsjzRtJI9qN37veu4E9aqpIN2Oq59amG5WY7sqT0rT4dRqNupYST OflJx
+ xUhZVjU4JzwKqxHI3MduTkink/u2wQcdDU/MTUWyRmZioDdjg0FyBjBJI7VArDcCM7s4p4J bB
+ bIbg1EnYNVp0LGW2bgdxxzx3pAxL9QGPXiq4O0sOeT60iFlLbs4/h9abcXqg0ZMZSIsdTjBIHF
+ DkeXGD90Dj3quzjeQVYgjpS5XYDg5B6Z6Umr6hyajzIWITjIYYNM5MjAnoRzTC5eY7SMk/Lx+V
+ Re Zg8tznJq3toilFW0JJCGIAb5hy3tVdnKMGwfmPTPanMAZHYA5LDAFQOT5uCc4PGaFq7MqPY
+ eSDnI ZQOBk1A7nkxlQMdSP1p5ZjGSRk96hZ9q/Njbjn1xTjduxKuhWcsgBK9QRjvSbgH6Ajoc
+ DvUGcqCO gPSlyhcBj3zwalvoyZJvRonZgAAThgeSPWlVgp6E88c1XEuG+ccnue9CnccqRgdhT
+ vrqwTsixE37 3kEHOeTU/mZyEA39c1TEkaz7gWz2p6kFgUYBei+tDjZ3a0CUepbA+QkMCB3xUR
+ J3krx7Z4qNiyFl PcY49aUMhUZ4yPWnDmtcLisQVLEdeMmmvnawXHHem4DHhjjPAph8wgYyfXF
+ S9VqNOMhJCSEPAzxU OSHb+HnPPSpSNpyPTjPrUEj/ACsAOeBTbVhJdENdhtTZtb+8RUO4AlSe
+ e1K4ZITk44qDqSw+4OAe tVpYdl0ZKzA5yTioy2NwyMjofam9X5yQR096iZmUsTjavAoTjazHK
+ 0WrClhuwOucZHpTHD7Gw459 ulIz/ug2BuIOAOtQblRck/Nt6ZqeRPYUY3I2l+ZdpUgDP4VXMg
+ MZAUnBJBpAzCViFyOhpu/94eR0 xjFXyRWlhcq16jH24Vty4B6Adc1UkkI3JhQAe4709w/PKbB
+ 3xVZ93m/Ng88E0RjHVFQ31FILxgZA 44GKrF1D/Nz1GfU1K+4jeO3FRsBtAce+aatorkyu3zDQ
+ Dx37kU0LtZiSSccc08ZUqOQDn/8AVTXO 11BGPX/ClOWtgc3JaC7gykg59qiB4yWUKRnn0pec4
+ 4A6moZWG0EAYB5I6CiGl0jPmauhQY1QYPP6 VGZG344A9xTSf3TBCAcdD2pj/KQcj0OPWnNt6W
+ uNxtqROWxhsbjxnHBqnL5iySE8j+H2qVjtUt82 BkcnpVZyzEnO0gZwTUrnirrcqk3FnMoFZSM
+ nIPPsam3MqZyc5G6qyFDtByB61KSwK7fulT1Nb02p PkbFCfOXBOD1YZ+nXFXbeUmND/F/Ks1N
+ vm4PzY4AFWomKjA4IGeaThFaW1JaSdjTjZSCFHG45zzj 61MjgySDJOOlZsMrgeUFwauI24ggB
+ eOR60rSStYIxcXroaCy5QY5bp+FWklGAOQV61nAbnyCQe5q VQiyHcwI4ORRypPbUtST3NMN8h
+ JU5wM5qRJS3yMPlAwDjrVNGBJ35H49qkRwQevqvtVciT0Kv5bF osQNucZ7U9WY4I645I7mq6k
+ EAntyc08PlvMAxyciqTSexE2nsSxmQjgKTnk4qT5sNuPfp61WL/IM kkjsKkTax3fMWHbNZOLS
+ ci2tidB90BiQRkg1YVhjoMZ9KqAgAqM5wATUwRRCGLcdeKzlNaLqTKLW o/zMR53oVye3NPDNs
+ 4YAbutV2UeWQAVwRtzTztb5NxY5HT+VaqXLG44vlSaHnaYiQQW3cnPFCnbJ nIJ9xTPlRDkHIy
+ eaQujfN944zgVF27dhqzW1yQyq2xM5OetOUzSOSBhe31qDzNpBMZweoxzVjcfL BQrzyBUybto
+ S5vsSA4ZiSd2fwqyPmiYAhXBqiCS+Xz6nHaplY4CgEg1EU76Cv1ZfRxsIZieRg1bj dTM2RgDu
+ azI5CJAxPy9GJHQ1c3Hy02+mC2M5ob63K5tDQibDgEH5hn6VZjI6Lwcck1RR+FUN8xGc elWVY
+ 7h3GODRF2K23Reib94MOMhcgYq6shBIY8HI+tZiY3jHLY5x2qwrbiRnqauotnuKW2rLgkYf KC
+ ckdDVhjj5Mc7dwqisgG2Rh16D+dTGTc6nhvQ09biU1cs+YDtBHG3kjvThKMb9rECqxZhHy6g/T
+ ofSnBm8plbkg8epNFkDkm7ItiRWdgSMgYwO9GflxkYYVAM7gDwSckgU7cAcFx0NZKLvfcXXQlO
+ 0K Q3zD245pDNu2kcHOPoKrmRQwRiXGM8HrTy2JMAqAOuacoq1maKyWo9WZXBYgnHSpeDzkjnH
+ Xiq6u zA4BJHT3pWkURnggZ5FKdrabmUtWmTl03D+Jj+mKiZsPkKykng9qg3MjoY1Zwe4/lQST
+ FvOd3YZp xSTsy2rInQZJzjI6c1FvVAey+4/Wog5zvORk460oCnJORgc+/NUopJpkKbUrsVpAE
+ 65weTUb8kk4 B64PWlDYBPBXd0qu7MA2GXI6Aj9KlRUmXFtrQC7MeCMY4pCcsSQ3A7UbiAASOn
+ YUxuFBJ4H605WS CU76XGNjgYO3tUeflyGUYPzE9qCQyEbu361BuInA5IAzz3qqabjdFNN2J8/
+ KOdx7VIoB+YEe1VlI LKd2MHjPepuTu4ycZPNQp3eo5/DclHI5OR1z/SnoQuGGNpORVeMHAJwC
+ vT2pzMwj3ZJx6Cq5r3I2 67lnfucjIzjOD3pPMbLJ8u/OR/hUO5XjQ888/WlDK7Es2DnPPYYo0
+ S1JSTeqJTy69jjioSSzHk4z g4pxfMTHjp8opm44APB6kd6Oa6uO3RBIQGGM4Ax1qBypJy4Az0
+ 70rP8AJ1yQ3PtUZfJwAMepHein a9hra41i+0Asufeo9xMJXIUDBzimtJkAnp1J9aY7Mq4JB7c
+ d6bTfQGlLqIznLZ7ntwTUDOC3cknI 9qldm8oAKC3fFVVYb2JIyetSo21auIWORTKQWzkHmoWw
+ ASGzx1NTOyiM44B6MB0qoVAlJzv+Xrmq VrdhOXYQsHQ4wr+lQH5lY5A5HSib5ckZBGDTVfgsS
+ o6np1qpNdCYySdrETAFT83IPrVZidzNkHtj FTtIARhSQc81A58uMOgJJ4ORRdtFvfyItwYspB
+ OB2prL/o4LHljnGeKU4YnjBx9KgYqI+pLA560J pNJEtdEDsfl5AGaRtvmMfmPI6GmuS6rgZwc
+ emTSrw4O5cE/NmrltZEpaNtjQ5MZPJB7Y5qFlxGzI cHuD3pWYtKcDJPSq7FgwQsGIB6Ci2uhX
+ PZWHO+bfI4yO45FRO2QQx4OMmnsy8YOFPXNRMwwU424y OKm7a02Jb6WK7kqzBsHBwM96rvgxb
+ jnrxUhO6Rh94YBzmqUhbywp+bk4Naq0ZJX1Hfn0OaVmBw2O OelSCUNtKHcvIqrHiQ78nKnnnr
+ VxDhfkwPTIpKKb5uoc0bNrqTq+VYDO4kfjVrBJzzjg7qrKSrkM ue4x2qwjbshc4PJJ9aG1cSl
+ ZbFtWCyEg5weoqyGBjHXLHNUlZFBAYccEVZRiHxjgD07VD91Dbk1c vrgOBndyCMVZYgMB1GDt
+ OKpoTgBCCMfL/jVgblxlgSDyxHFCfVCk3uWkYr8p5JGcjoanJwPTjnmq qEgKQRycCnqxySxUj
+ 2FUtWJa6l778RAYcenehThixIK5waqKQV3Ipz9aCxymDjHUUkpWZcWnp0L2 7AZGxjtx1oBHlk
+ LgHpzVXeTtZ+BgYAp4kB+bgc85ocJLYOVK6SLqkbwrNyVxxSkjYOcDIyKqiQ7g WxwMcDvS7+j
+ jle4qfZtvUtKz3LIYgkHLAHpUuWRC4AA3DHvVQElcHC89TR5hGd2WA5FW7WaQra/o WncswLDA
+ waiB+fPPHpQZAzEHAGR/+qotxwAMH09qhb6ExbtZqxM8hwzbScfrSJJ1G5Rxx7VXL/Ju H5e1K
+ N4fGzI7nFTy2+I2SsXQxfcSdw3DO2pEdhls/TFU1fYjKDwx9KsIxchPup9OtTNSvqZKbitC 5F
+ Io2jgluevFXRKTIEJwO2Ky4yAcKQVBJJx0qzC28lyDg5/Cl7jfMLmcmaQbCb8jhueeatLIzHrw
+ elZqksSCpVeM81ZSQKMD5gXz9KSSvoyoq2xphwp8wn5c4wOoqZWbPDDJ5OOlZccn77BG5Tzx7V
+ dV wMEcZGTU8/Ky57abl9GUjG7d7elPWTqvJJ6Gs9HbqBxg4zU0LuwUEEgLkt6GtL2V2yaitZp
+ F4N9z JJyccVMCobnkY79RVIvhVPTj73anKxKgnJ5GeetO8rXuKMVqjQV/lPzDJqMygwg7SWHB
+ qMSKof5c 5OMelJhd+7kDvRdaihZbkhZty52gZ9Ke0gyeRjFQAOJSeo4xn0ppYYAP0pWTVjRS1
+ 0LBmIfCHHAJ JoeXEhLdevHvVbdjnHQflSblKN1YD35NDjGJPLbct7yqqPfJpTKM4PUHt3quGV
+ iOchvSmJgH7rHa MHmp5Y31E9XqtiXeS5JXqeMUrKzSAbdox92oXZnU+x4pu5mdxnGDketXEpw
+ 2bH7nLjO3AFNdSpPB L9aYWGGJPWo5pG2BOcj86Uua+hV76iuRvBz0HamBizNwRt9+tBx8rbXA
+ 2VGwKsPmOxuQauLurDbW 0RJCBIpz82OcUAEHhgVNMBO4MT14z6VG2clFDDkEZqeS79A5+ZrXY
+ mfgLjv+lSEEREr8pz371CCu SGBwB0qMj90x5GW4PahxStYlSu73LasScMw47Cl8zJTuuccGqw
+ bDh8hmyQRinq6iNhkKO+exqGnb QN3ZFkkLEMck9famkgEvkF81XD8rn1/KpGkVkJKkDuaTi1o
+ Db2JCB5YGTu6ioncHaeQT1/wpuT5K tzwcnJqMOzBtykKTnPvVJcruhRl+A5mC8DJz3pm9lG11
+ IZumaU4AJYhR1x3qJ2BbeMgD5sH071Sd 9LCnNRFYKVCg9Bgiq7MFlIc4HT6Uu9ch+vHTvUBYt
+ IzldyZArWF0rkpNK4M5KEg9DnH0qENmDpli Tx60skp35UYUcEe1RO4weOMYX1qJPsK1la2orE
+ BNmd2R3/hqvwAVB4xkihpBkDn0YUw4ZGyMccYq oRvuNq71GHexJHzY9aiJf5m4PTIpzMyOCAW
+ Ug/yqPK+WE2NnBwc0QulsU7Kz6EW0+SwLZ9R+NRs3 y4ZsnPBFOH3/AJQRxyDURwM78Ar2pv3m
+ J2bI3I3MAQA3vyKiLHJC8sODTz87EEHnmo1IBw3IzQ2k tR8sVqwHACBucc+1Rs23O0n3zTcru
+ Y5O4DkZpnmbc56+9K2l0Q5/IduZW+XHGSeKruQWDZySOR6V MMKBkj3NVzlpCSyZI+UAdKFbuV
+ HRa7jG27cLxnrk1CThWHJwOQKkcbtuMFfb3qu0qguFU5HynFXL
+ l5dTOd1qxgYfaS4U4KY4NUJA23byzdMDrVl2D2+5c9gT71Rk++cB85yMmiEXF2Jb5ndH/9k=
+UID:934731C6-1C95-4C40-BE1F-FA4215B2307B
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,25 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Here;Custom;Fields;All;
-FN:All Custom Fields Here
-NICKNAME:custome
-ORG:Major League Co.;Macosx server group
-TITLE:QA Engineer
-EMAIL;type=INTERNET;type=WORK;type=pref:custom at example.com
-TEL;type=WORK;type=pref:777-777-7777
-TEL;type=CELL:8888888888
-item1.ADR;type=WORK;type=pref:;;1 Goroku St.;Mountain Top;CA;99999;USA
-item1.X-ABADR:us
-NOTE: Many customer fields are added
-item2.URL;type=pref:http://www.example.com/~magic
-item2.X-ABLabel:_$!<HomePage>!$_
-BDAY;value=date:1999-03-18
-X-AIM;type=WORK;type=pref:custom at example.com
-item3.X-ABDATE;type=pref:1995-05-21
-item3.X-ABLabel:_$!<Anniversary>!$_
-item4.X-ABRELATEDNAMES;type=pref:Aho Sak
-item4.X-ABLabel:_$!<Friend>!$_
-item5.X-ABRELATEDNAMES:Sanma
-item5.X-ABLabel:_$!<Assistant>!$_
-UID:AFBB77B8-0438-4825-A1DB-A75D76B6C3A8
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,25 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Here;Custom;Fields;All;
+FN:All Custom Fields Here
+NICKNAME:custome
+ORG:Major League Co.;Macosx server group
+TITLE:QA Engineer
+EMAIL;type=INTERNET;type=WORK;type=pref:custom at example.com
+TEL;type=WORK;type=pref:777-777-7777
+TEL;type=CELL:8888888888
+item1.ADR;type=WORK;type=pref:;;1 Goroku St.;Mountain Top;CA;99999;USA
+item1.X-ABADR:us
+NOTE: Many customer fields are added
+item2.URL;type=pref:http://www.example.com/~magic
+item2.X-ABLabel:_$!<HomePage>!$_
+BDAY;value=date:1999-03-18
+X-AIM;type=WORK;type=pref:custom at example.com
+item3.X-ABDATE;type=pref:1995-05-21
+item3.X-ABLabel:_$!<Anniversary>!$_
+item4.X-ABRELATEDNAMES;type=pref:Aho Sak
+item4.X-ABLabel:_$!<Friend>!$_
+item5.X-ABRELATEDNAMES:Sanma
+item5.X-ABLabel:_$!<Assistant>!$_
+UID:AFBB77B8-0438-4825-A1DB-A75D76B6C3A8
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,11 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Thompson;Default;;;
-FN:Default Thompson
-EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
-TEL;type=WORK;type=pref:1-555-555-5555
-TEL;type=CELL:1-444-444-4444
-item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
-item1.X-ABADR:us
-UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-444-444-4444
+item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
+item1.X-ABADR:us
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,17 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Contact;Mulberry;;;
-FN:Mulberry Contact
-NICKNAME:mulberry
-ORG:Apple Inc.;
-EMAIL;type=INTERNET;type=WORK;type=pref:mulberry at example.com
-TEL;type=HOME;type=pref:777-777-7777
-TEL;type=WORK:8888888888
-TEL;type=WORK;type=FAX:5555555555
-item1.ADR;type=WORK;type=pref:;;1234 Infinite Circle;Exampletino\, CA 99999;USA;;
-item1.X-ABADR:us
-NOTE:This is a contact created in Mulberry.
-item2.URL;type=pref:http://www.example.com/~magic
-item2.X-ABLabel:_$!<HomePage>!$_
-UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,17 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Contact;Mulberry;;;
+FN:Mulberry Contact
+NICKNAME:mulberry
+ORG:Apple Inc.;
+EMAIL;type=INTERNET;type=WORK;type=pref:mulberry at example.com
+TEL;type=HOME;type=pref:777-777-7777
+TEL;type=WORK:8888888888
+TEL;type=WORK;type=FAX:5555555555
+item1.ADR;type=WORK;type=pref:;;1234 Infinite Circle;Exampletino\, CA 99999;USA;;
+item1.X-ABADR:us
+NOTE:This is a contact created in Mulberry.
+item2.URL;type=pref:http://www.example.com/~magic
+item2.X-ABLabel:_$!<HomePage>!$_
+UID:ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/F0A6918D-8E09-43FA-9684-226810B8A96F.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/F0A6918D-8E09-43FA-9684-226810B8A96F.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/F0A6918D-8E09-43FA-9684-226810B8A96F.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,2010 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Inc.;Test;;;
-FN:Test Inc.
-ORG:Test Inc.;
-EMAIL;type=INTERNET;type=WORK;type=pref:testinc_sf at example.com
-TEL;type=WORK;type=pref:777-777-7777
-item1.ADR;type=WORK;type=pref:;;3 TV Street;San Francisco;California;99999;US
-item1.X-ABADR:us
-NOTE: Company with picture
-PHOTO;BASE64:
- /9j/4AAQSkZJRgABAQAAAQABAAD/7QA8UGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAB8cAVoAAx
- sl RxwCAAACAAIcAhkAC1Bob3RvIEJvb3RoAP/iG6hJQ0NfUFJPRklMRQABAQAAG5hhcHBsAgA
- AAG1u dHJSR0IgWFlaIAfaAAEAEwAJADEABGFjc3BBUFBMAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAD2 1gABAAAAANMtYXBwbFYcEOZVYuhIRg5LwLIi62wAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAA AAAAEXJYWVoAAAFQAAAAFGdYWVoAAAFkAAAAFGJYWVoAAAF4AAAAFHd0cHQAAA
- GMAAAAFGNoYWQA AAGgAAAALHJUUkMAAAHMAAAIDGdUUkMAAAnYAAAIDGJUUkMAABHkAAAIDGF
- hcmcAABnwAAAAIGFh Z2cAABoQAAAAIGFhYmcAABowAAAAIHZjZ3QAABpQAAAAMG5kaW4AABqA
- AAAAOGRlc2MAABq4AAAA ZGRzY20AABscAAAALm1tb2QAABtMAAAAKGNwcnQAABt0AAAAJFhZW
- iAAAAAAAAB7vQAAQXsAAAJL WFlaIAAAAAAAAFYqAACp0AAAFF9YWVogAAAAAAAAJO8AABS1AA
- C8glhZWiAAAAAAAADz2AABAAAA ARYIc2YzMgAAAAAAAQu3AAAFlv//81cAAAcpAAD91///+7f
- ///2mAAAD2gAAwPZjdXJ2AAAAAAAA BAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUA
- SgBPAFQAWQBeAGMAaABtAHIAdwB8AIEA hgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0
- ADVANoA4ADlAOoA8AD1APsBAQEHAQwBEgEY AR4BJQErATEBOAE+AUUBSwFSAVkBYAFmAW0BdQ
- F8AYMBigGSAZkBoQGoAbABuAHAAcgB0AHYAeAB 6QHxAfoCAgILAhQCHAIlAi4CNwJAAkoCUwJ
- cAmYCcAJ5AoMCjQKXAqECqwK1Ar8CygLUAt8C6gL0 Av8DCgMVAyADKwM3A0IDTQNZA2UDcAN8
- A4gDlAOgA6wDuQPFA9ID3gPrA/gEBAQRBB4ELAQ5BEYE VARhBG8EfASKBJgEpgS0BMIE0QTfB
- O4E/AULBRoFKAU3BUcFVgVlBXQFhAWTBaMFswXDBdMF4wXz BgMGFAYkBjUGRQZWBmcGeAaJBp
- oGqwa9Bs4G4AbyBwMHFQcnBzkHTAdeB3AHgweWB6gHuwfOB+EH 9AgICBsILwhCCFYIagh+CJI
- Ipgi6CM4I4wj3CQwJIQk2CUsJYAl1CYoJoAm1CcsJ4An2CgwKIgo5 Ck8KZQp8CpIKqQrACtcK
- 7gsFCx0LNAtLC2MLewuTC6sLwwvbC/MMDAwkDD0MVgxuDIcMoQy6DNMM 7Q0GDSANOg1UDW4Ni
- A2iDbwN1w3xDgwOJw5CDl0OeA6TDq8Oyg7mDwIPHg86D1YPcg+OD6sPyA/k EAEQHhA7EFgQdh
- CTELEQzhDsEQoRKBFGEWQRgxGhEcAR3xH+Eh0SPBJbEnoSmhK5EtkS+RMZEzkT WRN6E5oTuxP
- bE/wUHRQ+FF8UgRSiFMQU5RUHFSkVSxVtFZAVshXVFfcWGhY9FmAWgxanFsoW7hcS FzUXWRd9
- F6IXxhfqGA8YNBhZGH0YoxjIGO0ZExk4GV4ZhBmqGdAZ9hodGkMaahqQGrca3hsGGy0b VBt8G
- 6MbyxvzHBscQxxsHJQcvRzmHQ4dNx1gHYodsx3dHgYeMB5aHoQerh7YHwMfLR9YH4Mfrh/Z IA
- QgMCBbIIcgsyDeIQohNyFjIY8hvCHpIhUiQiJwIp0iyiL4IyUjUyOBI68j3SQMJDokaSSXJMYk
- 9SUkJVQlgyWzJeImEiZCJnImoybTJwMnNCdlJ5Ynxyf4KCooWyiNKL4o8CkiKVUphym5KewqHy
- pS KoUquCrrKx4rUiuGK7or7iwiLFYsiiy/LPQtKS1eLZMtyC39LjMuaS6eLtQvCy9BL3cvri/
- kMBsw UjCJMMEw+DEwMWcxnzHXMg8ySDKAMrgy8TMqM2MznDPVNA80SDSCNLw09jUwNWo1pTXf
- Nho2VTaQ Nss3BjdCN343uTf1ODE4bTiqOOY5IzlgOZ052joXOlQ6kjrPOw07SzuJO8c8BjxEP
- IM8wj0BPUA9 fz2/Pf4+Pj5+Pr4+/j8/P38/wEAAQEFAgkDEQQVBR0GIQcpCDEJOQpFC00MWQ1
- hDm0PeRCFEZUSo ROxFMEV0RbhF/EZARoVGykcOR1NHmUfeSCNIaUivSPVJO0mBScdKDkpVSpt
- K4ksqS3FLuEwATEhM kEzYTSBNaE2xTfpOQk6MTtVPHk9nT7FP+1BFUI9Q2VEkUW5RuVIEUk9S
- mlLlUzFTfFPIVBRUYFSt VPlVRlWSVd9WLFZ6VsdXFFdiV7BX/lhMWJpY6Vk4WYZZ1VokWnRaw
- 1sTW2NbslwDXFNco1z0XURd lV3mXjdeiV7aXyxffl/QYCJgdGDHYRlhbGG/YhJiZWK5YwxjYG
- O0ZAhkXGSxZQVlWmWvZgRmWWav ZwRnWmewaAZoXGiyaQlpX2m2ag1qZGq8axNra2vDbBtsc2z
- LbSNtfG3Vbi5uh27gbzpvk2/tcEdw oXD7cVZxsHILcmZywXMcc3hz03QvdIt053VDdaB1/HZZ
- drZ3E3dwd854K3iJeOd5RXmjegJ6YHq/ ex57fXvcfDx8m3z7fVt9u34bfnx+3H89f55//4Bgg
- MKBI4GFgeeCSYKrgw6DcIPThDaEmYT8hWCF w4YnhouG74dUh7iIHYiBiOaJTImxihaKfIrii0
- iLrowUjHuM4o1Ija+OF45+juWPTY+1kB2QhZDu kVaRv5IokpGS+pNkk82UN5ShlQuVdZXglkq
- WtZcgl4uX95himM6ZOpmmmhKafprrm1ebxJwxnJ+d DJ15neeeVZ7DnzGfoKAPoH2g7KFbocui
- OqKqoxqjiqP6pGqk26VMpbymLqafpxCngqf0qGWo2KlK qbyqL6qiqxWriKv7rG+s461WrcuuP
- 66zryivnbARsIew/LFxseeyXbLTs0mzv7Q2tK21JLWbthK2 ibcBt3m38bhpuOG5WrnSuku6xL
- s+u7e8MLyqvSS9nr4ZvpO/Dr+JwATAf8D6wXbB8cJtwunDZsPi xF/E3MVZxdbGU8bRx07HzMh
- KyMnJR8nGykXKxMtDy8LMQszBzUHNwc5CzsLPQ8/D0ETQxtFH0cjS StLM007T0NRT1NbVWNXb
- 1l7W4tdl1+nYbdjx2XXZ+tp/2wPbiNwO3JPdGd2e3iTeqt8x37fgPuDF 4Uzh0+Ja4uLjauPy5
- HrlAuWL5hPmnOcl56/oOOjC6Uzp1upg6urrdev/7IrtFu2h7izuuO9E79Dw XPDp8XXyAvKP8x
- zzqvQ39MX1U/Xh9m/2/veM+Bv4qvk5+cn6Wfro+3j8CPyZ/Sn9uv5L/tz/bmN1 cnYAAAAAAAA
- EAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0A cgB3AHwA
- gQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2gDgAOUA6gDwAPUA+wEB AQcBD
- AESARgBHgElASsBMQE4AT4BRQFLAVIBWQFgAWYBbQF1AXwBgwGKAZIBmQGhAagBsAG4AcAB yA
- HQAdgB4AHpAfEB+gICAgsCFAIcAiUCLgI3AkACSgJTAlwCZgJwAnkCgwKNApcCoQKrArUCvwLK
- AtQC3wLqAvQC/wMKAxUDIAMrAzcDQgNNA1kDZQNwA3wDiAOUA6ADrAO5A8UD0gPeA+sD+AQEBB
- EE HgQsBDkERgRUBGEEbwR8BIoEmASmBLQEwgTRBN8E7gT8BQsFGgUoBTcFRwVWBWUFdAWEBZM
- FowWz BcMF0wXjBfMGAwYUBiQGNQZFBlYGZwZ4BokGmgarBr0GzgbgBvIHAwcVBycHOQdMB14H
- cAeDB5YH qAe7B84H4Qf0CAgIGwgvCEIIVghqCH4IkgimCLoIzgjjCPcJDAkhCTYJSwlgCXUJi
- gmgCbUJywng CfYKDAoiCjkKTwplCnwKkgqpCsAK1wruCwULHQs0C0sLYwt7C5MLqwvDC9sL8w
- wMDCQMPQxWDG4M hwyhDLoM0wztDQYNIA06DVQNbg2IDaINvA3XDfEODA4nDkIOXQ54DpMOrw7
- KDuYPAg8eDzoPVg9y D44Pqw/ID+QQARAeEDsQWBB2EJMQsRDOEOwRChEoEUYRZBGDEaERwBHf
- Ef4SHRI8ElsSehKaErkS 2RL5ExkTORNZE3oTmhO7E9sT/BQdFD4UXxSBFKIUxBTlFQcVKRVLF
- W0VkBWyFdUV9xYaFj0WYBaD FqcWyhbuFxIXNRdZF30XohfGF+oYDxg0GFkYfRijGMgY7RkTGT
- gZXhmEGaoZ0Bn2Gh0aQxpqGpAa txreGwYbLRtUG3wboxvLG/McGxxDHGwclBy9HOYdDh03HWA
- dih2zHd0eBh4wHloehB6uHtgfAx8t H1gfgx+uH9kgBCAwIFsghyCzIN4hCiE3IWMhjyG8Ieki
- FSJCInAinSLKIvgjJSNTI4EjryPdJAwk OiRpJJckxiT1JSQlVCWDJbMl4iYSJkImciajJtMnA
- yc0J2UnlifHJ/goKihbKI0ovijwKSIpVSmH Kbkp7CofKlIqhSq4KusrHitSK4YruivuLCIsVi
- yKLL8s9C0pLV4tky3ILf0uMy5pLp4u1C8LL0Ev dy+uL+QwGzBSMIkwwTD4MTAxZzGfMdcyDzJ
- IMoAyuDLxMyozYzOcM9U0DzRINII0vDT2NTA1ajWl Nd82GjZVNpA2yzcGN0I3fje5N/U4MTht
- OKo45jkjOWA5nTnaOhc6VDqSOs87DTtLO4k7xzwGPEQ8 gzzCPQE9QD1/Pb89/j4+Pn4+vj7+P
- z8/fz/AQABAQUCCQMRBBUFHQYhBykIMQk5CkULTQxZDWEOb Q95EIURlRKhE7EUwRXRFuEX8Rk
- BGhUbKRw5HU0eZR95II0hpSK9I9Uk7SYFJx0oOSlVKm0riSypL cUu4TABMSEyQTNhNIE1oTbF
- N+k5CToxO1U8eT2dPsU/7UEVQj1DZUSRRblG5UgRST1KaUuVTMVN8 U8hUFFRgVK1U+VVGVZJV
- 31YsVnpWx1cUV2JXsFf+WExYmljpWThZhlnVWiRadFrDWxNbY1uyXANc U1yjXPRdRF2VXeZeN
- 16JXtpfLF9+X9BgImB0YMdhGWFsYb9iEmJlYrljDGNgY7RkCGRcZLFlBWVa Za9mBGZZZq9nBG
- daZ7BoBmhcaLJpCWlfabZqDWpkarxrE2tra8NsG2xzbMttI218bdVuLm6HbuBv Om+Tb+1wR3C
- hcPtxVnGwcgtyZnLBcxxzeHPTdC90i3TndUN1oHX8dll2tncTd3B3zngreIl453lF eaN6Anpg
- er97Hnt9e9x8PHybfPt9W327fht+fH7cfz1/nn//gGCAwoEjgYWB54JJgquDDoNwg9OE NoSZh
- PyFYIXDhieGi4bvh1SHuIgdiIGI5olMibGKFop8iuKLSIuujBSMe4zijUiNr44Xjn6O5Y9N j7
- WQHZCFkO6RVpG/kiiSkZL6k2STzZQ3lKGVC5V1leCWSpa1lyCXi5f3mGKYzpk6maaaEpp+muub
- V5vEnDGcn50MnXmd555VnsOfMZ+goA+gfaDsoVuhy6I6oqqjGqOKo/qkaqTbpUylvKYupp+nEK
- eC p/SoZajYqUqpvKovqqKrFauIq/usb6zjrVaty64/rrOvKK+dsBGwh7D8sXGx57JdstOzSbO
- /tDa0 rbUktZu2EraJtwG3ebfxuGm44blaudK6S7rEuz67t7wwvKq9JL2evhm+k78Ov4nABMB/
- wPrBdsHx wm3C6cNmw+LEX8TcxVnF1sZTxtHHTsfMyErIyclHycbKRcrEy0PLwsxCzMHNQc3Bz
- kLOws9Dz8PQ RNDG0UfRyNJK0szTTtPQ1FPU1tVY1dvWXtbi12XX6dht2PHZddn62n/bA9uI3A
- 7ck90Z3Z7eJN6q 3zHft+A+4MXhTOHT4lri4uNq4/LkeuUC5YvmE+ac5yXnr+g46MLpTOnW6mD
- q6ut16//siu0W7aHu LO6470Tv0PBc8OnxdfIC8o/zHPOq9Df0xfVT9eH2b/b+94z4G/iq+Tn5
- yfpZ+uj7ePwI/Jn9Kf26 /kv+3P9uY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAoAC0AM
- gA3ADsAQABFAEoATwBUAFkA XgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAKQAqQCuALIAtw
- C8AMEAxgDLANAA1QDaAOAA5QDq APAA9QD7AQEBBwEMARIBGAEeASUBKwExATgBPgFFAUsBUgF
- ZAWABZgFtAXUBfAGDAYoBkgGZAaEB qAGwAbgBwAHIAdAB2AHgAekB8QH6AgICCwIUAhwCJQIu
- AjcCQAJKAlMCXAJmAnACeQKDAo0ClwKh AqsCtQK/AsoC1ALfAuoC9AL/AwoDFQMgAysDNwNCA
- 00DWQNlA3ADfAOIA5QDoAOsA7kDxQPSA94D 6wP4BAQEEQQeBCwEOQRGBFQEYQRvBHwEigSYBK
- YEtATCBNEE3wTuBPwFCwUaBSgFNwVHBVYFZQV0 BYQFkwWjBbMFwwXTBeMF8wYDBhQGJAY1BkU
- GVgZnBngGiQaaBqsGvQbOBuAG8gcDBxUHJwc5B0wH XgdwB4MHlgeoB7sHzgfhB/QICAgbCC8I
- QghWCGoIfgiSCKYIugjOCOMI9wkMCSEJNglLCWAJdQmK CaAJtQnLCeAJ9goMCiIKOQpPCmUKf
- AqSCqkKwArXCu4LBQsdCzQLSwtjC3sLkwurC8ML2wvzDAwM JAw9DFYMbgyHDKEMugzTDO0NBg
- 0gDToNVA1uDYgNog28DdcN8Q4MDicOQg5dDngOkw6vDsoO5g8C Dx4POg9WD3IPjg+rD8gP5BA
- BEB4QOxBYEHYQkxCxEM4Q7BEKESgRRhFkEYMRoRHAEd8R/hIdEjwS WxJ6EpoSuRLZEvkTGRM5
- E1kTehOaE7sT2xP8FB0UPhRfFIEUohTEFOUVBxUpFUsVbRWQFbIV1RX3 FhoWPRZgFoMWpxbKF
- u4XEhc1F1kXfReiF8YX6hgPGDQYWRh9GKMYyBjtGRMZOBleGYQZqhnQGfYa HRpDGmoakBq3Gt
- 4bBhstG1QbfBujG8sb8xwbHEMcbByUHL0c5h0OHTcdYB2KHbMd3R4GHjAeWh6E Hq4e2B8DHy0
- fWB+DH64f2SAEIDAgWyCHILMg3iEKITchYyGPIbwh6SIVIkIicCKdIsoi+CMlI1Mj gSOvI90k
- DCQ6JGkklyTGJPUlJCVUJYMlsyXiJhImQiZyJqMm0ycDJzQnZSeWJ8cn+CgqKFsojSi+ KPApI
- ilVKYcpuSnsKh8qUiqFKrgq6yseK1Irhiu6K+4sIixWLIosvyz0LSktXi2TLcgt/S4zLmku ni
- 7ULwsvQS93L64v5DAbMFIwiTDBMPgxMDFnMZ8x1zIPMkgygDK4MvEzKjNjM5wz1TQPNEg0gjS8
- NPY1MDVqNaU13zYaNlU2kDbLNwY3Qjd+N7k39TgxOG04qjjmOSM5YDmdOdo6FzpUOpI6zzsNO0
- s7 iTvHPAY8RDyDPMI9AT1APX89vz3+Pj4+fj6+Pv4/Pz9/P8BAAEBBQIJAxEEFQUdBiEHKQgx
- CTkKR QtNDFkNYQ5tD3kQhRGVEqETsRTBFdEW4RfxGQEaFRspHDkdTR5lH3kgjSGlIr0j1STtJ
- gUnHSg5K VUqbSuJLKktxS7hMAExITJBM2E0gTWhNsU36TkJOjE7VTx5PZ0+xT/tQRVCPUNlRJ
- FFuUblSBFJP UppS5VMxU3xTyFQUVGBUrVT5VUZVklXfVixWelbHVxRXYlewV/5YTFiaWOlZOF
- mGWdVaJFp0WsNb E1tjW7JcA1xTXKNc9F1EXZVd5l43Xole2l8sX35f0GAiYHRgx2EZYWxhv2I
- SYmViuWMMY2BjtGQI ZFxksWUFZVplr2YEZllmr2cEZ1pnsGgGaFxosmkJaV9ptmoNamRqvGsT
- a2trw2wbbHNsy20jbXxt 1W4ubodu4G86b5Nv7XBHcKFw+3FWcbByC3JmcsFzHHN4c9N0L3SLd
- Od1Q3Wgdfx2WXa2dxN3cHfO eCt4iXjneUV5o3oCemB6v3see3173Hw8fJt8+31bfbt+G358ft
- x/PX+ef/+AYIDCgSOBhYHngkmC q4MOg3CD04Q2hJmE/IVghcOGJ4aLhu+HVIe4iB2IgYjmiUy
- JsYoWinyK4otIi66MFIx7jOKNSI2v jheOfo7lj02PtZAdkIWQ7pFWkb+SKJKRkvqTZJPNlDeU
- oZULlXWV4JZKlrWXIJeLl/eYYpjOmTqZ ppoSmn6a65tXm8ScMZyfnQydeZ3nnlWew58xn6CgD
- 6B9oOyhW6HLojqiqqMao4qj+qRqpNulTKW8 pi6mn6cQp4Kn9KhlqNipSqm8qi+qoqsVq4ir+6
- xvrOOtVq3Lrj+us68or52wEbCHsPyxcbHnsl2y 07NJs7+0NrSttSS1m7YStom3Abd5t/G4abj
- huVq50rpLusS7Pru3vDC8qr0kvZ6+Gb6Tvw6/icAE wH/A+sF2wfHCbcLpw2bD4sRfxNzFWcXW
- xlPG0cdOx8zISsjJyUfJxspFysTLQ8vCzELMwc1BzcHO Qs7Cz0PPw9BE0MbRR9HI0krSzNNO0
- 9DUU9TW1VjV29Ze1uLXZdfp2G3Y8dl12fraf9sD24jcDtyT 3Rndnt4k3qrfMd+34D7gxeFM4d
- PiWuLi42rj8uR65QLli+YT5pznJeev6DjowulM6dbqYOrq63Xr /+yK7Rbtoe4s7rjvRO/Q8Fz
- w6fF18gLyj/Mc86r0N/TF9VP14fZv9v73jPgb+Kr5OfnJ+ln66Pt4 /Aj8mf0p/br+S/7c/25w
- YXJhAAAAAAADAAAAAmZmAADypwAADVkAABPQAAALA3BhcmEAAAAAAAMA AAACZmYAAPKnAAANW
- QAAE9AAAAsDcGFyYQAAAAAAAwAAAAJmZgAA8qcAAA1ZAAAT0AAACwN2Y2d0 AAAAAAAAAAEAAQ
- AAAAAAAAABAAAAAQAAAAAAAAABAAAAAQAAAAAAAAABAABuZGluAAAAAAAAADAA AKPAAABXwAA
- ASsAAAJ5AAAAlQAAAEwAAAFBAAABUQAACMzMAAjMzAAIzM2Rlc2MAAAAAAAAACkNp bmVtYSBI
- RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAABIAAAAc AE
- MAaQBuAGUAbQBhACAASABEAABtbW9kAAAAAAAABhAAAJIjAgAqqcBCT4AAAAAAAAAAAAAAAAAA
- AAAAdGV4dAAAAABDb3B5cmlnaHQgQXBwbGUsIEluYy4sIDIwMTAA/+EAQEV4aWYAAE1NACoAAA
- AI AAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAAoCgAwAEAAAAAQAAAeAAAAAA/9sAQwA
- CAgIC AgECAgICAgICAwMGBAMDAwMHBQUEBggHCAgIBwgICQoNCwkJDAoICAsPCwwNDg4ODgkL
- EBEPDhEN Dg4O/9sAQwECAgIDAwMGBAQGDgkICQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4OD
- g4ODg4ODg4O Dg4ODg4ODg4ODg4ODg4O/8AAEQgB4AKAAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQ
- EBAAAAAAAAAAAB AgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhN
- RYQcicRQygZGhCCNC scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RV
- VldYWVpjZGVmZ2hpanN0 dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4u
- brCw8TFxsfIycrS09TV1tfY 2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQ
- EAAAAAAAABAgMEBQYHCAkKC//E ALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXE
- TIjKBCBRCkaGxwQkjM1LwFWJy0QoW JDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZX
- WFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWG h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5u
- sLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp 6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A/Ie6uZ
- LZoIYXSSFWZhjkgn1NZS7Y4I4yQS5woHUnP+Na MsLq7qIXfaMN22nrTWmbzIWeOMzBmckLxk+
- gr8+hZLRH9Z18KqM3KhBK/wB339SvFbQrNGluD50T ESbj96QHjHHT29qeG3hT5bIQ/QnoQc5+
- lLayrFJuBUqSWb1PsD606OJriMIiFwpLZA6nv9aqTd9T PDQlBuNlyteX5l3yTvExmWMFjGjbS
- wORknionheOeFHDNHHGVyvBIPpke9SWrJJp7XJjdCj7QrHI DdTx79qhfe8yF43TswJ556CsVe
- 7TOujOMk5T1b2a0/4P4knkhYYpX+WM5wpPLDtiro+S2AEqMpcP tJ5OOPTjipZGtBYxwLcKzxK
- FZjkhjnkj0A6VXnaFEa3KjeAfmLHll5OPwrJSctzahOM1zTXlr26f 0hk8iCYCVGcRqVBU4ySe
- vTp2pYrkRWwhijf/AFo+Y/wDqc+vNVgPtE8QY5LMNuOy46/gakjAdfOa VDGSRu7buw/OrcY2s
- zOc6DlyzfL2/r/gFuaWzkib93I85kZyScDnv+lRbBFYi6iuVE44ZCvKhuo+ tU3SYNC/lERwhV
- nXbycnOKfI5iu1yI2Z3JAK5XCn0pKFtEzCbpxg47rzas/LYfbWtotvHbxyOpLk M3ufT8KhY2q
- zpGqzOrEklTyxHA7dKgaaJpt5+RnLeWoHOewq8lqy6bFNNxuAxn+PP8Q9hVyvF+89 yeWMZKHM
- 9dkun43IzEtveq8b5IXdDIP4hjmlDKvlvETvRQoOPXmmTpDC6qsglOSAy5wABn9al8pX 2BiI/
- l3Kw/rS0aTZ2wjGcWra9dOnn1J2kkmuVeY7nmYvImMY/uipmVv7QYbvNlOQcDA9DT2SBZys gE
- gLsQ2/G4AduDVgNbLIk+/y1VVDRHJZuOSD+VYOVtkd9GEqauruJUt3QXscZieVHbaXQ42rj5jU
- gtiqQBra4WJUZt2RwW/+tUhVTEv2dgiIjIzH+Jc/zzUKwSN8gcyHesZBORuOTxSb1vsTWu5c83
- Ze fT0CK2NytuFOCAoYMOpJOP5VVuYLeLWY4nR/JbkgnlsjqPbNaEUUn9pBY5Nq43ynHCsoPFU
- mE11J GDJHLM5CxqUx26dKqMnzb6HHUjJVZRcvdtuPsZrpLee7eMwCOQ7kdeST0I9qqJMG0Z1U
- Au0gOQeB k/NT4nJmW3uGZU34I6cY6n2FVot88oQwi3UDa7MOhxnn61ooq7bOCNOFObdR6rrbd
- FrdNDFJCu4h ZMwZHQdzUxluC5ijmiETHccjOCKbaW1ybR2mjwu7y3DDLKx6CoYU3/ZpJy0aJE
- yOgX5icnBz071L 5Xc7FHC1YP2cb37atefYltoZbefa0sKJJnJwTkZ+lOhSe1v7a4BDRupywXj
- nI2/U0yGTyFikJVZj 91X+br+FaG95VjXI/wBWcpj/AD9aU+a77M6amAnUklF+71v0+5Ic+nH7
- RB5S/Zl+64kOTHxwD79a 6OGOKz0xGRxFLCqou/n5S2effr+dV0s2uAkCy+fEBucr958D7wPoK
- fLJcqvmQ2zpmUK5lAYFuAhH tjPFeXVqOpaNzzZJSfspPZ+Vv839xZuLO2llZyfMZzJsVTggdS
- D796ykkjjihZIZVlaMbGJ4bDcM B6ZrQeeSO2l+0OivDdFXkC4BYentg9Kz/wB297AY3zuG2Ln
- gj2+nWlSUuXXYKUavspKb93p2fr0L Cwtc6oZWmj+3RAxt8vBPVjiqAkjltpc3cCJJIX2Eck5+
- U5rcmtjLB5UkkeXk3l4/lOPT61j29hbq zxoj4VsBmbIUkH5frmnTnFq7exyuLk71Hr2026a/8
- Ay/7PimJlW4WUcg7ONp7VlH7WI0AiIWJGXd jtnk/rWtdpcNNbm3QwTR4S6VunqPyNVru5JulJ
- ZZHYnzggwGbjkDsK9KlOXr+hrTryvda22XbzMq 4tJmuEKkxwqWXLdx1p/2SNba0eeUwPKDIwY
- ZJIJAIx2qaRNt8n2hxIkjE7o+MnNSfZX+feduyXY5 bqpPQfSt3UdlqOqubXn19PyK8kCKiyS3
- MbTkEjjAb1xSwRSecs0Ubl0BGBztLcc1ry2dssrm7R2O wl1XA2noO3bvToVaDT51j8uSZ5Rhg
- Oox1+lZe393+rDlUUYuPK5X6tW+/cyhCfICSyxxXG7ALZww xx09ahgjK2oiDrEHO9lYcjjH8h
- V0Q3Hn7Agk3bXDAds4yKlubf8As+/iJQXAZHVW7Nxww9uf0q/a K9r6nXSjTU4xb5uy/rVGZHA
- Yrf7xYMwKsBxjHI+tWHUNbKwR/KVgScEjd9alhVo7dI5M+Wq8ZH+e tRT53feI3HLIBgLVczcj
- veHlBLmh+bFgsYLeKMl8ySSZCg8px1NSwzz2lzHInD71/h9P/r0yN3ku HVG3SEEhcdcelVgGG
- wZYZOWbr+P0FJxcr8zuYuh7kqcndPtbT5WNGa7+03Jk2vnYRIw6Z6k1qxXl ta2kA2s/7pmyD9
- 0HsfcnpXNWl00drJtVJfMcktjtjFSi6aRSoYDAC4C84/8ArVnPD306Iy9gqqip ydlt/wAAvLe
- 2UlpHbLBLaOxG/wAxs/vAeD9KoXN5IU8yUhJ5Zw7nH3iARx+lN2ESxCSaPC8hthO7 3HGe2Kpm
- G4nMD3JO4hmjAGMDkf0rSFKCdzjlhnKahZv1/r8CHYgiKMwUkbhk+nUVYxJcQqszIRt+ cKOuD
- nj6YFPjhdrYZXcqMAOmcH39KU2zGVUE0RILK3BwR3IOOlbOSNZS5VZp66WV/wAfIqBQqBYZ Bh
- cgMeg3dqgjU21itvHIAryF5UIyRxgc47DmtGG3fjy9jKcn7oIB/KoVhgMNtGyuk4Y5JP3ge9Vz
- o4sRgnzRm4Wts1/wxLGyyBlk3Pt3AFeAw/hxUi3ziwt1kGXRtkQAxlfX8DVUKxjjEP7xdwDYHQ
- DP tShVLlQ4TnKp/Fn/AA71DhF7lV6PtUnNv1/y2LNy141xG926uWRmygxnnBNRW8+9nTzRCjF
- d4cZy vfFSSTb512QuVOflYA5AHHQVGro+2d1j2wZAAQAMzDAz6ikl7trDqKcafs6b/wDbX92o
- 15GMwC4E THAyONo6dqRY7aOSBo4pZCrBmAPQjmm7oxb2ykFZo1KsWOQ2TRE4K7MFFZwVJ64HX
- 86trQmUE4Wd /nv+RHOZGYhV3KuD7nnINJCwi/5dJ0yCSSQce9OdpQ2duOPm/OpCkbuzM7uEHB
- U8PV30sdqT9ro3 fzt+bRRfyxlllUlgMYHfpUaOzop5aUZ3Nnj2GKsSqYn8wxOQBlRxxjHP51U
- SR1kDKm4nOSBxn/Jr WOqPKrt+2tK6S7X1JXvGjgCyfvS45UDsTTPs6i7kiRAPLyrHOee/8qHT
- McYuYsbV5IH3v88U64ig Z90TlCARjPfvmmrLYhqrUfNUs1HZPf7yqi+ZIFOYgSCM85wDVyNFL
- EBxtHK5bt6VT8lpJ1VXwcjy lOeR9anWSObISKUuQRtUe9VPUww1aCk1PRrXV7r8iUw70kYXCg
- LtzgdyOn1qtHGk1mJVnHmqzOR7 4HFNDq4fZG9uORhzktgf/rqHygVRh+6KtxnvTjF9zPFS9q0
- 4bLXrr95LGt9IV/eRKVBLHb0TuPr1 qw1zI4kXzV2bsKSOoqKNlAPy/KxYg+uOMVZtI2kMqYjG
- Yy4LDjCg1M2lq0Vh7r3ud2e+rexBHKWU +XukPm7sg8DHb+daUkMbM2Uk4J8rLDG09KywrySwF
- nS3TPI2/eXv071LFvGNisMhiwkOfWlKPZmt CX71Jpv8n8tSREkS2FvwIgwLE8jpx/M08WpQEx
- sWIX5lU4NNijaWBsFiv8BA68frWgIklbyw5UMh ZnXtjms5TsddGjR9nJvRLs9eu1inLKGg/eb
- ywA4H5imvPMTkElWAx8vbuakVf3JlVMZkAOQG6DIP Paoo3Kyp5hcbpRuKgfdOeOnftQrEzxk1
- Fzd7eW5RnEk9wjZSELgNuHOMVLC72+/5FkweWHY4/wDr 1OYraR5GxK64BHPTsM/lVa6WMzliG
- A6nB6mt4yTtFo5VGUE6yer8/wDgWR0NzDKtzEqGRwpwxwQP XB9+aHTY0KSJISI/lAx8oOTz61
- El6r7Y2lDGVioYEgA+/HepfJDSKiv5jlQWYnjODwP89q4NVa57 6rQdTmVtfWy+8diFLfeqhxt
- 4PbJ6dqVHk8uOFoyjpG5XaMFgOpqv5DmGN5oXiMZ5wcZ9PypIJriJ ot77pIQyL8vr1BoautCa
- 1adRrkitNr7E7TPBB5UaFsKAXA+UKcEk/wAs1I6tPcbIgCXOTg8rjnB/ lVRblJIiSRgHaDnrU
- sckksJkASEliNpGTgd6ORo3pQp83uy37L+vzNK9juJIBcT2wjhdyVUIARk8 /liqUELXNwsfll
- XIZyS2dzf0yMUhlaS4WNlYnJ3dunNX4ZYvPE/ktHvJJZSAuPb2rF3hGxzV5+x0 STfSysvu/wC
- CQ+ZNBIj20QjVkztdQSTjBwfQVloI5ImcYIU4JU4y3Y1cG1PKywnjdt5APLYP6CnG ONt6b4kQ
- kyBVXb8x4A6dquNkVSpxcuZQWu7/AK1M+B7q2X7KXzFJMWm3c845Ge3FTsXi1AGNcsSf LDYJV
- MdD7+9TvZPDLEZhmZVcMo6Agf8A16bYgjLNLF9oKBF3rwQepH04FW5Ra5kccYJNuO3boIUk vg
- w8qFHV1KsqAYAXrVwPc/ZYkkClPLPlnbxyen1yMCoRtW6RpWAZNygKcZLcDPtV8xxxXgidyypG
- RIQM4bnGOOnNYyltobYOnL23M1a22jbX5FORrpWe2WEcnJURgsoC884qSK2d4kkDAITsBJ/i7D
- 8a sl7gRIU2RKdqNLt5Ax606dY0+0I86zmObKmMYDLtwMD1zUc72R6MvbRqfu1pfXTX9EPSxii
- nME4k bGWV93+qA+8G9TUc5R4cpaMkZbdvzznHH4e1SmeGWO3ktzMJlUocnOSRj9RmhIJjLbxB
- dmEypccL z0ask3e8maU1Je/zX8u3ys/1JnNx9ntwyxw7oecxjghsntUgKyXKvPewIjOXGFwdw
- 6HgdKinmSRp VEbInneZuJ3bTjGD7e1Z7/Z4SHjDuq4G1m5G7t9RSjDmW1mbVKEpU/fVn3snp5
- XW/wAydFE9/JK8 6Rxl9sjZwCSDg1lMpjjQEPxyDu5HpV2DdLbPabdpVvMXPXj1PeoI2228hIP
- mAEdM7hnlvoK6IaNn LOkpTbe9vNW83p1IFKjzGZwjhsktzk/lW5pywSwj7QQ+3fFIqcHcT1/C
- qyfYjGY8CSUuQX7NjnOK nfLmJ1gKOYZDKqjq5Pt+FZVpc6tax5uIpyxElGKs++zGuzCaexBMo
- 3bQUGOR3oWKI2DCPDO21pSf +WbZIx9O9VYYdluJhKHCuoZQTknB4q99me60yN4X8yRVyFQYJX
- uT64pStHqei6c6XKtEu67+Y2K3 SV900tuAgYhiv3wDgMParM9my2SzC6tXULtXYuCecfzqtBD
- G9ypuIplZZQqIMDcCM+noK6KOH7Pe Szq8XltIpEbrnC45H171jWquL0ZvUquDvGV/u1/yKMMN
- 1azxMtzFG03zcj7pBxt/HNasst4yCBQj G3baAF5YZBP49QKrTOJHjYSRbURgeOpIzkfSnhkaz
- WWK5V5JkJi6/dHGT9O9cc25WbX4f10OOpyy kpVlr3tp82tSW6EE1v5e8O+M+XnlvmyxPuBUds
- PL1k3gh3RIAsW0Arz/APXNR2k8rt5DRb5UnOJV XCuCOCPbrSztLZeW/mqwRHUccHBBB/Wps17
- ncy9rzxdBR+L8fQS5upbbUSkzoyIQ2AuCxX0P1I/K oIpDqdvcTMjIyEoqx4G8sfvfnUpSwYXT
- zzK1usoUEtk54IGf50lxcSWz+dCY3G2RWVEwMn+orRJa KK17luMI1oRowfP+H4GVqG+P7RF5i
- J5LxhmP8TYBPP61nS8Xlw8ULOfMbew5HzDqPQA0s7b4YYQD vjTLHOS/vVgRTNHZKh+0bY9s3l
- 9ixyM/hXfFckVcqvGVGznBJ32X6/8ABK1rYx3tpGEbLNCzKpOS WBxke1MeEQrFGRLGshP2jzD
- nJ42kelalvttryDzJY8GIlAo25HO7FVkjEbRyRMXAUlt3OHHQUe1k 5Pt/X9epxc85y5VK3a2m
- vqI00bM0cwIDL5cbt/c759TnnNZCRrMojMpEqNjcCQCfUe2BXRefI1rF LNZ8gFHZkADMeePSs
- xLfc6K1tIZBtDhBggnOCaqlOyf+ZrSUuTnlt6poIQLQh4tw3gsm9s47gfh/ Wm/apLlvNkgkmX
- cF+X+DIwR+Oafd2c8W+JQxij27mPc4zkegqrHPcJeBomBmfd8qLxnHp0+lXFKS 5luUuRw56du
- bv/W3yBpm8+EzJHt2FQMY3EAqPyphWNre1aMOx2ESknOSOc1OJw6mLCTwsrNlV+YB R1B7DOfy
- qmsrSBBEqqWLKBjO4AcmtYp+h00qsZSUpOz+eo1EM0wliO11IfIHXB/lVpHS8nkkZ0Tc TuCr0
- P5YxTJBHFEoCSxuQAVJ7cEGpfswM7bWUBHCsw4BJ5z9M0SaeprSgm+ZRs+uln+oxRmLyYzH Fu
- kHUckjsPwqeSJ7edQI0CliXjIBZCOACa0bW1hlTzDFIH8wsqhumDwPzp32JZHmVRJGWcNIHfJB
- 6msHWXNqW051GmtF0M1YVmslQQyi6DYBByOegxVEFTkfPmMlFDHpnk1uJauLjz7aGZoSGaIk9N
- 3A ye+Kz1GYAtrt2jmZ25GeRx6Zq4VEOKjBpL/N/wDAI4EaZZUWGRwSASDwuPWldpRegSRxwsm
- UbKjO WGM8DoK0vLZ77yYysUjvsUjox/x60kihYZI2ZfNaUm3BGS6fxNn8OM1HtE2YVKkZ1OS/
- 5XXmRyxM LY28c9lIkRysoj+9gc9u5rF8qdbjdMgZt2WCDGwZ5B44NakqolqwKywxcmFnPLEe/
- pUDKqR2srF2 Mineu7lZBxg/zq6bsvU56kacIr3t9NLfjYqrLBDc4kXaG37EHHTpmnW5865hia
- AEODkouCCRgc1M scTQOrgxyrMIzvGSCTyfpTolKSPFGrozNuScnC7VB56d6ttWfc5+Sm4Nyf3
- 30/ryC0+zlhBNG5Ql dpDfMAMhuf1qGe0iacFAUhZG8s5zkL/F9DVqRoRLbuCJ0jiKDbxtPO4H
- jqM06O2As0kadCVUDC9W UAk49OtSp2fN3KhGEZqb+F6aa39Oxm29qGuIlwFG3fhurY6D8aI7J
- pLnzImSBgzbUc5IHbPFXGtT PbJNbF5WwPlXkg4yf0qncvvKJCSY+gI6kdQa1UnJ6MJ041Obkf
- y/4BXFv5bKHky8ZJAYE8f3SO5N SYkjjjWMKu6PIUg5FSwzCGaS5kiWYyHaoZchgeC34UnS+cS
- MDHl48hcDbj7w9hVOTvqHtYU3JxVn bp/V/uZlssghVJ2EkpUkOnAx6fhVeWWTciIhcZ+bA6L3
- q7HdvLAZEaEBSYz8mcj/AOvUjwB7IzGS N5A4UxgEELjmujm5X7yOOUeaFqcnZ9df+D97KE8v7
- xkSVX3NtVj0bHpVULJAuwsMMTnIzmtjykct EHhyFLA7euBn9azpYj5ce4kblDDn3q6c1sY14O
- Tb3a+RXkaeZoyVyBzlONoz/iKcYZ3BPCHO4np3 qd/JiLhldweFC1Ahjhk2K2/erKMnP860Um1
- ojlqUlGTcndvfX7ug2VIphGGkMuwll2tjk9c+tW4Y vMhYBh8rZJBz26VF9mSLT7Zt8UiHPCDB
- B9+KWCJxs8ncAPv5PXmlKScdGRg1FyUuT1SJDGHk2ylU VQNuxeTnmlW12tF98jblSPTPf8asG
- Jhcuj7mKnBKjgelapvJpLe3VPs6rtZB+7+9g5z+PQVzzqyV rHdOmlUXu3bfUznjUlhOhV1lCK
- i8E8ZOP0pZ7URyLHcDEinDkZGD17dulaNtaRbC9zOvLqSmfmQ5 7n+dTXEMPnrsdxIzl1aTlWQ
- cbunTNYe3tKxq5e+1O935afO/+Rl7pgv7t4oI1m+8yjAY9R0qREba 77CpmkZlz2Vei/nQ00Vt
- cFFT7SN3Ddsdc89aspELmWLadiJueUsPXgKPc05O2ttDGWHSrKpb3eun 5ozZo7iWaMzZQyP5g
- TGOvf6VApVQxjjJ3Nkkjg4PUe1aSxzpOjeW6FZdnzgHB9KrbUQsSDGM/Ip5 IBJ4rSMtLG1ClD
- mfs3p8tBDG+2TEbRHuOuDUE1tsQCSJsYLo2efx9avWscb2SyPMytliw9QOg/Go 3s5nijZSXVQ
- Bx2B6/lTjNX3DmpV1zKO3Vr8hwsxa+Vb+X+82szHHUjn+Rp0Mkf7sCKWTcAF57k1X GJCsiyyP
- s4Bzzk9/oKuRguD55VG88YKJtAU8Htg84pS2u2drxCov91H3enW3qKuILh4Rwwcx4zn5 h0P0N
- QxnbCfOkCS+crDKkhgBgnilkSWOTZhWfqWxwcUwHfPE0iYc/KBjoewI9am10XK7ilzbbdEP Eb
- GPcDCEX73y+/H86mDBbxVSSFWdiqq6574xVJFLkAKyEA8N3NXI4h9kb7s2clW9MUS03NFzTg4x
- W6/rqh8cjtG9w4GwuwXjsOM/nU0RcwDJUoGAQkcKCOatgFLTyDENzMNy4yBn+Hp1NQPH5byBV8
- r5 tzK3X0ArDmudOFjiPdVTp16/cCRqVaQSBpY1JxtwB+GKZEF+/JltykjAAq7bxKw2yRSO2AZ
- Npxnn oKkEcflwq1tOjMhYjd0yeD9MVDnZtFRTjUd2/XS/5lCJNojdMMPLLEZJyc4x+NaElnY7
- baMLKrYK ctyG6kfWrUdvBJNFMFEEEbEAuf8AWcHDD29qYGFsSdyNKiqN7cq2T6euM81hKq5PQ
- 83EU6lad4dO 2n5f8Eo2FgzXzbwBhfmLj7uc8mrcFrHHO8UiSuyx7Btb7xIJ3fnV9JSzXaxMqq
- kvljIyWUnAOfal jkt5r3EkcskuDsZeA+DgYqJ1ptts7E6nvSinGy/pt6fmOtDbRrHHbwvPcOo
- ZyxDBCvVSPXrReQKs LxxWbKJvmQ8bmAOBzWeUul1W3iWCSVcsrNEMc9zn2PH4VoPcXtldW7yR
- 73+ZYlP8Kkc5+hNZSi1J OLu35nL7KSq88Xd+r/zKB0+G3+zuZ/tEkUg3JESCdpyT9Of0qS4Fx
- cWqzzI8aJuO9OA+48H6cUye bz7iLYzCRR5hC85Zf6Y6itOSLzdPee4BVS22NAcAh8H+daSk4u
- LluelSw0qVSFSUU9db7/cY6yKt oDNBKT5jBwpALcDJ6fSniNGkSD7K6xjO1jjI6ZJ9eKrJbTT
- 3CRKQZmIyp/vdMfXirNxHMk1qof5j HLKMevdffgVrKydk9R4vmg1FSu797WMmRoortpEDBVOI
- wW556Zx1pbaB5YHlkkjk8qUZSMYJGMkV YkkQwruiGXG5D/snGPxFaGnxOlmZBEZ0dyx2d/X+l
- aTqcsLnHWnKa5pRtfTff8SvC/kyLIjQxM8L ja65xnv/ACqJpWlhkBjZrltgG09Ox/E1It2SYL
- nckDueY2XJBAwOx4rQlhkklmR0E4wG8yEAfdAI 9KycuV3aNVUSp891213/ACV/vJVkijS4Rts
- eydMggHqMUxYxa3H+onit5MpG5bgg9R+dUrBZL9Vj YeQxYtM7/wARwSD+VbxtLifTEjVPMR8y
- Y7gcEL9a5qjVOVm/U8+M6cJW773/ADRAwu54t62xT5i3 QZQ4wAfc4qQXrLoO+6s5VYS8oxG7A
- x8307U4JJHDClw/Mo3SFeNhB4U+5pt0Ymt7m4hhuEkBIdZH zsyRgfXqax0k0rdTohCNRwUYvf
- 0/G4ly9u9wXhjeZH3bERudoNZNoXN0yMjOoDMqqcFV6gfh39a0 rnU7FLOaILvZ5FYMnGD6fTi
- qktyHnit3j3ZDI+zAPJBz9Pat6Sko2sd1KVRx9+DS23ennb/hgmvF GqfbIZ0MbfKoU8Zx0qe3
- gi8pmuvNmRGCvl/uE8bT7nrWWI0lnWHymOWEhKnA+XI4+tSwec8zR78v PiWRD1Vl6fpWkoaWT
- tb+v8yMRTlVk9bNL00JLmSG3ln8sLHtZYyj/N1HX61SuHAiSOJZkaNsYds4 9j645zTZZJZZ5G
- nCrlt2x1+9kcEVIyxy2cM4LjHE565Yenpwa1jHlSudCp8yi5X8rf0iO3hCSs15 kxE8Opxux6H
- 0qe3ke10+OdyJY2I+WM4O7ORz9K2ATdQRgWrS2rRF1IwNgHG0++ax3hmMiCZY7WIE Id4OMseP
- xrNVOdvmOJ0/aybqvRb69P8APuMuLiV5YTcSQGRZnkwkeCORgVblZ5ba6khXlZywKL6j PT86W
- C2tlupYZ7232wvtEjKTuBBzViDy7ZYonu4XiaEMyDruGcc/SpnKK+FbeXzMXRo0rcsL211T e/
- 3GNMjzW65L2ylvMBckggYGPrzmrVvZpuVJXklaQMAyn7/Pyke1PuLW4khgRTstjbGQOwzu29cf
- jUTXoSM3USZZcRkHoCw4I/WtOaTjaLIqxqxpr2Oj9dCdhZxRSW4eUMXVWd2yNxXg/QY6Vlrata
- Sx BicSvlZB1QKCcH3NLJK0izxFMSkneCOm3p+OKrO0kiS+Y7NGzq+M9DjitadOSW5UcLNpcrs
- 3vcWd 43uifOjiHllAuMdV9h602PdbWFsgik2BS27HO4n1pscoLtsWN15Xdtz+PIqaKCN5UVhI
- wPLKD0Pr 9K2doqzOicFTiqmjXp/X3jVndoyskamQ42uUyWXByRx0FXQ7xg7fuugVNycMT3Hqa
- q2bBp4w8Duw RxheORyD9ParttNvKbpYoV4Rd4zgnms6mmyN4zVKm1ZW31T/ACLtttggZQDdN5
- 5QtGcYHGPxp9xD Ld3riNDahGJZnPQAdD75/nVRkQ5kil+RZCWjz8xx1/Si2uJWlLgtHbysXO8
- 5JA4PNc3K78y3HRjF XlGV/v8AwRfSW4tYFkKfIZFj24+4CCSakCRQvLJK8NwrcKsa7cjsaZNe
- faLVXe3fyVdsHONw29fz xinWcMQS28yeOFBGpbzed3JJxWT+G70NVFSpubXrotV2Wl7kE8UbJ
- bhJogxYs3tjk/jWbc4F0rvE YoJmYoSM4A6jNaE0LER3EAZvNHmtJwVB3YwKzpXnN1biVlABBG
- 5eAGPP61vR8mKlF04t0no/v/D/ AIJbmu3jVRHGkkboz/MARzxx6VmWYW1uobggSxpzIeoLNxj
- nvin3EKeepEu7HIweOPb0J7VJHujt Y55SBM6syIF4PbOOnrWiilCy6nFiMDCUbKHxfL7+q9SO
- Wa3MyKqM8bI24Dgk5+XJ9afBbO8byS3N vACQ4BzlgDxj27VJbi0EEZO5H+z7SDnJPI3Z9Paqp
- aWRkhDBV+X5m7EDHp/nNUr7LQinQai7tqK7 q/5ofPIkjj5GQzHz3YdAewwB0pkJuJJGtzJGq4
- BGV64BPHFX/IWXUCZImjhcuzRg4aIgYwT7dadH BFbtaTupEUkBIlBOOuMn6modSKjYxq1MOo8
- kdX0/q1yhNPch42lUQu43rsXbjPGeO2KS1ma21pXV YbhWOxiEGD2B56cVchghclppGjBIUM2T
- 8g+8PqT0qNp7Z2eFYtkLHzowPvDH8JPfvT5k04pDqqMq UowpuzWr2+6+7KbkLem3FuyKXH2dm
- wcIMk/XNMktLq5d5ZlW3t5SSHcYAHccVoMsFzcREsyokLBC OPlJ6/zqt9octDGq4VY2UFjkMS
- fl4qoyl0WpwRoVXdKNlbqv6X5lX7DbWV1Bu8uRWi37kHynAOeK ijkY2ashtk3MA6NHkn1q2Fm
- iKPcwbT9x+ANue5+nFUp9n2sx+YGXcQJVGAcDrW0W5PV3G8LHnfJK +nay/wAiG4jS0uh5DLNb
- fOiPjPbIyfxqmsiGHe0bsVAR+RgN+XpV0pF9iRFjYmRAyHcBwCQfx460 x4UVy4CoAwkwec4re
- LVrMKeGrqnZO6XyRXeGH96RMGBm2x4GT04H4/0qiI4hp7+aU84TqyHB+YYw fpg1dVF8yFzllQ
- ZIHBPOalMa/ahmFmLI+fqe9aqbiclfB1JQbntHW/f16fkZkRCiIRE7Sh68jrkm pLZJJt0bzxx
- sCWBI4Ix0+uasMR5sEMZSJCn7xmHK56j86cUnhvCjLG4VsEoNvaqlK5goR9ooRbT8 l/wdSdXl
- +x7/ACnhm37SsmDle/Hr05q7bWjFyTE/l5Ii56joaqWMc00u1tsKLJ8zscgAjgfU461t W1xFH
- YC3jVpy25vLJ+YZGOD7d64603HRHXepCCs25d30XfyEFxPbrFAPIjiKjLvHuJ/rUy3EYhlL we
- cUxGj5wFwM7envmp5tPmexEm1vPQLCseMlivVvpioV024W4khCPKMBl29/b6/4Vyc1KSvc7I08
- O6ammpd9bfcKytNZmRbeABJAOIxl1xlselI1tcNpweOHKSMXJUY2gfdB+lVIrm9hlPAYFhlNvc
- 5A q0t3cnfD5oCGZcE9MHjP0puM47WMJYerSkpU0rLXr+WpmzWrRXcQEgO+RSVHJJA61DIWm8r
- DRhWT Ifb05/xq/cLAmqrcCYqYZwqjOQwYcEVmxb0CJcIxw20qDgqBnNdMJNq50Rr1IzlHldml
- stf8iqlr FHbDe0jyIxKhScEHv+FXbVCjw3QYtFHG3G772Ov86r2sbyPCkTAOww5c8dTz06dK0
- ZbWQsIVt5pG SIquw8A9wfU1pVnrZsxn7Hk5NEuqf+ZmrFiRY4AQuCXyMnHer0i5ulitz54ky4
- CjJUYzg+pqOWZ0 fypRFHKVwy7cFjknjHTjFTo0wthdTR+fHIefKAU+gYH0HpUyk9zor15U2nH
- 7v+B/lYosS37wMVXh T6564qxPsnufM3BXaQnZ0wVGcj2qEmN5dkYMg35ZwcA46HFXkgWRSYla
- 6lYCTKDhSeCKJStZm8W5 JSk7K+t9iASpHeCbiXcCxwf4j0q3b/Z4woLuWYlXRV5z6gkYxUyQw
- vMYGi8s7dysewHU1ONOhawt Z3k8xtzPiPgt789qwnUhszSdoVUotpvt/nqWRa+fdokaSGFYjt
- bPLvjg5qt5ZXTp5HurdyZAsigZ bd+XFaC+ZFe2rElIS2+MZ67Rjd9PWqmTc3DbEAj3h5ZgPkL
- Lnbx79K5oyd/I6ZVZqs/eVl2/zf6E cBuIzEBC5lAV3XuoU5z+VaNwGup3nWeJpGLNEEGPkBya
- maZPtab2Te4cttX/AFfy8qfx6VWkDTab GwuIpHjiSIBE27cnv7mo5uaSdrDoRU5+05Xrpqrp/
- gkMjgDOkiSQ4Me5sDoD2qBZp4oZETyywkCb SgY8DIrVYWK3lxHuMKCQLhj904x+XWksYrO3WQ
- efHclGyNvYYPB9z2pOro21+BWKxk+b3o38mv8A gfqVI5pDf77qaKOLyysi7QCWYZA4HXOKhUb
- bS3EJRpFQqx287geRn8aFjtpLfaI5nkfawTdkrg42 n3pLdZf7Ut4A8QdnLkEfcGeVPvWmiuwl
- WjD95JWXbYm868ljg25LoqeWijBbrg+/vVeYyXFgZpLh ZJEm3LjPzgDqPYGtGa5kN3tAS3ihl
- LAleYgBwGPfJ6VWia3lkaNgBdyzeai4yBx93HvUxl1t/X9f 1sc8KylO7gl/XdrYRbea8ZmXy3
- dnDZVcZ9SPYirElpI9zPbDd8qlzluM8FcVXGousKskP2aRiFO4 cBTxVkCO1u7ppneVi4SMoSN
- ydz+FJ86f5HpUZSbbS9F/W5Xulijt0Rfmnum83cp+6y9vx5xWWl4X hJBH+sznuOxH5VrXIdrp
- BbxO8ZbIfr+I9KorOXhUpBHAoZ1eMqMtwMHOPXP5VrT+HVXJ9k5Plcb/ AC1CztlfUBEWKQ5Yu
- SOVUcitezjlRdkcTxxSDc8h+7uHQj0HtVG2aOQB7iKSRiQp8ttuT2P09aZP PLatJahZfJLqW3
- NnGPQ+45qailN8o8TRdWTj0SW9/wAFfX56Gnd21rCYhK0c7spYqnGQOSRUD2sR kSaKK4ZZUDC
- MSc9CDz7danZ7K7WRo3y7ThQuecY6j0FRW0Zee1iZnclBllYjGScj8MVzxclHVs8h OolJp7fL
- 8CS3keA28cKpKoUHIHbsf51pyTyXEf7wtFG0hwqfL9Bx6077IZ5GiVT5bEspXgsp7j2F Qm1Js
- 4Wk3PCV2OQfXowz71zylCTv1Ob2dPmVRuz9LsqwRPE0Jud1urxMVaVsg7Tiq7yTTTIZZEb+ Jw
- owCemPwrRFpKkCR3SSXHlSbZcHgDjP07VJcJFKyiGNvJBYNg8s7Hgj2q1VXNc6PauT1fz0sUpI
- 55A0VrBBKBIfnMYO3GMZPr1ouLeQx3O+DzFSRQ5jUAn3FWU0poneRJZYvKVo5kLnl+uar2yoE8
- wX gZ1QxyR5J3l+jD2FOM1unt5GuHc4vmUrpdtPxK0lvLJAq2s8AVVwqkfMFA3Ek49aaIJbiyt
- naWJb jDKSOM7uc/0p8HnWt5aoJFCMuZWcZCODyD9c1anJniMUqCNDIxhIABJxx+FaOTTSHLm+
- sR5tt7+v y1+8zLSwWUW0ckUjyNESvzdgTk/hU8kUK3EkYAjfysBmOVyR6Y6mrP2NURRcTlZUT
- CsrEDb/ABVk 3apJFHIgZVX5QSc7we9aRk5y3PXwik5Pm1vtuv1sWDcPAYltn+7DtcY4ORnI+l
- NWbzdQsjdobiIo wQJxuJHDfnVY5t7oeW3mqA4YnkEAVJFHvWLfLGSsY2Y4IXOf0rRwja4sRha
- c73VvO2v4ECRRrbJE 0qK4ABDDnOSTz9KtzLasqeTnzZZPMXLZEZA4U/UZNO+zRuiXcJQxrPsc
- MMnpgn6c1QjJ+1IwSSSJ GYqQCASM4Ge/pRfm1T2PMrynOFqU9F6flpcspLNLexwREh/LZEjbn
- aoOTn8Kbv0+2tmWVtrSTAWw Y5JGM/j9e1UFb/SbabftZlLMcnII6A0x1aa4gLI1xDFExDKMYP
- OOSK1dJXtfQxxmHnN8t/d06fkN 2oXSRkcjAJAOCRnnJqKYASptGwIpXkfe96crPJDEpI2rEck
- d25xUs7eYib0L74wcJ25/xrdaPU9K Eabp2m7P+vuIkSXzG2hQ23cPlGOnIx71YRg0EnnREfON
- p9BjoapwFn8xmjliZSVYk9M9varMtzMU ghVMrIQM7fTvRJO5FoJxqJadO463kmiYTKECsD8+w
- cHHAzSfafNtcCFWllbexAA2npxTB5scLjIK LJ6ZAB/rV5/tEVuDFFEsYLbiEHBGOPxrOVr3tq
- czd6ilKKTv94uniJtTEbqYxjBU9TgZzmtWJpks 7dBp8kplXOQAAOTuFUreS8lkTbAJG8t1d1j
- 6hhwfwrW+zXIs83TMYfKby9nBU4wM1x15Lm1NK8m6 nv2T7f8ADMryNO8u0252LuCxgcsRgKfp
- mqLzyS3G4oowAJAR1Oecela0XkLHZKI7g3MSYK7+SoPJ /DrU8ULTSIoSMwYZiwXnIGefr1FZq
- rGO6NIYunST54fozPupC2kSrJEYsTD92ODnr+AHpVCKVDcX TmLzYyQc+4GanlYOiuFJCKeG5z
- u/nVeSRvs7wFfLEeA7Yxg4zg/lW1OK5bHTD2UIJOOj316FdTHM lu9wdptlAQKMbwxOSfpVe4l
- ZnUGUbI49qjHJGeoojbzwH6yMhby06jB5/TmmxTxSFYpo82zOozxu Az1z2HrXWo2bfY5Jyo0V
- KUE35ak0MkeZGby92Rg7Rhh3A9OKc8quXkSEDzNpiCjHA4z/AJ71TeOb MqymPMbkbQMZIPX9a
- lku3jRFhhA6bTjI2j72KXJd3RxpSlH2jTafT/h/+CSyXRQb5YpYpJZc89Gy MMfoKcbSeQJbxu
- ziJBGnPDLn7w9qh27L6QIfOCEomRn6Ef55q2i3l9GSWX92WVSo2gk84NQ/d1Wh MKMoPm0Ue/b
- 5Fh4YVtnt1kEjeb5ipnJAHUZ/Ws6QK1zFDAylI0ZY36A7j+vpTUed7UxbWWRCAMDJ I60p+zyw
- l1byWMi+XlumSTj9KcYuO7uEYypx7t7Pt52H2kUlsJUkBjSRWBLDow4xn8c1DOY5LKxi t4XZ1
- ADuOpOcA59K0CZLQyCQNcoTuGOrMRyR7Cq0lvC0DCJiZkZUCdd64+99KUZXldhGc5zip6Jd tV
- 8yocbRJMs7gMyStv43nv8AhxxTbiS0MUdtFGTKmUZ853txjAxViaAWdvGVYOrSkgEcYA6H3Pr7
- VVaO6BVjEwkLgYAAJYd/yrWDT1uc1OKac29Lvq7fdchMLiKQLbywFWKhJDk8nlen41XKFrtdrR
- gv NhMjjZj+uKs36m4lS7WUu0U+0qODjHB/SqyRRC3hVgytt3Id3Pet4bXOaeGqV17OOke+uv3
- lkJFA HABYNkgdwPSqIQP5aDckRXLORyuD3OKvgqLXauzcQPnY/mKpyJKbqWPOIweo6DvVQO+v
- QlKiotNJ bWtcj/dHa3mLkqdpwPWljVVijaR2YFmO3dlgSO/HeqBNulvEqo0pYnc2cbD2zVm0W
- JI3nfFwqnYN vTd1/lWso6XPKVeFSpF8vvL+t2vyL4hHzS+asfQOGH8eOFq7EBbiWRJbeVklVN
- q53EdTjj8KoskE lmrBXjYjeGZ8hsHGcU44F0G3M4znA7DOT+Irnacla500ZTqQbk3u9NNf68j
- X8uNrm3X7aUadZHjj YklPVT7miZpreFEX7REduSS2SrdMfX/Gkjeymvo/OkYbpDJE+cYHdavy
- XFvLYi6f/SVdi8oQ4Ikz wPpjtXE5NSSauZ08RKNRRnG66K36r9SigvnhEks0LNJltnlgMdnHY
- e9OvDNDfwybUysbKPl+7xgZ 9acLuSNoRAFGVPmbhnPzc49KbJEkt6R5NxHAJP3bl8/L0z78mm
- rqV2tA53CV6isu3l6f5alEcm2R 4WaR4/nPoT0/HHSltZrWJth5ZiW8x+QrjOFP1ovnBZYY4mM
- inAkLcEDio2mFuohlEZAY4UKNwKnl T7nsa3tzR9SMdVahZ3XlbX+vuIrOTa8dysTFEkCgD1OT
- ileSG4VnzLFIzcgnqTx+n9arW81tLdLP skSLzGZ1EmQrngHoOgqKP9/CgK/Z1TO7J5fPQ+1bO
- HvXegQU6tS8lq1pZrbz6GvFFE0cklyqtLIN 0WTycZyelJ9ilktoGIKLnCNuwqg9c/U9Kmjl+0
- QPLJsklLYAjGAqkY6e3WplsPOYQxSbmbHlyk/I VHBPTPJrndSz1djtlXjOKU2k46/CvzKJtTb
- XEiuMXCOscfHGW7EeuM0+FLWS/aRRKlsofG1iMEDG M/Wp4o5IL9YiDcoW2xrjlmAJU59qo+TM
- kFukkBgm2sJMjAbrjA7VSfN1HQlKVXlet/67r9S1GzND HMCUeNAkasMkoc5PvV+2hU2tlFIk5
- dly5D8dSQoB7kVnpHJJLBGIGeRY8bB/F74q9GYWvkdUaJwf vGQlcnoMY49qzqbaHozpTjsrSX
- W9vvS1/M6GSa3ZYEdPs6eWzs7444+UD60RLCliZZQqhx80fcn/ AOuMmqFxcWElmu6XzH5ZlUH
- tjFU2aP7P5zQXEbM52s8ny4A5HH1rz40W11Rw4ag5zV002/k/vZam J/syVxEAIpcwuy5BRgMA
- +tTobUKGkCnJLOkfy+UQMBD6n0rLaVZpPMtnAkPDRMchmA+8B0wBUwu3 ijlNzBujdgVZV28Fc
- YJ7n3rZ03ax2zg+XkW67Wu/vf5MkdZFtN0sahAVZWK8yEcbvoKczxPpbFxs Mh82EoNpKrwc46
- 81nm+jMIhmk8mEYVA2SSepUH16VOpguppNolKgiNFB5j4+6feqdNpXaMnCjTs5 PVav+r7jUuT
- au/kRlmLqised28ZJH17VCt5NOiReULhVkCymMYZjzjBxxU1zJbx2Qs4cxRRzhiXO 53wMBgfQ
- dxT7SQwSCQxh4mV2aVFwsjAEAj0Har05XLl1CU5Onfk19df69BzXIZZo1jZAXy7NzgqM jP1qB
- Im8tp/9ar4kV0HcenHQZxVa0ZLiNVtw80+zDqB1cHOfoB1+tXfsssUzfvY9oYOQM8LnJ/wp 2U
- XY3w8ox0ST+X+T/Mkjltb54zJMsMxZvMkIyvboParvliaWVYVF6SwkRVHKY6g8d/xpdOtIbbz5
- ZXgD7225HAPUDFWItQSI2/CSSzQ7n8lMFuTkj0xXLOer5NbG6dveUW/L/g7/AIg63LT75k+xwy
- Rl 2yvbODiqKafFbS/eS6tG3eW45ywwRzirE+2GysRHdLcElxIxJPDHr9Paop1+zRQxSSC5hOW
- ZI+CC Bwc9hSg3bTr+hVOcqkE1Gzbta35dn53K0QzayS3dpLbSSTCTOMDaOoAHTNOlNzNbQyIy
- PG43QIEB cgHvxzj60599wYlKSsVQbjnjI54+ucVatoWbTVmhdbhxIFaBOGUnrjsBWkpKOrMMR
- VVCC9o7u+z1 X/AK8QK5lcRw3KSqjnb8uepbA6VrQ2aILqe3LEzsZEJPRB1x+dY8KzxzRTMVtk
- jUoWlGQ/PLf0rc VVluPLWZZ1IwFjODj1Ht2+tc9dtbM893jUdRS0W9rteny9RcC2tIlfzSzQg
- xtuxgZ4H54zSuYRE4 a5T7SsgQJk4PGTx9avGWC0y8LKYdshIk+YrnGOvY9qzphfNBb3cDW8gl
- iZjGIvmVhwQT61zQbk+x eHqutNRS18+v3iR284h81JCzyjzPmOcBf4ceuajSNXggmlmCOFDOq
- 5G3JyeParP2KT7Ku6R3ZIvl CkjgY/nmrMkyqkkRCK+/93Ht+Ypx19ap1OxvKpUWy2/rzKSTxu
- ZE/eujtlpFbhyTxj6in3NrIoI2 R28Q3I7sv3WYgKD9R0rWSSC2nkZ7JsKzonTGD/8AX4FVZp5
- 005V8n55CDscAlNg7/Q4rJVG5LlRn GpUdRcqt266nPGG2+2tbtdKDCGjZiSdxwTuHsO9GZoYL
- FXkRkcI8cuOFAznP1qY2sBtt5mElxMFk lAODnODj6iqk9vsD+W/+iLMIclskZ53fQV6EZKWlz
- 2pRhJcs5aro1+Rblle5V1itnYvKF+U/dX+I fWmynT48JIjARM2Bu6jI5/Kp9rCSdzcRSQ+cpP
- lcc9x7cVRP2qRxNtWGFV8phIuTkkkfj0qYJGbi pPlUvdXqtf68iu09ldmZYfkgDERjv07n271
- Elq/2dZdwdfJ4IGBx1FaVvYQPq1pCwGDGQ+3gEjOT VieCW2t5Y2ddvBicD5dg6jHrWrrRTUYs
- 3hiIUpKlT95rX7+3mYlnPHBJCBGZIirRsoP3i3THv/hU l40IsIoIyDtx0OOB/U1cRIDI00iNJ
- iNgI4yFOOzfgOaoMIfsX7u2mXDKvmO2Qxz249KtNSnexk8P TlX5nF/kr+jf5FNba2k05RG0xu
- dwZFBz8oOCKlKFbu48wbRvwUHGCeg4qyzrCiDyg6OCTEgAeNc9 z+tUrqGRYxKQ8WJQAGH3gRk
- NxW0ZXerFRcIcyau+m/53/T5kSCORLYQ5FwM4GcjaOp/DmqbMHkjV B8zKc8Z3YJ5FW2VwyyKB
- kjAK4AUNkEGpjCsZjVA4kH7tDj7pJ+nvWqkkzKOHkpTnzrRdX/V/Qpu7 CYrEpJbqCOMcYP161
- IFltpxLFNCzLvAyM5HQnB9c1OHhkihtMjcCxMv949KiQPIYklgk2qjN8pAP HWlzdzk9tKpU5Z
- K3l/w7/wAiXzJTakzwmNFHlxqy8kkZ59TVyWK4mhgkkyFiUqwTAJcjg/j/AEqu giaWykWG4eK
- SBiPnz83IzWhYi4iEG2WMIsbb/MXIbGcEficVhUlZXQ4zStZXaelv+A2MSG4WKN5x IGfBGw4D
- Kv3jQ7xxXwkVLs2bSfIXc4P9DzWtAwEdrJdyxSvEhiUJwDuHP+FMkmE2nLZxxH92/lbC MsnOS
- T+Arm9q3LVBh8TUlV5asb33euxT8m8EE7tguW4bpgnqv5Vntc3ioVVWR3cbmBwMjgCtSFd+ po
- QXVjbsyBjxgevqfeqS3EUC/ZmI3MQwc8jI6D861g99LnfKNvdSWnlb7xN1xPcKkieWrg+awXjd
- nH4AVmY2xlZFke6kbEW3ptHUmthrgs82UYTuMMOMAngjFQyW8M0zRRxyRSLOq4c8qP7v145rSE
- +X dWMKuIdLr+GnzM5FJtIdqsswT5COAVLYz/n1ojhjOnzRxyQNmTJGPmUjoM+laRithfOlncR
- kM25N xztxzj+dOmFnHKZ12t03qhxlT/F+FP2t3oeXObcly/l/n0MiK2JlxIWZv+WhU981sQW8
- P2gSCSOF 9sikOM4UEc/TNU4GtVeQRbxznc7E7mydmK0bS3lFqs8zxowOWVhzycE/QdxUV5vq7
- GOMrVeXlba8 rb/mTRxQT2StIV8/cdxXjJPRh6DA6VjrC80aLbxyywuAyFT0Az19T1Oa3IQwin
- id4UMMwiA2+vQ/ lUkUQtL53hdXBXb5S9ieN30A5rnjVcb2ObDV504Slzarvf8Ay0MKS1X7L5s
- iSQlFKoCceav94e1M t4hJ5DRvEspiIbcuQG/h/Tiumh+0rai3eKOchRl9uQ2OGIHYYrJs5Ekl
- VAUWOIFUbbjKnOOfXNaR rycX5FrFVZU27Nta3vp9zRHayTmBbe7CyMs6NtAAZB3BqvcOm+a43
- KjSox2Y5ByBj8OtWTAQkW+K V2f5iVOMDoQffNZsVrdjWIZnhaCJUYnzOR0PP8q0hy3cjOlUVF
- udt/Sz/r0K8xMcbxorg798xfnD EYIHp61EFWOWErKTcZIB7HsCMirdhaXV5BAgG1Sh3O4yCSe
- /4VpNp8SXF2qIT5NxGQp6njgA9vet 3WjH3X/XQ7VXpezcUtd7Xute9+nkcrBbiaaG33GBXbd8
- /Odp5z+tXbpITqNxJ8oCy4iRBjC4/pXQ XFoilfNjadt26UwjbtJ6AemaomLakl3JbneGO1Wx0
- BwQfehYnmdzmwlV+2UpL0WhhNG8l7Dl0jjY cs4yvHJNOu8C4HlkbJAWDHoR2NaTWbSSy7djbC
- qsRxyTxj6jis6a0uA9xGbeYMk4TaRkpz90+9bx qRb3Omo2q0pup8tLFK3tlkhjnLQywxkiTYu
- OcVGJhEYkiURKPmCvzub8qsMpS6kjdNpUlWXbj5um KesYQrJNE02wFVAAwMD5gffmt+bW71PP
- +r+z95Pmb/ruRxXM/wBsjlgMTMqlMFMqAe2PWrtmZBIz Twqux/njdASRjBqg6qpDoQGDYDKMA
- jtx61VkeO4uEKzDOeSWzlhSdNS6EVKLnJzmkm/vN+Ke3MjP NaSiBcquGxtOOn40sU32p3jZfs
- 3ntuDEfKpVTx+NY8UUwgdDcIq53iNsknHXt6UxvMW4jaKZDEWD lcenb61HsU27McY1FTk4r3v
- np8n/AJGr5scqwzufvxElAcfN93P046U0eU1hFIrTLIpKMxYlQCM9 KpzRzSSlslNzl3UJjA74
- 9BioxLGttNHvXLykxtnqOAKPZ3WhtWjJxip6d3/X+Qj+btj3FZFcH5mJ xxznp+FNQN9n2idEw
- /mAMcnd9aTyn+VA6yMUJXC4GM/1p25IzIGUPwMAKMj1GfrW/Qv4qvLPX1e3 3f5j4lX7PIjsFI
- +YHsVHJH1z3ptuPJkjmmYSRfdcDtnlQfrVYqk88Kq+QB7/AHh0H4014pXVCySh nYn7uACDiny
- 30b3POxMruUYz+9/18jp3kWaQ/uQVlQunlrjgde3rWlayzskUslxAjMykJswSB6eg IqtLHHK9
- vktE0RaMoAQV3cih0t0tmWfzEkldCDnG04PFeVPllGx6VdqtS5Ze75dfxJkETass0roY mV3XZ
- kEgdKyrhrhdhIJBHO4Z5z2+uanlh8uKOMSNiFSu7P8AF1P+FQMJpLZJ4Y3eNADKSc4brW1N Ja
- nqWi6XPUfvPRfIdsdpynmbHXKBCuSR3H1q9A1zBC2yIRr56nzZFyAx+6DkemaoiOfyY7mRQjOr
- FVz8ynoM/XNWIA94nlSloZhIBMjnqQPvD09KKjutdjDFV6dSmrbLrq/vWxoTrDBDgx7xvZMgYK
- rk bgff09qdJa2ksRgtGkdDKzJls5GB830ArLuiJSpy6w7Mx7j6kA5Pc1UlX/iYeTE2ZtxETBs
- Ar+VZ wpNpPm1M40aipKftPhd/I27RYY7RRJeWse+YOx2+33fxFOknnmMETp9ms2jMmXTOecVi
- JDGzhWmK oZBtAPL89R7dqvTSlNTkbdhHVwFbnZjjbSlSXNfcy9lBt8z5uv8Aw3n6oqIr5VmKM
- ypuUFOw789a dHalfKMTu5MiuGTPK5wfxz3p4SP7AjXKSlAzKhVsZA4qRUCusdufs6Bm3PK2QC
- P4a1c9NDrjiadS m7QSW1/6epYuZo2S980pNtIUYGCSTnIPYDGKyreIJeJCvmnLsGXd0P8A9f8
- ApVhJlurdZLiLaytl BnGFB6H1Oe9OAtpNRaZo5WJjYqySEAnHXpSinFNWJWHrSpX5bX22X4bl
- WNZliVJZ7dJI5mjGxMbg er8DnkY9a0Vim2F5C8sgmwdvRsr0/ACqkMP+grMkQniU4Y4ycn39j
- WqlmWkRWDJIyu0gPQkHAYeg 5pVJpdTWhenFKUv1/KxtRW9td6OptldoU4J3ZJ29TUEbyS2Bhi
- tDCrsCrsBlcD196itre7+zkNHJ FEiBNq8ZOcdvzPrU8kMcUbeRFchoWKySM+V3g+noc15+ibV
- 76nbQahNJT5ne68isZ5Xs4RHCIwRg hhn5egPTtzUjqs9vEk+54oodsUsZxnnjOeuenNW72QDS
- kSRV4DIrhQOMjp9c1T3I1hDE1vMdn7p1 U4KkHdz9P61UZXiml1PRjiYSoxaWrbX9aXJ2s3WGd
- mmEN4swxGTzgDmmxTyfZ5P9GkRJJUYEcc9j 9Kie4me/kliUsJJo3IbkqT1X8RUV0MEpLDO1vG
- +yMqSBg9BnoTSUW9JHn4mPM7TSdtbu1/0uWzbM YLVrhiiuT5ise+7GParwjtbeK8tkSa4/eM5
- eJsFsEYCnqOKy7V76MbPIllPyZZuQmeD/AJ9auvDL l7dbG68hA2FVhv4Hc1lNO9mzyXRl7ZRb
- 09bfk0XYY1kndyrWSzoWQXHzcD/OPxqxaTPPLLLG0TSM p3QquPLOMH/GqkTWsVis12ZI2mIZQ
- 7Z2jGDj271E8lsmnLcRCSRVYKGRsbgep9655Rcm18v6/wCH NIRlJtX301S/Pf8AE25ZrhHjLy
- ReSkflEeXyCRgkn071UgLSXiFZ7e42RnYyJ26H8T2qH5o79ZIp cIVLBJMtkqeP0Jq1CWMjfab
- SZUT5AUO3JJ4P0HesuVRiarDuCklZ6b6L8P8AJkl5cTWkFvtMe2OB hEWGdxyMk+vXFZsswXT3
- BYyTp/AD8xQnJb6DvWxcQkaYzNDJhm3BmPygAjcPxqjPeCYrHHCsscpY 741ALAfxA+nalRaaV
- kOjOm1GSXXfb+vvI4HRdTu2u1WO389Qvy4OcZUZ9Kx3u72K/QosbGYlinlg hevBrVMv76DzZE
- jQJudnHAboD+VdT4i8Q3/jHxZFf65FpkDWkEVsiWFqtuAiLtUMF6uepbvWvtHC fw3TWvy2sut
- /U6pXpzc3FO6/q3Q5ZYYpkg3zxC5dAzBeFceoFRm6d52QGI4beFC9SOp/CiSTN3bC GeBh5Xyq
- F+bAyM59M1lXE9wCkV7GHSSMuTF8pY9Mj29q1hTcnqKnH2tS1r+vT00RYvPtKRxRTKQX OfNQb
- Qy9Tj9Kou58yYxszTAmXy2+bb/eHPGO9RwSzRs7NBJOGkOHHRQvWrEV3K6TsQsgKbnVUAJY 8D
- nHT1FdcYOPY9DD0eXmcEml1/q41ne4t7jyImn2sE3x8A7un4cVUihvVgkjXC+SwCRtyWz/ABD2
- FRJNtj2tIYycq2DjeR0I9u1NEi3VmrfaPNmGAMKRsAzkHjk1uoNLyM6vNLRNfd/X6DSN0kj7wF
- En lgs2cf5FV/LfyJICSqGUMDJnjAOF+prWjb7bvgMPkOGErsehIHyjpxmobYeZdxy3qhJGd2Z
- TwMBf T2NV7Syd+hhXxajG01drorFQrAzRqqSR7o2KKxyeT096favJaR2+4qrYZmMq5Bx/Dj19
- 6cwEssrN Iql3jKEcAEjoPSrMk0T2MisFndZMsmOVPcZ/CiTurWuY1o3tTjC73+/8DOMwMTK6R
- 75QpUouGDZ6 UjtAjHG4uEIY5wc5ois0KxP52+Jst5YPz4ByRz3xVi2U/bk/1ckksLMAy5GTn+
- VaOUVex20MQkpK Mdkt1/X5BbRPFYyyfIdj+WqkZ4I5I/OtGW38rT4EM8TQZDK654H8Q/HikUN
- NeQ/aIZJ4kQKwh+X5 m4H5ir0KhLQ2UUbW0gJJW4+Yrg5rkqVHf+v6/A46mLrJRpu1k79NP1/A
- pz20K2MhR3Yh94TdkqM9 D/OrFxaSqUEUcgdonkJz6c8+9Mis4LnJM26V1ZwVzjGM8ipYo5PtE
- RacwMSI1aQkgKycnFZuduuw 1VlCEWp6pt9fyX+QqW8k9jbF5FWCaIOnHzAjgjOO9VntIAj7YJ
- jJJJGQWIJGc8D8qswGaJbYSq0s PkeZGUGPlQnj8aVryZmjOwQQvDvLuOxPUVKlO+g3iK7Tell
- 20X3LVsUrFcakIyyRyRMqoD1MZHzH 6jjmnXJtZroQNbS27RyHZuf5mAXqfWoY3ni1aQCNLiJZ
- FQyIv3jj5QD71cYvaaotzdYTcjK+R0cE dPzrN6NWfTQ4akFzys29LpJ316kUEUD2UefJWZURW
- ULyCW6H3NVTbPDeX108JeIuUVcdeOMe1aSL Msk5a3Z9rEZUj5eOAffNZ8mmKloUYXMLljuWR8
- 5I5/rThNXd3uc9GvGDak7J6ar/AIYZDJCIgJrV R86bNqgEjPzfrWxPBFdWoCoVMgxkHqWOAw9
- sDpWRAbgXkm6LzJMqWCjox4WtG2tLpZwv2e4gVNzT lzkK2CcD04qa2jvc5selTmnB3fS3+TGS
- abc2czxwSpJlXZyR95h8u76YzTbe4RYLQ/ZpHMdpIEYH mRT/ABVPHLcLZRSeW7RKilNxyQAck
- E9zin3+pNIs8lvp06ySI3kEKCAhwCQB2qFKTdpK/nsZQ5qr UatrPrdL7zNigjFtbsxuHC8RMs
- hHmLtzke2f5VCkc6G3uSYVE0Bk+5gADjH+HpWjZyRWFnE7I00a ryueSR6eg56Ut3uvltjKVSF
- yrIqDBeP+LFaKo1Jp7EwlKDkm/del97+SMCGR0vRFAx5ZWjEhJ/dj P6mrQjhmljt3uVHmxMYz
- k/KobOD6k9M1oLPDDq4RZLUwsrC1cr98YyD9M1E1sIrEzPC0sjgeYU4w cY49BWjqXfYqTU6qi
- pWb2/qyKCW0RvJoWuVt4ZYw+4k4hbsh9yaty2c62P7uRVLSbpQc5VwBx+Iq 2sYVSuxduSjhgN
- 28Abfz5IolmllK20REUTYkkLjJ3LgYz71DqybVjSpKTaUXtve3+VyKG1uPtVxk E+bOoOP72Ol
- STW8htPL86JDtZWZkz83p+NSPqFxFDMUMcryOXLBeFY8AflSCzuHjSOdxK3zBgowX C87x7Vm5
- SveVkcVab5lUmkn007eRTeWCNHcsk8oYIkcYwX5yD+GKzJ7K+utQW4mKwS3SvJhsjDDs evJxx
- Vy4LzXtwi+Tb5dE8wrwWYcEelQz6XcSPKnnSSXUXMYVjhwp+Yiuqm1CzvZs6G1F25kpPurq 3z
- 0RhanA8X9nv5ixNJC7sHGfbH1rP87zYlXz43iUlSdvQngZrqbv7LfwurFYplAMG9v+WZ5YfXjO
- awo9OMO1YQZxKPMBjUk7R3PFd9CquS0tx4NX0qaPXW23muhRnja38t/LDtuKsATwfy9KSCzU3q
- RK 0WcsWJXvjIH1xSvL5IgguonVnmXMnQRqMHJFW7iJjdA28UwV5XZmAzkge3TAro5mlbv1MJ1
- 5TrOm 9+70/DZjBaxMiFpViATDE5Jk75X2xS21rbPKZJX2RYKgZ/iI4FXbWKGfT0kuHCTFcbW4
- yp6EfhSC ezhv4yIGdFjbzCG4Jx8p/DpWLqSd0ric6klJQk5SW+iRHaWVwdQWUxlNwI2OM5OOR
- +FULjS33Isc MrIEz+NaDwzyNCAjhERUc9dhbqTn9aIiI/tQWUyCNwkTA8eWec/Wmqkk+ZMuTk
- m+eV21tbRfO5if vE+0bFaMNMp5PTGcD6VDsZ7uNFDlmfn25rTktRJM8M0iwsiliTnsQapSNBL
- f4EjxIkvX269q6ozT 2KxKp001De26RIYdt5ttiJWCMQ4HDL3I+lQLDLuj4LKEIGO4PNSnzRLN
- dW6uI5C4HooPUfrTreZx ClrIishkDBioyBjpReSRzVJzilJw5l1t/Vjoo2WFZRNDLPIpJZkOO
- x6/n+lKl0o05UDI7FSU3ruK jo2ffuKWJZYZYxZzQ3SKGQsFz19c9T6VGVZd7CDJztI9Mfxf7o
- 7+tedaLev9f5HqNUue+7Xz/P8A yKH2OST7ivLtycqDg46896kTYSoEcqpySmeT7j8K1bKFbV5
- TvYxk5jyc8Y+99O1QxNH5m8XEO7lm JQ/MMcAenvVus232O7629Woad7bfqjPe4VYY1w6AnCZP
- 3u/6VE5jlvYIbeKaWQuwMitx0yrU/Y82 9vK+8+MkfdOMkD3p6Ru/ARP3hVSduBnoBWqskP2F6
- XxKPX/h9dRi21wumZEE6qhA+fPOTkkflQyc tIJI2ZgXUqvKhuMVrS6eVmERkJEX7uUjpuHIx9
- adDHYpFlGIlSI7AxzvB5NZe3W61MqfIkuV3+Vv zbKAhaWz852RCZTuGOd2PlUemetNRFmkPnS
- eSzjIdhwQBz071opa7cyAbWaQDY38Bxnn37/SorSI PMkcEYkVshsjdgnkip9qrPUKUlaT9orL
- 5fduZMgMssWJgwALAAHAz1qytuHcRI5MahpA56YyOTV4 2U6sFW1Ko7MyuBwoA5H41FBE8a7wj
- hFAzuPO09vzq/aprRmsOSUHyavpbo+4WvmQC58qS2mgaQfv dgKg54HIyAfStBLRDqrH7JOCJN
- rMCNoUjP8An61YOnXMt0IRAURiTKw4UPj5f0qUtFbW0c3mkSCN g6s2S2RgfpXHOtzP3d2cc5q
- o/Zp+8+3+dyGOO1kvmtYLaZI2/eKQ/G0DJNPjt3EZuVlDSvEDAjdR HnBz60skUz2hiSRAY22L
- tHKpjJU+pzTxCstrD5LFInjY8nJTkArn261m5ab/ANf8E6acvZpWdk9G nr+ZYjdbaOCNmkkR1
- aRcN+hPtUd3fGaZY7VsNu3SHqrYHBotrNBqcoecRbJESOR+VAPUEepp89s0 GsRfKixO+zdjv2
- /Lv9az9zn8zVKhGo03dpXSWiKpu4pLCWafMkjMCyLxliOCPQVG0s0dpiQGCdDg hhnb7H1LZ6+
- lTysgvxE1v5hRC6hfp0I71nG5ma8C26b5ePkZd3AGST64reEU+nmelCFoNyVra2bW v+ROZLgX
- MjxvEpEnOV4YnoR7CmXksL3scEXmLsbYCzZDZHB/nzVy2e4XEpiDo0ZwwUYXJyQff0qm BBMI5
- VIgwmArDJOD14pxaUttjlnyufa+3LqWx9qh2Rf6xHKEt/eCnPH4VoSXCxXUoEc6QOzNlnyR 3H
- Ppms4AgQRxP5mCrq/93HQH69fpV6G2mbUpI3zKjNwR/Gx4JHsPSueoo7s55UotynK2i9H+JLNa
- pcS6fiWNoxExkBHEpxwV9ADWnDZW4s08vdFIIh5ivyAMYPHrWMj6p9sWWONYUkUvGjqDtUHbnp
- 07 1agsbydSJxPGwIThsBsd/wAa56iaSTnoJRcbRdXTfT+kTSQQ/YvJjkKW6jaJHOccZHP51It
- y7Jh8 iSR02g9G3DHH0qF90sgtzNFCHbeA4zn2H5VdunumUvBHGjRnKhkBJPHSs30TO2jKo4KE
- bX6Xdvns UpftaxwWqymQRwlmQ5JXB+YGsZjapcQyvDcRxyFWQq/3B3B+tbRe2iCefcDznYZwc
- bs/0NVJoLFp mDzbreL5AFODnGR+Z6V0UpW0aOuE1GMoyjb0X5bDnezyrBXdVVmZN/K4OFz9Ot
- VJnH2yIMJ5AsJM rI+N7HoPxHSp5bsKVMcaNM8ZkPHB4/lWU6B7kvLdxRK4UHk8Ajn8q0pQ6s5
- KdKKg5u67Xd39yHyQ TxQWrW8MytJ/rGLD5WB4PsKkiu7d7j7Net5tugJEkfB3AfLg+h9Kg+e2
- tt73a3MI+RyufmZjxj8K bPEILxEGyVYlAbaMZx3/ABrdJS0ZFKopR/ePbZrf7/8AMkSSBUR4h
- Ise07gWyQT3NSiaTbAITBLN 5LD5ExvP/wCqiO7T+0vLlEUapDLtAQABiOM+tQRW3kadHcQybn
- ZR8vfjHI/Ok0upM5xhpb06/wCQ k0MyMjq0EXG5mKZx/wDXOahkVSWhsYMSiTMRx95F9fU5zQR
- fQSCCQ+YVBK/KD781FDZ33l+aI5F4 YhvYDkVqkrXbRqqa5b1JJN7Wf5rqbNhCqvLdX0yW4zsb
- K4y38B47VlmW1ktlaRvtjq5wYiU5z93n 1q8siR6DA6p5zDHnBju+Y42j8R0qoklsbM5gWJ496
- IwGA248Hp1FZQT5m3f+vxOWjGpXq3ld306J fduR3MsX2TDhI5pGDbMYKEev17UksU/lykmLNw
- N5A6qV5btxioZUNvPChKOpQhWxncM849/etdl0 2f7NbJM6LIS5YsSenC/U1rJ8iVtjtrupQgu
- TVd0k7HNSNE3lFElBYMwYNwoPH9K2IYX/ALOuUlgA Pmr+8AGY/UZ9D1xWhaWtlFp6+XPFG+4M
- vmnJPoKjF9b272UkmXBiYTYPDMCeMetTOu5aRW3/AA55 31icpJxhd+e/4/8ABKcDPBOtz5c21
- GA68NjIP5549K0Q7XVwqySLC0swXBHzFtuV5/n61Etw7okk M0LRoNgiK5O7OT+dRRy+bqMcty
- 6w7ZVZVxjnJx0qJJyu7am1bmqRlVWkkun5WLkENpcyRI/mwZfM yq2CWPQD0HtVojT1iW3Nyok
- 3CRy55BXp+GOKQ3FnJLJvI+0vJn5eNvzfrxmq8UUMetXW+VIVWb5f MG7dwSPwrmd3e91Y5XBy
- fM1LTp1v/XkP1I28sLNB5iDEjDL8YYA/l/jVeBUazjEV5BGpj3kOu7y2 B4Qn3OaWK1tWhQzzG
- QeWNwVsdG4/StV4Izdp5Nvtt0RhIMDOTz+lN1FGKj2O5csaai09Nf6v/wAA iLw3FjKZ5IiJSZ
- AkY2lZOyfXjis1YruCWFJZo4z5DPJ567xGQeQffpWnHst7ASwQm8uVKxIV+64b knHr6HtUBkj
- eKJ79SvkwmNU7shbkn1IpU5NXSWn9dDKivdajDT5X+4UTi4sXjSTzD5uAyt94dd34 d6zgt3Nc
- h1n2xuoYGQk84p4FtHE7RhobJpdsTMeoPv8A561KtzYTT7lL7zJsgTfjKnqfwx+VWly3 5UcU5
- uCbjt3texEYI59IneJnL5CmTccOc/LUstrLb2zol64mllJKsxJ4A/TtVuRryN2jIidAyliq YB
- brkegqbzWuZ5VIQs0jYbb1XjJHoKzdSS9DzcRiK0ElGWi1/r/IQDybKaVCzsx2qM5CqRjp61mN
- p1uWiX7Yw8iFlPzngjBA/Gt2K3DObUP5bZZstzuCjlh7VB58clgrHy8SHc5C92GP5VnTrSi7xZ
- zx xtWPurV/13RTSVDv3xtgkGfn+NuRj0AHUVox28kkcSYUMbeXqPu7e/0PpWWl0rytawotxuc
- bivVS B1+mBUYtGW9h86eSOCQFkBcguvRiD6VU4edhzhzTT+Hl1tvclhsYJ7a2aZWYKoZGU42B
- hgA/zqGC 2uLTyh88ttvKyEnOWIOOvr2psFxC0zRafcCNgQEEmWAC5wD+taSu11bRpcN5CMQQR
- xs7Kp9STVzn OOj27Fz54NX+5p3/AAI547f+ybOQ2t0ZGg37RJySvC/iKiu0uX0qNoF2zDBkBG
- S+D1HoKmNy6acI GUCXcpYMOjE4yPRfatW4kWRIA6BmS3dJzHwNxIxWPtJRa0vqTCdWHI3G+vm
- 9PO/QxozJHcySXMO1 SWymANxGMEegFQzJLN+9SO5S4L7Qd/G36dsmpQWuPMjmkWRWxKu3g4x/
- I4qyVuis0ovbZAW4Taej Dkf19q05uV36luElNyej/roVioe2AUrbXBlDCKUZMij+MY7AVGsar
- MxDvEsyFkmckrg9h6Z/rWi2 nXCabJFHjyovlSRlyVJwApPqajiihMslpdB43J3MWPAK9VHpx2
- qVUVtHc5rRgubmv5X/AKv6HOrD LHJGd0UNsnlj51yfmBHWqsFkvleXH50siy7XMb4A2tyPoRX
- YyW1iZxGzGVZlDhA3Me052H3rDl0u 7N5G9gsjrL+/YZztC/wn3NdNPFKV9bf1/wAObTxUHzJe
- 7deiOXuYrd9akZFZrUBypJyW9D9M1XIj /wBHdTLcKIyJdrEbH/HsRWx5MCXMUTXUeAGEJVfvL
- yT/AFFLbRRR3RWK6gLcuQUzgqO/rXo+2SR1 1J03CLT97qulvWxVtQG0iGWCWMx+YyTlueB9xR
- 6HBp94k8iaYosZWLQFGMQxnH8Rq4Z0h0qNE+zy 5bMaIuCFPUH1J5we1QRXFu8Rmj89XTPlKZN
- 2E7/lWalK/Nb+vwOLD08To46a9X/TQQWs8GnpdR3S 8qUdG/vZ5FZptoVuIlMjmRVDPg8eZn5R
- +XatWJ9Rlt0DeT9mYhg4QYw3JX/ePrVOeCC1MMyMW3vv VS3JX1zVwk+ZpvXyOiKqTj7ObXM9r
- fkyvI9xBqVx5iDzBMFbeuduO35dqpMVcvLtYj+FUAB29d3I qwytOymabLq6KBnllPLE/QdzU6
- pYvcXBG7yon2RsW4K//XrdNRW2prVcabsrp9bLf+vIwS0gjVd6 hd7sx7EEDA/SrME86P8AIgV
- iMfdB2fXIpzAb3aOARxsC2G56f/XqCU2yGMs7NyG2huWbNdN1JWsY xpclOdlpvZu977nV+ey/
- vjCbeRWw644OeCMeuMU1LZpXUyXUaoke1m59eB9TULGaZTLJDIY2kfJH GOBkH9KsW2nwskZkn
- 8tZIi4BP3mB4/AV5ztGN9vxPYp07U+fl+e6foxxt44Y7m3hguUkeUMUkfJQ D7yn86pysn2ZY0
- 2sm3ggdw3StMhRCnmXQllizuYA4Oefx9KgaQKqzC1ISZc4OOcnGR6AH9amEn1/ r7yqClF+/dJ
- bX/4IkbCOe5SaNoUaQMofqBnn9KdcRRhVS3vIZ0dtyRqp3DBqWG1Z7g26ROAhMcnm HJDt/hir
- C2lmtr5UxaN1kwWz+QqJTipXKqOmqi017KzX9fMyY5JItzqsqSyTfNubgHnK49T2qdLC Z75o/
- KcquUAAGV2jp+HetARRRlEuNsaBC0bHtzxn1I9aoXSXcCQkM6IhaOVgf9YzcnH6VUajb93Q Kc
- p0pXste/6alo+QLCOOC6UOpG5mBwM/1NPtxE5lMit5MV0kYKNg57UyO032FqwiZ1TdgL1ODzk9
- 8fpTpd0V2LqFGW3Me5Q3Ic4xn8DWWjukxQhOrTkqctXfdobPdXIubl1LCUXB8tQM7lI+bA9OlN
- gQ vBgAh1mX5Tz8uM5PtxSCCK50yCaORmuIyqRop5zz19STz9BVh/OsQXiCh5lBfK5OQcZHsc0
- 9EuVb m1Kh7vJ7ql6b+r7F+Nbi41WKQMxWWIzvsOArAYIP86ovGZLWFEdJCrRh37A9vzqSNY44
- 5LjModJF hChsde35VcNoq6vMbe0n2Rt5TEtkMSRj8RXPzKL/AK/rqcdVRUpS5tvS1/1KUpeyu
- yLcGbe7Z74P /wBfNbUy202gBEXaXdXjQH5sAgH86yJYb2wV38vlZdh3DOxs4Cn3INXY72eG8u
- FdoGaORYV+ToG/ z+dRUi5JSjrb8S3S5oxmkm12/UqTacvn3X2iYv8AvWYIpweB15plrF51t5K
- M9u0jCZTM24v6sPYY 5q1LcGaSaORhJGjlXCDBBPyqCf1qhJPqfkJbJCryoTHKQnOTyNvoMdq1
- i5yjZs6I1JWSlq/w/wAi pJBKwlVJBJhhIze3QCh42guy8wZZWUqxBxtbGT/hTZYHHm+ZIseJA
- oUn+8Pl/LmtNU+xOIgyzMbZ pGLc5YHtmt5Tsl1O6eIaS5NfJ9f0sZ6xyywRP88Q2qPLz90dCx
- /GpJY8vFbBg/kxhCyj7xJzxx3F IuoTDMgjX5Gx0zjcclT71bSaI3SGSJ5ZDKCY1O1gV6H6c0p
- Oad2jnnOtGSlOndLVa9flYpKftF4E UNHC2CyA8kdCwOOgrZP2y0nKQSJPHEjCNgPvA/eaoolH
- 9qecAsK7hjI/hwcj86jkWGSBHlEySu2A Q/ypkYAP161jKXM0un3i5ozq6r3X87f18x7yyT6dJ
- P8APGhQqi7uQuRmtWG6jjtXlR3ZhIDMNxON y8/TFZsyvYwxqtxGfs4MWCvXuDj9KjjSaWSONf
- 3jyxSSlV4C4HQ/SspQjKPkdMXGVNc2iTeu34WN CyDfbE8ueKdI7faqheQTnGc9TQ2o3NvJyVe
- FU+UEfxH/AArIgSTfZyEOiOo3Nnjdnj/CpXmtE8xL mKcPJligbBjOc4P1qnRi5a6m8nQdVqKU
- o2XTX8CXD3jW80sLzgR+WqxnbuOSQ49h0qC6n8prmJRv 81g+7HA9f/rVZN9eRNE9vD5cQVsbl
- BwT1qv9pVFtpHmguyImXCJjGDwDnv8A4VUVK+qFOrONT3o8 3az/AKRTgvIxdsXBEewqrE/dUD
- gH60eXNN5TwvHc4wr7V+6cdDS20PmyvEGgjRW34K9R1Y/QCpFu YY4XELBVBJVQOSc8HP0rd6P
- 3VqYShOVW1Na9nt+S/MSOdfsxhnaM7ZVdV2YLHPX8K0poyUkaYBv3 oRGXjI75/GqqzPvmmkjg
- lRZUCzKoAX0B/Oo2e7acLHmSSFWDei/XNYyjd6aHLLDSjV9yKsvMfOYD BOwifzFbYwJ5XjnPv
- UVn5n2CadEcohAiOeCpzkfnV20t02r5sggjnchRIc+YMYz+dKYfsf7h0e4D KC5jOApXp+FL2k
- UuVGk8VFRcEua3m/8AhiB7G4uGt55LS7CheTu6nufoPSnyQTiITRyB/wB2+zaT gjcAPzodVkn
- MdxfGNXDSSDJ+V+m3jpx2oQWbWlsod32QjIVyNuW6H370Xlp/kKMKianKPytp+JGI 0uJriJoJ
- UeNkVgGwN3/1qrhHt4UTyGdJXDsx5Abv+FWJIrtpXhhglUxSBBzySfU9zT3tmguJUnlM NzGxG
- 1+ijAzke1UpdL/I2s2/ea9N7fdr+BC93JLFBJ5EbLFCyA7BkE0QiOSGPcnl8rIHHADDoPp7 Va
- kM0wjQRo+JMII1xuU9G9wMc1Qe5khnYh4nzvIULkegFOOqskHKnDljDX5/1+BKJIJZDhZJpZ0M
- gCHG0joPxqOFQlrEZZraIxtsCyLkgNyW/lSB4Y9OUKcpImFVRhg4PBz2HtV57KFrSBZ8xyMuAM
- 85 B5B/CiTS3Oeoocq5m/69V/kZlvagsY3u4Y5Fk+TKn5gvJNMVDPdIFni8uQfIzDgnnA/pWt/
- Y9tIF WJLkKX3I2/kDPANE1rJBptzIwV44rkFNgxz7HtzT+sRb0e4lmE3VXK7y87aencdHCEtT
- E0LtKG38 /eIX/CqcTyvdxzzRtsZQ5PYFsjn61Izz2YBk3G7hLQ5J4Ibkkj2BrRSAzpOks0f2b
- 7pVRg8DK8/h mseblTb6mkW2nKfXrbUpLsZo7Jka2BwJC55YL6Gp7lk8mFIZjEs4MsgZsnOMCr
- o09pNl07G5GcAx 8csOn14qxHYSpdwiJ4bciMszzpu2kgjb9fSsXWhe9yY1YSd3K/L5/wDDlBY
- Z5EMsz/Z4QAPMHCo/ YfWopJFYsH2tkEmU8qB0K4+vFb9pbpILVJp4ii2jq/oDnIz7+9ZDrbWt
- v9r86J0kZXRPRQMAfXPN RGqpSsTUnRrVLNO/TRpf16/cZgR28xoGGwrmONlzgjgjHrUFsY/7N
- kuJNqyLdRgR4wyZ6j8e1XpV sp51tjMyTPIrK4PGf7v49qfEl8k7JPBGQWbJ8sAZ7fjXVz+7qZ
- 1qXuNSirrdbO3r1BHaW4vGTckS TKrlj91ieAamFmWBhRnm2EqZIzjeq8kj2rOkR7cXEW9UIkB
- mLDhmA4H1NadtfTJAgkKJbylWJK8s xB4B7D2rKpGSV4nJisNVjS54Ky83+Xcc9pmMsPPAbLJ8
- 5zt7nPpVtLCOK4ciOQxhWIQn7uB/jWDN qL+WI/MHmJMgGD/B/EKtz36Q3HnQrM6P5jBi+R24/
- nUSpVdF3OCWHxEYqM+o3Z9jVZoE8xvLAfaP vs3BI9uaikSSDT9tk27a5WPzDuKqpA7+pJofU4
- /tEJnRijQvt2nAG3kVWW7spktWZpOYnaQq2Aec n9a2jCejaOinh5qpFqN/lv5b9CNobiz1CNV
- 8mK7lTKoU546j61dg1NEMSbo5C0LhyE4V88Hn0p01 yktqZhBJ5o5GW6ggZx9KC9v5VswtARty
- ygANuJ+UE05e8vfWpo6ejq1Y3vp9lbEskkUmlWyR3UT3 L7V3f7p+9+Nab291Lbunn273QmLsE
- TGOO4+nNc59lmmSRmhdZy4VEHHGecfStbF9BNEjTxSRxrIu FHzEHGGzWNSCVuVmVWF4Rakm09
- tPxtuiMM8QSQGKVUX5nVcLg5H5YrTtoLY2hQ3UZZXAZM84Xr+h qlC8Zhj80jAAXbjG4A4Y/QG
- iKAPBcNBcxSqCUBC8t3Y1nU1XY5q9GlK17p9+j8tjbu/LNpJFbziJ GcMN+Tz/AAA+/FZs91cC
- 8t0uvIjmdW3Hy8Yz1/Gie12QIzXAOeAvcn1psTyGYABGZEKjeufcn9Kx pwio9zNYei6Gmthqx
- piV2Yu7OigIeQDkVjX00sNsypKyyvIrlgxAGO49j6Vsz3Eql3sgiYmViWXI A25C/U1lSi5ur8
- XEkW1JIWE8W0ZDEcY9MZrqoXveWxjTjUvepJKPbS/3GM6tJPdLCiSThw0WxfzI 9s9qdYi6m1B
- xcRiJ3bcCUABBBBH41pW9w4s4EneDEEZjDogBfnKnPfNKLiKW3ISeBJHkWSMMOUDD kH6YrslU
- dmrfM66s+ePJGHz3t9yMq6hiHlGJlA2oIVJ5jXP3W9W96Y6TQ3U8s9p5UXnbAdvABBz+ FX3m0
- 8RP50Es4QbY2jbAZM/epXjmuYJjbRud02/LjI+7/wDWqoza328y+WomubVeen4mbDOFtTEo aS
- OOZDHGAQxABA/WqEhY3dvAdsPyoR5o3K2CTke1PFjPHpcUhWWJ3XchkP3gOv5npTyInu5XEcoU
- YMbHoExyPc11pRV2tTR4ai6TdPr89fLZfgWzY2cjG6muI3UxsrpH8pDdmHtisqxjmitlkZ4VZD
- 99 l+V/7px+OPxq3cLHLcwJHMGhZiY0UEHGMDJqrKhjmInSVUQgZDEA4HH50oJ2s3uedChUkn7
- XV9v+ BomRMn/E4jKTxiZgcRkE7F53A+9Ytu8ciQvHE7jzwgfqI25xnIrTiEswiAbzp9rLiNcE
- c8A+5qqE tnvIFVGUq3HO0BvU8V207K6ZXs27yjNbbNar+vQ69EfzZYLp1QkhpCeAp5yMe4xVi
- ya5tdMtQiCN VG4TTKGDDJHH51npzJN5jGSYjDKOCzHPTg9Bip1lkiSKOOTcN6J5bjJ39Mfj1x
- Xl1INqx7+Nw0ZR Ttp2dkvlrf70X4tPeaGUzMke1xHwuO+cH396jha5SCWMrEVEm1Y9nIBHJHt
- irV0oIZZ1mSASssrq 2Ar4ABqnpSRrrM0qrJP5J8vy92S+c/N9MVgpNwcmccZynCUpu6jsv+CR
- LbRxX8TefldpDndyCDgZ PrWhDJG2oIrRmSMMYwndSeASe9JdPY2/2aZVdlH7tOcgqR9/3wahQ
- tbWyRQ5kKnLS4+8V5yPqDTl JzVy515VlzRur6a2K5Rft4hc8xxYG8ZGz+L8ff2rVMFt5KpEzT
- 7QykhuCeAD+PaqZilvEku4k8mP 7sRPO5cevvVtZLRtJFrLOsCYZgp+8nQqCe5qakr2t8zsrVF
- OUeWWmzSW36lM3VzDFJGzRl4pkUoF xuGeSPqcVaRAbO4cQSRS5KoHOQxzxgfnUbXVtDBGZDHL
- NMpaQIOS/wDCR6D2qMzyRQXNuJ1GJV3b 1yV2j/E03FtaKxU6Kk06Ufwf6Fa1NoJVd4J4xjBw+
- MZ+7+INWrXylupH3M4EmxtxyN204qrc+fKF lDxOFdRIij7wAzxWhYvZrqs2Z0jjdsszAkZZTj
- FVU+FsiULU5Sjfz3YBGmsxFFGRKoy4bklh3/Kq lrhmPlvOTsBY7+CTnn8K0YI0tIZU+1RyylQ
- 5IJGQvJx9QarxSSSXAmcIttgKsaKASDkdfY4qFLR2 2No3hBqMdPuf/BFFxIsHlqrXYOG9c4HX
- 655zSwm5+02pWEP5sJldccsQfvfQUR+ZNcSolpMm3AVw funHQ8VbAgaye6j8yO4OWUbs4QcEf
- iOaiTUdLbmNblppQS1l6P8A4Yql2aaOVraRYgmM5A8wHv8A X0NZ6ht8ckU32dZWEhMhJ2gkgZ
- qxDZJFELh55JogNqKrY+Ugn9M0yRVNtI6sBHHLGiuBkFdvWtYt XsjalSja0Ov3fjdDoLJo3Ju
- cs+4GIZxuVev9Kp/ZpzPsiLNJtKBGOSB1wfrmrsptiLUO0rJEjRFg /wB71Ye3OKkaWM26xsCY
- 9oLqp+ckcDn3pqc9+4QjiXUb5r/LT/L8iKa1aO4txBG880oO1E7KMbif 6fSnbNt6ELpEspacF
- uSdowpB9D6VPE98LZpoyEk8xioIyVzxj6E0qRX0EOJo1doMxu5XhQecfmah yfVr+v6Rk+aMru
- af9ea/IhguS9r5k1zC2844XiNccofc9qpxCB3iaRmuNvEcMZIJHPJ9/wDCtCIx PbbruB2DMPM
- WIhdj7cAH3pbfy4rRHjtZCIEMZbgnceMf1p8yV7IrDyTbtdv5L/L9B8eoqsTuY1XK kuHAYhxw
- p+mO1SBVlaO4BaOQx4HOCwK/MfwPNNksLh4YmBhdUQJt2ffIGfzNOlsmlljPlTRYjJkB fgEnh
- R+FZN0+jsdsoUo2Stfv/Vv1Ik02OBY5ILpZYo/unJwSejfT0pLxmaWMyQ4LfIjEffPQn8Kl W1
- thPKheSSKOVUCq5BGf8K0oEjkmEZUYRmMbE/d9vqTSlVcXzPU6lUnQleyb726fLr6mCtrMyqsQ
- eU8MNp4BHX9KtpaRSWTGJlbegJA7Ed/xFbHmmSENGyW8jlclxnkA46etVZZCqzg3EH3FZgq4Mb
- Lx il7ectNjSOIqVpXpzSt5P8d/zMtkkRI4/IZnijCFl43buao2sSTamsbQecPLO9F6lgD0rqk
- W2mtA 0kolU4VVj4OV6knuBWBMr7A0A2mSTcSBhk7Ek+hrSlV5rrY4qVf2kpQuvx3/AD/L1Egh
- zo0weRYw XXMZHzFiM7voKkja1SBPKLzuRhirdTmrtvb2cd5cySyM3ly7FGeNnf8AHnrUdxDap
- GVs9ysMxg7s 8kZFT7ROVtTGEoqpy6272svw1IkPm3O7y28hXEUS55TOf1pz3rxXS+aUAGWOR9
- 5upH5VFbxyR2qP JMjE7QmB1ycZpJLCaO/YFhiIFCjDJJxwPrVe45WZvHkm3GaWv9biPKsN3I0
- USSR5OI3AZjkZ3fQC po2m+TMSyW7EPHsXBZQPvA+grQ0+1EdxELi1fyXXMsh7seQo9Owqw1tG
- JriQxyRuJgjjOAoK/dA7 VjOtFO1jCq4RnyqOvfT9HuVoLW7ju8bTPskUbh3Pb+dPniie9Jt5Y
- 3O10eRzuBHUfj1qS1g1VILw wzRySLPGxbZwxx1HtWc6Bb9JJLmORRG0aCMYABPGfc+tZq8pt3
- +70MvZSlVclJJ22V7/AD6DLd2n v2mbKR4WIdssehHsMVWubX7E3mN5cx3FmOMhW6FTn6062Js
- J4mgcMUXZKrDIVycg1PYRwPqEg1CK dwiFDhsDPr9ea6m+VuXT8zun7WLdSWqS7a/iVZl86UeV
- EwjbcoYDAUgYqxbRytZ28iyLIDEVbIyQ xOB+NbEVrZ2sNvHCZFghDIzu+4OzHO76Crwi8nS4V
- YxgSHzCVXAADYK/WuWeJVkkjzp43nSjb/P7 ys8LQso3llBEaheoJYYH1zTJGnk1G8hRUbdMpY
- be685HtxViaS0MkqxOZo/MX5VbB3bsq2fSmXZE TXEiONwlIRh2HXJ9ec1zxb67/wDDHGkoSs3
- q9romhMEs8clx5LSujOflGMMcAY9T2qL7MhWGAjaV gKMo4IZgc596lgaRdUW5uBHIkgDKqJjH
- GPy5rQjTzLhUMkYDDCjHzEDOTmspTcXoJy9nJyh0676/ cUxMILRIYInQLtyXwQWA4P4c1TSdn
- uZlvsw/MH3dAxAPT2reW9AXHkp5DBWUlR05GTWRc284ijkK faFjxG5jGPmB6fiDSpyV2mrXNa
- Lgm+aOr/r+tTLgk8/U3CuIVnj3srf3iDwPapFht0RYmQzyZTcB 068ED0HeqlwCJhOrxxkxsEX
- HKDODmtSE+QUJuIEcQsWZlz05/rXbU0Sa/qx7mKpS5VKOqatbX8dD NvYkF+QRGJWJkV1GAxXj
- j0z2q5bWtzC0zTl/KaYNGp+9gDJ59s1dxc3tspXyc5CBwn8JGWA9+ODU +IntAsjOojhIOW+5u
- HAPvWUqz5eU86opOHJHfr1+4zZk09beViVaMMI3JOS5bgOPpmufuIpEkFrb q89tAyJKQejD3r
- pryWb+yUeIQyyFMyAJwxGOnpxXNrLfy226J02GRdwVeTzjmujC3te/3sinBql7 z083/wAAr3q
- LNJA0YVNx3NIPUnCj9Kr3UTK6W6brkmRzII+MHjcPalNptsRERJ56SFZELZJJbqPQ YotYHi1f
- E2YmCPh26Adya71ZLR7XM1ShUp817OOvX/h/wEaCGKFraOGZ388s6k7iowMYx2NU4rgQ X6FoR
- sUsNu3p8v8ALmrhCSQtEiyxyFQDK0hOG6lTxRDp10IZ5FgZQrAAyDPXqPrirjKKi+ZmkaEY 0+
- Wa19df8v1FsxbmCBmdxJIFI+bgbc7l+pqxIheyjiEgLIMiQdAo5Off0qC0tJFnxBPC7biEGM8H
- gHp9abIJbYykMrEOEx6gL1+lQ0nPRm1PDSlP3anvdE7/AOQsZ/cxXKzu2Y933iCoJwc1ofaobP
- TG kjkaR7h96MxyNq8HHsc1TMN6lmit5UhZy8qqmCAOgHoO9KhLwnzot6rGAAF4+Y/LgenHPrU
- SSlq9 UZKjOrK+um+yv5FqbUvKMvm27FpLhREQQMKACTTrO+ZLy4le1kjJfDLkYGec/wAqz53k
- dJFmgYkY AYcckZqeAieNPOlVQz49MBeGB9zxSlSgoaowxFKnTu59e2/4HUrMJLWUSeXI8kgMJ
- UdVC4JHtWRd XHkRRRxlmJj25zzu6Dn8zWBc7AxigklZ41P2dt/ATGSD6k1fS2mGirctMAc7lR
- uSuR3/ADrCOHjC zb3POU4UeV8y1e1v8i5hcRRAkSpGomdj8rYOCR6VkXEzwaxJJ9oBO5kEXOe
- V4oK3f9ns81xHOIX2 yGJcbjj19OlVwjw2dtJPIszOm4qB83Odx/DiumnTSb1uY02nPnWt9LXu
- EyW6WFgziaGRbfy5AzE4 cZPb61bszbyaX5kxEUrsj72+78vBwPyoSa3TS2McJuYVkTzi3zb27
- EZ6D2qCKySa7bbLHKMsXSMY J56j2q27xak2v6/rc7aNKUqbjUbVu35f8PoX7+8SeKZIkU2yvh
- 3QDqcHA9KLGV5IZZ5C4tyQwI7F eMceo5q1cxzGxePfBsZg2FTB7Y/E4qaGT7FZ3LXSKsTT5ZA
- uNu7jH4Cubmj7O0V/WhrUajh+SENP W/3eZi3TtLaLNENivbFo0bnCg4/rmqE1shgQXE6IgdeB
- wSMYrduWG2BbOBpPJ3QM55Vh1Ax71gTw PNPapPN5anBG7sD/AIdK6qErrt+YkvaUbN2t56/dr
- +YnmpDHIyPDlWZYjt+4meR9c1VJkltfnEig HcxxnlakuIooNyAhgh27gcjcecVSkhlSOWRUkC
- LN5ZQnkMR3rrhGO5FfDUaLjOc4y9dikHmEbCNA 0gl3NlR3GT+tRiUDaTbuzseCGwE9AfXip1J
- YyseGBAPbIHBH1qooMbqgyoeYAE89sYrsVjilNU0k r8t32t8kdUlsVuoTFIrsVMgwSSCp4z7V
- rLJd7fNktlU+YJTlRyQfmI9MVNGIYZVkluLfzIFZBIq4 VgecY9TniqjLci3h8y5iTbuEAI+8u
- fmz647140p871Or2sK1W84Kz6vS/wB3+RrjbdXL3AIOSef4 BuPcepHQ1mTR/ZEEkUiiV14I6A
- c8mnGd2sWZZY0CzqsZUYyjHv8A0pzzXCNeQmBrmB5cK6DoD2H4 1jCLT8jehDVtPTte35kqzQX
- GlqLgxyRYUKFXBHOP1pkd1DaxxIwM7S7nB7Haxz+B6VVd9Si0+YS2 pikZ/nwoAU/T8qkdYY5P
- MmXIVGTav8DZBCn3NPkXXbyMuSHKnJ6Xen/DbEs89y/lSIvlJIG3KBxu x0Hpjj86gjtjbT2kV
- yBI6RO0idw/UqffpVNbuGW5SZkkdBjzQrdJD938u9aE8SmCKaVi/l7gxHVn zgNn0yelaOLhaL
- 0Npy5XGHL6f1djkXT8xyurhpommyTxnH8gaqbrIyQId8L7P3nmtnJ681cgtylk rzj513QyA9m
- J4x6Ais+aeaeaWHy0iRiWO5Bk9Mc/hRDWTs9vM2oSUnzRbSXX+ty3Pp7SqsxVzIso jmVCOWPO
- R6ACoBZzRSLcW+4mKfayOufM54K+2KlijvWe6ltyZMlgWB43Y5wPX0psEdzdaLApdonY EgN1I
- U9aalJLWSsYutPmSdVcr6FgzzedGtzayMLdtrquAy5Ock+gFWpbotcyLA0LpEJN4Vfv4+bc PQ
- Cqcs7z2NwVkUtJMrbMfNntzWmjKkJk3RGV2Ln5OhPG0/XmsJxSSbRdWlTjFT3v0u1+g2W5uJ7M
- +eq2cciBmlIAVm4wRjt2/GsqQSR3LIgkdWbEqqeYx6VekkkUvHLPAkQO2NWTqfUe2eKpWN3Mmb
- kj lNsUgYZwxyOfenTi1FtImkmqbjHTy/4O5enjJZ45InMaodgQ42AkZU+pqaC2jjm2CN2gydk
- TEEhT 0z+NZzieHUVXLeWu5CzfxIR1+ue9ajR3I05fLXdK7AiMctEq8EN6+tRO6SV9zplSbik9
- O3b79RiI 091ZRmHASB1AI68/MTSzwwErLaRSxXEKlnWQ5BLDjj9auLcTW86yybIpnZkJdchi3
- TA7ZrR+1JHY sWWMTMMsuAMkYCiueVWSaaRlKq1OL5fknb7+5k2EktqC0xTy3ljxuHscD+tRTX
- d08hjSNsl0EvHD FuSfyrQkiZ70htsbZLbSPvFeQw9h0rHnE0kUEsQa2kYiYmQ/eG7g/QVUOWc
- rtDTjOUpWV+/b9S1e 2rnT5vtUUkSrJ+67ZQYzn1PvVV3IsZBHG7xKwOFPOAQeT61YlZ/LnLah
- FLILjLA52gDoMe5p6wRz 2Db5lilcgynsrD+H6mqjKyXN+peFa5V7V6X81+DLVvHFDdTXCOVDh
- xtds8tjBH0pzXsLWht5JoVu o8KzEYDH+8PbFTzuscSQMgcxp1AwAvGQfU+9VGa3m1a6FsiCNp
- N29hnA24Fc8fe1ZpTpSm+aSbt9 35CNawy6a5jcKZpRJI+eFI4K/U0lrFFDujTeu5SGLN/Gen6
- UsM/kwKqWsv2lwHZnOUGD8xxVu7jR 1JVJJELFS0ZwNxI5/pVuT+F7Hou7ioN2+f6f8H5EFvCp
- W2XzQsW0Nk99ucVaWN5pJDJCiGRlO8qM L8pyD6msiWXy2ZYZAkkZA2NyV7MPrVyOWZfPLMSIp
- ECj0OO9KcJPUzqwrOL2+4pzz2tvIVKSIykK hDYByOf8aRgrDG4FdodGUcNtHH5mtNprI7S0Ik
- kdPMjPXCg4OfU1H5cCXieQVEKIwjY8hkB4P5mq VTTZnEppL4NvPcrxNehIpZXt4WX92WaPhj1
- z/SoGs70xx3KyxS4AyEX7rBsAH3NWJnuY7xZCnmoI 3RgBwG4yfwFSRqbgHdDLBChKMd+A/fIp
- 8zjroOFWUW2rfd+BTdCxuJLf5JxcFIg/TB4PHsc1OGuI IQ1yBNtc5KjmQgfKwPpTzaW7Lvkkd
- pXBkYK2CGX0/PFNvINwaVp/KcltwOSFJHTAo5lJpHVGPtOW Mne/lr6dyT7QPsCXE1vPGZXRkZ
- m+UBe+KmeSO43TAMZCxdQD9854bHpnis37ZdR2Sh4lmIdCrhfk K9CMe5qSVriWNo2spIY/NVV
- wRkDOSKHSs/8AghUw8IRTqaa9/wBN/wATShvN9rcK6skr3AcDONoz jafcnpVRUabUlSeAr958
- jgAZ+Zfr3HpUEccaXL/aIp4l3n5WfkAg4P4VU+yqpRFuDCxUMA75Jx94 frmiNOKvZi+r05J8r
- aXn+mv5izI04k27VgKAmQD7zZ+U/j0odbopbSy3lujPCxddmDt3YYdOvvUr xRpZKFl8obtrK5
- z8x+6PwrTginuojJdQlvIfYuBjjow+prR1FFX6HVGr+6TWy6dfxLtoQ8c8X2eT 7OkyeSx9O4P
- qfeprmNpLxljjkjWM7cOchQT90+5I602SZ4QzbGti6kFW/hHcmrlu9r5EihyAWDBm OThTwf61
- 5km0+ZI82cb+9GNr+v8AwSsjW7xKrPGyhz5aIMMFByQfU+h7VBHpc8eru0dxHLZyOZEB GTtUe
- vv/AErQC3GLmQJEYmkykioMHI5xUNtdS24hi8yJkRSACvKg+tSpySfKcSlVgpcuvf8A4HZ/ Iz
- 3sofNtpGlYxmDLqGOck4XHpWqQ8MUv2dhIS5IBGSoA6VmNcSPJKlvbmWEbTkAdc9KlN1eTSNLH
- H5cu04GODu4PFaTjN2uzqrUas3FSlp6qxpwSvI4Wd4drRMyoqYPHU/TNF2sc9rCXmEbOvmSkHA
- 3q OMCoYpDECJ4jE8b+XHuPJTbV+Kc3S26SCPCxkAhcY9j7nFcsouL5lscqoTTvHZHNCKMooME
- ql2LO XIO1gM49quNaQTWSTw/61lO5Sc85A/KpL+5jgjiT7LNcJMPMZozjcemR7Y4pbeGO2mmd
- ILhTFMUj DyZGGGTn8a6nKXKpHe4SVPnWj/P8b/gEsSy21xAW8opdGPepwDwCuKx3EFpcPDNI6
- CYhiznofT8q 1kHnRndIibdo6cZHc1HJN9uecS+SUaQFDtGFGOR9cinSk1p0NMLGFNuC1XXXVG
- UjTzvPBaspjiKq X25Bb2qi9p5UYt0mCxKrHaoOTg7uv6VrhJoZWeFQ2VLsij72Bzj6ViPE8ln
- 5aiTMLADD8vH1Jrsp yu9NEOrDnqe7FL03+exERCZVu1czcFGjB5y3IJ+hqfylluXdgyxRYTzT
- yGJ5J+lQ2lpH5zXMtzGk RdQuc/Nuzg/hSSSxQ3JktbpWicFgCchmXjj866Hq7RZHs4qbhGV2+
- rv/AF+ZJILf7SjxSLKm1o3d eiEDof8Aa96iS4nuZbdSxiTYAE/vAn5vxz3q3BePFgxRRu543b
- fllJOCwHpiohcyGVEW2zFuCJtA znnHNSr9UDpTjFxdr921+H/DlGCxVbi6E0rwx27vlsnnnGK
- c88aSRTiHzI1j2qpGdxI7+pAqw0N0 IpYxbSZZjLIzHIBTsfrUbpujhuVjK+Y6FUx93J+Wtea7
- u2b/AFeDSd/x0/r5kSNBLbRx/Z7rzEQq H8zO7v3FSxzTK9qIpYtz25Z0KZbIGdv5cita68spc
- KIDGiSq0kx4USDgL7fSpY7ONIZLiUokxLsr Y+Xb04H6Vi68bar9Tjq4hNezcbLp1/H/ACOUMk
- LF0McksKjEJDc7cZyT3piQGGO2mjk/cmPzJmxk K5zgfiK2IraBr6KQvHHaNAAueoPZT7ms9ra
- K1tJo23AvMHkjLcgg/d/CuqNWL0RTdNz9lDVf1tcv wS21vZtLIY8TyLhyPuqO361QnfL2Yhcl
- fIkJzyCVOB/Om3TRXcSBW3K8YCp6MTx/I1SVolZISxQC N1aUscHBzwO1KnS+11PIjl6hLmb6/
- wBdmagF3KgiSMQxMS0e5c547/Ssk3l4t5AMQSBLchMx5BBH NaNtcJ9lZ3nWSE4MajIOAefzrO
- iWWK4SR4XKgMoyc/N/hz0q6Ss2mkY4WlBVXF2t06a/PU1bCVfs QlaSJi0iK7BPlj/ugj1P9K1
- ZYIbi4SNJovNicmIxjb5qLyT7jPrWJBNFFZkeZG7W7hCQuAQPUdzz 1rpDOv2bzYZYJFiKoSq8
- juR+NcuITUrouvRlF7t32v8A52KsmosWeQwqULBlPGNp6j61UWSG5SdJ pUw5fqc8Yzj68VOLy
- T7S7xpDGrqzr5iZDJ3I9MHg0wWc19bQrcyQRzCMsDGu3GDkqfU4xUxUYrXQ 6aapQa5vdfe//A
- /UZAtumnyyW7MqvIsgBbOzj7p9zUEtrbzxu2HkllK7kDcqWPT24zUsL28jQlIJ STGfM+bhSTk
- DHrxVi7zbTlkhIjfDD5uQFP8A9c1fM1PTccm1L3b3/MxbpbizkzDHHIj3BJUqDtbG Bn+dUpIJ
- YLaWQyorMweTcM/MOnY8nrWkZJbWZZfNRhjzkjcZJAJH8jVR57O709AxaAq2JWz94kHa foK6o
- OStpocEsP7KSm43T3dr/gc9crbgL8yKwQDk9fr7mqgjWBZlIyBNk4PtzjjiraqstpLK6bTH KA
- QcEk9M9OlV1imS7BWFikZy4c/qa9WLsmrl4qUXeUUrLa17/wDAOhS3idrkROWiVxtYEkYx9PWr
- X76ZImeVJV2NIVHDe/bip5kWSKFrGSKS3ZGxtTOecdxTzb21rpjSeaY7xNqKrHOVyNxxXmOpdL
- v/ AEj2VOM6NN21u/Pv5XXqT/Z4r3S4HRXiR2yuT1wMAfnTIEjWRPtNpd206Sqkm+T5ckHAx65
- rVilS a5dFjK2aTO7ODgZHQD0HtWJqCi5htsSMJJdshwenYA+/vXJTk5Plei/I8K85N05PS+//
- AAb/AJml HLMk91ujIlR9knmjI3EZHHtVFoVluoVkP7lwfPfP3ZAMqPxqovlSPKDK9xlT5SKfm
- LN6+uKvwyQW liqG1uHR49wkL4Dkdx+NaOHJtuegsBOLUqT956WVv1ZVaW28i38qLY+3bMM9WP
- U/hxTGtpDFKEn2 Iku0yMcqVxk8fWpzfxNaR+TAsOSnzNzkscGnPLK32y3NnO7gtsVT/D0JP0q
- 1zJ7EUlUhO0rr5jJm uLZpJAj3KSyqUYH5Qdveqtuw3Ol+6KisAQPvMcEjB7dKfarC58ss8LjD
- RSO+VwMgnHua0T5uIoo7 ZZJYsDO0cHHOfU9vxoclHTr9xq26TcW/efy/HYLWZrlZhBiLePMVs
- cLkfMD6nikiGYo7gMDH5REc SnDEHjP5k1HFfvLeQSyRi0gVDHtK/wB8kfpTbuxmmkhCo7xJhE
- MZxwO9ZctpWehjFxpNptL+u/8A wRIbG6MqxG1mhEaFXY/xMORV7SxdW0EqSRF98yy+WR8xJBy
- QfQelJDPMFkR4pogTtDs+QST1/lVK ZRbXFtLcSSblRl++QGcHkfkaG5TvF/1+JT/2jSdr9P6u
- aEnzTQ7UCyJC8RmZco2DuLY/SqSQKsfm WQaSVnJXccjGe47kc06K5dZhcX0TvG5DeWnGMcMPy
- waksJY5dQwgEEQlLgscjOCFH09qVpRi/L7j aFOvCLVk4rd9PTq2W4kuPtL74SY3wVfHAIOAP8
- afLcXsQe4VPNLviUovRs4A9qtQzvDb2gkIklEB 2qB1HJb8fenpqdrJFbspCRSr5nPYqcCuVyl
- e/Lf+v+AU61Tm5uXTyJD54M6ytC3lybfucqQQSfwz RPLK80uQgWONozIVGCx5zj6Uyb7MZLlo
- JDKJL1fM+bOHHQfjVq5vHgtC/wBncu7FipUcnpWPVWWv 3DpzfMmrO/TRW+8pvJE+nRvKHcfZ8
- 4DbWfoAQewqhNNcxDy4YTIF+UbhnIzyw9h3qaS6uy7pGIuQ BsMeTgc8ela0cSzzM5jc5YlwP7
- uM8egz1rS6p6tXHUgqfxK9+n9aBaWVv5k7GLzlUlUcdJVB+Vx9 ecVcT7Mt0ITblRJHuweoxnm
- pEgRYbe4wzDyP3m1sB+eCPQe1WDPFJamKKFt/mNnJyRnGPwrgnUcn 3PLnV5p3SuVv9FaCAvE5
- +T52zkEnnH9Kom3RXXZbyKBGfMjBG5DnOD9KsraSnWopI5VEPll2BHCl e31q39pkkmW5ZFMTK
- wIC9WPb8TTUuV+67nVGXsp2i2/M5mC2aW+mwWI3bkTPO3vWza27PNOyzKFM 65UjO4kdR7AVY8
- 6B7u0aTbDstnjePock8k/Sr08scWnOPNgMaDYsqDAYsBz+PQVVWvOVlbc66let Oy2v3X5abmN
- NCdrPMiXAlPm5iXBCrwxPt3pqxzM8pBjWJ5FBbb98spwR+lIryqsizXturyEMkeOY x0Kmo4Hu
- ZvLjjZRIqcKRnvyPqAK0s7FTjUS7tddkhs2ltBpA+0TIo8xVQnIPbP4UwRLE26FWuIw2 GZTxk
- HgfjUbSPNeQFXaZvL3pk5UYORkGnia7hiWVpYHdgIwipw248vWiU7avUuMJxjac1d/L9P1L hJ
- DpI0J80Psk5+UsevH0qA3EM4ZEtppoQwSNo3xjjv6mrsYSUtCt1DJIkiqzgcO2cAj8MiojLEru
- LNDglh6hecY+uM1imr2tqYuUIVLPf56GRskMikSBlBRDgc4P3m+lW5IofPWNLa4uY5d8keHyCA
- cL +dF2YUQhd8RiiKKCfugjjPqafGzC2i8wNskw0YU4yE9Pqa6HJtJ/1/XU76kuSKneze3T8v8
- AMy4I HjkmsGhneUKTjd90jt/WiyEkK7r5njVxvJYnHcZ/lTb67vWuDdeQ8UUoYqcgHAAB5+tW
- bcSJbtdS zQsPLKiNhk5BFdEnLku+v5ndOpJ0730fTe79dbfcLFfLIzSxhXjT5UDc/eHU+vNVj
- cSmfa0lvMI1 2nan8RHBHHTtSKY7uSeGYpA7EkMi7VA69B6GrL2MCWMsjh0MjAvLu+VSeSMe+O
- Km1OL1WpjH2EZJ TXvPyX/A/AzUWzaxjlh3mdm3bGbOzPAU8dfetlPMjs1DXCgRnbK2ThzwQR/
- KjTbRYZWmdR5ckqSJ nogAPyn3FRy2NwLxXhmAKYJLDKvzzx9DSqVIyly3HXrqS9k3dLW7tf0v
- 5fMvvtvrq6kmnVVSTZGT 0Klen51Zt43kntRNGwLxlpQBjaQpB/AHH51lzSWa/wDLUSyqGEZQ4
- G0EZB9W9DWnAtvA8k0XnhGy V3Pu9MD/ABrkqK0fyPOxMWqVrvXb19ehBsd47Yq0hRYQow2Bub
- jNPQl7x4nXyGVRtZ+c461LcP5d vKDHJGuVeJ88bVOSPeny6fmae9SUSjcVDA8epI9qjnVtTOD
- hHSW729fkTzf6FaFlCFuhIHTnJX64 70W4jw0pwskThGTPIJ6H8jSP5aWocXMUgB29M7icfNz2
- p7wbtQQgNcbFIdYuCGHTPrxzWKempnCE akL7W666+WqJhMSssZ2OQ6lGPPANSPKRbuPMiHmfO
- WC42lT938azYS0gQnbEDAWkdhw2T1FXH+w/ YZD5hKyN50eG+8FHy4+pqZQSZ1SioOLStf8Ar0
- K017KJPO8geVEAhXH3R1xVhVluWX7RGwjdgz4O CpXufYcZrGaRRbiZriL5tplXHQt1P4VoQXs
- sUyxxEeVENg387s9K1nSaj7qKrUajheO/4f5El3Dt VHBG9Q0bleFZ2xgj+VZPkJbm4nud+2OQ
- RuqsRt68fU1dlmil3iSKaF3YSmTf8oAGNuPU+tVry9jF k0qrneA0isc4f0+taUudJR7jpzlC0
- Hd839b3IDdwR2iraXC+YWG4P8xGRyPyqvEbeJ4zI4RPn2lu SVIwaagt7qEGK3kSSRW3ZP8Aqy
- TkZ/n9KpRXzs8CPEt4FQjfEMAnJOefpXVGlo7fMyq4eN2438+9 vUW53w2UfmhZYQyD5FwVOOh
- 9+lVbtPPs9oEcLRO3mLjld3JrWVpZURoYtxjDFiVyuT2x6nt6U5Ve ZSssAgUx/vC4+9Ifu1pC
- py2b6f1sFCm5csnDZ91+Wv4FO0lkP2VXgLb38zCjBYA4wPTHepLu2kij gMsn7ndIHK8YPUH8e
- gqMTC1dI5UfzfNUO3/PItzj8qY0t3Hqn2lIpJYd4yjcg844p8rcrrQ2UHOq 27Ra1t39GyeOcm
- 2lHzI4uN7BznjHSrEt9bHTohKoDbQItoxxnk/h0qa6aKG4LDYYEYxbx2PUZ9fe sc3MDCRZGjd
- 5JF8jAwGx1I9s9qiMVPWw4uEoqXLZL8zQdI557p0JCGZQqs3bb/MUskz2LGUt50Yj 2FevIxx+
- tRRPFdGVlina53kgxnClj0IHpxUM7XE0GZrWR5SNshU4G8cjj3AoUbuz2FKLqe7KVl2/ pjEu7
- c3XmpbTJlsIHbKsDxkD2NYz2TmeYtdR/upk80nPLHIJ+ladzZRTzI0YkjGd+C33EH8P1PrV SS
- BHtZ3Ln95IHIzjO3Oa66TivhZxR5HUcU3d6bf53IpbB1uYYUBlUgHzE4A2nj8+aoKlu08quJEh
- MxdVJ5GOhz6Gr/2KYQLMPPMTAMpD9CORz6YrMuMpcyTtufcu4lRwpbtXTSfNpzGcaaqzbdS6Xb
- Rk DLEsyqN0rvtKqnGWJ/kOla1zqEaSToskasrOrgjq2BjH+e1YQh3XrEllKOwVc4YbR8p/E1a
- eKSaB ZWCsWctK5GAGx0rapCLauY1pxqVouT08/wCtSxZvBJd2ql0KgFWXH+szncTV1PNKyeQ2
- 2MREyoeS GHGfyrIitXe8hd5UiD5ZXxhffFXY2FrGro/zAb2JORJ82Dj2rOpFX0dzedOTk2nfT
- b+tP1OgWT/i UZbaJFJjDkcRAkZQ+57U37JCHRI7o70jZGXeST3H6Zo+8t/JJGTbNciJE78/xf
- nirEXltHKsIC3O 5TtbrgAg/n1rzrtbHBR0jyp63e2y9W0Urf7SQscEDKe4YZyOoNF7Yl5PlMx
- hRVZZA/AHX9e1axVZ obHZPH81u0jEcEkfKD9MdqghQG4Ehv7cRFSAMZBwNuKSrO/MtDojimov
- m/BfqYd3HFFdrcRuHiki YZf5s5xjHtUVppsrW0bQTWzlSSVCfe54P4VpzW9tcae9ujDeg3I2e
- EC9Aapz+abBIVYBpR58hiO0 oRyV9s10xqPlST18zgxbVSmrXu9/T+vMyXu0uXmkcxQRhXQpsx
- 8x6E/iKyklZZnmEgEj4Vwy5Bz1 NaV6sKziRrZ1idcnkDg9jx1B71nypHJYRSLHIGUlQikbj7n
- 6V6NJRS20YKFKlBK10/JfodK8UElq 6wyOJlYsoUlRjAHSmmOK3voBJvS6nQvG8pBQZ4xjvnmp
- FW2jluZEY3OHOxIzjC7evv1o+0tJZWbM Ix5UJGxly5HUHNcSb2W3/APUbcY+yp3t0vv8/wDgj
- jBciM2rEq4bZtBwQBySfXHeljHmyC4Ks6j+ FTjfk8EegB7VKfKnh/1jtO5G1QeSp7/l1ojTTp
- kSKJblZTGH3+ZwNp6EeprNy01M4RjKDTbv2tt5 7leO5jZoJriKOO5j+Rwq7QGJINXL+xiCQfu
- p4lUlGLP8vr+HFNheT7agMlvGFVivmx5xu9fUj1q9 JmJGMVwkzW6FW3DIJx1qJzcZqxnKFWlU
- XItfV/5f5mNcwSWlmiwtDPBvyzBejLyBTS+5JJgksDOn yFnPzBjy30BqxMsdxYqROFgMy/N65
- HLfSmzSrbPFALZ4oWdkidzkBDjJ/A/zrWMrpLqdtFJRV1eV 9/8ALTVjEV5LgrZKtxNHIVXAyG
- Xb1H41YRJ2iImtrlZpVBQA/fUHnHvUaJNCzSQQyOJmDxlDjIGf 5HrVxms4LaLzXlW5KsQ5ckL
- xyuPfPFROTvpr+ZH72FW9PW/rf8HsVknji2IkLRQXLh4Wl5A4OB+d TNpkku1pPNG2LaUV+WOM
- 7h7DvTIHeS1SV7dzBkLGpxlM/dJPsev1qKWVxdXXnmSBvMEMkjMdqk9T jsP8aWvN7un4mNOb5
- 2ua3fS//BIY3ubuztrfyZHZoWmQr/EVPX6DHNSyxOGEs9tJciU+d8hwMjg4 9BTJT5AFta7yYV
- MW4HkEkHH86da29691GtuGh+R4nMnIUsen171b0V9EjWtRhThzSklH539X1RXc i41S282KWNm
- fIUtwTjnj04rahtrIW7SSwyxRJOGbEmMjHB+maptZXH2qO3hbNwsR/fNysijhmHpU TxXVtEoE
- c1zBIygOG+VQDgZ/Opm1OyUrEyp05zT52vJP8f61NcLHBYxRQM0beUwfzTuKv1xn6Vbh UCyt4
- /s3nTGAhGQAKQei49TT9gF0yNxcrIFkJHEjjqwHYAcVPPNGixi2t5S4Qyrls7AOgPvXnym3 ZI
- 1dRNxhCN7df8+5UNusskccLranIEofna2MDPv71PJbX9sSrJ9sXaQAg5C45bmkE/2lIPIZEO8j
- btyQgOSSe5689q0rkiJLnEFzK81wJoiH6xgcge1RKclJImNZKdlq/P8ARsWxs/tItjHGViWHy3
- kb uwPyjPvXQWunTRzKzRs+IWLIvWIgcq3qcHNWbQRCVLiCVIkGY0BGQQ38WPY55qaEiHEby+e
- w+UFC RkdyfWvIrYmUmzzMbj5Oo4rbtZmb8jWcSRQMsbIrKzHO7HIx7VOkAmWSVmiEm8A7RjKk
- 8/4UkxtV sA2HTceDu4UHinXSmYmJZo3hDEsYhgnAGOai76aEwckk07fL+v0GSR2ttdTPIrJbq
- pC5bqvr+vNV AlqYQouYWCgcgdxnJ/rUpWEW6y3SycKQkecce/8AOqRikayUzyQ7eMKi7TKAeW
- B9K1grrVnXCPNr KTv3/wAt9fmVWgjlulmKtMoXbD5Zx5ikE7v05qpLdwtHG8bKWmgEkkY7t0y
- PQD0rRt1s3uTvuDkb hEVYgHGaq3AspLm0El1axRtCdyqMEljkYPpkdK64SXNZp6HRCvFN8zbt
- 6/1+RmKYpWCHKMw2+Y/Q DNWJLSJLhHt5wylJPMKk8be31NQrLIbtX2KiKv8ApBYZCzHoPb6e9
- ayXcxiJuFhWODdHIQgGGYdD W1SU4tWLq4mtTa5Ze6+l3/X4mNbllTdEolmli85IQPmAX39B3r
- TTyzbNdSyQJCZBIGK99vAH41Ri vrWOGJmjaFzHtyT90McYNS3rF9IurePbI0UwChR0A5A/GnN
- SlKzVh+0nWnGLjp3f/DWNKSSBHtnt kVSYnMuRnbJkEA+9c7LdzvqLRbNiDIdlGMs2MVPdS3U1
- kB9imYyHO2PghiOW+g71KksNskSzTRNM snlv/wBNGYfeHpkdKdOCgr2uzeKjSjdLmf32K/8AZ
- m7U0Ed0paNvLlDZbkHvTZmSOW7V5N/lyHy9 v8ORlR+dXLW5Es/kraTlMA4Vvm3DI5PepBOss0
- YjeAyLCQYyuW57n3xzVOc+b3tbG9T2/teaetku 2n3f15nOzsGjh86YMnkgTqB9yQcge2atW5d
- pJPNVZGbcz4XhG6Yx71VdbaNykkcjR7Fw4PDHPytV a6kuBEQJBIZZczsgxsJ5H0yK7VDmSS/r
- +v8AI6qlLnSSW/loWIzNHqJ2wGOMxHzN3Pl+x9yeadvm VY4btWMUICMc8FuWH4ntS3n2iF5Xt
- juLzEqMZyu0ZP4UtpPGIkjvJY95ZDAccMncn1PvQ7tcyX+Y qk5L94o3W3mrFkjcYE+2Rwqw3r
- GwOSMZakvZE+wLIkrPsXaWV+BuIIH1xmrS3cRnjMUSFER9pwCT u7D8OazJZbCKyYW0oeR1IjD
- cgLjv754zWNNNyV0zPD0n7SN4vXorfj1RPbJFNqiyFCsETPGiHqAw 4z6mty2sc2v2eAtNswy4
- J5VRkj6msA3jtpaRRQP9pRhuUdcFeSfpVmKaeyty32pIs/KuQSX28hhj tg4NTWp1GtHYmthcR
- J6aNuyTV/yNCJctcrIkquVLDzGyAD7VMZWOivbPcwxokiguQcOeuR7VSGo3 E1lFODEkyREOpX
- +8ePy71NLeyyQwwBrc+c5ZW8vggCsJU5XV1/SM5UZtxbVrP8fmhyJPsYRlZZnQ sPl+UnOOBWm
- rSxyTysrsqvh0XggheTWa0837mfckcaRNhQvLBiMVXlCxz3iolzJL5n7tRJ95QvJ/ M1Dg5bly
- oycXG6Sfb/M2J5IDY2j7WMZhdWRTgglhg/TFZsdzG7/Z0Xc0LbAfUPzx9MVFDNdyafIk 15av8
- 6gFUxwetVJLuK2uCgdBKpKSP/tbTkfUVdOha63ZFPDxUOTVy+f9Mv3cy29rEWaCaRxtjVVx lS
- Rk8+lQ3c5js5oyvy+ZmCQHG+IEEsPoaxnhiFnBPHeASBBhXJJx6j9aZDe3YuUjhQ3LDOwlcgIP
- Ue9dMcNomtbfI0WEcEpJN27ppFm4u9QDgxbPlOCSuQSev5dajeW+NySINyZVJSRkEZxkVHNKUn
- ka WGVYGLgNu4JIGPxzUFpBcRFC8u6dkYFM/c55B9z2rdQSjeyOmc3Gm5NJX7f5pluVVW9lSW9
- S3jjk ZIgVOcDkZx19KjkK+UrmaKIgESEJwHOCBj6VTa7K3EMXlIUCfMsq7jke/wBOKszzpc2i
- iXbbAOzy REfMxXoM+pFVySTVzmk5qUVKL+VvyaL9rLEhWZYpzFMTKxD8DA4B/DmonKzhV81ow
- ULIxbhj2/Md KwBeh3jyWWIRsAo7Z9cVde33WzSrcoYUKqNvcgcfzpvD8ru3Zm8KPLJOctXt1/
- ployKlt5nkTIZH BMjtlY8cBT6sfWozvkgaSAkSmQgJnOwD5Sp9z1zSERGSzHnfNtj3J1yDnKn
- /AGj2NTbYrbVCZCwb DeWOnGO/qQTnNLb1Oec5xk1zNW/ru2KLq7j1CO3kUJbxKxl3LnJXpz69
- Kr3ZkS7t5YIQ7EBmXbwp H8HtU0rl7WFVJDxoVaU8qWHr9etTKXWwgxLHGOfNaQZw/b86Sai07
- A6iSulZy0tr+lyzZpm+keSG W2mlckZbAVQOePY1SVIoLiKeQzGMx71ctlW4NWR9rNgkp+aSWQ
- TFwOEwPmX8ahlkQ2wQxyIrI24u 2QpzlR7VlG/M/PQ5YSnKTUldS00/4JRk2/YfMS6XmMKUYnO
- abb28jwWrNPHejawW3hPzEfxdqc8g WGJnUGT742jhR2BHqRmpJlu/sYLIsXmHMRjXaVx2/Gum
- 7tY0rKrLljJJLpzW/TVfeijbxzPcJaZk gRUfaHyfcCqSR+feO9427LLuVBjIPf8ADFW1t1Qkp
- cExfKZctzkjgA9uajuZJEt5YJAg2kCQFeck DC5roi9dOovYTm3GLS032t5ruZpk2agZIysqI5
- 8wj+LnsaS6jl+yvMsqxQs4XY5OX78fSpIYmkae IzRQqCMswIAI6DP51AiRlBGHMs/mFozngdu
- hrp0T9DmxKUPdWr6v+tCS4kYmyWORXYKWCqMbue38 6sCRTpxcTRyTEkyYHA5xgenrVaRvLuFO
- 1WAUJuC8Zx0+tOjjWR1jlkS1cgMA3Yj1pOKshQpRp8s+ ezWun+a/yNpLactG9pL5yR7lcjoWx
- xx6/wCFbKb5Iw8vyXQAPyjHTr+lchBJKJZwJFjZiX9MgdD/ AFrRg1OOGGAtKX2hg8hP3nPQj2
- HpXFWoze2py42VZNe957a/MkDpPBFvv7dEKFIwoPILdP61cgtJ bdblYrqCRIpFiHy5+90NZNq
- VnhdECl1faJAOCO5A9hWr5klhbpOgEqJ+7wf4snhj6nHSlVTXur7t DpqYia5Y3u+istya6S4h
- uJIIjGY0QgELyWQDjPuaw5lultvlcCbzQsh28JuXhTWq2pG8SVLUqzRz FI8jqrcA/hg1hNNIy
- l4b2CaKI4AUHLkHntRQhPqtTzpRlN++kpf18iCeRxbrHNbSkhRGxLdz0OPp WSscsUJaUvEQAO
- mMcnj6966S7ufOhVZbZ1kSQkkHGQCOPqKwl2/bY/OLtCGLvHnk7T/9evQoSfLs JSbV+W1ul7/
- dZnTNeNFbzKluqBZgWyvP+zz6ZzUzXl3EZHkaBi2cBYxxhgM9OlPuILq3PlWuyfzX V5AV3E7T
- x/OrOWnlMV1ZOJtkjuVwNhB4Brz24WTsmvxO6nUpQs4QvHu7N/dYoSTiRproJlWlYAqc BvlwC
- PQe1W7KSWOKNTPaW7RgQMkiZbkZzn3qNXtLWeASq0YaFlkLHKrJgkcf0pVFxENNkhCSzqg8 9C
- ufMGeo+lTKzjawSq3hpv6f5k5trmCCI3SiS3SIq4UYYMTlVJ9apmK8DqL0eSGQxsQuOpzg/wC1
- itIkuJiyyMokJJ3cSFRww9u2KYriW6HmyJmJVKKe27hgfU1EakrHbhq1SVJpfr+C7+ZS+y2jzz
- /Z pGa383aELdFI4P50XKQpaRBVcDzfLAdsjkjj61ZkjhuLF2bFuMt5YPGUUjB/GpLSzmVXKXd
- pHhw6 iRMjAHT61TqWV29iKtSUaampu/8AX9bGfHebrgxIDIomC8H/AGuMflV+5lFrqsTAQfZ9
- hDiVd2/J +8PQZqjdtb3Ea4i2Y3LG6KAJAT19znimxRQPdRLdPJBbDCLFK3zg+59iPyqnGL1a+
- RlUnT9m5TXy 6l26kIt5S6mTMhwsfy4KAY/Dn9Kz1xc2yKjCOUxESLLyGJIy34fnS3ZjEc6rIZ
- WlYPIQeFJI/wAK fHbbyfsuN2HQhuSpyDg04JRhcKMKdPDqUtLvT/gq2w24triSC0bG4lmMmwY
- MhHHFWLWKMX8qXCXE McUy/MZMbDgkbv5VVNtqNvbRtLudFfIC9cdx9TWtJcTXFlKgVI3aQCRS
- vzO4GQ4/2QO1TOT5bJ3X f5hTs6Tho0+q6fn+Rbwz7rqBiwdhtQHDE4wCPRR3Hesclor17e6lY
- pEpRsNgNkZU/hUTRPa2L7pD LEZsIQxAIPP61baGCS9SRrqG1x/BMCSejDP1NRGKj1ujehTVKi
- 6knfpp5en+RHAL2c2+JhPkFW2A 7sHhjn2rZjuXs794IrW4DJKGVnbIwOpPtjtSabBDLJLMZ0d
- pJgz+WdoBHOAPT2rZM3kKZLsxxq6E oxXJA6nPrziuWvWTly2uc7xidRwUbp7b3v6LcoXzSyvu
- tzEkqnZGqr/A2PzPfNbCQusUJuIZv3YZ XkLfKp4AOPSs2RJrmzhbg74S5KDBBBBI/lWpDIjrZ
- ySCXzZo3Yqz5BI6ce1cdV+4l2v/AF+ZtWqR 9lBJdXtv8/8AhjchV7e0iRNqiMlWZhnacZwaUs
- 32i3DK5LwuGkXgZ7H6VB5T3Jji83ZuIwSevHU1 qOYIwY9rI4BIDH7hIHJ9h/WvLbs/M8rSMny
- u79CnbQw3CwbW2ybD9/kA+mPWpt9qrojq4DIZDhsH J4FV4TCb4EMZMHcGXjtwKfI+6RGCjzNm
- WyM4A7USu3qQ8M3O8l+NipaBJJYi+XdI2JBOeQDz9Kbc CCaCJF3uJ4TchlOAAABge2avwm2ba
- pV03LyxPXNUL0R201vFFHJEOdjPyAgH8s1alep5ik4Kr1uZ MMNs7uQdkisNvPG053Gsm+2iJl
- FjcSSkB7eRWGAg6j61o3UN1FDHPbzwgxPHHuZMg7vX6Zrnr2S5 knMRt7hzbuYo5I3wFHUqfUm
- vVw8OaV0z1aVPmqJ328/+G/MezQeZcl5hHvl2xqxwWyAA34VKY4Ss gSSaeRkIWNZOZFAxn3Oe
- c1VeaRlt5tsUMMhxh1yVBGAM+oq/9hhiiWKKC5M7hN0m8fIwPK/1P1rp k+VK7N6mJcY+9Udvl
- /wH912YTxQp5dsjyRfu8yLI2SzAcEe3t71bt7jVPskKRRrMWPmSAL82BzV5 NPsY7tzFvlAZzE
- 5bOAex9cnpTo7M3F48ipM67P3hjbblm9PbtVyrQa1/E7KTjVpvW6Wuv9Ir3N5e nT55HcRbrg7
- WxjAwOntUomhvrJ3MLN8xMu3jL8BcelTNbuLefbNCJBMPvrkNxyAPyq6ZIksWa4tZ Cjy4Pl4X
- aeOPqOKxcopKyHQdKnytxW/R2/D/AIJSVL0pPH50UUyFTKoTlcct+XeiXYtpcNBPDeP9 oBzCu
- 0le34A1ckslkW8uFuCG83ZKcn5sjjHpVBfszaYvlH7ZuTa6wHaykEYpKSlqvyN6kaU7TSe+ 1v
- zf/BMp7l2ZCQqqI5I5BjqScZHsDT7UyyaUImjMilt7FcAkL8tWWaKW/eNDDEFQhXddyk5BNaIk
- Z55YkeJEO5lkC8bSMhfrXROVopWOuvg5WjHlt1/4bb82ZVnbWkNva25lmKMkjuWk+6SeM1cY2t
- vJ bhZYXuVRvlIzjjj+tWo44IUiZ9sJWHGJOcfWnC4tLnTZVKpcZUHMQwxAOKwlNt31aOL6s9I
- 3fL/X l+phxahJmOQRoFVc4C/eOeSPapkurZp43lFs5ZWCgRj92PQ/U9KW9dxO0Nv5SBZEEa4z
- letTXTXD q5MMIlEu8ARhcjv+VbtRdtLXOmWEp3Vla/oVbeKK3vspI12PIcuqNyNo4qHLJZW2Z
- o5IjGu4Hkrk jI6dauXCEkTQARylW3EdtoHB+tWYy7i2nmmtWUl96rFgYI6/hQ6ltdxTxnsVzL
- 3umu+nbQozFRP5 CwSiMtu3bzztH3enc+9RLcyQPFdXGxp5l3sgGAOcDA7Ag4+tTCVmW9uIyAk
- ZEa7udw/vCoDBMzQz KyS7omH1PqB6CrSj9o1UKUvebsn66mo95b3GnNFsks13lSJD9zJ4U+9U
- Li2eOxMyieLy28pizZJG ck1Tfz3t4g0DhRuG89HJHWlW3mYuIZfN+UERHJyD+nFEKShsycLQk
- knGdopu63X3/wCZZ85/s58p WKvIuQOoyeB+VV5rKb7YZXhkjZZywRuScEZzV1rfzLGdVtp7aS
- OT+Ju4HyilslmUu80wxIoMu/kr Ic7R/wDWpKpZNomcpcjkpK35kN4Ynu3+zxqdoKy8fKWzkAD
- sKqo0RDeZvtJScE5OBxnGBWtcRySF EaAzziEtOIgV3MtZEu0DYCIzNiY7xnHHNVSacbGkJNwU
- NYrq9391/wA0WYXuHhiijMcjIoA3LkZJ ycjvVhLWV7QR+Yq3CFwXPTg96o/ZX3maDe8Xlneqn
- 5iD0IqOWOSG2th5joDAXkVmJJyfvfShxTfu s8+vh0q0ZU/h9F+P/BQyWKKDy4/OWSeYbSpwQT
- jqOOlUXiuIxEzxtDuGQHGenWtT7Cjo0rFmiDKE cH7q5xj61WvYTFfqJGJXy3CIWySO9dFOor2
- vc2dSU1yOrdLo/wBGU5FMke7yEy2Wyi4BPXjj0q2b HzLT7XGXSFkZgm77uOn41LBaXEcW1yLh
- iFK+WMcdhVwQNLa2xt0ljlEJhCO2Qx3HPH0zUzrWtZnN KrGEocsklfW7v99zDmgkRIudkkij5
- Ccscen4VLHHJjO8SERs8Z6/JnB/OrVxZRqrRs5meINgjPX/ APVTrG2tklijIfa0JIJbqcHd+G
- KuVVclzrrynGl7WesfSxBCyy2DkoyoB+5Qnk5P6mtQWUV1b2TW rneEIcFsjcTwf51Xdke1DR7
- PLVAFA6/L1Oakyy20zRo1u0rBuT0GPvD0ArCbb1WhhONSdOEovlV9 P+CiFI5YrxYyzyuoDqgY
- /dU85+tNMspke8iZZirmJQBlSCOuParUVs0aoySiNVh2O7jOT1BB7Crm l2s728s1zA0ZNwGQb
- cZC5zUTqxinJkYiqlK8mn36X/Az0s5fPgYSJJCIXjOOrEdDTjAJtJjledky N7ZY/K68Bf8AGr
- Lia/ZER08txuEqDCqc/d+vGKz47e7lmkS4heIOCyjphicD9KFJvVuzRwztOfvS St+RkYJExI+
- 8CWAOPmHQ/Spr0rLpY8weY7Yw68BwMfN9B0q08KxQxpG6MxXLA88/wj8cGql9HOsc DiLYjuzs
- uOIyB8qn9eK7FNSkjoxOIpzUPXt/wCO2kaC4fy/LZgjbWIyGz/Fisvyyk8RdigjHQjBb vitq3
- eb7RGSkNvmNkMjr8vzdO3aqlzHi6toHcOIoz5jr0c47foK1hK0noYctJtpU7d3e7/y+5me2 Gd
- S2A75YA+vYVMd0YlKxsZAWBJ5wMDI+oqJ4gm0eW8cQbcN/LD2zjnipXWUopiZtpGVXGSFzk545
- rdu9ipSc2o29F3II7hpNNWRVUMoCEEc4Jxk1ahGx3DvCPKk2hSuc+/4VTZ7hRbCEoEU5YLH97B
- z6 e9PRJGkcDLbe/qDzQ46M58PSqzvSl8tv8jQNw22NBH5MRjZ2XHJyMf8A16FuLeK1iAlaVlK
- sNxO1 yO/sMcYrMaHyzCil2HIXqTgj+vNLBFLhEdssdwVyhC9Pu8jrUOlCxDp007S0t0v/AMM/
- uRpxXUUc MhiURL9xR1Lbjy34VD+5O6CCPyZTIIyWOQxPcflVR40WLdMjxSGQbEJxlRye3rUQz
- O0g2NGjOZWy cnIHBz6UKkt1/X+ZhUoJtSp38u33atl/UY2F3taC4G1Ww27jkDBNNhndrUySRR
- 25B2EPHk4POfxq oEu2AnLGVGiJEnOMHqPrmrMMUd0lsJJGjRQURievPQ+9DSUEn0OWrKmoJz+
- 9f8E6UxXE3l7bedoo Ytow2GLlsg/QVNCJtt4tzOvmtdRsXAwAuPm/Cp/PaZYVEMqp5Z3OrYG4
- N7e1XJbaJrFgQxdSowDz IMckewrx5VLaNf1c2q16Sdp6Lytp+hmtBFc3F7AoMkTzMysOvAGBQ
- v2iK1Vtiyl90nAwV2/0NF3b CJZJRcK1uJsEJkEKRj9etMtEktLW4lcPOgk8uJgeCh/qau946P
- 8Ar+rFqKqJO910TWj+b2JPtZgW 3lLqsc0bSlWXO8njK+gHpStcQtbyOQFdJApI4LKAAW+maGK
- TRM4TyYgrIyyc43dh6VWNjcCKOYwT LE6AYJ+/2BH9aIqHXRnRTjh1G7XK3+I9s3F55iSI0RBw
- gHQHj9DSQx3dtYBQ2wAgNuGTG2eAT7jm pWiVdNVYg29JgiAHkqTwPc5zzWlFKsOoSQzxO/mMz
- uc/xDp+VTKpZaL+kEsReKainbo7GMtpIyTm R0PlyKvTGQOQR7VFciS4lYW0BSNW3NK/ONw4Br
- d+zQX7xzoZCZox8itjBIwB+VVFO3S9szxrBEBG iDhmBOOT3Poaca93fqbOvGpO6d5Lps16W3+
- ZV+yeZJEv2CdyYyqMrAAjPBPr606KL7NfSzStl4Hz IRwCcenv2rWtdPEVn/rzAys+0OxO0AYG
- fpnmsxnKpJi6t7oIEEjKuQzE4FKNXnuk9PmTShHERlfV duv46Ed1IL21jMKzRSlfkQv91Sec+
- uAKvxQwCNwjklgWiycliThWB9B3FV5UmRprdpIpFJLkIuGX aMbc++aUxI3kq04Bh3KQDjaxxg
- H8KUrcqSehM6UYQjGKsr/1qPkVlsV88xvIG+RwvyFc4JA/l6Vn K0kdxLJHcW0zF8RnZn5AOv5
- fyqNvtMbIRHI8Rk+6ecqOv6mtC7aJrSKWKMwSJLznkMuMHj9K0UeX Te50wpSppQjeSl9xHLbk
- WqZmMhAOHh+UMBgk/jV6CeXUbeaO2uIQN4ctKmQSOoGc4Bx0qOwDzqkM 3yQkboF7gLk7Se5NJ
- FaOz27xK8McsGWI6Bycjp9Kyk1qpbo1pzpRTjUa5lt/ka0dzcW+l3Ml2wLz TiTKrgRZxiP6mt
- VbyZYonkEKeXmNFKcjJ4B+tYqW7pbK0sivMXHynoDnOCPUVqPb5uLpnmVZPMCz AjgucEMPQAV
- w1YwbIlhFOC1vr2NNHZoFa5ilTZlTtON7Zzx+FTvcNJ5hjOzfIo3OM/Ke/wCFMAkT Jdh94EKe
- oPTH1q1LHILci6XY7ZI2jHAIHFec2rnAk1Llf4f5Nk8sFjPaMWYjDARbGI3ds/nUcUip qEIR1
- /1LLIWGdrZ6H8KUbftJhgjM0ZZCSO2OlRSyY1DzY0CiQFkz/wAtE6Eisopv3SIPSVOW3mST Qp
- NIB5ylSMDbkHJ+6ao6pc2lvpUYnmywATGeQ+4YFMlu7qJbiDMWxv3ocJjaF4xXOajOGtZTc28z
- FZVWPBweO/vg11YfDuU1d6BDCSUlzPT+vQdPcSyambWK4hDh2ZlK+nP6npWXqbCNEkAkjuJYsl
- 85 UKfvZH973plyrTtJFbRskrMm9mPPXrn071HsL3jQteW7qp8v5kJ3qf4h7V69Kmo2fY9CjRV
- NuprZ bq2vrdfqadnHC1pbOZBcBg2xR3Cjj8upqKNorS682ZLqOB5QzSOxI3c4/A1lCO8SaOKF
- gsRxJESP 4AeT9McGtC7R73KJBLNC77wUOMeg/Kh0/e1ejMYYHnquMp3Uvlp+RaE4lkjlALIpO
- FXghugz9OtM mj8qAyMJhsmVXkSTCuCOmPfPFMjt5Q0TXFrPFFP2VsF2z1B7DpWhb2dsk0xlt7
- gMAymKR+hH9fSo coQPXpLD0tnt26/NP9Bkd3FcXC/ZoHGwFULHIx7+p4PNVo3luY5gbG5a0mv
- FcuDjbt64NXVhSyWW 4t4mcB1Aj79OT+RNOmeWOCOa3jeG1JLxs3IKkYH61Cav7q+/7zsjGLl7
- iTvs3vf8wNvEJsySPty2 3BwHXru/A1nTW1ta2VvLHvjZ0LNh+M9h9TWxG9vskSW4jJU5KnqpC
- 5C/iahYWz2StOrRuQSu88Ed ScexpQnJNbipynGcd7X/AK8yOGFpIbQ23kRz+UUdXQEq56Z49K
- rPZyQSSz3cbsiKqkRnG5/4fwqe SK6WxthCyuoIMkyDhH9D9at/vCtyslrPKfNPmANx04FPnce
- v9XNqdWcNJWcX9/36Ff7d/aMqI6xx Ha4nDJnLHjj0HFNWzhs7a3fyZplERiIjfGSx6/hmpbZL
- f7GrGNuSiZXgknIzVhp0s9UcypIY1RlT PIYAcmocrPlgtOxhKUVJxpJ+hlXFjaNZNEs2y4jkA
- XLHI+v1pk1sJGH2i1u3kTduCuBuyOo9s1YX zJ0haaCUwsyGIjALjPJz6dKgiW4bVnZSY1eQzO
- JDncBwAPTJNbRlJLfYHOUYtb8uu/4aFk6cIo/k LQsQQpc5BzjNZ0rRkqr4uWCEEQnbgnp+gpz
- zyxXxDzeQ0S+WEk5yxOc/hVW6uSZZJfL2TedtMqj5 VOOBj3rSnCd9XcIKUXy1Hfqv+C9x0890
- LIOFjhSVWcIUGSOBTIZQIWnSVZOARCv3s+o9sVOJbkWp a4jWCWP+KRMhezKR61ltcWjxOkI3l
- 2+RhxtQdsetbQjeNrfcOKiocj0T6rVP+vvNW0uGOXcZw+UX HDKf4h7VSniura/iMMqyuh2r5Q
- 655GRiq0RlvrjMeLeJAUXPYYxj61K5uI7a3jvE3iL/AFbr8u4A 8/0pqHLLp6GdKmqc7Rad+mn
- 6lqS5eCIqm9Z/OIfec5J5B/KofNEeoQXdxKHBRjtUYBJ4H4gc1CJR 9rldv9YV83cem4f05qae
- 9lURxrai5TecPtBCjjFPktolua4mCp+4o6Pf/h+xctLi485jHukVv9WB 1I6daoPGkljcmV1W4
- dlZFIOVA/xqSGWyaISeY0MiuqMNx46+nvUM4uCqS7oJnRwsgROq/wD1+lKC tPsZ0ptVG7NL5K
- /zehfhaWOAXqlXckiRVHHIwuB29asQWt6tslwjQzPFGsWGTPzMT+lQTLd3d0Y1 hMMsbkwxqMf
- u9vcdyPWtQXUwt7dIEUJIhlcgc5BAX8u9c1SUkla2p59R1U+aMVq9U7PT/IhW2P2O WCS2mLx3
- CK2DjJHJ/DNNkFzJDPdYt4WSRY0MkYPyH7xq/JBcurJ5ojmy2+T+FiMEn8R09KrKUl32 7N5kY
- K4wedzdF+tYxm3qRGnOMG1bzVtv0Bbq5jKIYEmiThVjQBip5Xn1qvIkLWUN1tktVwNqueRz jd
- +BPNaW4HV5tP8ALbfEjh8dcheCKzLiS7fQ1iUwlJY1kjhKfvCF4PPoDzRBaq2hn9Wipxjbl792
- n96+9L1Mq5EVru8yZLptjJhDjuM/jzVKRo2ztjltyIyAWbPTA7CtWYJNLa+SVknjhbY2PlZj7d
- yR mqK2zz3rIwChFIOD3xx+dejSmrXZ6mBr0uWUZy+Hpf8ANbFhPLngi+0yI7mItiJduARjB9y
- cVHm0 t9Mtfs63DTq3lyo752ueRx6Y7U6GMtEv2sqilMxKowSAc/0qKXbPMbyaQQeajOIuc5PG
- cAfjSS1t fQ5Hg4ydoS07a6/gX7v99by3ShirLkBTgY9R+VRxXBh8u6inJEh2APyEyfun3NZst
- 5NFDH5U6yDf ukbb8o4+7j3qAyXLmIACNkBYqVwFx1z7jrTjQbjZ7GijWlScJfj1Ld5DLNOjQw
- zR4J3Kp/j9MD0H Wm7oRAkrPNFPGpHzvkE9j9M1JYSlQ1yrgySEsqHnPBGfw71EsKC6j8qaNZl
- gK7XUkEEdfQ1Sdvdf Q56dSq4OLWi8nr5PfQqWgh8xEnma4d4z5jJwEY5wOR1prsoji8xAHKAY
- 6FCTwD71opFFZwRtJLEW GSQqcleq/wD66wiEvLyWSeQRsvzI3bHpj16Yrem+aTfQywmIxKlKS
- b5f72qfyJyRb24QRPK8bkTf NkcjPSq2+MW0iKj+VIysjM2T8vUZ/GhomEy7ZlmcHJRM5bA69O
- g71JCY2aS3kPEkm9SOMe341tZJ XM1FRnOa+etvwK89074aJkFukwBjYbmORyM055fMkSOVUIi
- JBKttBU9v0qwqqmpxFoluJGjO9FAG DzyffHNRm1EUfnTwyiAnCKGwX4659BxmnzQ0Oe2G5k38
- kna/4lKJRNI5iljK5wWJ4XP8PTrTBFho ZGE7gMcBWwpI7HjmtRYZora4jUW48pwrIke0u7dDU
- OEtmiWVHklti0b7ThXB6kD15xVe17GUqtSS tKN/JP8AXT9SsYrhhHEyPnaNmFx8uc5+nvUQjZ
- ZJHaKRDuyqsfu5NaE92ViEETboADs7sAeSCfao Y4ITbs84mCK642MAWHeqU3a7R0bU+aUfkv6
- RQnVLvUINs3kRQlgTIxPHpx3rQEMDoLhJVMCtkr3y ein+dVldBcylFDJvLAMoOSO/0pI5YpXi
- neKRlX/WbDtDHJ5pyUraHD7OpG9uutl/Wn3sluJIhZok Uu/BBTbwozyRj606NHmvpTHZy7PMC
- yIpGUB7fWnWEjW2n3Ea+RLiUOPMjDYAppdUu47i78xi+XUx nYGJ7cdajVXS/r8jKNOpGjJJW+
- e/l/wzOus7MJp0ixeZIxw2N2c7W5I+g6094SmomeKO5Z5cyQLv yNgGCMfjUtlfMdyOm0ySAEg
- YwRk4q5JeSyzK3lqfMR3aNBgxkAjb7fhXiTnUU3dBPFTVZwcLrvff 8TMgVQkRW3uJo3UEgtkf
- 72D2FLDFcG6SVpo48IymNh95ugOOmMc1FC1wLHTGETRNFblgG5yc4H4Y qUGVbUywXEE+2WMBA
- uTjNaSvqd8ZVG37y107/wDDF17aRNPYD5jHLHGXPRuOWqjZ4F6Uk86YEAjD /Ko54+uOaciP/w
- AJOss8jtAyOxKkhVODwaWFbC1tLAQ+chlx5ckj5HOQT74zU7Raet/6/Q5atWUF yuV79uhKkd3
- DY4DoEaPzPNZcjjgfzojSN5Lee6V43+6zbsAuQRinmS2geO3aVihVgYyclcj/AB5q m9kiWFqs
- cdwU8wOCzk5H8X45NJa76XNIu6UZOz7liwSYR+T8wuQVBUdQQcEfXFab2rpGXkEca4yy uuSpz
- gfzzVd5UmuoYoYpPtETFpCD1Yj730xmoJrqYwRea4QIyhdw6oTzn1PpWUlOUr7FShN1NF+r Jp
- p3j84SsjvGGWRlGAC2B09+tZkkVrEGRZ42iwpi29SByM+vNaBhvjqaNGiz2sm4ZC5x2GfpUaW8
- 1u4t5/JjWKMIJ2ThiOeK0g4xWjO2lRp0k0nr6r8inOQs0ki3CCTC+aSONwPI/GrD31o09y80DO
- BI AXj4AJGQD78Yqd7WO5lXzHQs0ZZ9gxtIOdp96fmHy41Elqm8MQGT7xxwf8KfNFpXX9f0jpl
- UozUV JO/zX4lL7SbnSwY1VZjggY+6CckH3GM07yppEl/d+aZW8yNsfKB3OPSpbO4MUojiaDbI
- A6ErnAHH 8+Knm1HyVuEmAkmjuFAEY24GOR+FD5lK0UQo1qErU43e+u5Xgto7j7T5k4VlZY9y8
- cdTj69KsJdP taG2lWN3kEr71z5RXov4+1QEW7SuIHKTbTkseGwMjj3qSWayfSYEMiJclFM+OC
- xJz+lTK8nrr+hb nKrK87y+W3quxNb+fPPubduddxQ9UI/qauJJILyN5FcxFOWz39D74qOGIqZ
- 5/MQr5pVUxyMjufQC rd1ZgWg3b9kUgSMqeCMZJNc85x5rEPGUvhlK99Lf5GiRJFEHO8RxsIyz
- HPLEc/hT5biYWz+a+6Np C59QAfX0rBgRZFZVeUxqwBLOcepH196vXepNDYZihKo8wLhgCYicf
- Kf51zOi+ZLc5IR1Vtdf61LI uWEe8kyRvESfLOCrA8DPvQ1zcvaxSJJHFLsZY2dcqysRkgemeK
- r3NwEucMyy797L5Y2jAwMfnyKy p75lSBDGxZVXcB/snk+w9qqnR5rNI6KaVVXiti3dXl9BaTe
- W8IAk2zl484YjhR6Vg3OqXQCRsUUR 7UbcuSSfm/pinRxFtWcPDdSRyKzyrv754qrezRwxsHgb
- Nwu/LH7pz0r0aNGCaVrs74UKDajKF330 X3EjMY2vLmOZJy7bmRDyoPb8BVZd8k1zHGYSyzHyW
- VeXXHHNPvmlNkPKeApLlnVV5LDAxn61Xtp5 I7+2id41jcHeuMEBff1rphH3L9f8hKpTnTc73c
- f62tr+BMHYWsAuG3ThTDGqccnn9D1roEuZEt5g GR8yIr4XuOCR6CuVjn23IaaJg2QSM8hs8H8
- jWw7izM0VtOl0FOAByQf4s5/Gs69O7SK9hUbUJNWe 2/X7zciYT3TW85aOBJcqSeSo6Ee2aVWt
- 767ZEaWUTK8uxW+Yds5/DNY0d3NJbiLz4IkMTOSV5+U8 Vr2N5i1imgt1ZlQwhlAGd3f8O9cVS
- lKGqNlhPYvnvbsr9e+xJa3VqscEUayxlIvLZ5GyMnpn9aYt y0dqq3iCZVUoNgwGz90j6d6zry
- 3lS8cqymAMhyv8ZQYGPqTVqG+hEszzrtd3aSNW/hA6j8T0pulG 3NHU9OGHp814av1Kaox0mRn
- iaB0b5pHOQCOin3NaOnqbiPZclYFQSZDDJOB29BSkrd2cdoqlWkTe M9VwclT6sexq7a2lrKsm
- Le5Sdd3yGT+A8mlUqrld9wdSMYrm3T+75sq2e7YjGOS7gG1EihOC5x97 PtSzRCKSVkjui7Ocn
- zPvYxVcLcWgVYklKgBh/vZzU8duLi7tnuZJYTKhlPzkdKUtG5X0DESnTi56 Wfa/5Ji2V3BPMI
- Zyo3nzC6cKOwH48UOIJLZxIXgUPuxM2SATg/rTJI445MleH2EsvHQ/4moL82ro jSvJI6kRNEh
- wST3pKMXK6urnH7OCkpRbjf8Ar+rlt4cBjch4LaIeWjbsD5iMkfTp+NZv2WRvOXz/ ACssuS2f
- kAP3fqeKsPfLaXEttK4CKxYGQ7s4GSP5VHDBazQGdpn8zeCYtxyR3P4VcXKCuzGvOpQe qtf7v
- +H730KitZSah5kqTTu7F9obG054X3PFVpjE07QpulM8hdwvTPYj2qW5igi1jz/NCwgnao6q D6
- +vNZ7Yhu9rSiMb0eRWHzAjrz2rrgk9U3sdNS2s03ey8/yBp7pdyPE5hYNnfyckcc/WqSw7ba0d
- WQlCBIoGCAT09yTWhPHKYJ3U+egnJUqOpPU/SqmJkZQmwNghht6HHGfc9q3g01oRS5J0vaXs/L
- b5 ixTyQFY0yrSMRhgMBwOn5U15JXaLfDNIWwqEdMHqf0oFpN5ClsfvVEir1OORmpGuStpbRtE
- 2Y4yu fY1Wl7rVlTV7ONm32Vv1uS3VwpupYo4xGjlipI/h45z6cUttJI9kZ3eNwrrGCBwPUH3x
- UMZZYoXh ULGCysZOS/HQelSxvCmnMu4LKrKGP8Jbk5xUOK5bJGVanOpRUUrR+/8AHUZLCU1MO
- kTGMneExkbj 0rQF8ZtqzoE2D96AuPmBqratb7fnMpCsEDbuOeoq99h8lk8mRG2IRISMh/8Aa/
- Cs6jW0txLbklHX +uupYslukl8zaSjLvZmPKkZyP1rQkgMttcJgTbXC7Ivlbpk49qpOk76SjzT
- o1tlVAQYOWPr+ArQl jdLuY4csx+cqcAHHI+vSuGb9699TKVL3lNNL0/pMtfYJobBLhJ1DFirh
- 8nlsc/QiqzWrjUvK3Kxj VsKg5bA6/hTysUVpBteRnO6VAXJAjyAQfU56HtSCG/uppoXUpIJGU
- soxhSMkfXgVzxbV22cULwTb ehVMV5aTwlXCMIWR55BnzM85/XFUJIrtQC0TBYSpAPUKOo/Dqf
- WtcXCo8AkuEEJXEYfnIJ6/nUrg LctJI32gq58x1OFZivAA9/6VqqjT1RFWFnfkun/X9bnOIsc
- tvJE48uVbhRFKpwoUjJbHoT0rQnlk jlgVogMRMLiRVADknt6YqSWXyNLjhuERhtJfYuCrZG3P
- tVCETSaw0jW8qouYrhmOVVz0I9Oa2Xva vZXKo4eLhzVFbsuv4W/UzJIXFhiKGeMpIoRpG3bQP
- vmoY/PjVwqLcxSAyoSmc+4z/CO4roGit/IX zEuA7OFdA+MsOCP8aqXPlKoVIpo4gQjvu4zt4U
- enp9a6IV76WNKdWHa/9etzHlillZVkaGKNxmRg mBkjOPqccUSpcXNnKRKmPNC4C8gEev4Vdku
- VuJYoUs5mEcWwLu5B9/cUW81tbARTho9y7gCfvAHj 8a255Jba/IVSLuuZO/bRmR9knc/ZiyyS
- JOdskXyqNw+7+OOPxq3mYSgQtA1ycsqrH83pz7HrioZ5 Yo5YZYSWjdd2QTkEHjPvV2CVGigaQ
- iHzLd3DDrkdOfQf1rSpKXKm0YYmPLG3R9H363Kd40kl0luB 5rIrAbR/rF4JH4VSWCVr+OK2KK
- fKI+cZ9+aleORbRriWbaBKFGTyCw5/Co5TJDcsWzsiOzKnB3AZ 61rBWVkJq9JxhZeWv6/8Agk
- tLqIK5xbrkKSy53H0zUohQxmGIlZJGeTy2OSMdFz7c1CgmMqmOQ3B CFQoBbGeSPrzTrbZEVkl
- Ei8mSJMndx0z7Hn64rR3tuYqNorRc62t19VroSuVjsxM7h53OH2nAIYc EenSpnmigEEkEwbYC
- HVxuCk9OPfmkuUMaedG8UsLhWKMOwPaq5uHfUd8USH5SChQEE54P4ZqEuZX I9i3T5pLRd3+A2
- 6+zo8ioZZxLhwVboF9c/jU8zW0ljcS27FZzeY8p/mYll/lSxp5qzJPPBGkaurD HzBvwHY4rPF
- qJJYXWVERoy5kOcHtkfjVJJ7vY568Iyak29Oiu0/68iK42SSQQRskrSMDEE4YDGCD U8Zht7i4
- dYpCY5Qq7myNuDuOP1p0Fi/2xZJIzOIQXPl8EMDwM/rUEjxXOJkV4mE4WQZ4cv3Hp0rW 6fu9D
- n9qr8s/h8tH+hoW8yNZQIixAxzb5cr97j+XqKylkS2kRoVDJjnI3BOTwQR19Kmc2YnIBkiQ Ag
- nOdxzgEVItudnkNJD5O8sHxznPTNTFRje/UyhGjScoq+u9+3luQQSzTzRTsUZI8/ukGGc9PSod
- 86XCB1TeBu+5yKsvCrahKWmhgbdljzznkkADtVXyUklt40kMjSDaoxyK1TidTlTo8yUtGtdHb/
- I7 KZI547YWjkwqMSuD1Zj8vP6VqssEZkbf/pEM8aICezDBB96rGVjbt5NuU3uHRRjlFIJ/HOa
- v3M8F xePKAoUPuIA+9/tfTH614NSUnZdP+G/4YyVGTgktUZDy3lvEyBoikbrsi25dlB55rUik
- jCTT3Dww xGQqMLjBPOPqOKcl/G92y5g2RnahKjIVuv1qaeJCdiFCigRxjH3+cg/XrzWc530kr
- ET1fK4cluv9 aL7jlLm5S7uYYhFNbzSFjIxfgfQf561pWdur2ygyK3l7vLQ9Rg5/+vVtklmgdU
- SF/MPmsVj5DA4V fx9KuyRoLxpruJg4Zjsj+UISANp9zW1SuuVRWh11Z3UYr7r3f4laOeFGKFo
- /PJSR3dcgk5zj2Aqv K6vEXjkB/csS+flBBw2BRbxo8Kuq/vQ6DLc9G6Vca1Z5JVCMJHVpI48d
- FH3gazvGMgoctOreKt5M SGOCCB5oFmuX34wrcnjrVULMQoEDrGQrOz8jr0/GrouEWJhCY7cyg
- bUc5JOflYe3WoXt1huZpJbp ZgCA0anbkjuPbmlGTTd9zspTVHmc939/+RLHte4QhbgpbP5ZVZ
- MHJ+YD8qkd3muZmnkiWFrhDFkf e4zx9TxVa2nsYplZ5Tl0aSbLcb/uj9KfLfu11JHB5aiJ9ql
- lztGOfxFS4S5tEZulJ81S11br/wAE ZPO0VmXWe2WSb94yleVx/CffmpUngkgkhupreLbIGzsw
- QF6dOxFQu8UsqxMEMbByCR6Y2/map3Uq q15mMTM+C0gHy5A4wPQGrhTUtOp00cPTqxUZNprtb
- 82NvD9rmYwosaTFpom6AAYG3j35qaxsgbjy bpjJ8xbcDyMDkH1NVILtUjt51uIXlj6psyD13c
- e/9Kn8u8igF7HIGjbaJABz+H1zW8lJR5b2NJTn y8rdl0et2/X/AIIs80iG1Ft5bM0Ls5xnDA/
- 4VDEWkjjnZUe6Y4UqoAC5yVI7nHOatXRaVGgkUK0b 4XYuNw7j8arXFvKliHmuYgQp8tQuCyn7
- x/DilBqyT3MaTb5eeyu/X77FporWZlkM8kaTuHjw5G0e /v71Y811uZUguhNK0mDzkDHbB71QV
- 7a3sxAtzFlMpIWyfnOMMPRcdqLS2E2ni4hV5JM+XuRuGG77 w+gqXHS72N/rLUZKUrJ6K60/H/
- M6hZokuZ5GBjbzAjg9M9z7cVkzTTG4bfE00bzqGCfwtjgH3Ip1 iuHZ5SfJeQsrOcjJyqt7ioD
- BcQIJGuEH2dgrErkEjJJ+uDXNCEYyauYYeb55LnUn/W3/AA5o+RaR MbgmVEyFBd87M8BT7nrW
- bOBb6nKxbdDHEYyzfxluSRWtJJbixiIuIn8yBiFxn8frXP8AmWsixRMZ ZJJXIR1fhlH17mqoX
- d27mlGvDmcpN9n/AMC9i1a3cK3ELtdwmMpuYY5JGdoz7is+/cSyF7lHDK6t C2OMY5U+tS3Rs4
- 7SWRFEOZo2jBHVfT9KT7R5UjSXEBmiJdkQf8sznO1vXiuiEUpcyQoxXtPacvNf rez+RWtRFKy
- DbJ++yevTaOR9TSSSZ1CzxbEMSXKHG4Dvz+tEaXDndbRkRtC24d1YZ49s1C08Spa2 13L5bm3K
- tJtJ2nsDjn0re15aGtShGad3p+RJC1xNdD7MhdlyGOAck529R37UguDKVdnCSrDhjjGS D396l
- ikf7T/elUMrRRjaQ2MZpUS0hJN8rJlVAUHG3jofc9Qad0m9DuwmJ5INJbeWvz20FgvYjEkU hS
- N9gUOVz17VpSanvtTGhWAqVUKV/M/gapR3EEeoRLPaFoSCxAwGjYdMn24p0NvE8p3zwymZfMYI
- MMp7jPbNZSUL3aO2lXjGV5wemqe5pRW0kgtgk3mykM5wTjAHJ+n9akspLeJgJ7WWQzIph5GfLz
- zn 1571DCzxLFGiMo3GMHP+rycgH602YyQ3JuJmyrZxt4AxjIHpXO05XTM4znKMrt67Lr+hqwN
- ZHUyq szNIXkLhuBt6fQZq2Gu4YYrqcrmTKoFGPkP3vxrLfybkrboCrAFlKnoO4P4c04vdy5Mi
- P9nCnafQ AYx9SK55U0/+CH7ru0/Pf5O5dMd1O8ciypDGqeXECueD3P0x1oiZIJJTOTGXIKSOM
- hF6EY96qRSx iHbIk8ULKJYSX7AY5+hpbxvJtt3nJcs0m/avB4ABH454qeVt8pz1qslU5H17b/
- ft95JK0FvctdLI s9s4+RAeSBwKquwhQoDG8sC53EZ3Y5NV7ET/AG2KBIzHald8fm/NgLk5zU8
- TyOQ0jxtMclDt4ZM/ NxW3Jyuz1/r+rluEVU/eavvf9CvLdQ3YcztDHayMGj3J8z47g+gI5qGF
- trSMkiyF2ZnYDAVgPu49 6Y9xJdwLGYY0hd8CQKMIP4R7dPxouFke1eNXTz0ONsa4IBHIPqfet
- 1FJcux0xUJRUUku/axXnuVk ESKhMrruK4BPrSpCZ7NwGjSWOVVYyjlmJ4P0x2qaJg9xEqWssj
- jJj56L/Hn1xUweOGRMGOFGVvsz PyCv94+p96qUuXRI86vWqQl7NW022f8AmV5oJFkaSSaPD58
- xEJGJM8L0709IEYebHHI0k0pkMW/5 htPAqqxLQTfMzNDKkYPbB6k+p96jYXsWqF7csF8tgoIz
- jPT86qzatcVSM6q3Sf3J/cWb5MRSbZMS +bhuf4c549BVSR7a51aJVyokzI5J4G0fdqeNp3soy
- 0ZaeBypXH3R2VvUnmqPkSAqpw87/vQiA5AH UdKunGys2PD0Zyp8t7W8/wCtPUlS4ZbpVaEMjp
- yhAwM9D+FT3FrEqiFGEczOCzNyvTAH49qjsY4L a/cSrLHIM7GdshB3BHer32d5PJjUiVUdR5i
- nqxBK0VJ8stNDpxVepGom042+4SzUEm3l8s+YwcAD mPYOAfU1ftIzdXjLBHKWUKuc8EfeIx6n
- FNgWRLyJHjUGFCPNxw4P8X4Go7gSxW8zo5BadTGyErx0 I+tc0nzNruFJybdOT1e39I6BIlJub
- tQCDL8kJ5wCMdOmRUtzMgmUM6nETngYOeBz+FZCSx/aLcNP 5bksdjE9M4zVzcxtmKOk6LMFDq
- OoJ5FcLhZ3f9dDmp3Tbldtd9B0U88jLiNFcIyoWXIZepNMaG4Y ySxziNhGq7T/AA56598UrCK
- e9LDfDJggLu6gHJxU8ySeT58Q8yNiHVR/CvRgfU0XszWUnG/Ilr36 /mZdvZOuoxfb9vlvE7Dj
- AXb/AI8VoiH91lg7tsbeUOB5mMgflVSZ786nEsSh45EaRl25MfGAtNju Jfs0iwQT+e7jYpbqC
- OW/LNXNTlZtnJX9p7Vc7V/69BkEjfabXeyBWtyGjcZJJycn6VWNsIz+6Z4A sTKpkbIcdd9WFi
- e3817WGSdZHBU5zs2jhST65NUDai5kYsLi2JkJIZ84X0raNrt30/roazVOMuZS Vvl+RWllRZP
- OkjuLkH5nMb4CNtxj696ogyxtCyyrMY1I8vB+b+6/5n9KdsiiDAiQqSXjJfjaOCp9 +nNNWVUn
- 82AEgoIkHXO/rz7Gu+KSR0XpuDcv+A/68rFzy7i6W33lfMRTE5jG3eW/i/DGKjaOOMGT 5WkaN
- izMMgMo4WqlwsNo+ySdhKn7r5SfvDp+eagtUje1it0huXKE+YQ4O4nPIz09KFD3b30PPhQc bS
- T930/zewNfK0tsrpDbyCArHlOCfTGOtNAmNrHvVtm5ZFZRgKBwQfr1qOaAbkIUIxUuC2DjA4H6
- YqRbe9aw3q5YqygAfwg84Pvn9K6LQS0NsRyxaVl6/wBXGxXckKF2jMtqhyAQDuJOFP0qnPbM08
- qN unkSYybl6Px6fWti4lmuIJYvLWRjJgbFABI5LD2GKxpwGkLhZPNYA/KegPXNOi7u9rM4IYe
- lNup9 rtr/AMALW48m+juSpbKFnRRjk8U27lE01tIytEFQg543sT2pk8KJeNHFL+7VtqM2Tkev
- SogigQ5Y HzBlVzynOOa3UY3Uh1qVJT5ndPvqa1kpTVP9JglEP3QT90D3/GqbzzPPIpeKBTMok
- O3G1vwp8t3d W0vU8t8rEZUnufoav2yzyyS3EqwlPNAeMIMlwPlNYy918zOLEy9lJyk07rT+rW
- uYk0YnC7i6OOcZ 5PYk0rW9w9rbkZELuSVXqDnGB6ZqeRnNjFIIJo5GygyB68dB1NTIZ5bm23I
- YiJAr8cFsHpWrm0gx FWlGmnTd/wAH+enyJLCUPOsAhmGYpHUh+vv9OKrXLNAIEIiETkOp28se
- uP50LiOWKVRJDtTZknIA yd6n3NQm633yTImzy1ICvyApG38+9Qoe9dLT9TgeFhKo5Rimrde/r
- f8AzK8zN/aC7kxFtwF287Ty OfX3qL95b3Ufl7jGgwyvyTkfzq55LTJBGJEdURotwGd+Odw9qh
- AhFo6sxxkGPI5IPfPtW8ZLY7Ka hiXZ9PXQquqGSMsrFFX5RvwSPfikdlR5iwG4t0A6e1NYmYR
- naoDFV3dOe3SpQzBJ5JCFuCSWTHIP Q1tsbQnC/Lf5/wDDWPQtNDQlYLWKXylYB2kO4tk9R6Ad
- x3rb33H294hYFkXJOFGcA4J+mKxgbZb2 FJXeJMPvKvjLdVxT4b2W9iNul7EkjOhdyCPn54+hx
- 0r5irBzblb8zzoqUqsny2XXfT5rcubYRcma KEJAq4hUgFtpHf1NZ++ZgqxywSLCrLhRzkdT+G
- a1riNra1ZFUCVz5sYIyFC4JU/zqo88F156GLb5 7faCyHG3HBH49amnK6va6/r/AIJ6VGEpWqc
- l0UJZILazjiO8LLGB9/DbgflxS2cErXU7TSnypDgu zEgtggH+lTy6YssMlymfs/nI6knOBnDC
- l+yLBb4iEgj83awZskFWyPzBrb2kOWyerN6+LjCm1Cbu /wCvkKCLO0VjazRjMZUOwyoB6n15q
- S7iM32gxXaRusx8pv8AZ7j8802WK9bVhNdwvJFGxSIKMBcn Jz69qe2pKjzR2yAsvzK7AEZ4rN
- KV046s5uXmanC0pddV+pUWy1C6uLV0ubYqi7Rtj5UN/wDqpjWl u8CxPL5kxQtgNzIecYH4VDc
- G8eXz5IZgsk2+NYjtIAGMce9aDSRC38+9gkhEcq74hw4kxwM+ntWz lNW1+6w1iakJxnBL0Vr3
- 69v0CygP9iWgQRxOsLKzSpu5Lc1bW2CIskUOUVdsink7jwvP86iHnGAF 3RcI/nLjmN+oBx3NU
- bYXLQxtvMathgWzxt6KfU+9YNOV3cqLlUp80ZW1ZYuvOit7uFogjpMqxEgc 4A4/GoTA10s8Mc
- sOxTmIbeWXtz35zzTxeTx/vXw5kbeARnZ25qKO9LTRyHyxb28PlNIoxlyev0rW Kmloj0KM5uE
- Ukrp/1pZjzBJ5EFuq2wkWJfMJiB2ZOSD74qERySySwRyBY8jyvbI3EH344q1DOzNM YADdGaME
- HngfepbYfZ7mZLd0mkE+5Vxksq5/xx+FLmaucs5TTajFX/J9zNmayiaCRorrMkL7C0nQ DkE/j
- Tmkku4FgmAiIi2O56bsdvQdK0J4DNBZXGxGtxbuT8o4w2R+fSs+7lLXUd3FC4Z13bD/AA7h jn
- 1xWsJKVu+pNGfPCL5m2m+vUhtrCK3Yfa5I5WkbCL64U5P51qQzx/2WqxAKrIXmVTgq44X6A88V
- m232OWbfcSMAjhFfdgBcYx9T61qmN/7OjgjMewhg42/NkH5eaVd3l724YhRVZObb+Vv8/wBCs6
- Sr aq33wyAxBe69WP4ULeGd5EmxBHu8x2boTjgfjWcv22O+EKAxyLgx7+flHOKt3PmTBJg8cjr
- KMIgx 17Y/M1TppOzOmeEhF2l/l9//AA5PeQt5ANy6QKyqAcYHOOn0pzzwwIYIoCZokdY5cArg
- 9eKpedNI k0V66FTmVTt4baeMexoSWeVJEysU81wJUV/4F/uml7N2V+n3Cq0nHlUlon8v+CRl4
- Lixjtw6QgBU TzBkkA/e/OiK18rzkeQl/MVJPrg81B9kEUJuZgS8c6rJ6Nn09B0pJzLJffuxKt
- wsmwc9d3St0t1F 6Fx55XUJWj30sSym3+yjyLqPzWUZUoQc56A4qnA4aIJfeUjiYSRlkyVC9Qe
- O9aCwyrBcI5gLLIDK ioA4IOOtQzwILzDkukAxlemDzVRkmrXO2tCpiaVpzbt979NP67hmS4uJ
- Ag8t5nMjjGCGHIGfpVq5 hurpbePy/nkVn3kcA44H1qta7JIp3kjlFj5u4SbueOBzVRoZnvJBC
- 0rqn3WBPODU8t5drHDTpt1P ity7f1c1Y5lijRZ0KlEVVZhnC5+YN6k+taFq9hE91LGytD5yhS
- edqkcg1myxrMZWuI5IkL+YjE9F /iz684FJm3NkrQspkMgIXscA4zWMoqS9fuOudpRs01f7vvL
- E1wV1F/IlWOAY2Mwzu4xmnCRbaG3g m3TuylMH+L/a57DvVaWeKWztCWWIhAhDDgZ6/liqkhMU
- bbMkn7ztz5ZAOV+pqowTSWx0SlGq4x5e Xz/qxsxh2mhJuoZpY0kQtGMKfQ4/SlElwmnOZ3Bif
- MhbJG2QDCj6e1Z6uY7KVWR5LffGx28MB3Gf rUlw9nM6WtqJsFt+CxI47fiah09fL+mRKnOE1z
- q6XWy/P/gFiG4VGj89JI5Ik27mORjuMfka0yk1 ywNuoYzQl2kxxuzjgduK5q4tpLYw7pcyL0U
- 88dyc8d6Yst1FexRp5imNCEQHkoeT0qpUFL3os2lR U17alv8A10f+Zr3LzWiCORxvCMin0BA4
- +ppbGNomVJd6rErbHc8EY5H49Kjt5XMSNbp+7WE7DMN+ PQH1PXmq0ySXt+Fg37mVfKAbA2dST
- 9DUKN04vQ4788XGbStu+33afmTz20i+Q8cy20Dw73LgkDIw F+tPsfmt4y6NJLbxnyiD99e+fX
- iq0Ya5uLnzpFCPIpB7fL2FadonmzS+ZC6sgZTsOAxxzj9KVSXL Gz/r+tjKrVpxj7O7l+X6GXF
- dtbFJYSPPRCE3Lu/dk8n6+9SlxLqb23mL50T+XE+Pl2kcnH+eabbx SJbbXspkneHCBjn7vapo
- WZLuFvKEcrRfMxGQ5PQj8eKqXLq1v/X/AARfu+VuH+f3+RVhEMazr9si hMlwPlcE7doIzVu4S
- WKyuHkYTvK6lTGcbRioRDIrmL7N9rZVIbAH3yOKmaJJYYQ9yiTouyVDn5nb GMegxQ37ydyqUX
- CanLbraz0+SuvvIALdLJEkS4h2cFi/3t3J+tW7KIygxIphlEZ3O4ySRyPoMdqs XMFuJooIMTS
- 7GZxn0xgc96rRSlJSzK0MJYu5Y8pg8KazcueN0VUvODcE0/P/AC6ilY0uIYbgxyXM kTYwPv5H
- 9BSQSRyXSwqkkCkBgzHgqOAaXyJbh7meK0nBkcPHMSMDsQPaksILS2keVpQpBZJfMOcc cEego
- fLyvuKpD922n926ZJcBQyKS6hx2PRV7Z9ScUk63tzbJFJiEGJn2FeQV5ozaMIEVJpEIBLb+ GG
- ecfTvT4ikmpXSxXUJiklGwk5JYggY9AaSulfsdOGlKnG838Ouv/Duw2GLzkgnZQjSqzlj0PPb0
- FbVhKLiOZIU4SVURfXJyT+GKyXVo7aSCSVY5Y/nXjpt/hqGzvIZXd4IZ1Vn4G/7g5JB9T71FSD
- nB sdXnq0m5v0N4+fBfSm0MboQxAKZLDuR7daswXH2q1+cCCLpF/uHqDjqeM5rPuJUZ5tysu2N
- mhKNg NHgZ/P1qrC15HcI0Vu7RNjcuQeTxx9BXN7LmjfqZypJ0+a2q79S+IWUyXErFmRkRdvAO
- 7v8ATpVG 5+1W9uzLG4uEUur4+UADBFXJdR8qcrHPbkKwieMpksW6H8KxLu4dLkW8CzNOA5Ys2
- QMHpj6VpRhJ y1RhSd6n7yK+f9f5kVvcI2mvcKZDFhQED87wOufQHrVS6uk+3w3CSGSXb5rYYh
- Wzxj2oN3HGFgO2 IKu5Dt4Hcg+pPaormUyfNF5CIkbIfl6Z5Cn3r0IU/eu1v+R0RhJv3oavzaV
- umyIFluHmCTL5jfMw 2rjGeB+Ga0IZoY7QSEok6tzuGVwODgfXisqERxQC5lkMUZGI8knecgkU
- 24cyzTJG28FywAX7o6kH 8a3nTUnboLEUlVkoQXurdp/g+5LudmVmRWmADMXAPzA8/jzVkm3ht
- 9sTb5Em2ttODg84/ClimvZp raNbJmjJy+EwWY98+nSorSzmXUWh3KLjd5u9h8uB14+hqXbW+l
- jJrn5rWXKujNJYtMnjucM87glN qtyMfdI9qzpLZbS9S1j8yVmJWRN3L8ZBHsKmit4JrkySLII
- pHdwUbGVH3f1rOWVRfRpJcpBM3yq7 g+vHOKmmnrZszw1T2kJv2jtHv+WhZmQRyhHt52i4ICth
- gSM4zWbds7XBJ2xkk5xxu9CPatAGVLto rpzKZyJW2HG3BxVUN9sugYouJ/3sYPITaSCPxxW9N
- 2d2RCrBTd1bu9l/XyM+OMz3TDcI1MmAWbIG egpGheOY4jkyDgHHtk1NPbBbsxllhUL1IJ5xnt
- TEWKMDZIXVycY6jiupSvszeUZOqoJ6Punb7+pJ iOS2VmnRmlYs/GQp4qOB54xLItwjHzQWIzg
- 56mo0RQpViqvuUbj93vS20pkHlsm0s5bKjA+v0qXH Rnm16UYKSvr1029CT7XGZz5qkQBWSMd8
- Z4b+tRzJAjKgL7h0O7/WN/eX2q1Z3Hm2Hl+RbTMWd8CE E9evTp2qCZ1ubeGW4jcqke0NHgc5y
- Ov+eKS0la1jOlUmoqXLZdrp/hoVSgQBlYyMflAB6MTyPrUv 2S4juLeaKRUUbyxkGQ6j7uPqeK
- gR4Ycy25MTCQkrL82/PHHHFajRwz71cTu0TbFUP98+306mrnKS 9DlqxqT+J2X3fLcmtYilmFE
- 0SXCAqVZehYZAPuTWVe2zxpG8jAttw2BhYyB9wj1NWLkmBZZTFIpk kVgWPDAjqP6VHDPHc3ck
- jyxrub5S/Krnggj1x0NZwUk+dbGMaNWm3KPw7+b+4I1t28OrcJiN1+Xa ecnsfwNCiK4t41Y4l
- Q7ZHHb3NV/NNtGIoplaPaUT5AQyk8t07VLaC1tS0aSAKJAGJGS5PvVyTSb+ 4wdOpBXb130f/A
- O3SYS7kkMcjvKrKir83XB/SnXOnW0MwktXJLuWiYE4yOgPrnnFQJYPaRj7Mr3E xJbg52heo/E
- VoWotpWLBzGFb9zG5ySjjgn8e9eHKXL70XodSw7ilOL0fl+auNjtLxftF1Mzpifyi jc7c9R+P
- amy2cKSBFD2uI28wyN905xt/KtOewEOlpHHM8p2qJFLkkvkYNVkMWnT6isgZ4HuDjzDu JLL1y
- e2axhWctUz0cPiZS1Tu/JW/AgtcW2/96zRsVAJ+7kHnimSTvJq4ZUZY4YjG2ejMT6etPWKO 7g
- tFwZRCFiOw4yCcn8eOtWPswgaRgJFtpJCyhjksOm4H0zVOUVK73/r9CcRXvJ8+rfyGi982J2EU
- qsZcgscjjqPqcU6W2jmeQNC7JM5lRo8DZgfcPvWlbWyAKEiaSZtzKvqBwf8AGsgwy2kUKO7TAq
- 37 xTgEg8YHvWMZRcvd0/r/AIB5PtXKWyVvPX8xEmuI4osFI0kw48xc9PT0qnDPOV3Xmy6dgSx
- QYC/N 0Of4j61atf7QLgTRpPEJFV0VPm5zgD0pYhHDPIhUhmOTnu/PT29q3ulfRHZTcY3en9fi
- XJZ7p2jl toMSOrtsKA7SDgFvXvWB5sxkt4TIslzKn7wpwMDPIHarcz3kH2RIoncmMLuB++M8s
- PakNrN5zOWR cuSzY++o6lfQZwKqkowXQ1w0uTeS8rNX+fclhgmeN47iaGNdwEYZOSAPvfTpUV
- tGkhfDRS7pFEgA +UkfeYD0rRguopCyi3kJchuSDtGMMKqSRxLbWazRSoiJhirbcgHDZ98Y5qV
- N3aehcHUTcWt/QuGG 3tpnuhIhQOCBnqB3z+NRyR7buN5HRYyhDOo6Eds+9WltpJtQMVo0f2YA
- iJXXcdnfPrgipXsJFsmc zxOElRRJt+ViTnOPTtWHtEnqw9ooz5ebXz/4bT8ShIphW3lkjcRxw
- PG0Stg7mP8ATNZ627QrNErq JIpFgjD87lP3j+tauLhLy6NxIpE7eeCV4XZ979cUtncyXNi8iG
- F2adJXOwcH0/CtVOUVf+v63G+e m3ZJ/l+RWNnZ2zRpIyPBGHCjHTHUn1rOWST7JEu9ApXcDjn
- g5K/XpzW20UEVtc3UqSSsbgKGDfKF /u49e1VEht57ny1tJ4N5LqjPzHgcqfcmqhUurvUinOct
- WtPkVLS1uJrSRVYCZZifmGSo67frirRX zdNhBtZY7cqPm4zyeDn9KmtYEigE0UrK77N0ZJJjY
- kjafcip57rar2m9GiPIXHOV6HPpUzqNz0CL lOquSS06tbFeKI/ZrdIYQgjiZAZQGO3PP45rPu
- bV7qS33W8vkAEPIuBhyOp9geMVcZnmado4ZCBK jKqtymBkg1o+bbta3UARyrSFzGG+bpkEH0H
- enzyg7nb7GVFJ3u+/b8TjlW4ntxDdZzGcFQMc9GJ+ nFSk21tKSgaVgOG3d14P+NakLpe6fKGM
- cSK6oJSPvlgefpxUU2mQi1DCTyXRWWUsfauv2yvaWnkd tOvFQ5Z7Pok7Ge/mm8WOOYC6Zd0gI
- 4zj5s/hTn0ib7FC63cd0ybo4xHn5xnvnrxT5YrdWeZZ1WRN qkkk/e4x+Wa0Y9Pia2dcywBJ/L
- ALHK5IwT+FOVbkSa0+RlicQqNSMrWXmv8AgFFNMmbR5I3lSE7w QjA8flWlZ2FxHfPJDLE8aFE
- zt/1h67h7VoBoI3eJ23xGXKt3kI4BB9M8VIXAWMrhZEDeaF6GTPHH pjtXFPEzkmu559XF1Jxd
- J7P7kVX08yPi7ljERgYQsoxlAcs341TklhlQojwW+xgRleqgc/4VqQXH 2tbszJseWRWGT90EY
- AHoMjpVC5itRbGRbaZJiMEFumeP07/WlCTvaRp7SpdQm9trWsUJo4ktg4lg Ikw5i2/MCOKha4
- thdRNbRSSzONzKTkAZxtI9cZ5q8F32IhWAu8bCIMOwY5yfyqOZLmS+uVEaQt5g fbs5TjlT/nv
- XTGS6m0KkXB3k387fgihFcHbJ5kkUayT8K4zuUcAj2qmziI23lxlpMlXkToME/wA6 vxwQtN8s
- yrLje0TLyAvoen1pzyQzwxRIoTE6hnzwdwyf/rVvzJPYVScoNXu119P1KMwMskCz7wjQ 5MgOA
- v1/L9adbPbRym483cwUoV7kHqf6VpS2yy3KpyvlMYxnkEt3/Ksi5V45YrZRG6hg6MigblHU 59
- zVQmprlOjD1VVTipW7pdvuf5lmaBdkjxpMsDSL5ah+ijrTxcBIzNbxNGYN0asxyME8D69aikik
- uru5itJSys+8nPG7GcD0zUkK3QEayshcy+b5YXpjnB+vak7curKquVve963S/TzJYpI0itJ2kU
- Oh yy/7Hv7n1q/9uFq8cZSSeSZ/3LIcZTGT+Oe9U47yC4uJDHaySBpzsUEZQY5U+tSNZXKXkct
- ycxOp AK8YU46elYTjFv39Dj5Kbi5S0t0vv5K2pm3QMmp2WJJlUw7mG45B7CtiGKDb5sRZmjm+
- QM2SykYG Pxqo8MUGoJmOWaHbuOG7rnaM+9aWmT776WG4iWF5U+0ZPG0pwB7c060m6d10OrE03
- OlzQTaS110+ etySygvgXNwNgikCYx3YfMT9Ksi4g814Tbqp3rIkhAy4UdPrRb+VPbFi8jM0uL
- k7/wDloeOPSpXK pbyieJ5I1AijKnBO4evtXDKV5O6MVyTjzaLyWn66kDyWtxfJOkTMkqMylWw
- VHYfU1BG9vBam7lid 3YBNjHIIzg/j0FAgS3WCOEthEdMHncTzx9T09KUwia1topEe1jYFlMh6
- Jj5gfcHvV+78gclKacn7 r0a6kMt8qwYCuHQiN0B+65zio4EsjqDRXc6FmQDAyN4wckVKloN0Z
- 8xE+QI7MM/MTwT6kY/WpJzg zSLFHclB+9eNfuMP4Pqa1TjblidKqQUJUqd/vsx6CwMcsoBSKO
- RU5boWrPCxxXG2RQ/lkEmPjaec GrJhsxp4W6tbizjkZZA5l4fBx0qzdRWdxqJWOUNN8xCIT8w
- I+99BUxkk+tjNckLc3M777NffqZv2 cSadJcKWKOyqznnLg4H59aWO1Np50MbJuF4CwYcj0X86
- vfYrZUlDF3Rm3fK5AJAwMU4IXs9rFY5h taRzyFZeuffFU6t1a+hrVqup7t7r+uhnTRNDqD3s8
- oUqsgCEnrjhalVt9rb5hu5HaP5NkmMDHIPv 71baOS5SQuoQSEypkDjjgH61TFvLa+XeM/WDH0
- znimp8y1eparua95pNfiVHCw6PG5t5wQw2sWzv To34iqlxK6ySFGY2m47STluRgAn1PWnvJe/
- Z7VVDBPKwu4A4z1PSneRLN5qmN7gtKAsUWAzKBw49 hXTFKOsjLkpQXNUafdq70+eifzGQBhDI
- JHt9+5hIXTJDgZX6DHanokU0dskZSVmgKTlTxvPINOlI W6khSN4bcljI7c7iR1FY8cclsDKZk
- kYTCNdvZSOv1Aqox5tb2Zlypu0ZNPpZJ/kXDa7LuOKArLsT c0bLncc8MKjR/scbmCSF2LlW+U
- ZjB55z1qjKVM8rQtKNhARg3UDqac9xIzPnZsDEABeSP7x45xXQ qcnvqb+wqOd07p73Wvz0L8s
- WLRPJuT+7GNoY5ORlj9BVO3jurbTJJon3rkB2HVQTx+BpVtRFEJWk aTYwJ2HA4PT8afcuJGdo
- pAUmbPljgqegBpK/wrVCoyV7Lb009P8AhyENc3DLATvVWIVVAGcntx0q nKEjuSLkhz5mFI757
- j0q0izrceW37twu0joVz2PvVdEmuZI12KZNw25UFiSeK3jZPyNK0eWL5bKP 3W82ORi1tFJbEy
- SqjIwz0Gev5ZpskczS/u0cqJdse3+EY4P41f8ALMF3PCkEsUjPwD6E88e1RXNt JbLA0Eh2SSk
- ZIztUDnNTGor+pwqs4S5Oa76aXb+7oQbJZWmA3BiN4B5IA6D602GB54gAoXEvDEcK jfeB9we9
- SAwi6liEu/L/ACEDHy49x+NSXEix2lulnJ54lVlTbwSFOS386bk9kTjsRFqOr5vnp/Xm jKIxO
- Yyrud3AHU4p6t5yK7MyBVJfA689R7dqt2iwQXQkQTTMqsDznJYZ/wAaRzaw6cEjl8yVwAM9 Nv
- X065rR1NbWJWJ5pck20n1X6joDHDcK8ToxbLeUB8xA/p7U2Uo0MZWCQg5yQ3B79Paq6wkwqJWE
- LKArKwySSeufTFNXayNJFHLJHHMFByNrBep/GlZXuRKvClUU5J39N/yX4Mmfa1uqCEMyJy2OM7
- uv 5VWRJwkpkmjBEu3KJ/CRwat3F+0stwiW+3c+SVwMen4UrXDvE6LAC6j5iQDyB7inHnS2KhG
- rUd4p xT7P/gFaK7gjt4YtwEhO5POG4DngYx9agke4VVljhh8k5LmOIBeTg/lSn/WCRooZBGhQ
- nYMDcMj8 fQ0ExbEgYvEsURVhnv1A+uavlSeiPMqYd05W5eu/UjWYRXcUs4jni37cIMH5eAOnG
- anjluIdQBji VnVsyIY8/Mc4p8c0ZiaGUxqZ5lmZdv8Aq9vY/h6VEzCG5MqRzRu8oaIs2QAOoP
- qaN7po51rzqS1f f+l+B2llMxska5nRWZlxH0fhjkZx6VfkurSG8imgmjCKrjDDIznAH6mqVpm
- 2vtsiDgsmGHVtpO4e wGKlitpZtKhWNobjYUMhVerDkD8a8OoouV3t+B3ynT9o+bVfcvysi9+8
- mhlEaygs6uATypXt+Hes 2NZLieYNKDJIWYMQcL/skevFMf7VBPNcTHaIpPKVRxuD85rW2Tr5j
- w+XuRykI29j97Pqan4Fo1r/ AF/kehFzi/dktdv8imlm/wDZ00bM8W6aJmA788kelaQtZElZtz
- QmNXKeaxYHPXA/L86rSMRaxTWu RLt2lXO7cv3dw/DJrXtYRFfsTcLMY4WhhB5DL3P19/asKtV
- 2vcynWUkrS+XmVLe2uYzbKrtJhFV2 U42E87fqaTasGp+WY3gzEziSZtyLjtj15oW4aWztkMcu
- 0xlmCNhnx91gao287SSYkV0UDZK0h3Zb B/LtUqMndv8Ar+vQ8xRk5ObXy6/16otG6uTZAPsWR
- gHyF7rwahW0lnlwd6MCUyfzP+NTPbXLWP2d mWRSo3FRyR3x+HNSxypAojSZQJv30LvyGC8H86
- fNZe7uPmUIpwfvGch8m7JEU07qAD83BBUkEe1R /aHazhmmikP7t2jIONy9GI9qutcx6jBdNar
- 5cjSxu3sp4K/UU0soysZSaIkiIDn5QcHFaJ91qdSo QlNSqL3u1/1EhW2/szMcheQsNuDyF9a0
- yktxAqPD8uMFvXJ5P8qW1Jd3tkSLaWywwNxPqPRQOoqZ poUtItsy7fKcKxPUMeP8RXLObcjL2
- jUlFLW/rYhit0/tFCrFjHHJFhSRjdzk/kaGtvtVsRFMPKEi gqDyw7MPbNUo2voTsFtNcyhfma
- PgH+9+lXtPaOSWWO1Y2t0doiMx3L5XOePz5pzUormvsdk4VEnP m27W09ev4GZeRyNqgUyGXJw
- Qh4BI5/AjtStBO4jWBH+zCM/OnHLdKu3wzZxxuQiOpcy+oyMVVj06 5uDJLHOYDgZkfO1Mfw49
- e9axn7qbdjSlV09pOf36r8BdLtg0iRzOwY7S6s3TGc/jU5tyuqxXUayS wupZWU9z3+nAqZ2WI
- Nl1Z2cFdowVXHIPvjmq1tatbqDbSM8GCIAWJ4/r3qHNtuV9zKVS6lJytfQb FHkxvMrgSFXBHA
- JGefz4olt/tN1biWSNopEZpIkGHU9Ov4CrTwxfYZCbpFMkqzhsnCBSPl/GnSSw RXjebbytE0h
- wUIGTwQfoCeRSU3e6ClGVlNKz6dPzH3HlWlkA43NKnmNsGDkMFz9MVmvbW7I8tpIW aN9i/MT5
- g3Y3D2HSrSpbSXZkkSWQFGM534GfYdh04pGjUERrYXCFXKffH3CMsfwODTg+U6NIpaO/ olf/A
- DKEr20MVxFKu1TKuwLxgdh9ahkt5vMuoo8gKdspfnL7f6Zq4+mKkhKsbna2WP8AexySPr2r Su
- CkVmpjgknadzMVUjcAMdfw5rR1krcutx1cV7N/u1dv8PvOQitVDQxRwzTDaFnYNwzE4BH0rq4o
- 7qOzkjitpGJDEM2Du2HrWbCmL0T2YMX8IWT5twznd9B1rSjjvLvUjsLEhyFK8BxjqPaniKjlu9
- F3 FjpzqNLmvFau9/8Ahh0Ane5mknWOKBnVk3LypwT/ADqK8RhZWiSxMshJAYcYI9ffmpxAIrc
- tdSEg Iqtg8ZOQP6VflMk/lwSwPAqRu0hfHLgAcelcbnaSa/rQ82rGTnGS2+77u5gw290JIti4
- J/iI9ODj 8elRYmiMYlhlMYQqxb+HBxgn1NXltilmwS6BAwXOT8m05/8Ar0gu0lhuXlvLaYm5G
- 7YuByOP0rbn bba1GnUTbi7p76NW+ZFj7dI6wzRxgEeYoHIfOFH5CrjRTg3SECSZpt6uAMHPH5
- CorkQwz3TpGSxl VZthwGOARj0xUUEp+0XT28zFzJtQuchRg5H1zUvVXW3/AAxpXhBpOCv69zn
- r6KSPU5PL2xXIJXkc upXkj2qs8e2VjKGESPsUA43YH/6q17oXZEMsUL+aqiMhhuOSOP061SmU
- RWSApJJdRBUdc9zyDivT p1HZI9GnXqStZJ306XXz6IpPs88AecJyN8ke/lWFDW8lvvljI3tMr
- R7+T/u/rUTNJNtiCfMsLJLJ jktnI9/arEMkzyyJ5yRZUuodc7eOe3auhqSRs6U5Sdvne70+Qk
- 0kkL3CMPIM0sZ29GVe/Iq5LNGj 71uYpUVHWJFB3HJwDn8abZQGc4klVkEPBIyX5xkH6VNLLFH
- ZxCGITREEblAymD0J9qwk05JExmva KD/Db/MzbhI83CKrAxEDMZxlsYJrRFx58SPDL5CiUcTf
- NtPQA/WlaCGJZLYyjYzeZI7dWA6kH0NC GxaXzSJCgIRAp+6G4wfVs96JTUlsVXxMeXl5Wvy/E
- 2r20NxE0DuCylgTGMZxg1BbzW2VkMbvKq7d in5sMfvZ9AKhaZZI7iNJDJNFdxqI14YhRgjP+e
- lSwXJ3T+TbMsjuphDgHMecGuFRko2f+R50lKKa k9Pu/wCGH3gSW0IidQqEI23jzGJ4cewqmlv
- DJqMZkM4iVGH3zhCPX3PanG3eC/u13eXEsgEYY5xt HQ+5zWsjzCIAQCR41KthRwDzg+pI6Gm5
- 8itFmksQ6KUISvft/mytJPFJppUPGRuyQv3lBAzz9RxT 4b3zIzFAMRuR5bv8wxnDD9M1Uku5D
- AqxeRBHJC8gDplowP4T6n3qlNNG9jbnzEgjlXfuHG09hx68 0KjdWaLVOpGEbrr6/pqad9DcXU
- yW8GxsRM3mAYEhyMEVnb9Ta5ngRYy5U5AXGTjrUrXlyLx5HzEs cwjLEYAJ6UnmK19CFuVEkQX
- J67ufmP4VpBSirNI0hKdOD0TtqvX+uhVWGCSC3+0Q3abmQqHl4UDI 2/UmtZdRsbK/INvI7YOV
- UjKY42k+vNUbrL3f2hWE8MTeW5j6B2Py/lSLEftl24mha5QnfxkMRySB VNRmve2+ZdKFOpFqT
- vfZXdr/AKEkTxXV/NECYRDIApdsgqByappcmaQKsokTaG+TjqeQfUnpSCeS SWWeaL947oSUwo
- +bgjFUv7MuIZ99vIiIFZH3clGwflPvWsacFe7sXKGHjNqTs7adfuLSX88mqbxG YGLbiWORGAc
- YIovpHMzwbmLRLhXB4fHPA96itwohjC7pCoViOrMxHHPpntVq4V5I90jxwztb75lY fxeo9ABV
- +6prQ6aNSLrptWT07/8ABKzvI9raFkdZHVmUnoVPGfpUTzPbSTNbbnmLNGxH/LJemD9a Y8jwX
- NpK8q3MKpx5foB7+uaq3DSCFSm6Aw/IMjls8kn1+prWELtdjmjSndqOsW35X8thY1cXqecs vk
- yL8zk9fRh7VXcSRXJZ4+REwYkcEnoRUiTXb3MKwSRHCO7Lt7d1plyxjsEL5BGIwG/iOM4+tbpP
- msy5VZqraVlfTf8AIqGCSVbeKFHlmwQ6ge/FWo5HAlt5Io1Eis6uVwVHp+YpYGmbe0OItkgXOO
- Tn nNNFvDILePbI52Oxw3KlTnn61cpdH/XUyq15QldfLun+ViwJbn+ylQIJMDG8LwT3HvVSxjm
- uZopi 0YhjYCR8dPr71JbzTw2xuBbyO88jAgdFz0OKnt7gjTJlVQhZzn5eGx1NQ7pNJGdKDqLk
- TV5X8vzu RXweS5jKlIlDHeSMkjsayZJZGnQqjnOckfwntWlPHELCAo7lpOChYkjHf8qjy8cu6
- Hy4x1CuueM9 +OtbUnaJ00YzVJ8t9Hb7vkLEIyWSdZ43ZS3mGTPOOTUbK8mn28yszRBQshxkKe
- w9s0wvJHMjocbQ VAbkc05i0NzJGfly43IegK9M0Wd9BVqMo1PcWi1syFTJvWdiFKMVbK9Djp+
- NV4IxIAzYj8s4BJ6e 3HrV24jaWzhnWGRRhlkOcjORj8ag3MkBiZAJiWMuR159O2MVpGV1ocUJ
- e0nzWu+t7FhDD5kZIbck Rf5TjkZP49qekME1qtw0iwsVdSrDp6/zqKAv5EskEWGEyx4b5icg8
- fWo/LdIFikBRhGwIYn5uefy rNq70ZVaUqtoUrLvtf5+Qy2e1iy5jlkhUNH97JJz6/jSS2bRws
- 8BdEjk2ybz9854x+FCBUsQ0S8g 4k+XIGen4moAsko3jayxnbNhccnpWttb3OaVKCirv5f09Pu
- Hs0RikCh423ERqTy2DwatSQ3FxcW4 hjwrgKTnjpk5rNjiENpI87Kk8c4AXHOTz/Srq+UksCW5
- lmnCNvCE8EDNEtNjF1alkue1+r6evl5l MxsbyzXcsm7JcIMYHfPvgVanmtnnDph1bIUA4KjHG
- Tjk1FH5jzwLHJGzuhwqjnGOn1okiS3ZNp83 kF4/4l+Xk/mabtzHHNxjUum5SXTa/wDXctQShb
- HyktgWcqS5ALMp4bB9OBUoSK1ncEnEPzQyPyrg df51m2sP2G2SdnMi5C/7xJ6j2FXEdJtRBu9
- +1W/ebc4z34/Lis5x1dtjjjzTlJ04XW/d36qx0mJI YoGaeMSIrZkbnDZ5/TFNit5BNnzcKcbl
- jcghgcqD+HP0qOyjMEK26AZWNmmZ/mG/cMD8q15khfV7 ieQSTAsQqwttyAACfwrzZz5W0fQU8
- Q6dGUZW18l/X4jF2m8kmAdojkvuORkDIpDL9ujhMEc0oWIE Kr4MmeMj6HrTpJ4ltQsDpHsmSJ
- S/IJPr60sVisNxFFv86VS77YTg4B6j256e1Y3ja736GUa9JpTc dfnp93+ZTtIEl01oZZGt5I5
- VJZ2PzAnqPY9MV1SvNb37TxlPJjJjkyucO/QfhXIrczi5UPNBHHFG FLMmc+g+prZa7uotQKKU
- MLSYPy/eJ5P49qjE05SZpjaEX7tlZ9/00NGS2mLvsUiQcEjgAL149xUU peKWGCG7tFMgdolaP
- 5iB3J71I01vkZS5QvhnPmfdPv8A1qbT5Z45JIJLUXA3j5gozjknB7A+lcd5 JXfQ4Zzkknbbul
- /wbk1s9zBbQyzQO6xtGkjADGOf8ap6hdR3MDwQLEUjU7NqgEBSDTbm2vXKokhg GFJDfxc4/wA
- KiL2kF/JIx+0SwnYY4uCd3b60RhHm5t35Bh8Iub2srN72X+b2EVoy93JeWlwqSTll WIhCwwMk
- Y7Cqypbx2gjimFsInC4lOTwcn861LkC6WdJswtET8/Reg4/HinpKwtI2je0VppRK5eIH Cgcj8
- 6r2mn9W/UiUpRkua+r26fqZ1pZzzzCeItLNIoIKHAXJwRWvHCY3kiNxbNF5mCSnfsR7e1Zo eW
- aUEK1uxfEQU4yv8XTvnvV1pIBb5lvIWtw/mMVGCe2c+lKq5SZ1TxMpSUNL+Sv/AF+A27zD9pkc
- Sk7gpCNjJPYe5HIqGNrGIRbFltTs3J5j5IHVQT+dTXd/E5ZVhkdGmCtIDwW45/HoPeojfSS6i0
- bw oI43KOpXlc9j9AKIKXJqvxOxVJey5eVu2rs/01Qtx5H2GCSIPdAx5ljVudwOQR6AelWbG7Y
- RTBri GMySrIXZflyB0x7iq12zI0k/lEIW3bBgFhjGR6AUs8ccKRoJog23OTzuyRzSsnFJ9TJw
- j7O8ou3f 9LDbi1nlGzzFMoZWdFGCgU5Ofwq28Vo8M4M+N7CcMHICr0P4YqTzJ1WScqLhwHRTG
- MZ3YFZNpbTR 6qEeVUQBFk3gnaQOh9jzSi+aOrtYmlUc6LlN25dv6szYntYI3gWNHnt1gcsqNy
- W/h/DHNUYmQ2lt JHDMp8rJ3tuDHPJH1FajTwRASuQ0ZQ/KOoPTH5VHBb2qTrBBLulSNiIy2dg
- A4B9+9ZRm1HW5WGT9 nZxbXfW3z7fcUbqZSGGxiVyqRqcErjPPqalWSS5szugnSOQI4Jbrg5b8
- DV+OG2hsoGkIuBIAQVOC +eMj2qNrMCKWBVm+R1ULu5UYyc/zp+0haxvGtSlBJ7973KzRl9ZaE
- EtGwfeFODG2MgH8KznkWKS3 mnt7pSVww38bm7flVxLEFFnbz5N2HiZXxuHOfrntRLcQtZwyRT
- RQtNwiT/MUJb5Qffg1rFq6S1Gn T5+Vaxfrv8v8hph+x3TKkMvnuxdSzZVQq5xj3q3a6jK9lDc
- +TteWMtIqqBh2GOPQY7VWYmdh5kou 5gvzeUcc5pFWCNJ3iLRSk4G85X2IH51MoqStLcirTp1H
- yPfv/WpNFJILF0wIgkqoWlG7cU5/TvVv CXdzdebeI7ySsSyEgEEdvTpiqsBkSNFZfPUHcSPXt
- mnRXCrNI0mn3FiPOBeSQggFeQPy/nWbi7tr f5f8OeevaRcrLXuv+DqUTDGdoil2wkAFCST055
- p7fZjYtE6CJ1kCJ8uCwbGT+HrV3c91fyXG2ImU NMiIuMheCR7UyVtLk0+RlcpsdFikZ8iQP24
- 75q+dtq9yo1Jykk38+3yM+6nl+1xW8LpIgjbLAenQ n3ogeSW1hiht2nkj4LR4G75t276VA8qQ
- ube3ZEniOHdvmBwDnikt7SRrqO4dnjcxERhGICrg5B9T 71vypR1DEQi6bctLbX6v5WMe6kv7b
- UWulWWK1Mv71pOQx6jHpUMaNc3MckrEbrZnXDYIKk4B9TUk 8M/2K0CzLPHcASbSCcEHA6+9Ub
- m3kju4wXYXCMXlT+8wIyB6DHavSp2asnqdtGrCcLxfvbdfyZLI bIWoYmRZnVMpv+7jgj8+agc
- R+fcxKkkhD7Bg8qR/jS+UJr2Qh1hhdycuc/KD1q0dPu7NIZNpkGHy VH38dG/WtOaMdL6s9GnU
- jBqCqczl3enpctIxSO0uACoERzg8HdxkewNVY5723sMFAVhbycFOpJya tjbPbZ3iKRYyqs33S
- oAyMfWs1pgiXWYJA00wcAvwFxg/jWUI811b+v6uVQp80mlDm7+X4luW8vhN bS+XGrCBsZQEbT
- 1J+varcNxZLpyGJtsyKqENznLZz+FZ8TQ2jPm1m81W/d+ZJwVxxnikzeyabZGY 28ysrZZIgu3
- nIBpzpp20sv6fmXWoLminDlT7WX6M07qWEIsYKNsBLSR8ZyeCT3JFVTf3iyW0cGwk rnbt5AXk
- /pSBUgsbeVLyFZJfmfcpbkHjseOoqNrW9vLgxrEWQzDa6gDaD94VEYQS128zhdOmoOUt I/3v0
- 0X4M0lvLoC3lleKWFk4VV5yTwSe9W11SFY5JZbuG4KKVPloV/n1J7elcxIJFvAVimhkUgkO ch
- QeDx7VPMkLRK+1ZkDsIfLG3egHBPrnsfaplhoNq/4GU8JHmSavfayS/H/gpmrJqFg93HEEYxcc
- nsAemf51RubssLNjbhjP++Cj/lmd2AuMY7Z+hpLVHisprgRqqEkB5ACAeMD8aDqFwyuCkUUp2n
- DR j5SowR/WtacYQulG/q3o++htLDQi709fV7fcJefa5LqNxMirFceTJleDu5yfpWjBiGZDJAx
- fa4Zi OAOmPqTUCR2H2eKNoLy7ZNrkxy4z1IP40xHQf6Q9rdLCylipk5JHf6CsZaq1v6+85Kan
- zcq0Xpa/ 43+8049OS18kwM7jbiWLdkh/U1jLdTwyiXaI5HObgMMliTzj0xxTp5LloI5ITJbxy
- WxaZ3OQW6Ae 2f61nQzgWke2VRN5ibo35J54H+NXTpSablqdcqUoxu9blppoZLeaS33yFSqZXo
- CD/PFWEAjvwrPK SY2bhvvAkY/E9KWWGVbmfzWigRpG34XAVl5B/HOKq/ZUEkbXF4kb+WVZDnO
- 7GcVScWtyZVoVIct9 ej1+75E3leY0k8EcsbIdpg3fNGT0U+p71YkW+RkN1F5khhcbcDPUbs/h
- xWcst4IFdUJdUDTcdW6c ++OafZpK1/se+QSpkRFskMvf9KJRaV3bQVRVFC7Sdvm/vW33Er/Zz
- pXnW0DxxRNgCU7gw6j9aGKT rELn95ggt5fy4b0NRyTSS23lKCLO5w8TY+6B/CT68VVMrrM5Y4
- YOgZfU+v41UYO3mP2EfY3bSktd 29yyLdDcR27q8IWErJJnqd2f/rVTt/7PmmRJFljdpCWkd8o
- GB4bHp2qWS6nn1JLeN49rI+Pl5OOp qqyQ8Qput/kG6RznnqoH1rSMXbV/cYVI88rzbvbp089d
- /wARC9xbPMDGGiMh8zHHPYZ7U+3e6eXa 0RVW5PGOp6/Sq5t7qdGRElJR13J1Jc//AFqha/ZXJ
- jY5V/lP93HUH1rfk5lZWubzpp0nHRy9UW3l ZJiY3WZQpB2jjHTNQx2iuin7TGuwFyCTwMfSq2
- WmkaV1G8tuOOMjPI4p896jo6wwtsJCIVP+rHXk 96vkktEdPNZJ2t935Dw+5U3OoTYwXI6dqml
- Ahht3ZPNi5A2Hkntk47URCc20E0LwtKWWNY9mTjqT zVOWRXupd8wH7wmPB4Zs54/lSWsrI46u
- NVSTjTaS6/8ADdCeGa1ICybS0bsOv39vIP41LFsuJdvl MjyZbnk5J6VQ3SpMSIQBv3FSBkZ7U
- z/VuFG/zFYjBP5VfswhGpBOUrrs+hYkeJd8Rm8gFgAjdSQO vFSAI+9ndGM6E8DlW3CqBVVkia
- RopOucKTwO9StIZAI/MjjCHKMBgNj/ABzTcexyzrVU2lJvza/4 BbaVob9oYATKZc9M846Y9aq
- AfJPJJJvZCEAI6ls5qwsTlP38gWRm3JHn5yR05qRLqZmkiEcaNLvI VkGRkfz9PSoTtsZUK7pu
- 1k+7/wAylGpEsSNA3mJEwBBxu5yMjv7ULDJMziCIorANOc8f7P65q2YI 18mZdSi85YwCNhOB3
- zxyapyzvDelrcq28MuMdBnIzVpuT939TJwTm3Tjb1T3+6wWot7mGETHyiqM rk/xMSdpqCJFVI
- w6SRtn52Z+p6enAqKC6la5QxxbHXJORkNjkGopZQIozE2fm+bqehz6VsoO7MqL hGc5Nt2Wiff
- 0t+ZIXcruaN4m8xdgHGFH3qr+arTqQ29GkzuJ4C/wk+3rT0EbDDSn5Ry27gHtmqwR zDHuPlfI
- VII+9zWqSFifaTqXg/Xb/hjaEsks0UciF0CucoMKfVh7VmebF9njdJ0bCMMEcsM/zo8y eW0jj
- dGLxJsiKHGVPUn+VVYYTJuU7EZpQFVhjrnjpUwpqN7nnSlOF3K0Uv6uejyfZJJIIpmYo6MI 9p
- xj2PqxPT6Vct2NrBI13wVcqzHjLY7e2Kz3vLR0hlMRmdmyfLOPmzgY9OKuvHLcRXQMUodrrPmM
- cpgYycV4Ek7JPRHqRvzLndovpdf0vuIWLtfqY/LC9GDAHDgAj8cZpbGS5urzzvvTmUbWUYCxHO
- f0 5qNbe3ublVknOxVkZo1YhiR0OalhnU6arAqqnl5FOArEcL+lOVuWyWo685JNxuv6+9mpeWh
- eVWgj VAU5JUENjG2mrJHJMWuJI2Zn80qoxsI4I/EViNeTyXJVplCyDzMAYGewH1xUkdwlwjef
- PFGzAvKQ uNjY5U/Ws/YTUUpDnQm0lUlv1SuzpZfJuZZGRhErO3LHhRgZP4YpAZZZNyxSxpFk+
- YDw2ev5Vn2U tsyQSwndMIBEATkbWPJx6irEAuAY4mcnzM4IPBABFcrhy6du5moxpt8zbXS/T7
- v1Lkkm284aQJuG 5mbhHHRfxpGjiN0UYpkShy6jGVHX8amSz/0LyDIr+UViyf4wxzu+vvReS2i
- zsJJE2cRIVOMqTz+P vWXMm7I2nONRNpP5Fie5iivBIkR8vyZNxcZCE/dB9T3rCRXtUjkQNPtI
- jkPbI+Y9auhp7e4JjQsg uVDbxnB6DNTT3jXH2mMrHHH5nyybflzgDH1p0046LYqhTjLRbdWVG
- d3gd0tZo2mcyFyeEzj8uOfx qzbXMLRRySxKVVWjQYHzB+Fb6Usst0kSxBoCVBibCdAT83446e
- lUIZY4bySIgyWUWBAw6vj7pz6V XLzRehHs+aGnutee5oT2aiO2i2v50RLMFPDOnH5Hpj1piR/
- 6MwkkWQlgwVRhiCO57kU1r61aWVjI UdF27y2AQwyRj1J71nvcXUjpECkm6RG2IMPtAznPt3pw
- pza1O2nhpxhzS6fL9bGsZDJA2AGjlILs P+Wew/dP1pl1bImoteSyKY4o3RohwcnHP4UyP7XJq
- WWQeW7MyqgHy49fXNP+z3kzT2qrucsCHIyD x8xqV7r3sCUef36mnXW2n3Dx9o/eNIwhtkQ5J/
- iOBluvTpUsECDSRtulupTIrsqfeJ9c+maxWiug yqzMVDAGM85Rj839Oa6ATIkMqJE4hwS7LgE
- MD8vPp7VNVWSsa1qMHFKK/L/hx7SQz6bKDEYi7M7u 33S38IHoOMYq1bQyujSSSwb/ACyCiphu
- Rk80NYh4ZzAHebz1CEn5SMA4x+dWI2uFkczTW7qzZASP ByOn5/0rklNcvus5nVdOl7jt5df1t
- 95DD5pie2ZVYeYhYKPunBIwew46VG0VuodpLoxebKjZYn5g RyadKzreTbSFeSQNHkdPlxg++a
- p3dxM9kC8kMEhIVldc7d3X8qcItvtc0pX57LRPcjnMAEkSzPLb hiUWNsNgjIAP1qO1vLZyslx
- beTuQuY2xu3Abcj+dEkMu1TbFXlWEnAH+sA44/CqcM13EIyEiEZcq xdAcfL8tdKinHc0lGKpu
- z/HX/gfcXfOki2Ss0T26NtaONMOx7HPoD1p6X8TuivGiqEGxyBhic5xV ARsJomu33yxwYkiQY
- PT5j+HBpkTTC4LxXVo4hXy0zFkHd3/HtTdKLRz1IRcHbfvdr8ja+0/ar25g QCQF1wiDDYC/zp
- ILazR0ncziQpuxJJlW54JH0rNF3II332kiSmRfLZQBgfdJP0PWnOziZ4JJFkRW dJAByz4DAj0
- A9Kz9m1onZGcnLrK0Xvr/AEie7+1LYvMRzuwxQbQrA5C/T1Hesze0cskjqsTmfId1 +QfL0xRH
- crJefv5SYXAWQZ4EhBwfxNWnuEhuIES/sFWMMjRyJubdjOD75rZRcfdsFWPKuSKTa1vZ 7fcyB
- N8bxreSQTQuE2+WmGcnoc+gPX1qlc3kS3Hlos8FyIyCzt8uCeTikuJkuYdOdEf7YlvuZQeu Dx
- xULDzhNcmIq0xBZDydwHOPQD0rohBXvI3jB815Oza22/DsZFpd3yW8EsBSUq33GXJzu9PQjNNl
- 2SanMJ2dS83mIQ3Rf7v1PWtKVnjtIooQkryQliETkn+8PbGarQQOiG72NbrHlA0w3AA4wenvXc
- pL WVrXPQoUNHVStJ6aeXe3T5CQ3dtHa22YJSEXEjE/x5JA/KrjI0UJnn87fOm+Nd2Ain74x69
- KnEyr oqoIlnJk4KqPmGcZ/CoIoLiW9uYoyymLgCQ7jz1rK6d3sXhaPNBt2i+uv9WGTGAWjrBO
- qKzhmDZJ Vm7Z9B3qF7WeK7/fxuiKjIHPQnHFTBElgMinziHVJEQYyRzSvb28dvBvmkkldwSik
- AqCcgdOpqoy UdLnZTqUqV4Qk7el/wBVb1ZVUMJYZTIjJEgZo3GS3GPyzTnEcYkllRlGAihWx1
- H+FRgC1uRI1vMG 7BjkDrgH8ancSmFoDBK7yuG3Y4OBjj9a06m9Kynq7J9bojR1IiWJEMSSCEL
- IudueQD79asFb+NXj gDxwvNuHru7c1atrhkKR3scccKjcvygFmHfPrV1J7VbdJPOVYiu4gnOx
- uoU+5rnqVGn8N/xOGs3z 6U1JfejGkl1CDzDdIsuJv3pMYHzN/D/9aiVZ4B5FzEoiR8DauMkHo
- MfhVy93/ZEklkRJWbZGhXqP 4mPrgd6rTRmTThCkcrB5so7vkMBjafxqoSTs7IwjUp80JOCSbt
- 1t/n9wk96r2cYEZSI5eM9Q3/6j Tra+ubhts9ks6glm8tQp3Hrz/SpHkuEsLj7Q0Fs4dk2vHnG
- cE44OBVIQSjzZ7hwsAuCWdDjJIx2o UYOL0F7KjKN0km27av8AD/hxZJvOiUbHhTap354BHf6e
- 1SOZ3MsVuDdKhWLCjqxGc/jjpTJbqKGV TMDHIynygRxt245H1qCGFVtgrTtFPsBZuSAQDkYH8
- XatEtL2NqNWT+z6aX1/P8SaYhLQSMsyyEDY rNkMDwTj0FVZLUz3AhjngkIUvHtXBbaPpV6M/Z
- NLDAw3O9AyLIu7aAcAc+5pqWVzcC2ZbWXKxYwg A4YkE/rRGfLrcFJOF5JaPdr9P+CVUihnNxJ
- NKyszKck9C3Y+tXIoB+4M13DNFhi0ajDnBx1NOazM EIjkKQSo6LGX/i56n6Vbit3k1N5LmIqS
- cB14XeOQMe47VFSqrXTIxUlyOXNb+vT8jPjna1ljGxrd cBQ0vzAqTzn3qcajbokiwRo8oz5Tj
- HT+79TVi4hsZpLRrmRk35V/mwFc5OfYCqJBjiiaG3J8tWDY 58wEffHoBUrknq1qcMHSqtcid/
- w+8j81JmkeZWtkVCqA9z2xTNQCsVaO6hcunmEKvJAAx/WrErwT 6Zbopw4X5M/xAkAmsqVTHqg
- j80SqqvGu0fwj/wCucVvSSbvtboddKpCO6tJdOhDM0nmxu8LnzBhN q/dB45q4xS1gYO8Z8wAb
- tudu04IP50x0eDTkSJHaRic7jkocfMDTG82cMiSeZlecJnfjnI49ua33 S7FU/rFWjfmio6/P5
- sgn+3pO8UZcsjkEhCN2cD86rvE1tHKjJyjgMGj+4wPANWhc3KXhmyWcxEBi vr1P1psb3N3HHb
- yyROpBKOQBkepOOee9aJyS1tYxqUqlKVpRjyv1uvO1jOEk6kyeWcs+FG3r6ipT GjJcNvFuVO1
- FZfmIGDn8qkMM8Cxx3Mi7hJvV1U4wOuPeniWVYzI1utwZCx2bc8E8GrlLseXVxddx Sadulv8A
- MzoXdQBAX3MzNweQP4R9etKSq24Blhdh8oOPf+dX3tJtjIqx28LPuRto5x3GO1Z32Znj leWaB
- nEuGKAgA5z6VpGcWysPWgpOKSbt3bHLc7lMaKJY93oNwI7E4zTkSKe9DeaLcRkMu9uWwelL Fa
- qkErySpLI0xKiPgYPQ9O/NMaMecEMErMCACvc9qfu62NYxc6EmtL99P0ZYQmS8kbIU/MqLt/TF
- RMhEm7EixgfddefpnHWmGF0uoVWQu046AYPLdfzqyWuHtpEOGCykDj7wPBb6cUr2ehtCpV51Ra
- vb tfT5oa1wUu4JW2rNj5MJ3qz5swkWZvLWZZN2Cv3OxUiqXkNOwfZJjGFbrViK2H2+JXuEhyp
- ZzICQ p9xUTUbGePgqsZTdml836P8A4YrynMxKxkAADA/hBPf6VE63O2N2gbBVuR147/StKaSG
- SwV4ZUl7 ZVcHOcc1lF3N2+9cBWwwI61dNtoxo1Jzpqzsuy/pNEkc0sEUiKUULIAm5eSp/iz6D
- +tVpJY47h9x S4TfxtHbp3FTQqbi/tzIFmTkSRIMMwA4GfWmQBPMMUdvJkgklz9zGc5q0kmzj5
- KMpyXNZd3/AJLX 7ypgeXIY1cLuYEkVJ5RSFBt3ZUsDn17U8m1eCJ5QUkYf6scZwfXHtUCwtLI
- zGTIV87cfeHXFarUh Jyn7sb2+V/k3+Y+a2kKKYX3KuN+0HpkcVUkjeS4llfchMvmDb2rYciWG
- WW2Cshk2hUHKk84PrSyJ EYTEbaRZliIdw/3mz1xjgVMarXQmcY15OSp38lrb+vI6d7SHyo7TD
- QqVaSNyfvYPanXl1bGysBIl 0rlSxRZMYy3zZ9cAVopduW2vash3ncWwfn7Y9FA5I70RWwv3TM
- 0MrxwtyF7d68L2lrOfTzE1FWdR WUddHcjtkt9zeS26N3bAzyRnHX6VWY28jSWcbbYxs8pgfvo
- OrfhVmHzYjDHFBiKMYDEZ+g+tZslz AZLi4gUJOspiQMPuqR0/PNEE3JmeHrTvJNN9nfb1NdGg
- +0XEolgl2zbIzjhoyByPpT4rNbS4uT5k RhEnIZeR3APuaxwn2e2kmmjdmFwoVFOC0Y+8RW3DL
- bSa0pfdNESwi+bgqRkZ9TkcGs6kXFaO6LjK avOL5k/QtLNHLFE1pHGxRdgRQMrnk5+lR2y6gi
- Ncy42wMEK7e7cZqaxh8+SaKONoWldZd2e2Ocex xirssZiuo2ihuFhaPcdzZCk8BD6t3zXJKai
- 3E6sPZXi0n1d7DnEcdmCgfYsTbBnkg9CT3PWs37Je SSW8fk7EZA+9xnIHBxWxN5l1axWyBo5t
- jqxIyGwB849FGOlQyJLHa25WUPujyoH8Kk5P+NZU6jS8 y6fM6ajDdt79CF5LhbKVUMagziTLD
- O3HrTEuT9uBQKfl3jK5DA9xVRzdF3McqyqZhIgUcSKBjcPa taIuJDLKq2bI+N0q/LgdBx/nmr
- klFG8YU4wtJJt+n/Dlbzrh5SEmgV3lU7imQcDrRdyyBF226TbI 9kbIAA0fBLfnxUjG8luXeGS
- 3kVZVBjWPBTuwPvirYSaO6iuI3iuI1R1RFXkD057nPFRzJNPQy5Ve z+S1/PoZ9wy+TdGPy2Pm
- lom28AYHBHc9cVRSe5Nx9sS0O853HAxgjnj6dKddW3nwxlnMEsiK75PA Zc0kRwIo4nN5NgyMs
- fGG7Kf89q6YqKj3PWiqXs1bV9d0RxBjGqrM0EZYFVkyWAB9fep7+SWO8naO 43RrcRuETIbkdM
- +3f1qO3ZppVkmjeIhB8x6M2SRgelXrmQhbi7URyvK6gbE4TgcH3obtPVf1oaqN p2klrte1vvE
- txOtzG026XClJSO8h6Y9OO1X7OO43zJ5f2iNAE2qOR8p5PrVK2iaZWil3gSSB4W6f KvJ/H3rS
- WZIQJwzrK0W488NzjP4A1zVm22kcs6kpScUlf7whup4ESJIpZcRjZtPMvHLD6VYiurh7 ou0kK
- Z3YLJw3HUfyrPE48kq2YtihWJ6ls/Jg9gfSpAgnnneeVYTJJ5hHQRYGNmPWspQWraJVJJNy SX
- 9eo6dg8MMkrfvYkZJVXghm5/QVDDO7hI4Wh+V1L713EHsPxq/bXNpsaCORGaSMyOG5YN1UZ/Cq
- DS77dLown7VIELqvAAPXj19PSmuzRM4pq0ovy0/rQtSC9innaW5tZDHcCIrHHgjcM4rNuLq4Mi
- QR RDlWwSucAHk/X3q3vgneQhJIiZlU7myWPY/gKyLuC98yVFdFjw259v3QDkj8qujFN2f9fcc
- lOEHP ldr/AHfkZ83kyS284mk8t4H80lzwM8fjV03P2W0E7IArH5iR17ZH0FVXgeWGHLI0Usys
- MLjKDqR7 dqnuDK13PIAttDubJmXcoZugx/nrXa0nZMIwhPeV7f1p1BbxFO/7QssaZT5f+Wn+2
- PYfzpEnSVD9 pmQ4kR1C8MFxzk989Kql7h2uFhgUOR8yhRw/YD0759arGS5+zRo9sdyxKJDgA5
- BJ/SrVFM66WGi1 yvWT81dG5MqRXF00RyGlVkXHRgOB+IrLB3zubsJamaQ4Mg+6wGMH371VbVS
- u1FjL75hJKxHH1HtT bq7u5lZCglgMzksiemMNn0qqdCa0ZcI4ty5ZRS83v/kTxQzLE8oxLJlS
- rJ3H8RHtWi87NaSGOWFX UhQdvAz0P41nrMv2WNJw0blHLyA4UsCOAOwPHFSfZvNt7mUSAxyzI
- Qo4IbGMfn2pSV3eRo5VKslU qO3S7XYcun3P2ppPOjJiby2Kg8secj2xTjp5JnzcKkDIXwe+0c
- f41FcpPZ26qUuHXd+8YtwGGOtX p4FZzbHcjSTtLhj02gHFDnJWfNv+h6ClXp8slPR6aJFWyhS
- VTunV5y6yjaCFCD73Hv1okjf+0DLH e25jD4UKCCw6g+9MgvLgXkjwiCKSXlFMY6dx9Kcy3G2K
- eV4gpXcE24LHHOP51UoyUtX/AF9xpUw7 jUak7X9L/kW7ZFF+u5M+ejSOq8c9AR7d6ou0tjaQr
- 9nlVhhQ7gNjnPNS20aNPbubgAG13uRnjnit BkV7me3Eocq29QfUjpUN8stdTWdBxnd2aS6r+k
- Z0qbVmBkimnnl3bsfLhe4HpUqs0FnFJFiW4jY+ Vx1TrnHvzVoQRNbwyXPzSJExJU478n6Ypsc
- 0csEiCaIlySkm04CH735Yqea62MlSlV5U1pfXtb03 M2RElTfMHDMf9Hx3TGc/0ppeNLW1RYjb
- mVC8zy/MpOcAgdsCn+Xd/unaI3VurAKsXoBwc+lV7iDI Vmy+CJCg67F7/SuhWbs2bOz91v4dr
- flb/NE9xbNEI5rrfLAqMigNjpjHPvVOK0WVVE100crksgLH CAdc1Ok4urtsxTyxGTzUi3fe68
- /SqQMshlgwI3I3lWGScDt+FXBTtZuzMFGrUnaUrNden3bFqA87 1PnKSN+85ByCB170yUKWidW
- WcxwiAoP+WjHkMP8APakniWHTrCSK4jEgiI293JORU9nEJraBhhZZ jvZz93cCen4DH40m0lzH
- FOUYx55yur2/r/gEQQW908+Y51yy/OMkn1GegqOK3jfzhcNLFNGpDHP3 8n5WH4GtWWS3lngSB
- 02yRtKQRnYc4Gfp3qvFbPbLJvjeV9g2yBuGAyTUqr7uujNac3zc2ql9xYEU cUEsVvKkciuBKs
- vzcjnirqXDSbHS3n8wNmNlOFVemCO55rMhmRmU8FWIKKPvKP8AaPc571ektWUz SrLtnWRfMPR
- cA88Vzzir+8TUoc8rS/Hq/kZ9w8wjQ7HVo4yCZOcjP9DVy1uZri+dpLSaOUk/Ox+Q DHPHr6H3
- qyrh7gwzzQMGYuWC+/8AKq1xLN9te6kjZkMZA2fKpB4/Q0X5ly21Eo+3vSsk1/XkZKzx rcx+a
- CRIQVJbiMkEAn6d/Wr0L3L6itvbR+YsTbJ5Qvyl8cAegPTFWIms5dFUtA/nQMICM8kn+tZs tl
- Khe3t/OEzSDZ8331HJP9M1reMrpq3qclSEailzaPbXXb5oi+0+TfszW7RLtbcrYO3jCgVbZfPh
- iVkEzn93P5YwUOAP/wBdVZEtCZJCXWTzdpSRs4BGcH3ppmjmvnyJbYNzIhPIfHB47DFauKeqRN
- aE J01Kle662/r8yMmC3leIxuJ4wUbe2RJn+ID6VVSFzeRRorSxyQlgyenc81YjgMtteebNEhW
- aIq56 learyLY29w2VnkiUOqsr8fMOnTtmt4vdLc6FOdOLjF697f5/oTx/ub2ONo9qqDlnAyyn
- qQfaq32p RdAxWxlzGEAU9Ewcj6571CkFxFbo00UuyMlWOcD/ACeKvwpbSWpkKSCJ0OQDypXqM
- 02orV6nLyp+ 85N303/4O5WMM1vEbgKscRjZAJl3enHSoXnuXcweV5sMbFMImCARnGce1aEUEF
- zdopnJjERY5PCq BnJqhNBcIlvcvFKF2byduATng59OnFVCScrPc0aVWTUtZR20t92t/wAwtIF
- lZIvNcrjKtu4UkUGF fteLhTKYh+7CDbvGPmPvg1Iu1pPMLfZpwW3uT8jEjjA7Clhed3sY5XUR
- SMCxZeWK5yoP5UNvV3PL rx5FKUtu3Vej6/eRFriC3EoWN1kQMxVeAM9qYIo7maJpX8hUT98c9
- WPTHp2q1ckwtFIssXnoDCyb crzyePYGhrUPZRyJFLL5kRyUYcso4/nQpq19r9TSlWgqS520pa
- XMv7NcxiNpYmTjHJ5OSeR7VItv LA6wNNHKsrMEAXczlecg4zj2pryO/l7kWInr8vOPX6U62ga
- e0ZmUiQSkDH3l2jJP8hW8m0rtnTXi qU1epf5NX+5ldIo45l88svTcQMHnn0qz9oimjieSCSaR
- VfZGBgqBwNx71F88l1byMARMNxyOG5wM VYW0NybgF7cRQO2XRApfAxwfTPalNreTOPHKlKa12
- 6X0/C5meT5LbAGIVG6fxd8/1/Co5pxHcK5M W9n43LkOcD+ea0o5LZDI00ckiEDABwckc8+nbF
- VSscrAgKqEqEU8sB659q1U9dUViW1C1rfiQxPI kgSC1kkuTI6h1bhOOmMdcVVdQiWYMxilkyZ
- Cc4Htx61Zni8iVUeJ0Bz8z9x6023k813liSPdG4ZR ImduOo5H8qtbXRwywzmrKV29kv1fYI7V
- IUKxxzuWJwCclW7Dp25oeR0kVUaFlEyIzbcjHr06Vaju HkeNZ0JN0jyKy8BcAjn8qht7tksYE
- PkyKExuVB8vPfI5PvSvJ7oVKc6kHTi7fp+f4Iu3NusF28iQ uxjuTsWI7Qigc7vWiEIL1wkQJz
- x5w3eYOuRntViFx9kObK7kvuszE/LgHOMfStG0vtOvpnikKwRS MW9CvbAP4VxzqSUdr2PPrS5
- IStd269fuTJ20/wA+KeSMTxgToIwz5x/ez6nvVjyEiuS1is0oQneF f7x7Eegpbszx6a8TSLl5
- MqyDG0jBP6YqvatcHUg7zxso+VgoxlWPP41x3k43b0Pbmp1KKm5K3bo/ n1LF2LuWFGYMgVWEs
- YGDvP3RWAkVxJdslwoiRgN4xg7sYX9a2ob6KHU5o2indMjcS2clR8h/Kqtz qNzJayGPyTHs25
- MfJJ6mro88fdSKoOvCXso2Sev3/eTyxKmmOyrLKN6RFlbo38Q/E1pWV1KqxrFH CrR7UcMuSpJ
- 4NVpJAmlnzEJjWVUYDgqxAxn1NWW8kW8CHcZEUiQo2N+T/hWE3zRs11JiqkqSjP3r N7frc1mu
- DatI0sLFA21mQ7RyvBHtzSSWxa3ha2nfMcJCB2LYIIwD6k9qzxJpiy3UX2iQAMBGsshO 9O/41
- pRpZyBZ7aR5FmYlsPwmDjafc9q45Lks7P7i4KOHs1e/mrp+VtSC2trh7xGuRJbupwct2I+b 9c
- Va81WmjUQTTytEVKo2MkenpxT2uf3UipaXEqyzeai7ucLjP4U2W7hMSyR7djjfIy9ju4APbIrN
- uUndo6qdec58yX9fmStBsRirJbRmRfKEi5/dnjj8arCZ01Z4J5AYY45Izle55GfpV+WQTrLPIP
- LP 2gPEn9xc8qfXPUUySdFnmuPKA3K23f3OcbvoOlRGTe6IpVXKUkkn29fxZBbRrDaefI+CWCy
- N2zjl vwqq0l9bm0W3YyKvAkA4ZTyf06VoKIHtImZxLtUCQKcAMAePxNRyT3H2EC3lhEhG/wCZ
- M+WccqRV Rk29vvFTlUk0uX79v8xJC7adIyTRNG1xvUleSB3B9B/SqbanapKiBo3kZQymIbd3P
- P5mponme0Y3 AUxxNsUouAAwxt+vepDbW9vbwwuI47oKCrOuf3ajDfzqlyrSWvoOnXcFyyXXpt
- 8+pBI0bA3KrJvZ wxGeDngkewp8MtxgRPbuYSjMCV9DhR9apmWFbuI/62NcIqqcbtx6/lVp7+P
- dMlmrsvnjgtnJHce3 bFXKLta1zonUk0oxV/PoMLXSywuY2TeuenAwcfgKngjuGinN9BIio+2N
- AfuLnlT7niq13dXjXrtI 0UNurHcCnVgM4HpVjcGW3lmvI4oJ4iy7s/N83B/MUmmorbXsNwcIr
- mas+qv+HmTBJTEVQAhpFYBu u3JLH8KssYPmMUm6AYIyclgenNYJUhGmaZ3y2x0UkY+npVmG6g
- VwFxIuCSA3TBwv50pU29imnKK5 btfcarG1P2mQwyF5HDbUOChx0pjWcq2R+1SqpAzlRjcR1I9
- uaha5LzRAhQ7IUkwPvNnJx6cVfuby ONViWGV4JJyXLNnacDCfU1zvnTSRy1qzjaMdb767GRbx
- Q/apgJt7u+8c/eGPvD09KazfbZlTeYl8 plCk5LHr+dXfsokmmkVTbyqdqo3XCnP9arXVyrzyI
- 1nIyySeYRFhWBPHB+tbqXNLQ7It1GvZ6+b6 f16lcwgWmWtLnfHLkAPjI9BSPpzyXdribZCS7O
- kmSQR0zUUwmgWKSRZYyrKz7zwSM5P0Gal23J0u RzFOGFwoikJ4HcA+ua1vJK6ZzVoWio3Su9/
- 6uir58pZWR4y+zMhC9Sc4I/AGo4p5g0QHlvHMu9iV BMYA6H3q41tbTN5k0m2RH5CkjJzx+B5G
- KpfYIbczCOK4TZK6sXkznI6fritE6bViJqjFcqWvf+rD obeGOS28wxGQRHYCox17+vNVGsrae
- wEkry28u05+bjjq2PSlkKNPaW7tgFi0ZU4MaJ2Y9yTUn2uy 3RII5C85M0gZujA/dH4dRWq507
- q9/wDhzOnKaqLlb/r1GRRQK0kC3UTIVwHbkMSOMfU1ckV10YQS SxyCPB2qMMSMFufaqjTBY4p
- ljRAsLZ44LMeo9hxWjA159iX5I2lDqwJXIfAwWHtipqN6Nnqc81yu VrX0vpr62K9xcw3ssCsc
- Kys2A3RCe/qRjrVQEW+o/LJJPIjkZJJHsamXEksUVttMqxuoO3ONxzTE ZooTaPEJLoRlVOBk9
- 8/lWkUkrL7v1PSwtFtS5tF5vRee2w2V7YeW8cEgmBKyuD8qZ9vpSxNbtqEY 3v5aj52ZuN3t6C
- nW4lcxSgIZtwwNowQOScfSr9y0BaCVoC8fzNGUwMKByp9T70pSSfLv8x1HTpz9 lBuV+qav+N/
- zBNQiexfEItnk+b5wMcdMe3tV0XRigt3keCKWORY3kZeGBGc/hWdMI3t13jzYyF8k LxkD+H6m
- nXMSy6WgKEzISzx5+ZeR/KsHTg7K24pUKdVQppWTe99vX+rDrpJplGyaOUFvnSNcEZ42 fUjms
- hkMaqsSM4zt3A8Dnp+tW5wy+Z54YwiTflDgseOR7UyNZRfNLGVcIpZhjAYnoR7V00/diejF ul
- Tave3b/P8A4BYlldknR1aErMFUrwFQevv71nRXNs+2KUmMIpVZCffgH61HFPLcRFpSoKnYWHR8
- HP8A9anRR2huna5lAD5dgvBVjwBVqCimn+BwVOV+7q+unQjheOS9cM4ijLEvjjHsKgkEKNEY98
- i4 JQ7sHHTrVtbp44CIYoisbKFdkHfg59SaaGLCeG3VGjLHy3ZeNo+91HarTad7aHPGo/ae+rR
- Xn/wN y7PPZtYRKE2RFsBm5wx7f1pPsot0jlKSi3gBjdC2CHPfNZawBLRJBlkYI5IPC84596uX
- OotMfJiR zGjYVs9s/eY96z9m1ZRenUiOFlFpQlo3rpsvJ9yylkY7aKR3E2+MqNgxuGcZHtU3n
- pD5FqkckZfc FeVtwVD6/wAqoPOHW6PmsrGQIJM/KFPJIHbOK04UErTSxIQ8bmJd43bdw4z9Ky
- mnvIxqQl9uV332 X9fIdN8gaVFSMwusakjgA8Ekd8VNZ2TpMZDexM8YKcqSoAPRh3JzTYWsprF
- rf5p5mYeZsfHzAe9V x5hurmNw6AuquF4wxNZauLV7HZRalSdp2a30Wq+ZbmZWJaSF4XWRYpG7
- euP8+tVZ3sriGeTz2kTz QibDjaD2PqeKs3Jiud0ckv2cRNtLseGYnr+H9agnGLSTyZLeXzyp2
- Rrj5s4/PFFPS3QmnJRa55Ne m33hKtpHZXDW0qguWkTJJ3Dpmq8Nve/YUWM75HK7GxnpycfhVp
- ZJhmCX7OwhfayGPBA6Af1rOLzL CD5oL+WV3A4XceBj6irinZo5KkajpuCVne+qvdf16i3VosS
- tcorRF2O3zGyCuRzU4uIobwOLOS6W eRpMpjlV44qCG1dpopi5ePyismTxyMZHpUgh0+wsVi8q
- 6uFDEFll5QYyT9DVSatyvV/15nnYh6Kn K7b9V+v6lDZDPKfJPkyGMsfMORkN1+mKrTLCDapeI
- 8gt0JOzjfk8H3xUksTS+SLWTyT28w8kHrz6 CqUsc4d2kJkWBvJLjo2eRXXBJvf/ADOmDjWSg3
- a33r5/8OaD2zGOSSecLbhhtbJwc/1PWnGOFtPV IGEMbFgN7Z3E44/HFVAssis94ssUEkg3OCB
- 8w46VNeQEKypGxRgfNXuHUcfSptqk3/kQqicopVE2 nppp/wAOQxW6+ckUj7ZGQExr97jqPwFI
- sFzOVti8nl28ZAIb7wOfm+g4pZEjZU8y4ETOpd5Sp+Zi PlIxyAa0obbyoGhKyXC5O90ONvy52
- /U1U6lle4sRibtSk9Vt0t5roZptI0trEvLmJod7PnIJU9Px 6VDHJpqPIxt7pdzEqjScrkcVPH
- qTq9mPISTJUKm3O0E9D6k1LMbf+2Z5r0qY4nMaxxjBORyfw4p3 ne0r/JnC5TlL95e/ZP8AQyU
- KTwJFJgzhVjjPqeevvRBbpcrAju8PykrubhT3yPoM1cWOedA6w/ec EsP4V6Z+uf51VYFIgY1O
- RJuifPCqOx9Tmt+a90jSpJykowWvS61v+IxoHLPtljkJnTy2A6oQaka0 uo9NmkmkSWdZlVtg4
- 2sOB9asRpLLaSTDEfmOWjGMZUEcj2qpLBsvJIGuGiXcGdmBIJHOcUKbbtfY pTqS9+Mr8u+5ei
- aOK1jXymd1DpGncDOR/jVaRrdUidQ9wTGfM8tyASep6fh9a1khOx7hpoYopZPM Vip6D0rJ4tg
- xkuIZFOGARcZGc+lY02m20edRjOabir791fy/pox3tDFYRMjOA5PDnJHqfpTgYvLl NsWlIlGG
- A6Keg6dfWrtoxt4rm3WFw8rEuZedozk052aAXci2f2aPIHIHGR/n867HUd7Gnve7Buz/ AA9DF
- IfGzeHYEgMRwQPT9at28ai1t/OubeBZFyDs5AyRzjqanhMFvcpFIiyMFOeenrxioGZHuS3l +V
- FvK+W3JUVbk3oVWpyu43aa1utfu1f4kZuIJ9UtApKQRK0bNz8p5NXYRb3c9k0UkNyI90bQwxlP
- MYgnIGO1NWJonUqkQYHKRPGDuUckn1NXw2kO7y5KSGUBvKGxcHqwGOlZTmraJ/1/Xc8tvm6t/e
- 9f zX3lqxMSXFuSGtnW0KM0rZEhwcN/SnW1ktzoUMUM1usYGclPmPrz7VZSOyWSTdcpAJGKIXO
- d+e6+ wFNjkBeKOWNsRv5YCHGM8lfc9K4XNt3X9feYymlUVSnuv66mtFEP7NdlImj8xPqBu659
- +n4Vm39t eSSEJGJACSEjGGGTyCafEGTQBEsjHzJVZZB0XB4H51PcKyyN5sc5lkyzhHxt2nkfU
- iueN4zuenT5 FG8tf0/JL5DYI1huhb+WSHYlZTyMDJAPfmqqRI6CWaKQ/LtkC4ADNkgVHPbm2u
- Z1ijuCA4VAWyT6 H8M1AJY7h5LRWeBWJkG5snco4z7DBreMW9Uzr9i3PmjL+vk7k8MN1E+5raa
- QFgGjByZGXnePatSz uY7uVhLEYysnylu67Tmo7QSg4huo3llkVjkZ2gj5j9KZme0vYt0LOQpV
- FUD68+uKyqPnbXUmVR1p uKav0eq/MtTMnl2xtI43X7MWQsuT14Ge/erfmtHAySMiuyiRlUY4X
- uP60sc7+cTIq7mGI/lwpB6s PQU+SS2lEiSssksUioqrw3TOPzrlb6NHdFctoy1a3t+pXnXy7d
- ZYZZDJIhZzvJA56D05q5BbI1zc yvBMTk5Ct8uR1OPYVJFLJCt280tsQs6CVdnfGRj0Ge1W1uZ
- Jb4s7xDefMZFXGeOR+P8ASsp1JJWR NfGTpwdr8vfuQMi7j9n3tFMyyYB544yPY0k1pIb6eRm8
- qMy+ZEr84UDG0/jVea5k3oxeNV3CNFC4 JUjJx9e3pVeTU3kDxxwTBWyYtzZwgIHP40owqPY5v
- bOony9tf6/4Bf8As7BlAilZF5kCtjaw5AP8 6RlRJDO0MyQMgLOW4YscAj2FZllcLI8qxJcsRO
- cAyZJHp+eav+YRFbpOSIiCzZP3eeAaJQlF2Zk5 Si/eV/K5Dexf6KEVZGdZU37WxuK8n9KgnEi
- yXZF7AirMwjdxnCsNxXNX7m4Riw8+J2dGdNq4/wA5 7VmTeW2kh3+duQFB54xyfp0NaUr2VzWj
- OUeW63f9biqYmhmWJC8wKsIgeVU8n8utXBLaN9q8xGdW uFVWi4zkZH51jLOwvDIhUF4+FHVxj
- HFXvtVstqEit5TKkmWG7+7jH861qQd9jpxNSTmko3Xr+ZLc aj5spgSzmkYksy5B2k+tMedo1i
- geEhdg8hXGflHf6ZqQPpxvXOJSwASRlbG0k5Gfesl55odTEk2W i6ZI+8RnAX05xxRTgmrJWNI
- 4mM4unGNrd3+Wp0Fiv/LScxqRGcIf4euc+561nPArmNtwaOBEibZw ck5IPue1MkdjF/xMNyKy
- AyFDtKP3B/SoN1gyXCxXW1XuVl5Y8gUQhJNv8loRh6tVNrX5amwypp8i ThXZfmBRjktzgMD+N
- ObUo7C3ijSB3ZGbZv5ySMgnPXFWDIJtUuwAGi83ace68Eeg71Nb2CyRKuEm WKMRqCMk5GS3Pp
- XJzQ3qFUVRc/36bt+KKEeqXJsre5up0YL8pUJg4J+YH3IqWI2ss00q3MSpx5eT zuB+VfqalWw
- tG+zrIS4dQyYPHTmpZZbVIJUhiVptyeVtwAV6v+PvTcoXtFHVGpS5uSMdX91uhXFw El/0oK4M
- RMiY5BPBP0Hemxq9vp3lR3KTRcSEHJJYdSD9KsyXCPfzeWqMjLI6naOoxj8O1ZxglujI OI5tu
- fK6EY6n6dqcVffQqph41FdaFYPM175gMcls08ZVlXqOauNEsl0yAPJEZW3MpPyDqFb1YnvT BJ
- bCSRUuYflJZVA7AcEVkOb6K4MqeaFypUn7uMcg+/PWt4wc3poP6pUqScnaL/P5D5LKOXUmhhkE
- Nw0e5/M52Duv1NPMv2ey88rFPAZVYqqjcMcdfQmtHNw/mPbIiMqMAzjJxjr+HNZHl3Bs9skkdw
- fl 3+WuNoPQfX/CtIy5/iZz1E6sl7X4eu3520+8ry3P2l5GlUhBnMSjBBP9KtrIqJaNb3IjwCw
- 3nOV4 yv1p52R3bCe1ChG8tJccMpB5PrzSTWMccixGZXk8psKowRgZ5rTmg7LY7F9VkuSTcbbb
- Nfht8yRd qX9zcrnyFzhwehPO0+9RNdxvBJMtu0U42tuf64qujy3Uc7rcwNvwWjCkE8ckfQVfi
- ljs4YpYl/d5 KAuN4AznB96TVt1dm7lF2Vm326MrXAnlkeaOMZXcJ0Xgp6D8qglWSVLaNZBhY2
- 3nJ5yM8fhUzwwr M0yNLLFcO2Nr8AHGAfU1TiufsrlbYbnUmMhuev3h9T0FaQu1obQxcpxUVun
- 8/Q05lgXTwWWQHyyY WzkEcc/jTIr+CyuXuEPm5UKQ/O7I6j8arm4laSziWIYjhZTG/OFzzn1x
- 1qGCJFspo5IWaNJE78vj OSD6dKSguW0v61D21qLhNd9L7/16jzPKb1ASPO8hlbPQHnIx9KbFJ
- Hc3QkkZhEYdpCnHIXgfiaqO rQ6hHNKd0bkPkHG49OPxNRRlrd5zEDGsUiqyvzlhmt+RNaDliK
- krwpu2nf8AUfLHJHbwowaJEALM e7dcVYN1HHHDJbRL5w8xZFkXOAemf1qBWeRvOdWl2xjcM9e
- aqossT9dyiUZcjjHb88/pV8l9zlq0 Vo6i08tn67kqvcMkk7cmOSPbtX5cDPBHrV2N3RXkI/co
- 5jRRwSXOc0C5EcojZQgRiJkK8sazraQS 2rT3mIyS2yLOC2P/ANdTbmTujKTppPmVr7bu/kX3d
- 50SN7aUhJQFKHAPv9KYDJYXjlkATftcMOrD nH41H5qoYnimJ2ybio/iO3j8B3p0SyXhWSd+do
- BA6+5oSstdjKlC1+ePuv1/zGRvs0+feNs7SAMj fw47/rWhDewwh5JEkNw7Kw2tgHjb09ealDW
- cLw7rmDAUq4aMkliMAmqBjS6vYVKmGQJjeDxxxkis 7qd7rQ6aNSNSnJSg+VdX289vwNK0t7dc
- TwS/vYZChJOQoGQSfU81YbUbq2kh2wLIuQGbb99v/rUk hjjsWihhfIYq7g8Mxxk0kNw7xeVPt
- RmJbzCML8pwcfhXM/e1auZ0o05q8ld/p0sTeUhuGcoFjKEs pOTnr+dVmCMYQ0qJC2HZFyD7kH
- tg1PE3laxczFgI1Yj5uQuR0I96alz81rmDcEjO7HYvxj8KWp01 IuS5Vt3Wn5kk+oRQ3IItjIj
- 4dmGMt2Bz7U2OG1ighFy6hZk3Akkb8N2qEQfZvs8T289wAGXKng84 P86tF4L23isjZ3MXlkx7
- nYE5Az/SpfKkrbdWcFSrSi1ON0utmR3L+XbpNDl7eQCVwvXcpwAD2B4o cmbTkYbWYxu0qY53b
- h/L0qhPJcWI2grycmNhk5bByPbtWebkkho5gJG3BlAI2ZOOfwzW0KDaTX3k zwqlZv79QZ8osi
- RyBpCDEM9s81auppUgYxRYRZf3pdcjfVqeSzW4iiimjZEcbWB6gcgj8KzZ7mIt GQHSKeB5CXO
- QWz8v8q1j7zXumFPkqVUqkNPO4Ti7lKO21YmRn2sOqnrj8amsbwR20Fv5TSyqNif7 QOfm/A1F
- DJa29pDvZpLlvlJLZCBhzkVJO6GKJbcxstsuNyjBbn19x/KqkrrltoTVXtkqcaeib6NW /wA/v
- LEEVlsnQt9qKg+YU6A4+XHoBUCyz20dvcWkgLtBmVWGd56BvoO9NLz+VKwCW5UfL8oyytzu /D
- +tN2Ty6MS0L+bGxRCOAA3LA+tTy93oZum4uKqStF6NN/oE0rCaK4mkhOSGQImAyqOv4npTLgCe
- yile5gVZmLFtuMMM4/Oo4rO5PlxFPMETbAmMkgckj2GasLbWEsmFkwypnlsq4PO4e1W3GLVnt2
- MH JKakparsk9CqqqVhRfMk2xlHkjbAZ2OePYdKt2/2lbG5S7twUkuIxKdg/dE8fh24qVI7fa5
- QgtuU RgHG9eu8ewrOEsyWsmZBmdt2WzjeDz+lK/Pp/XcxqVvaOyaXrv8AInS8SC9uFcgxQ5hZ
- Qv3u2R6c 1Sku1ujH9oXbtXACjBPH9akltbZ7V5beR2LSMwQnJYAjLfQc5q/PPbwaXNPC1vPKz
- EgBfugkYH5Z NXeKaaWr0CdSnzx5U3J6dV+X5mUlxPLLJC6OsciHykPO09BWfJt+1qJIZNsJCH
- J6EdjWje3UjmRB GkAJOH24Z+nzA+gH86zfKcxOqiRzJJ9oXJyQRwQfWuqnte1jatKVrRjZev6
- 6E1zPFJLKodnmLk7l PHQZGPoMVG8TSwW1wkihPLYgE54B4J+lQuGZFkmVVMkZIAXBJ6A0WUcs
- V9bTsDFD5bsA4yGHTp71 ajaOj2OWpdQXJq107+X9IuxJNcaTl2ijkO5i5TllB4YH0xWbM8TR2
- qqNrhHyeMsO2ferZmJt43Id Sp/dgHA2n7yn1qi0QjhEKrnOGB7r360U1rqcmGoVXa8LO/f/AC
- /Uv2awCVVd3jgCtvZm7kcfhnHF XEjtn+z+VtOUK3Hy8I56D8ax7ZjHOrPIi7RjDISMHnmnzTM
- 1wHjDRMwO9ccEf4980TpuUtGddaDn UbgmrLorK/mdPcxRRwx/aoXJiUoCDjA43fiOOadKtt5M
- rBJd7tkYk7ADmksr6O5tEieeKQRRFSGG S5PJbntxVmLUIrS0vH/dyTb0c5UEcDoPrmvMfOna2
- v8AwTx41qqlyRT5+urtb7i7ZRBoTBHJH5DH JJ5JIyVI9OaqzXM8Ytp2/eTFFYvj5Wf0/KpZYo
- 2DkrKBHKRuR9oHy5FQ3E1obaPaxSTH7lGbJCsO p+hrGGsr73PTw9V2va8PMoz3krS2txcP5i7
- d4CDBIU4B/XP4VCbi5M8SW8SlpJciXaMD2/GmTwSS zW6Rt5swty0hTowB4IHYVEzs0aedbywj
- a/mnOAGP3f0x+dd0YRstP69DrnQpcqlbX06ely8zSxpN HvSFtwk9Dz2/PFPmWRoEnd3V0VhKC
- f48gAD061HbXGm3NpFLPHKobAIL9wMY/SrP2GUWgkhJDuQz Rtyc5/p1NZuSi0nodeCr0YOKWi
- v1W50Nus1vbODA11MisSq87Rgcc+9QwlNyugCXMh6MM7Tjv71U Nw9oywz3CSCSNpHdSeo+7+B
- pYHk/s4eXcwkD5ZAyZZXboufXFcDpuzfcxSUbycd3uXdQMk1l5bTQ KLn98zBfvbR1Ht2rOhju
- 0iuD5ckvluoGDgrkdD+dThmCeUVwyp5aI3PH94ew709lkguYYTKoGxvL bJwyqO/qT604Nxjyl
- 08RKlT5W+byaLVjcLbzSSXTRSKVGeOrEEDHpUXl2Uott0U4ZIwku2TGw5OQ femRW8XlBp2zGw
- LKAcFSPu5/Gqf2bfq7QC+jhUBRITnlz0/PrUqMXJtOxPNGo5VFLla9TV27Z1+z BYAswXzDznj
- Az+NQzQ3rTJJIoe3izE8YGGDnkZNVbotBLJgmZNjeYUJ4fjj2PerdhPDPFdNNcFC8 qyKpPTav
- Q+9S4uMedanPWo1Ir2kHzX8l/SMi1t5Li+DyLLbyL0VjwVHXH41uzWhN/CyRPcRFZJ5V jOD8o
- wBTZILe9szNb3KxyOyquSf4u341Pb2VzFZyW7u4aGb7OTz8yscmlVrX1vbyMcZjYS5W5a9t Uz
- F+0FDE4WMkR7sFB064/HrVdobZ7mI7pZ5XV5MRPgEAdfp/hWpcGOKeWNF3M43lcdQBjj2FZuLh
- oYdpiESIYy4XlApyQT710QldXWhvGrSUk3dP1HxG6hhRp7WRoTGA7AAfMRgVnSDybmeKeQpsmS
- Mu /IC4yfx96lee4k+0JCWfcN+M8YBB3fTFPghSXzXWCVw0scoLNnCdwfUit0uW7Z0z5qadS92
- +3/BG pDmwkEjSkDI5fJyM5H16Vo2dhb/Y4Y1w0uV3g8k4PI/rVaWd7Z32Wsgh+bypG5DqeM/n
- SW4vJJjL cKyJFJg7fl6L/U4rOfO43vYiNOs6PNL5K+/3G/dxNv2BXSGN9pdTjdznr9Knhv7Y3
- ds1sszYR9yh s9fX6VjW85HkQsxtmmPztM24MR1I9B2qxaEfbZUMfmKswMZj4MYUHIb17Vxype
- 60+h2U4XptSVmv UvyO6x24jjfYFU7s5zt649OtOnkd4dtmI2lLMSNuSg6AH8M00XLl5ljCvk+
- Zux8qEL938etTw3Jt rSBvI/1sS4bAwM9B9cms2mrO2p3fVpwjGX9fiPjjKw4SSKQiRQ6qPmOO
- hHoPX1prQqNQmWRiQjFW wTl2Azke3tSsbpkeKRo41jOHbZjcVHGPqTTRJcLA53xRzrMmSyZ2M
- F6H61HvdyalOo4tp7/12KVy Y/It7lYGjMcfzPxtUnnBH0pFW8aaWVGj/e7QkTx5wRUF/DP9g3
- PFI0CyjcFONoAztPqeetTXFoJk S4S88mMxOQCTwcDFdC5VFa7/AD8ypezhRj3lp3T8inLczoS
- Xy7OGbbHx8o+Xj+dQLGsttFBPcoeM fJ8pJzkE+2KIC8Ee62kSeLaMoRlgSM4z+pqjDLGl1bTP
- l41/czFegZs4b6V1Rho7f1/kS6cVCXdf P81oLdFo98Ak3bcgHPXBB/OrgmhuJmW4SUOZWdSGx
- yB0qwkMSynZLG8aHyWB5Oeuc+prDuEhWJwj mYqxbYMkgY5qoWnoZU3DESjTbtbW+paiZreTyx
- NDArK6KrjLEsM4qKWa5jtYw4XYgQoGQENx15rL WUhxKsifu5AFB53ZGMitOK5vIxMTGWljyrn
- aGVScYGDxmt5U3F30O2M6lKfI1Fp/L+vuZHIlxHcR hI2KtExRh0IHUioZpQsqExsVVAuBgdR1
- zjrTXuFGnwkCQSOcyEtxjPCj0zzVqXc4kLRbEjZs5H3W IGAcVabT1R2UMZKcveVr6X/ytr+Qv
- n2xsgYmKygqMk9hwAf1qQRCOwhmklJaKMhUyeRn/wCvUEdr KY4o0VCZAJWGMlWUdKRz5qONks
- Yd1yWOcORwKhpXsmcHPSc+Xm0W76/jqWYJjLHFK0BMUb71J5AP Py/U1Uu45VltXT5nZP3qehP
- c/hUiRTiyaFj8kL4nPq+Dge2OhqB0dfJ8+YSgfM0aEhvzxRFJSujl p0UqjcVa/wCP6fiiwFVL
- YxRxy5kLBeeWAHQVBGbSWxzJMd0qAgAk7McYPvTIm8qSKRSTsOWU87jn HH509ImjupgqIfL+U
- 7kyoq+Vrr/X9WOmGFxCfLKVktVrb8NSoGJWXzJkaQtuYhetWoWEljLCQrYu IykgHA4xj6Vcnj
- ki0yA+XBL5n3HRABg8HNN8m2huHQLIhjkMe4njHbPvSdVSj/XQqU/b0kkrtP1M uS1ZVlXEhli
- nCDHQAg8H3zUsQnUpsDCKC42tnrz1ye+KvzyXeUjJjXOOduN3v9aW2ZVeYQRuXMgY h+e/X86b
- qScdQnQbp2aTt/X9aEb2Rd7jkMBIN6jqrdqV4DLIdriWRWCtsGMk9x7U6BGgJjYtI0r+ YVB5K
- pkn9asbA5edQxEqgqqcEZ7/AIHis+dp7nXQq1Ixeune36Ec7XEQBlw5DYyo4JPIFaTWsAgM Zm
- VbqM7NhPJ3DLfnUsziw8gGHz2l5U9QmOMtnrzU9tZ3Mm9J4wud0nmbeQ46ZNck6uiexyzrQnOL
- ulbrt+n6mQk0sMokiZVwArRSDcSADg/hWskk8mlQIhglEqpIzKnRh0/D2qF7RxpxWcq028AMox
- we tTsst5A0EEiQlTuChMEAf0pVJRlZm1b2dSmmrNp6t9hsc9zcJcpHG0VxLIZg7j5QF6gemao
- TzTbk dHQqUICAYZQ3TJ7nrzT2jleAmebKOSyyJkBVLYIqN2CagySMq+TmJAOwcZyfXFOMUnoj
- jknLWCSS +f4/oZ8sCzBI4bgONrGPk5wOAT+tE6LFpM0C/ZxiY5fbyTxjn3qIK0M5kZTNFEApM
- Zxu545qxIft dzcNJG0UDNuZ+yt2Fdeqa10RpiaUozTTuo6303IY4YhcCIqXVSGDA/cPYH15p0
- oiVDayQFpI/lIX ggk5yPYGojIz237wEuU3yBePnzwP61CxhliLrP5cvmiNg5O47uapRbd2ee8
- N7/tJpq+ztpf1LbGB pZXtmiaU4GSPlbcOw/OqN0JY4m8sAGErGGA4YEdfc1bispk1EpEyqY3G
- 4Hkgj/6xNW5raGSVFjDA tvkV2bI2g4GfpS9pGMlrcdavGlU5ea/9f13IY5kMc8e8IyS4DtyBH
- jkfhTbeGK2u5J5DJLGG2RkE AAY7+p5qKFZVlGCnyk4BTO5e5P0qzJdTRG3gkltvsnmEZ2cgD5
- tpPqexqZJp2XUwxkZUpcri0nvq 9V9w0MtsZZDHL5ynDNu+VvcD6cU+a3Atrie1QyASBFA6gEA
- Y/OqcV3cG/ZgY2EiM7AjPQYJ+lV7p ZFslkklI3IBEF43L3B9SPWmqcuZXOapRnCqoOyf33X9e
- ZetpmZreSCSJpLfKTfLw574/lVAGS81K NEkigLtnLLwuQcr9apCO5tUSNZY8PG/Qcrzk596fH
- O8srJcRmXch2tEdpBxgGt1Stdo54YdTUpJa 9+33ktyluJvs9rDceaR8vz/6vjODUcM0DReakq
- ZdG8zcMjJOBgfhU0V5J5CM0Qh2KB5hTODjGD9R StEdsUUJguABtxGmDnr+lUnZWZU4y05nZd7
- /AK7fIrQ37TWbys8S7XAQOmcAdPzqQXsf2gPMjElN qhRjHOTT0tjDpyy+Syt5Q37gMZLHBxUw
- WVkiWWS1kYjcieWOGJ4B4+tKThrZE1I04Qumtd3s/wAm ZMitcz+bK+yN32owGFB6gVfXT34mb
- f5DgKxz39vQCqIguXuJoIY5M+fu2f3MZqxcs5smQrITGoG7 OF59q0k27KLF7Kc1pP7t16bGZc
- 281oIVZ1Eb5PzdSAeo9Kz5vP8APiCzDYxz908itWSWJkJjjYbc qpc7hg9OKryPbkp8mOBjcet
- ddOTtqjVUZypPmla3qm/u0Ic/daaWMfLg4+Xn8qsecUubeRURI49y OzDPJ4wT61Uz8yywlJDv
- 3AFM7fz4p2x5JGW2UyLyxBG7k03FdTln78bP4e7b/LRFyygViiksksW5 ZADjIPf6VrWkcUdsv
- 2dXnDyLzuz8uDk1hRrlkEciuTEc7euAauG9JtraBQUMULKhHG7JyDXPWhKT 0Zy18NVTUYz372
- aS9f0Okvb8ShZYwwt3jdSgONpJAGT+FZqSXFvpUYyhdZCnlFMuvfrW2tvBYxXJ tHiuplIG3G7
- Izzwf0+lZ17Z6ozFYIWigEnzlwCdgHAz65zz3yK4aUoaRWi8z0VUUFBW0T30/9JbT X6g89wuP
- N8os7mPcgxlAM7h7ZxVUS3dwpWWaEM7jgrgMvdxx0GKuMto2lI9zMFeSVEgXPOGGD+oq hIjW9
- 0UM8c/2VigZFxu7H8O1a07PZam+GqXbVN3f5GjbwQ+TJCrLKi3AKhRzjqD9KszmG2niks7w M8
- sLt5ZYnbz/APrrMi2NdNG+6ORX2pg4Geuw+56VcnuFuDbR21vuuWDArs5iGeB+hzWcovnXY7Kt
- KFOpfmunvsvvNCLZPcSyOvneXMAhX+IEcfgTmlubaGSLq/zuWkVf4cevvjNUivlRvcNdRK6N+7
- AB AKk8Ej37VIZbq1DzR3Nu00b4ZGTqOvT8aw5XzJxZzyo1PaqdKXpuv0tbzLcE8EEPmxhwJji
- ISHJ2 g4BHtzzTL1Un1m2tzcCEWiMskhPDnqCPY9Kkljm2LKkW+6dS8S8YjUEZXHqc0/zCby5k
- AjaWMhXU r1BX730xWStfmX9dBPlk25tv87lszl4LhIFBkllVgP8AnkOmD/Oo7uSEpKkmyNXBL
- SgdCuMD1ye1 UzvTyt1tMlqUKRgH5gGH3ie/NUY7Bmw0kwaKBfL9iSpP86UKUU7tmlKlCKvKVu
- 3/AA//AADW85vs 8z+bGYpSJRhfu4OOar3d08ojMBjhaUkPlOFJ4x9e9Ogjhh06CCRZVmFoVkD
- NnDZBNOWMtesw2g4y UYZ2E+v4c0LlUrmMqkVPmta3f/gEVtGE06NUc/u2Csp6gjP8qum9SaOS
- C5uhE0k24tkjhOv59qyZ UjsGWWBjcIxyCG/1ijgEfUmpNqvKJIruC2nj3mVZoycgdcVcqak+Y
- HRdT3ld+aW35/eWrlJpXijL iPzVYrn7ygclCfXHNJFbQQu3mSsodWK7m4LHgVfhmknuojFGJM
- li6gcxkjhT796o3W9o2Vp0hWMh k3DlwB1X2BrKMpP3djkoOpKbgtGv62K0YCtEl4PIieMhpOg
- yBjFK0VmNkTLcNGcIHSTAJPAHNILZ rmSCOdxJvy8pBxtccZ+mO1RvBPbX8sjgLFH94kZCuFwP
- 0Nbqze+p1UKbvLln7/ZaL/hyxL5ccYtX WWIJGTukbIJGCcfyp9rPO939olkimjILEovyjPXj2
- plrEshJguorm7IyAVJGPTHvVwZS3EjQG1yX K7+ijgbTjuetZyaSsdUq1OLtvff+tySC3tFjCM
- j3LybfKZW6gnoPerQtHmlkgkjdZoW8tFRsF16u frWQikPNAqvE6vj5jnGBnj8OafczTrPb3cj
- O7NvwEYgnoP5Vm4Sb0ZvBSfvRevTV/wCZs29l5MpP zLAgKqrHkhucn6CkmilN1bQ2ys0UduVi
- Oc5H3ifwNU7DUJSXV1Mwb5jjHY8L9a2A0ovY2SBgEVlJ z98YySPQZrnn7SEveOx1a1J3mtfl/
- mNuVNxYeZbJJulO7G7O4NgEj6Yqo8Ust3H9qguI7cRNI8e/ DOBwDmlS+uYdLEwaKN2dXTcmcq
- ODj6VbW5AneUHzWU5dycqvbb+INSlOGyFGUlD4bp7WetzMN3FK sEcUm1JVOfMJPGOPxNJHNHc
- yxqXUxrCElAOMEngfWopVWV0W4iMboR5Kr8pZAPvcVYktolt7yWOR I4TIGRz3xyP61u+VKw5V
- ZWtG93t5P/MhRre0nQjDsy/6tf4SPlAPuRUKRpDFcpAqRtFIqfvRu3EZ OfwHWh9NWW1uZrecP
- 5kgcnJ4HWssSQNdtBK0qROCyMW+97/jWsIKV2n6nHGFKo5VFK7XxafpsUUv pGs5JGcC5kcYZe
- AVPXj14rUitdqM/mRxJLnmQZLkHhh7Y7Uu6C31GZTbiZRc4PyjCfJkVTleS6nh VMwRbBwx+6D
- wR9TXS3zbaIbrOV+TRLdsjSzaSaSeW3biQMGXAQjvx/KrE87S6dEfs8sMTFpJSSM7 iwGPypFl
- maSK1jdYcKyv5vIT0B96WELKsHmXMUrOmDGoII3HFOTd7y6ETi3UVSotvX7+xUdpZL2F IEUxl
- cxIV5I3fz61OL2VtXcw2T3cTlkwBkEDjceO3rUMsEaahJGjOiRnYCT8yn0z+tMd5I42cNtw 4D
- ovBYkcEe3qK15YyWx6FWDs+RaND4vtJuQiCQIMMrHuq54/Gp5orqG3juoJUAcZdCuTkHkfWodz
- JPcfvlgZJFjw3O44Iz9Kv2yOtlDCY2mWWPdJIDwCOorOpKzTOTERcZXsrPfT/MymuViuZVkYyI
- z8 Ecb8HipWR5Bb7Co25jlyOV9zVyCCW6aZSmGBMiqFGSNuOP51BGlytr5SqMBgzHb2HU/QVXO
- ntudq qqok4u0l+C/ryAx7LMQrAdpypLY3bieBmoY2YWkqzEhWkAYd9wBz+XGauh45J2ltpDkl
- 2R2OVx0H Xv15qSG12WNzHMVhjdlcO4zg45pc9lqddBT7K34/qVEV8W8brIVBJky3G329Oasww
- 2812HQS3GDn APXA60sz25gikihnQsuBKzZVselWYIGlikiWMo0S9hg/T86icvdvsaVKS5HKL3
- 03/wAhslsyRmUR m5BT5lQ4OQM7h7DvVIIhh3NbTtuOZJEbhj3IyOBjmtFmaEETRTsGbfuVsAt
- 3H09qfGfPs3RsIC67 UA5Xjqfas1OUVdmK9rCKlLXzTf6fqZkUFvI7gz7o43PlFeGcMOfw4q3Z
- oWnt4XUxmKM+axPHXJ+n FPMa3FiVSFllSZV2rwWXHzEfhUhZEhuBDBOoklDKzHOAByKJTbViY
- zi7qKavtr177/oTvObi+VEl RLcqGy65OCRgZpv2vyZpEa5E/mb3UpkAc9KLiPmCdXSFnIXbtx
- kfwgU42luJXuJoJYn+YtGWGVyM fkOtYr2elxxhh3JPl07abjVYzyxfaJEETKXJ5HzdAtLcHbe
- wQhmQxHbchTguSMbh6AdxVmyjlJgW 4h8hYY1QxOBuBz1P6fnVRpn826LwmJxMqNMw+VMclT78
- Clf3rLoVU5Ze4nttbb7u4q2NlLGlvDfK h6eYWJUY6DHvzUN1bWSokkxlkUEttV8Eeise571Pc
- rHBcvcRW0hlY78Z4XHt7E81WhuZbu6tY5EW NTC20MnXPGT+NOLn8SlocVVT91yqPkW+quvuK0
- UUCTypGssNoVBkeVt2GB/+vTyZp3jtYwjxPC33 V5HOMH3pkEsFjqEQ8uSXEZ81G5AwOevvzU1
- 0JglognjzKdoVBhpCOTj0raV+YjGWhJO9n0b/AKuZ 8xdYYrcW4WURmQM4zkKORVBIzMUEiLCu
- C4YjAz1BOO3pWg9vLLIPNV0hlO9pv4VYZGPYH0qBGW2v LVJ0aR5IsKgONuD3rphKy03MvbRjS
- vDV+WuvqwB/cRIJDJKG271ON2eefU5oljaV1Y3KhiMbEz8m e39amLSS6pIYo1ZncSAIvAIGMj
- 0FRnfJcLJco0ZAALAYx7/n+lJXuFTC1oys997X/T/IWdbaPz1+ 0JI4l2qUGNyNgGoYXtIMiWC
- YiDzFILctngP9K0YkVoYPMntZHRWErCP7xJyo/OlTV1ghJNuhnLDc rqDksKjnk1ypN/OxwV1V
- qacrfzsjJQ3LXVokCKxjQtgLzIAOQKgvW+06dZtEksYVirFmyE3dAfpj NakkjvcwLKVDquNqD
- aQSf61TffFKiRSxy/eZTjgY45Hrk1rCXvJ21/4c4K6caqaVmvN/1+BDaWTS WxWY+bcSSfumj4
- GwZ6+5psZ+zNbmZ40Z49yx4+bgkAZojkuZ4ijzJBMWHloVwQoyG6VWa3lazjn8 xZltXEG9Rwy
- sTz+taattSZhUqzc+Wc21/Xf9BywRKSJ7gOi4xtyeD1H15qSeSYOBFIkkcb7Q6Jgj Pc8d6Rba
- eC+jVrWWQRoUlUrnLHOMehqKCQxXNtFImxRGY2OMZOc5Nab67nouVNrmT5rdNPyV2W7i ytGtg
- ftMqvHPtCsxOF4yCKmF+2y4RYVdTOroQMEKO1UpriRrqZjGrGRwTxwB3pLaYNbSjHlnzv3c WP
- mZe/NR7NuPvaieHpODcru/fb+vVjb5ZbnU2cs0R3MdwHVsdOKhVjPGipbmUScKI8ZXnkH3qW4a
- G5uVaAOoJwFLZPTn8qqzwvGINknlhv3jZ/jA7j0raGyWwVHVpRcYaXWyX/BKsoKS+XuULvG4YP
- AP +FOAE8YBxcgPtOxSBzyB068VJMrOHmkXyGWQY3dAOwPHWq7gM0qYUEys7benTgY9ufzrdO6
- Odyqu XIne+9/6/UPs4s5BF5ckYYFhvJz79qQW+IzJ83UEDJ47c8VVmtZ4ju84DrkMOxqKS6m8
- mOMqclvL Pzcgk5B+gPFaqLezIdRUItVo25dkl/w7/EvqyK7heCyHAA56dar4e41C1/eoFHUnj
- juKaYlmBcRS xmI4f5uhz0/StBPOuRMkcaRqz7x8oyOMY/Gpk+XUyxLU1dpcvc6kzxrcWz28qG
- WJZEkfqGJHynH4 /pWpG3mQQmW6EkcahNqkjecjJ/PiuY2W4uGihbfIW2qT0bvuFT2nnz+Qt4r
- CSQnyyoADoT1x6A/z ryKlBWTv/maYjDw5UnLlXV2V/wCvQtX0ofVJsGNIWuNy5TOwKBwPxpIC
- ks0kk08JBIDDbyS3A/Gp r0RItvard2rBo3D5HKsPu546mn2N1HC9tbmENcrEfOUoPlK85+uKV
- 7U7pf1/SLUlCgqkL3Xy077C L+5nYSmJDFIowV5XPBz6n3q9b6hdNPvhhhwFZCgiG4N0GT/nrW
- ebiOeG8OzALh4mYZ3KOT9ajjjm nlEgWZ0lQsrJwCAaiVNNXkdE6VGS9pLd97W/QsvA6zSNemN
- FBAcFfusF4Wli1GOE5V4cnDMXjz8x /pTY1trK9bzZzL5kgePechsjgn15p1u/2zZC9j5mMNcB
- QFYvgjAPbpQ0mveV19wOlTUX7SDkvu/B /wCZcN/LdWpllChlZj5qDaoY8Y/Gqs63U7Ov2qKXy
- yqOI1wZCVOMfyqoEvnWPMTwJKPkUrwOv54F OtnYxRhI3JEZeOQHgqp5z6ketCpqCvG39f10N6
- UY0oJwS/P/AIP3FnLpZKAJYW2qxaUkgMODx6DP SpltktxKnm+ZEHMiyAnB2jkn9aSPUHlumEf
- leVJtEe9c4DHkn8RUNzFeDTbuJmQwGThtv3s9MH0P TFRZ3s9CasnKqoysk/P8rotR7Lqzd47h
- fKMgbJzlsc4FURdXdxJE88iZnfd8q4JwfmH4DFEV9Hbx sksDJFISzBRjYRxs+uK1dOv4nRYka
- 2ljhZ0jfYPlj6n8T60pqUE3y3OLEOrBqMY389zKZInupJYy VMPESkkgj1+nNallZLdLIPMh/d
- p5bqF+c992fyqnLZ6emnM0UzbkXbneSORkZ/lTbCRlihk8wTxl R5qx8NjJBGfX/CnNuULxex6
- 1So/YKdK6e2qSZoqJba5w8ciuxDGXOFzjG3681Qe7WS4SKWaKOJVK NuXkNnp+lPu7dEglWP7R
- vJPll3z1I/pTIo7e5nlWGEzskhKqG5IwRj6ipgo25mYwownLmW738vm2 aMtwlp5dzgOTHIrr/
- tY4Htwc1Qs3uprMBFEssMibwwyGz6+pq4bT5o8SBJRbsWR8nb8vU1ammnfT YJY7yxhcKGm2xd
- 8ZA+pHSsVKKVluzCVKlCKT3b31Ms6beJNHIJFbehACLtKjP3T781Q8ue3lQPHN GIj5e2Rid5L
- dB71ckJuILSRROxMY2RqxBPzcH8O9Thpv7VLjExkLOEIyRt+tdCqSS11/A7KVVRjq 1Jeegrah
- N50kKQq0pbc6EfN6EfXHFRx3DW4L+TIHiPlqJDkAE5APvRNGkNvFeOkiIQZAucMB0AJ/ HNTmz
- tDYsHn865Rw7Krnop/ng1F6aW2hs8RF2apvle9no/XU1ofJuMXJkjlmB2qkI28Nycj2NN8m RJ
- WSK5MMucCRzlZPl5I9BzVW3kl/tOTZGV86f5owozyuMD0zVS5Bkt4AEmSSJQqqzffUHlvpXNGD
- 5rX0M6FV+35ItJPvqaVw8U+mSKsyRy2x8sow6hwMfljmoI2nijmb7VbCF5VkPyH5x0Zh7CpI1u
- Jw 8pjSQSZlwigEsBgc/WmzRXEMZtoVzeTkO6kZEQx84I/XiiNl7t/66h7ifI3Zd9H+mn3FZ5n
- GpNC/ +kIFPlugx5g6DHtiqK31vJbrEokMe0ADdnBzjB/CrSytYqktxGZwFAjdejL04/MVntFb
- QxGU200Z gmREy/Xkkg+p5rqhGL6F1ZRnPSGnR3/4KJ4rk+cyRMzbnBKDuR0I/wBnHaqVxeYvJ
- HBiBEWxMp1B HQVduordWtNgaVXDiF4zjCDnJ9frSTiOWZllkgtodmI2dckflVwcL3saUKlO7l
- KNvVf5bjjLJb6T KH2lFdvkK/NIMAZz7ZqlHFFdyRpAkoQfu1lJyHHXPTtipoTdHSrcqYrsvgK
- iryAD0/H+lU2FtdSQ +WJIZoC3lENhQT1B96qEbX/r8Dmw0qii40klq7vXRen/AACYrE5Bjt5R
- MHJiO774IyAfU9a2LZok jiR4o4lki3s20AoRnCk+tYAsnRbeFJGd3XzFKsf3Z6EGrIW9e+4tp
- 1Cy+UUPVdwxz/OirBSVuYur Dmi1KasvW/4kFmYra+zG/knG5GuPmD9Se34VYBSXWFmkXCMuXI
- 6AgcjHt0+tWf7PlWGC2lnhIC7Q 23liT8pB9KtRW26/S2urZxIwKySKSFLA9MY4z9aU60NWbwr
- 05U5N7Ja2aTt313/EzpoxPZwmFN7F clRy2eufwFQW0a3EEUbu8XHOW4CA8j6mrMkkdrqfnxQS
- iFEaNI93UnufpUaRJcqJJpoo23gOo4LZ GCw9qpSfL5BOo5U7JtR6SV2/nYdeWhglaSBmSJ5So
- Jb7ikc5pli91sESQSyoyjaMdh0/OnvIsUC2 tvMLhUQlJApwB1wcjk1es4C9tBK0U+1kBba2Aw
- znI9PSlKbjT946IRnSw37zW+2lv8vzIGt7VIJ4 445IZkfZ5bPzt6//AK6beO0SrAhBUph1IyR
- jFXLyKdlE9soG87XLDJJbrj0xTreBrfUsT27XDoCo C/x8c1nGorcz18jqoVYOldO7XS/6sSEW
- 66XcLLG7AXCiJd2cLkZpgW5aSYxRuZHlaNsfxtnOR6AV phbaW2Xd8iyxCYKTyhB6Gs12vVjla
- 4haRWYAGL5c55JH6VlCV2/1LpxcXeP3X/4a/wB5K8cy6ewR WeVTwx5AB69fypGkvI7RJY/KxE
- +zOwfKP4c+pNVpp/LaRSJDsx5YB+8uOTTbd4pmjtNs9tFO29Wd s4x/F9K05Ha7RpWpuMbzSSW
- r6/gacswiR2tLiFpzPtVduc9Mj9TSRtbpZyrOWO2cEbTg4HGPrzn6 UxjErqIpY5pgU8xlXgnP
- GPTNWVuJWvZGNk5iYliuBken5HrXO9F/SZwVJw5ubdLXsytfXcUjCGCN ss6AMeig8VI8JIm+0
- 3kaNHIURtpw+eCfcA0yKMREXUg2jz0JJ6MO9aM/myRTRLHFIs8m62YgfdHc /XpQ5KNktjr9pF
- SjFO0O779ejMuG5eR5Wn3TgFclTjGOSK1nure4QrsEZKtkNz1G7J+vY1lOGECR CBm3JkheCXb
- jFNurNEvI4FuQsm0KAepULyfwpyhCT7GeIVGfvN2a7fn/AEiSLy7rSjJBNnzFXezH IDZ6fl1q
- nbuzzvPdSrnft3JwBk9Me+K2UMVvpj+W0LQtKMkLjJOMY+lZshimu7mGOPyysvyMfukA ZJx60
- Qne6tocEcXUmnBrQqBW/tLmPgoWLYGQOScn0z1qrb3E7PbCS2kuH8sSYUcggnBHpV2FWMWL Nt
- 8Ux8+QuM7e5T8ccVqwRv5nmeXi3YhlKgAqoH3c+3etZ1VFaoWJrR5fehr2ujLiuYnla4WRVYMS
- 0JP3yehA6ACssRBruNY7iKVwmd5XOOPm/wAK3J7R2vGEaLl2DiQLwBjB/wAaoXCzC8eNTCzsPv
- xx 44z/ACq6U430MsNKLctenW2n4f8ABKLSCOUlLhQxQMQo5BHAWlso8kJMXJdd5ZmJDnd94ew
- 9KvQ2 6BZTPCJJY32DGPmwMhvpVUz/AL6znELxIiPGpY8AHqT7Vrz8yaRGJrQqRaite5OLOJbh
- zbs2USRM k5Vm6j9M1kok93I22PftdWYAc7sHHPpxV1IIoLkJcXiSW4DKux8EnHB6VmxSSiQC3
- lXPy+YwPBIz z7CtKadnrfzM6cHyySfNpvrb5vf7jRmv2YPlUlZpFl+Ucj5eF/rVBEE6wTy285
- aRNqIhxuGeWqK7 uX862VWSRXjLL5S4LEHr07U/7SkmntIWId3Mke04wB6e1WqbjFWW559WUoR
- 5YKzejs/+GZlS7H8p YQ21W27mOSzE9fpWj5scek3UMzssq3SlVTjtyfwqoCzR3EoVQfOR41AA
- 9Tn6Uryqtys8jQ3DHcJE C9T2b6V0yV7L+u4V1pHmWnTvf7ixdXcguwiSswD/AHgfvnjBqGO5a
- DUFlaEN5UhRm25CseckVTa3 gm1GNTMqgLkSHIXjrT98ZeUkLH+82hWHJHb8apU4KNjeEI2dGL
- 5U9+t15vYdJdGRycbd4xICOjdB 9Kngc2kz5AmkjPllfXPcfrVXa20eXypdS4xzkcAe1IrwLAk
- bI0bFiWZmyWPRe1NxTVkVNtrlXp8i NRJyQuF3Hn2xSRSMzxzRoU8sFf3gyBnt+IqeMSrMVbyy
- 2MFduc+oqNTtZ9kZIwCPbirua+xvaD26 33/DUgkj/doXGWJ4XnKj3OMGo5plggjii2Om5juxk
- g45yT61JKJiyF2Csqc7uj/SqSzGO3XzmR5n GFwuQo7g8da0jG/meRjVGLTaej0ul+mxDGxZAw
- lZmxgBzkVOGK3EQgj3s5wvGevHf+dPdovNVAUI ckBkGAB+VJakf2Y0pYk+aVUKcEHHB+laOWl
- 7HC66cbLd6eRatYpRp8scUgOZAxQ/eycjOcVNazT2 rIYkDOYmBQjJGDmlMTSXcUbSJFN5Z3A8
- Hf3Bx+dILJ1+zmaYW3y9G549eK5nKLvzdQbhGnyyV0+i X/A/I1ILjzTLcTKrIWAYxAL14IHpx
- WzBJZpvlYmBCPLj8x8kDPb+dYETm2W4gbbIHlRmAGM7c9Pw NWJYIbm8kSOXbCrEQF24w3IU+p
- J6VyVaabtsv+GPXnQkr2bXez0+W5p2bW6XOwlLto42ZnA+++eM Z9KAlukiXE0MsaPJlmL4Ib3
- Ppk9KswC4trYJdRRvMSVMcahTyPm/SsC5Xy4rOC0aT7ORukV23HPr ntWEFzydmc0IyqVPcWnV
- 7misksOoTeUgnXG0pt4PBGR7CrMAW0tw8Ql2qgHmM3yjJwePxrKQ3HmK U3PtjKlh2B9at20pW
- 5jgumDBYjgg4AO8YyKupB2PTrU3FNvWy6XEV7Ga8InlGxGEcZ3fdPofpWva TW1vqRcafduGcl
- sTHOegHTHfPWsW5soxIQq8OS8be6nGD6k5xU0aXBE8TwziFpSR83KFuxPrnmoq RjOO+nqRKdO
- vB22atu1b5Jq5rXXnXMYtLWKSIxoEBdsn73JqhdDZdLvtZ/lUqGjbCkE8jH0q3bKm 5lluf3kY
- xO4JHPU/oMVnm5sprsywx3LEyAwoZM4Q9c+prKmmnZLRfqRGtaXLFO0dev53JrtIbXUH uWzEn
- zKsQ67QAOPcE1nwb2gzH59xErYlbcSpxzx6etblywnaSEoGQSdSv8IAU/nmsOS3NjqTFJ0j SP
- dsU5O7AxyPfNa0Jc0bPcdCq6vMqkdX6/oXRL9rhPmwNE73CBWONoQgk598d6f5dvHDMiLkM6FW
- Q4ynQn/GpFtobiwsgEk2om2UB+euAfwqEC0jiUBzcGNirBGxuGc5HtUJrZfcKjO14rm9P+CW0i
- lR 2lhjx5ZYx7+Qy9Rx3qFJhL9nlnTbGUIRIxtyvPX6njNWZftFxGWhAj85twJ6Y4GB/OqccUa
- MkM6s 3kB4wynAweVH1J6VMHda7/idtCrzK6WvVrf+vQsLd7olHWWNlTYw5Q98+uKmhv7g3O57
- dJCilGMK hSxY4DfSqdpFZtYrDPDO1zHkqivg4/iB9T3pF1GzhmzHbTfNtYHfnPBwfpmiVNO6U
- blKjFxlFw97 5foy5vnXU4pLu5jWO3BikOMByOf14FaFwM6fMyvHctJIDIsa42nI4/Cqdoz+Ra
- BHiMphdWEi7hIx P3vp2qFp7uCFXlaFsuR5YXDMw4zwP8msHBykrdDkadWrGUZJNaWv2+X6ot2
- 9y0Sz+ZJCgZiVm2fK hHBGPftVZJ4zEhS9t43iiwqkclh16etaXlwvpcESERkt5ZRvmJ9W/A9a
- r3FrDKlnbugjIt3ZHAxu z/8AqqYyg3qrEwq0XLWNnfW39aleKR5YVS4kTyooWjMjD5SG5FXIV
- 228KI6XMsSSBVTqExyG9W75 rJspoIbTyEXzBNIr7nORH/sn3yKtoGlkRmguJERShhiba6An7p
- Pc55z6VdWGr6FSjTlqk1b7v0/M mNgzTwLMk8kfl5DRvtJIHX8jVUPdRNFOkscoCZ8sqSSAe38
- 6tSp5ltbhfNilVmWPc2QU/iOPamS3 9tLAn76FAE2sAOu48D8uaUHJ9LjoYhyTly3js1YZNPLO
- 6mSdENwrSJ5eVGc8KPTmo1vdRt71pDdQ CcJh9yZ+o+tUrgRTw4+0RxRW9wYY5MHBU4yfwP8AO
- p3uJIblg6JcIWKzKBzvzwM84xxWyguW1jvV b2kOTlV+3/BenyC4W+l01ZHZZjHhDtXGTkdPpx
- Vq7iuRNJB5sUku5yVC8lhjn6YqjLI8sk4mWS3l mYsMnCrjhhj1PalTzknt4re5S7ZlJKoPnz6
- Z/SnZ6PTQ5HOEUm2rp9tP1/QXyb14n3KZw6bj5ePk wRwPTNLJLNfRKmIond+Qy5Kn0/SmXwRY
- YpA8tuGGzBcnOCBnjtmr6tNGm1XhnMZcSSKvDt0Dj2Bq XLRS/r/IKtfnUZJ3d9LKyX6FFIZbM
- QTW8yzEKQ6qp78Aj070+zigjmNvI6WrjMjPKudxA4/ADr61 VMs39nzKWDneoZ04CEdAfrVyJ4
- rrUZXLJmUNhT1U4wq/UmtJp8rv/X9andKlTdHmqX9V+qelvkSR W1w8UDPIkuFKh0G0EN1NVGJ
- s7qMzmVwIyGAbB3D7uf51eWae20hYZ03yJgTBePLb+6fc9qz3kjjl mnJ3MXEZicZKkjv9Kinz
- Nu+xGEhupaJ7ef8AkOt9QuttvKWRyLdspt5GM81MLuZ5EV7oWzOglZ3B OCO341BPOsqiFlj/A
- HZCxmMbdy9z9KijuHilD26R+azEssqhtoUe/bFa+zTV+Wz/AK/rY7XhIqD5 o+8/T/J/kTW6vd
- TuYY3ljcrs55OM4GfXjmr95E1rpAleJoiD5QLY+UNyc/54qW0gkMMN0sTOHjY+ XEduMHIHHc1
- SSyYMs8t6hjLYaNiTtcg8H3rBzTlvojgqV5Tqp8ytHbTd9rX/AEH2lqlxdpmL5IlK gD+Pb61c
- kuGO5VgmV1G8KrYEY7KQPp+tYSQxwPDbrclopF3Pz0bPI/KiW6eS5ke0LQws4Zg53FwO nOK1d
- Fzle56sKEaj953fbZGz9pkkMb4E7SOJXSPjac/Mv6UlzHJcT3txLFcRA3QdDu7HsKpQtHai Ga
- VvNSWL7iNhlYnp+VWbNkt7+RmZYwkZCh+fYqR3PpWbjy3aRpSp06bk1Hb1s/Ly9bGhLLA42I4J
- b52QHoAvzCqLuLTWIJHt7hICCVSST72FwD9OaZDDBEY0luUmWJGwqEhgCOpPfrTNzHy4ZLiNFR
- N6 NLzjHQfjUwilpuiKDTTunbqtbfkatrZ2ly8Uqv5RijVCrnPX1qpLMpYj7M8UeTG0mRgE8gf
- kKUS3 S/Pgojq6ncBgHHfiqj3Ey6eiSwNlduG7Ke2fXipjTlzXvf5lfV3Gq5wmn6Pb5lq1CXF6
- sUJJSM7E GPmZD1b3x61O1hb2trdJ507SM2YoxIQ2P61SVdU+1w3Vqse2MAqoQfMucYqvPd7J3
- AtbkzNKMsX4 wB2/CnyScvdehx1K8o1G9LeqevntY1keFCZkZlE0TYWQ5A9/w6fjUsN7I1laRy
- xGacEBFiOCRnOf pWS75RZVkQRqwVYerIOmCf1NXwYotRgu4xJvSBxvY/KTjpis5wVtTLE14VK
- d56vp/l3JHjmhinIu ol8yXfFleSAeo9smnwi6k1GC5cJORHk4XkEHBH1zVY3TJEkkhjKYUnK/
- c7bfyNSJHEjZtJX3JIFj BYncvr+Z5qWny6kVJJUfZyitfx8r6Fa7tEmSbbeQh/NDFATg8csB2
- Aq5bXAnACouxyG3EYJwDzn0 4xUV4tusM7SxPvEmAVbHJGB+XekYQIbSRC63C24V0DYALf8A1q
- pvmgkzSTjPDK9/LZ2+4jur9pYE jYRR74lZ9i7djZ9u3FTRzq8RBLiSaeN/KzyM8Efj1qN4He6
- SzSEQwratl3AJOOQc1EM3Ailms57c ufMjOcbuMcfl+tPlhy6f1/VicXOn7NKCs/l/wPzLGoMI
- JdsbPCYm2F3bhm6hh7YyMVRgkto90pu1 dwpAbaeRyP606a1lkx5MUxEhOZZDlVOOn1zUUkOYR
- HLFHmRhueNAoHHK/oPzq6ajypNnLT9iopc1 79rL/P8AMjfUYzpZU/vCWVgF4bA4YUfaPN1mRo
- mSb905CKvB45I9v8KintFtZLfyNmdrE5GdpHXN Z6SJs8x5o0RbgINq7Sc9G/3euRXTCnBxvEl
- zpQi7LR/12JLlGNvDLHbTJtXIdiCNq9fxz3qnE10J 3xGJHbLsqrg7T1/CtW5Vbi5ubVJS4ViU
- xnHHUfjUVpJL9rnhiWOSc/cIXOUI+Y/pWsZ2hqjOo+Wh LnjqvNozXSQpG6FdrKyxbUzhW7fnm
- s+b7VLd21uiBQgIKgY4IFXkmminhZWRYzIpZCO4yFHtkVGk 8kOqztAP424YbiPb8K6I3XQ4ZO
- U4WsrrZ3aIGa9ZI4js+QMANg5XvT40aOJ1fazSLvUqOUHUj+VQ IJd0YZZQjKd24c568ZoSHfc
- pHuaMlTww5+7nP0rVpJG7nSoWqRTsuutvw/4BGsgZvMV4wcgDCHkH r+VPZHM9zuKkiRixxwee
- MVHYSxQCIXhEkIJ4ThjmrRULEfvbCzN5Tk7h7k4/rTk7SIjKdSak07/h +H6jE8poN+5E3DIHU
- tg8/wBabsRZWMYRlR8x7gCxH5U7f5IUrbqMgFtx4wRg444zUkzvHBtjG0kd W6daFe520IuqpS
- qr4fIjaRPJJmkBkZ+Tjj2PSoQWIcqrJ1JLdtvUfWophlH+YFchskdgOlSgyZMg TaNp2hvSr5b
- IyvUcrJ6emtiBimAZCyqzAwlj0Hp05qDEBL4VyEkCq4bjPXninmaT7OZBGTHH8qgq DjcMZqJp
- CD5UZAIbawx0I/ritIpnjJpycHa3q7siSU8eWyM7MzN8vT2/KrUbKY5W2rjcMEDAB7A8 deKZ5
- EaXivEhkKksFAzhff1471IDEFdA4GZP3RP90evvTk10HScqUuSS0XzLlulxPdvC20XM2WUn 26
- qfc02YFYUSRJPLhYEZblVI5Q++e9BkaJmkJEkqsANvHGOefrQtxgzI+JYM9ckEH0JxXPaTd0ZT
- 9tKstPdW19Hf10LFjD5ksQeVAskLMQfvDB4H41fEq/Y2WNUDyhWZSvQ5xj8qyYXH2BlQ7FTDbm
- HI wfu5981rWLvLNLdq8cZDbIo3X7wPAP4VlWVrtnoxcaN5Tlr07fl+hZ+0XAmfdJtkgm2ByMj
- kY596 seVk2/lzwl4YShyOozy34Zq22be2WScpIFWTcoXBLDHP4UttfJBcpF5AmEeVmwBkk/MT
- 9K4HNtXi v6/r8zOGI9xzhC7/AD+9FOZb6LbJDFiOPKs4UYbpz9KozpHJO7SB/M4wynA5GQfoK
- 6Rrpv3xiwhe RXIcZxuGMVgO8waWO2QOFKljt3Zxxjn0NXQnJ9LHThazt71NX73t9+hMXmSwV4
- kM4bMfmDkMW7j9 alt4Wi1h0ll+VIGBPZiBwR+dRbfKiV7iCeOZnC7AcDr8xA9hVi2aSa2lC3d
- uSg2jenOc8fmKUn7r sZ/WWk409U93tb87lNRZSxbYJJATGvzluE55Dep60t0kEVyTEd8cO4Yj
- GM+n4VO+nziZt09u8ImH miNcEEj6U+VbecRS20se9FZGGPfHPqaaqK6s7o2eJg3abbflt+KuJ
- IQ8skTiSFs7lUn72FBJ+lTS SxbYDbRG4nAK7D83B5BoX7RMJ4whRTOuHbnjGDj6ikSUR36LAh
- SRY2SEkAgrjv6nrzWf6GanC9ub Va2vp8xlwUbT32ziGaCREVdxGc8mo1kPnuFh82CdS8ip94M
- PQ9gB2ptxfSDS4wEgKyc+Zs64P8zT JJJxdTXLELuZtqquMgrzitIxdtTpw8mqWi1d+v5bWLs9
- z51nAI5o/KPzMw4xtAA/CmxfacmFpYJX 83dOQvOf4R+Ap1vaW5sEmiG7KYWHPLjozD2FSRKrS
- MsjBJopEUEcZX1Pqcd6ycopNLockZxhzOCv b8GXI0txEFZXnm+ZlaM4wmcf/WqBo7Z7VLmC0d
- JNu1Ucg7gGwCPahMPfPFBeRbZG8zO0/KEHT6Zp GihlngcXIPnJ5ihSQAB2/PmsldPf8zVJqSk
- m9NWnf+rE0EdsHnRre5gnBBVHk5Ht+NMF4Y55DOFj m+0bgjjOz1U+9VUFzc2UsrXCgPKjEY+Z
- +xYH0FWpPLSzlFrieXzVMRPzZTnnnqc55puKvZ6m8/Z8 /Lvf+tW/8i1GkZCJc3kW4xMV2ccDO
- aoSzwx2qGPzWSSRSjl87VHT8O59akt7x2nhhVUaRoWZztB2 kHJFNmu5PLeIpDEXdQW2DGWHAH
- pxUxhJSsznp0pqoo307X0+5LUnnK26NALX7QzuGRo+BtXqf1ow jXUrXUxEJYCURnaVI+6f8aj
- Zrh7Zjb3UDMXVI1wcopOOfrVq4LyrID5bYYh0UYPy+/rxU7af10Om M40/3fPZvte/4ozw0siO
- jTpwjqrY7sf/AK1Q28V3AJoZVilRdxEoQY5H+FWbx7h9OVtibXj3gquN xzkmoJA4t1ntpQJZV
- Y4c5DKOcj+Vbx1Vu5tKMXTSvu9P+HWxBay+YwkaMRwJgMWGQSTwarz3dxdt cllEXnEyAlcDch
- 5Gfwq2k15HYTqkK+UzD92U+YMcbapXAAntY5VZbkbyX/gJB4GPetoJc17f1ucv PGFRt2u9O9v
- PyHjy5kmuZLjeguMB1PChjnB96kuNh1KeNJo4NzqzScjp1PHpVe3uYhFaxXCbGVGD rjG1s8Fv
- XFPjhVLwOG5VTGHcZV+OcfXtTas3cyp1/Zxm3o+nb8V/n6FQCW5yrrLJIT5kZB4BPGPx xWlFG
- 0LzTy+Y4hYoyI2CSRwfp/hVS4WOYW7W8oUrErhFz8oB5BPcjrW9DcIJrsBont5JfnPUk4+U j2
- oqzajojv8AbzjD4bJ9Nn6/8MZsNxGPPCFVdpMDfyu3HLY/l6VZuTDCkc0KFlkBjCpwUX39ST3p
- rWbw24JELs7qVUDDZHTHtSSXVzZ3LLMYjMuRjZ0J71npKXu6m1Kftbezlfvr/wAC5Zmth9kRYr
- W7 G9SDIzg57/n71NbJCssn2x4ordjuIcZbJ9/bpVBtSvTZrDlX2Abzt5B9KrhkmTz7gtuK4VV
- ONw/v fQGo9lNxtI6KeGrKHLUdr7W1a+8sSafbw2SyTbmMM6wyBW5GfX86fcfYY5CEjeONg4iJ
- Iy3Ytn0q vDdG1htw7xzZlBkVhnzDnjH4VuXFsizSGSB50kfdGo6gL/B9T7UTnKMlzO5zqcqdR
- Nu/bVK//BMm zliS4W1SWUr5ZUNu4Bxk/rVoC4S0QXOxbcRbXBAyr5xz75rOjlRL9XuIWjRjvd
- BwQRkgCn3EcbwB mndR5oyrEkoCMkH1NVOPvevzHiWlU93Vel7Py8wtbdUFz58hZYpRFlcZIOf
- UUkkdvHCTAXZygPzD 7gHGDxgmq+5vs8gglVYUkAAfktuOd34VZiLpLcmUpLtkEcgAwCTypHt6
- 1o73u2dNCvLl/eyd+i6D 2hWR7cJG8sUaESOp4DAcD8aginBJCNvGBtJ5wR2PqcmrMoJ0xoow2
- 4SBtwP3yvUj2qcTndJKIInj c71WNQCCetZqTsFLFOMHKyfkMtrlJbxJQI0kZBu3pkcZBGP1qC
- UGW6MkTJJ5ThFwvBB6VE1s8iZS WPaMqrD+LnJx9elFtcXK292GKRsJApiZMNycjn2xVKK+KI3
- U5ptqSldf1/WhZupHjkWO5jlJ2uAU faOvWqyzQm8iWMmE7SMzHcAfU0rwsq+ZcszFiERQfmI7
- nmq8MipOgYRQptdCzqCfQ/4VUYx5dA9t S9lLkl739bLUs3d4HQNCzo8cvloFb+Hj5TjqT2qnN
- qUt5JvSP7PtmbzVIySemB6cUyW4iW2RLWJl VGZn3/MeeMH3qpbovmK0Nu8jtIcI2DtIAG4+x6
- YrSnSio3aPLcYqMZ1F72t15dNVp+BbVY3uJt4c AMzRgHBwBxn61qaWIIZoGlYxpNgh5D8vQhl
- +tUTazknzjHGU3KQBjdnqfoKlEMMcsMy3EchjP7sD 7uQOWx6VFRqUbXNqtanOm4pu78m/xSt+
- Ben05AytG5khwvybuWYf0piCZr0JPKLYBHDSlTtPcY9M 1FKzXjWKLeRbowwZFBBfHORWnbqiP
- Gcbo0t2CmT5gcc/pmudylGPvasqhiWo+/rLbs/x/wAiulsr RWaq0su+IsfmyWbOQw9hViB/sP
- 2lpraSSScecrMegHUdPeqv9omSCFoY1V0iESDaOecnH86fa3CG 4Xyo3UlcoZm3fKQRj+ZpSjO
- z5lodjUqcJOS5k+l3+n+Qksm6II19ChKjZnOUXrg+pNSz3CvbxTWm ZRGwQAH/AFeTnaffrQ0E
- V7MYFAHzqGcD74A5YewFR+baw2Qmt7qKOSVpNgcEjZjGcAdfQ1GjtZan l1a8bxhFu99rfnZBc
- yywSARN5cBT5CxLbxn7w+mefWoLhg9lFcx7p42cNJsbgFSAP8arRQW02k27 W6TzSqG3IXzuPt
- 7e1Pgtr1Lq3uYgnnsm94yo2jJ6EfrWyjFddV+P9dyKtWnUg5J2a6d/XqvX8B66 hIb65ad4o5f
- m+Vkz1HPHpVK7tWXT7YJAzl4CJGH3Q+eB9QP51Tv2mkuoCI9kUhLKpGTtBwcn9ald PIEodZ1e
- ab92+/5W9xW8aajZowlJRcWn8v6t+QyK3n/dxtuAAJMnTDHoCfWpZLtkWJbiCQXCxtEW Q7T8x
- 6cDrUM81zb3EyRk7FLJhgG9OaheS8jeK4mt5eSGiJHUDgn34rXlctXYdec+TWzXTVrX1IGk t2
- l8pt8YIGd3O0r26UlzNEI0eMofNyYyvYDgg+p96givWnvBPsiL+ZtUEZyM49KhmSRrolYVQlm4
- K8j2+tdMafvK4vbTnOLT9O/53JbadI2YzRO2MjBPHI61WIWS7iKySIUYEKxJL+1SMItjeYjh8E
- gA 9B+X41FEF+yEjzJI0bBOCeT0FapJamFSmuf33o+70+64scFqJV3sEycqSTyT/wDXqzJIMRy
- BhNgF ZAqkbccAn15qgJURvmid95x2+XtThKy3SxmEkFtp9vr9abi27l+1jF8ylZLol/wNSx9o
- R4U+YM4H 7ojoQDzxSODNbyyrIJVSYBSp6++MdKpJMHVTtRWVxjA7/wCeo70Ga5jKhI0Ul8MNv
- Ue1P2epz+2W 769lf8Cz5jQ3ckWCQcgFhkAdc9O9VJ3kYxeTIWKZEiMD0GORx0qWNXnlIMckbg
- c89ewxSJbTxlpk VtqPhi65ww4IP9RVKyfmcuKrVKkLRk/S6X6XKqRiWXJ8x9nKANgfjVeOJt8
- AiKA5PmEnnPXP0rR8 uaNPljYnG0ADnrx/OqkUN3MQ/lnYpJPyHnHJraM9HqcuJpRpOLlfn7aK
- /lrsTNdll2Sja5wq8djy aHx533ldEYBiF4NKsLKqlQZAVynHb1zUaoWARJUK7gZBg5PoOnXFT
- 7vQ6pzqO0pu9/T8+v3lnzld ZXkRn3NncBjdxz26U23knW5R7Et8zhcMoOARwTkY4phgAI2jIV
- Sck579KSR1gjtWjcywSStgISCu MEZNSkun/AOHGQtT5Zu172X6dvxL0QdY4nRSltO3VjnIB5P
- 4VuwK0SWXlobqaRJCuzptJ5H1FVLe 2jlWKLyJYEVsFXblic4I9B6+tKjzRX0UbMI5S6DJ/hJb
- t6VwVHz6HoRm6ivdNx1fb8DqZLiBNOgD W0/3N4QtlmHGT+dULgSXeryKlrKoaQ72BHHy5q3PM
- zJevHNBJKLkALs524AOPQVcijiBZT5gjtmM Bkz97eMj8e2a8yM+RXtqXRrOhBzjo/V6fIzYre
- SKK5K7pJFkjJIPDDHb8OazxJENWQRRysCDhlbg A9z9a0TA1pMsltchZRbner8gkDg/lxWXEqy
- WisWDfKuHTgR84w3qc10wd7s9Jy505R2a31/Ine2m jZJJGaNGO9WkYtuC8n9P51oWSWc10YJL
- iNJpnypwQF44U+p7UyZTBpgtpnZ4TJ8zn+HAwcE9iaqN uDqUSFJX8xsheVwOV+vcfWod5x3OF
- /7XFq+uy5bW+7qW7q6uLOS8gVRGJZ0cOy5AwASKZb6legSG OO2ZPOY5EQ+ZWFSJNNLbRXEtlJ
- GVjxC7kEbMfNkdz71Wmmne1txB5Z3orLtXHy1MYpqzirkKFOpZ cqvt9332LSXsMcNrHcSKksk
- uQBwemPyPaqKTKXYSI4ztHXBQ54H88+tSW9xLc3hM0cYjkYSKSgyF wQSD6DirSzQTyC3t7ORQ
- JFYlmBbAGQM/WnyqDen4k0aCpSlGMb97NafkQRXNm1uiuVOHKlffPDfQ UyRAwuAZFdoblGLDO
- 0tj5uP7vtWtbwQ3FkbmMRCSZ94wByc4wB7/AM6jXSjPE0LZjdxvI7oQDtDe tZqtBN9CcPXpKX
- vJr1s/wsUoo2WcSeTN5fzKpRuF55qHybmeRBb286OU2sHbluoz+FW7eO5srP7Q xOZlMgVhnfx
- gsPYGmv5loPtNzdJu8oqO25uMEe1aKb5nb9T06GLvUlyyS00639UWLXy/IMbyxyJb qIkZOCVc
- YOT35omDw3KQrJE2bZjkL1KnHHoPak8qO3jj+1uqxKWWZV4LNwQPw4q3FZLc6xKFSWRF CsoDY
- OQMkfjWMpJNyvp/X/DlyqR5ZtbW62t8iC2gWztZvLlXDSDG7kIM/dPuc1IkD2m37UrRKuUX HH
- llzwp9TzmrLyTSI8kVsLcv87JKAeW/wAqrdPJLFbMpKxiMhQ/PQg5J7moUpSevU56L9rZuS+/X
- 8Cf7Ozz7YLWTzI28oyqfl+7yD7mqkRuo4438yCRVfy1Qx8jP3c+46Vqgzi3muTIj+ZcRCEJkD5
- vv GqMscxcwW0ihg7mUMOcr0b6YqYSvo/67jptynaMk4+jf37laeLyQyI4WdnVdwOAo6c/rUA0
- y4i85 WaQbztVi2dw6k/iKvQE3ulNmCSVVKMrqcE8/MaiS7mGozrOTNDIjSEIMEkdMegx2rZTm
- rpbo7ozq Rva116O/oUPs4SwJa7+Zf9WpY/dbGPy71bK7J4Ty6hWLMvTrzgemOahnWcCye3tnf
- NswDkZUqOS1 U542ihMjrO6OC0bK3BXHJ+nNbL37XZMqilDl5rX+/wDr5sjks5pXZopPtKMzOr
- gnDYHXH8qdHI9x BE9xDIwYKY0HDFQCvX6jNakcEuz5EYuAxZU4w6DqPbB6VizvNPALiRkK5+V
- QMfe44HpWkJ8+hzrF KpL2bkkl1t+hLdrE0KTCQSo8m3CDB3jgjNV0g3Swkz/ZoIn+TzTn3I46
- 1O1iPs0UUbG4Kk/u4j1Y d+fqaLi0uHtT5YMaxseDzn2+vWqjNWtcwniIygqTavfe35X/AMiuL
- hXuAtsY2LuVBA/vf4U2C6lI j8sgAsIxIB8qgDGCO5680ItrHC8QBtwASsjHOM4Kr9evNWrGyj
- lbcZTtD8p6MDwfpVycFF3NfaNQ 5ai28v1X5DgJFjztnkYErFznCdDn396tpLJBA8UMLvMW3gz
- DcQoHQ5qK7uHjupzg5QADacAZxkfU 1YH2x3zEgUSKWBZQSRngg+lYPVJtHp048y/eR9P+CTW0
- EM16I5CVjZMh84z6H86sTWtpbtFIJBvc Mixn19RU9pmCzcyJ5qtKpDKMDnpj2zU9pbia5ka4j
- eSdZWjQrwCG7j8a451WpN30RksdPn3tFeZk zRpMyhgrMgCqFGCSe31NXZL6S28mMK0jKmGbGf
- nJwAPxrRm02Y7txjd02tIVXGHXv9AKqm2hudWM UW5pnTzPMB+VgP4gPQVKqwktdUjrlWpVI81
- rpev47GHJHLFdRRGJjPuQOvXJB5xVk2c02p3ASFt7 KxQnG1VHAB/2vepp7aC0lWaSVrgbGUFW
- Odx561RS4aTTokjMkchAA+bnqSB9Sa6VJyV4jdWd1Ui/ d762+epbRUs57VrieDdsTdEEz8vfP
- GCcmnTQi41ZxERIFDLtTghgPlJqtOjTSkwxMZD80pc5wcdB 6Ac09LmS0YbZo92xhG2zIKEcE+
- p9DU8r3T1MKlNuo3Tl7z7pfp/w5UY3K6mGwnnN8gAHD5HJA+lM jliil2eVKu1AG3Nna3UH6Yq
- x51vdTxp5UodTuUbuSMZx+GKkmhs3tMxuRcdSO20jn8a15ukkOU5y k1Ui1fTRbeen+RDc3iJZ
- GKGJ+CAHJ4Y5BBH61XV/tF+ZpnEbSTq5XpuIHb25rQZbmeyt7cW+1oNm G2g7jnr9AKkkt2zcy
- xR+WwugVLDIIyDkD0qVOMVbqcjrRgnSirX6tpsx21CeW5DSf6yJiqggYB71 dSe2/dyyyxqyw7
- XQpkk5zmqxgAvJzc8tvdnRMA885+grNG+S5hXckbBfmLDIJA4rf2cJLTQ6bUql J+7ZrdpL+vw
- L8TrPG0Drl2OVA4JA5Jo2xRi2nZ8jawk2HGGbpQbq9itIJnktg5AaMiP7w6Ht26U0 XX7udftF
- uIjKMKU5Y9iOOgotLpt/Xkct51ZabLzf+RUhkZ7MEB5WyUGD09Sa1I7MJZlrtm2jIV0O AVHp9
- ayVuGxIpZWywyUUAY7/AJ1YUf6JiIuxchvLJyVA9a0qRl3sdjhUkoqU7Ly/z/zNK3hdM3lv NC
- ZMHam3JB9PxFTW5mgjt2ifM7DzdrcjaB6fic0yIwQwyzSMZY1cIAhwSSOopJopblLVkhkjkfIV
- G/hHQ5/KuSTu7PY5/rMNFVel7cz6+T7/AHISRJG1aNrcLOUh/gTAI9f6VZtPPMcwA8mMPnEi5K
- sT 8o+lRx2csEqtuI2KY5FHUknIqUlRqIkWZdskbloyeUkI+UGlOSasjqrYihO/IunUn8yS2Fs
- yAp5p ZjuGdozyv5c1WLESsIreGWJUzCSgO6MdxUMBEdujt5kxdWaQ7uBnsPTPQVnyTQTsdknl
- RHIRSclT 12mnCldnDh6bi25W16/5dTQjnjS4FzBhY5QPLtx944OAfp61HPLPa6vKZWZlBOEU4
- yFB5HsDUEf7 /TlkEDkruNuV4BXPzH8Kvubf7T81ldSQ5Oz58kjGetNpKW1ylzNuqo8yenToZk
- UsTWcc9xA7KVGw bsZQkhsH61dk8w3RNqgM2/bGW+ZSmPmIz0xUxgmeximghA3qC6FchAT0Hpn
- FUp3jmjurgJJaywS7 FRm6Z6jiqupPQJSjNJX1/BeqILgo1iXk/eStKu0A+oxn8ayt8q3MeJAk
- gUlQy5zjtirZgjjVNkoX zAGG9uFAOMdPWmG1zPJErRuUb75PTHUE/jXVT5YrUUYqnCUZNL5Mz
- 1MIYdWjcMfLXqp7Akj1pzl4 ZA/kOwlLID2wBy35mmvCFViZELpLtG3ocDn8jTVd0aFVheT5jG
- zZ+VN/c/rXRvqjhqVJpKcZOy/L yJUQ/Yo8FW3qSCRnft7j2qq8saxwqoUOWGWLZBHcYx1z3q9
- NZ7JlC/NalSY3B68/41SCPLKCBGSG wTjH3qcHF63NbOajbWz0av8A0x6/O0qugc4ypjGMD3+l
- DxvGIjMhQtH8rFcbu+fyqZVtzZxjLJNu IJJ9OQPxp6Ry3d38zGQHhlA55HUdhjApc3XoTJTfv
- 2vr13/P8Rm+CaUptjcMDtIOADQLFwltIYpj bv8AOzL/ABKBjC5HXNacOnI2jwSlUS4MZCgLgv
- zjP51cnsljs7iGOQmXzAJEz3HXA7D2rnliYp2R nXxftmlJ2/B/hb9TFuFs57dGjhmh/egRl2z
- lO7H1HHFOhsd90ZXSVLZZNwJbjHXn1rQa5RHiLGJ0 KFgu3O0d1+tI8dv9reQXqfO5KoScBSKX
- tJJW/wCCebWhKEeVrfrvf08zDW5EN48kCrKgOYxt9uvT pVJGuJGUpbyM5UgFF+9z1+ldBLZkP
- Ir4uZGbgQqFAwuRj+tZkQkWBJchZVRQcd92cY/KumE4tNoq MqfMuV2b7oozrKh8uNjt6MMdPp
- 6VDGlyp/1eSTlsIBgVceS6nkWOIM+xdhxHyO/Jx1zTSLhYla4i kjITauR2Oc5Hc1upWVnYqUq
- LqK7s+lnp8hjpiIGbzfMB4Yfdx9MVnRlkTaxWQGTPyjG0Y5H16VMV
- ZpLZVl3hEJOfXng+tTh59q/6tgyA/d6ZrRaIz5FUlfVee5//2Q==
-X-ABShowAs:COMPANY
-UID:F0A6918D-8E09-43FA-9684-226810B8A96F
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/F0A6918D-8E09-43FA-9684-226810B8A96F.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/F0A6918D-8E09-43FA-9684-226810B8A96F.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/F0A6918D-8E09-43FA-9684-226810B8A96F.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/F0A6918D-8E09-43FA-9684-226810B8A96F.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,2010 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Inc.;Test;;;
+FN:Test Inc.
+ORG:Test Inc.;
+EMAIL;type=INTERNET;type=WORK;type=pref:testinc_sf at example.com
+TEL;type=WORK;type=pref:777-777-7777
+item1.ADR;type=WORK;type=pref:;;3 TV Street;San Francisco;California;99999;US
+item1.X-ABADR:us
+NOTE: Company with picture
+PHOTO;BASE64:
+ /9j/4AAQSkZJRgABAQAAAQABAAD/7QA8UGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAB8cAVoAAx
+ sl RxwCAAACAAIcAhkAC1Bob3RvIEJvb3RoAP/iG6hJQ0NfUFJPRklMRQABAQAAG5hhcHBsAgA
+ AAG1u dHJSR0IgWFlaIAfaAAEAEwAJADEABGFjc3BBUFBMAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAD2 1gABAAAAANMtYXBwbFYcEOZVYuhIRg5LwLIi62wAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAA AAAAEXJYWVoAAAFQAAAAFGdYWVoAAAFkAAAAFGJYWVoAAAF4AAAAFHd0cHQAAA
+ GMAAAAFGNoYWQA AAGgAAAALHJUUkMAAAHMAAAIDGdUUkMAAAnYAAAIDGJUUkMAABHkAAAIDGF
+ hcmcAABnwAAAAIGFh Z2cAABoQAAAAIGFhYmcAABowAAAAIHZjZ3QAABpQAAAAMG5kaW4AABqA
+ AAAAOGRlc2MAABq4AAAA ZGRzY20AABscAAAALm1tb2QAABtMAAAAKGNwcnQAABt0AAAAJFhZW
+ iAAAAAAAAB7vQAAQXsAAAJL WFlaIAAAAAAAAFYqAACp0AAAFF9YWVogAAAAAAAAJO8AABS1AA
+ C8glhZWiAAAAAAAADz2AABAAAA ARYIc2YzMgAAAAAAAQu3AAAFlv//81cAAAcpAAD91///+7f
+ ///2mAAAD2gAAwPZjdXJ2AAAAAAAA BAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUA
+ SgBPAFQAWQBeAGMAaABtAHIAdwB8AIEA hgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0
+ ADVANoA4ADlAOoA8AD1APsBAQEHAQwBEgEY AR4BJQErATEBOAE+AUUBSwFSAVkBYAFmAW0BdQ
+ F8AYMBigGSAZkBoQGoAbABuAHAAcgB0AHYAeAB 6QHxAfoCAgILAhQCHAIlAi4CNwJAAkoCUwJ
+ cAmYCcAJ5AoMCjQKXAqECqwK1Ar8CygLUAt8C6gL0 Av8DCgMVAyADKwM3A0IDTQNZA2UDcAN8
+ A4gDlAOgA6wDuQPFA9ID3gPrA/gEBAQRBB4ELAQ5BEYE VARhBG8EfASKBJgEpgS0BMIE0QTfB
+ O4E/AULBRoFKAU3BUcFVgVlBXQFhAWTBaMFswXDBdMF4wXz BgMGFAYkBjUGRQZWBmcGeAaJBp
+ oGqwa9Bs4G4AbyBwMHFQcnBzkHTAdeB3AHgweWB6gHuwfOB+EH 9AgICBsILwhCCFYIagh+CJI
+ Ipgi6CM4I4wj3CQwJIQk2CUsJYAl1CYoJoAm1CcsJ4An2CgwKIgo5 Ck8KZQp8CpIKqQrACtcK
+ 7gsFCx0LNAtLC2MLewuTC6sLwwvbC/MMDAwkDD0MVgxuDIcMoQy6DNMM 7Q0GDSANOg1UDW4Ni
+ A2iDbwN1w3xDgwOJw5CDl0OeA6TDq8Oyg7mDwIPHg86D1YPcg+OD6sPyA/k EAEQHhA7EFgQdh
+ CTELEQzhDsEQoRKBFGEWQRgxGhEcAR3xH+Eh0SPBJbEnoSmhK5EtkS+RMZEzkT WRN6E5oTuxP
+ bE/wUHRQ+FF8UgRSiFMQU5RUHFSkVSxVtFZAVshXVFfcWGhY9FmAWgxanFsoW7hcS FzUXWRd9
+ F6IXxhfqGA8YNBhZGH0YoxjIGO0ZExk4GV4ZhBmqGdAZ9hodGkMaahqQGrca3hsGGy0b VBt8G
+ 6MbyxvzHBscQxxsHJQcvRzmHQ4dNx1gHYodsx3dHgYeMB5aHoQerh7YHwMfLR9YH4Mfrh/Z IA
+ QgMCBbIIcgsyDeIQohNyFjIY8hvCHpIhUiQiJwIp0iyiL4IyUjUyOBI68j3SQMJDokaSSXJMYk
+ 9SUkJVQlgyWzJeImEiZCJnImoybTJwMnNCdlJ5Ynxyf4KCooWyiNKL4o8CkiKVUphym5KewqHy
+ pS KoUquCrrKx4rUiuGK7or7iwiLFYsiiy/LPQtKS1eLZMtyC39LjMuaS6eLtQvCy9BL3cvri/
+ kMBsw UjCJMMEw+DEwMWcxnzHXMg8ySDKAMrgy8TMqM2MznDPVNA80SDSCNLw09jUwNWo1pTXf
+ Nho2VTaQ Nss3BjdCN343uTf1ODE4bTiqOOY5IzlgOZ052joXOlQ6kjrPOw07SzuJO8c8BjxEP
+ IM8wj0BPUA9 fz2/Pf4+Pj5+Pr4+/j8/P38/wEAAQEFAgkDEQQVBR0GIQcpCDEJOQpFC00MWQ1
+ hDm0PeRCFEZUSo ROxFMEV0RbhF/EZARoVGykcOR1NHmUfeSCNIaUivSPVJO0mBScdKDkpVSpt
+ K4ksqS3FLuEwATEhM kEzYTSBNaE2xTfpOQk6MTtVPHk9nT7FP+1BFUI9Q2VEkUW5RuVIEUk9S
+ mlLlUzFTfFPIVBRUYFSt VPlVRlWSVd9WLFZ6VsdXFFdiV7BX/lhMWJpY6Vk4WYZZ1VokWnRaw
+ 1sTW2NbslwDXFNco1z0XURd lV3mXjdeiV7aXyxffl/QYCJgdGDHYRlhbGG/YhJiZWK5YwxjYG
+ O0ZAhkXGSxZQVlWmWvZgRmWWav ZwRnWmewaAZoXGiyaQlpX2m2ag1qZGq8axNra2vDbBtsc2z
+ LbSNtfG3Vbi5uh27gbzpvk2/tcEdw oXD7cVZxsHILcmZywXMcc3hz03QvdIt053VDdaB1/HZZ
+ drZ3E3dwd854K3iJeOd5RXmjegJ6YHq/ ex57fXvcfDx8m3z7fVt9u34bfnx+3H89f55//4Bgg
+ MKBI4GFgeeCSYKrgw6DcIPThDaEmYT8hWCF w4YnhouG74dUh7iIHYiBiOaJTImxihaKfIrii0
+ iLrowUjHuM4o1Ija+OF45+juWPTY+1kB2QhZDu kVaRv5IokpGS+pNkk82UN5ShlQuVdZXglkq
+ WtZcgl4uX95himM6ZOpmmmhKafprrm1ebxJwxnJ+d DJ15neeeVZ7DnzGfoKAPoH2g7KFbocui
+ OqKqoxqjiqP6pGqk26VMpbymLqafpxCngqf0qGWo2KlK qbyqL6qiqxWriKv7rG+s461WrcuuP
+ 66zryivnbARsIew/LFxseeyXbLTs0mzv7Q2tK21JLWbthK2 ibcBt3m38bhpuOG5WrnSuku6xL
+ s+u7e8MLyqvSS9nr4ZvpO/Dr+JwATAf8D6wXbB8cJtwunDZsPi xF/E3MVZxdbGU8bRx07HzMh
+ KyMnJR8nGykXKxMtDy8LMQszBzUHNwc5CzsLPQ8/D0ETQxtFH0cjS StLM007T0NRT1NbVWNXb
+ 1l7W4tdl1+nYbdjx2XXZ+tp/2wPbiNwO3JPdGd2e3iTeqt8x37fgPuDF 4Uzh0+Ja4uLjauPy5
+ HrlAuWL5hPmnOcl56/oOOjC6Uzp1upg6urrdev/7IrtFu2h7izuuO9E79Dw XPDp8XXyAvKP8x
+ zzqvQ39MX1U/Xh9m/2/veM+Bv4qvk5+cn6Wfro+3j8CPyZ/Sn9uv5L/tz/bmN1 cnYAAAAAAAA
+ EAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0A cgB3AHwA
+ gQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2gDgAOUA6gDwAPUA+wEB AQcBD
+ AESARgBHgElASsBMQE4AT4BRQFLAVIBWQFgAWYBbQF1AXwBgwGKAZIBmQGhAagBsAG4AcAB yA
+ HQAdgB4AHpAfEB+gICAgsCFAIcAiUCLgI3AkACSgJTAlwCZgJwAnkCgwKNApcCoQKrArUCvwLK
+ AtQC3wLqAvQC/wMKAxUDIAMrAzcDQgNNA1kDZQNwA3wDiAOUA6ADrAO5A8UD0gPeA+sD+AQEBB
+ EE HgQsBDkERgRUBGEEbwR8BIoEmASmBLQEwgTRBN8E7gT8BQsFGgUoBTcFRwVWBWUFdAWEBZM
+ FowWz BcMF0wXjBfMGAwYUBiQGNQZFBlYGZwZ4BokGmgarBr0GzgbgBvIHAwcVBycHOQdMB14H
+ cAeDB5YH qAe7B84H4Qf0CAgIGwgvCEIIVghqCH4IkgimCLoIzgjjCPcJDAkhCTYJSwlgCXUJi
+ gmgCbUJywng CfYKDAoiCjkKTwplCnwKkgqpCsAK1wruCwULHQs0C0sLYwt7C5MLqwvDC9sL8w
+ wMDCQMPQxWDG4M hwyhDLoM0wztDQYNIA06DVQNbg2IDaINvA3XDfEODA4nDkIOXQ54DpMOrw7
+ KDuYPAg8eDzoPVg9y D44Pqw/ID+QQARAeEDsQWBB2EJMQsRDOEOwRChEoEUYRZBGDEaERwBHf
+ Ef4SHRI8ElsSehKaErkS 2RL5ExkTORNZE3oTmhO7E9sT/BQdFD4UXxSBFKIUxBTlFQcVKRVLF
+ W0VkBWyFdUV9xYaFj0WYBaD FqcWyhbuFxIXNRdZF30XohfGF+oYDxg0GFkYfRijGMgY7RkTGT
+ gZXhmEGaoZ0Bn2Gh0aQxpqGpAa txreGwYbLRtUG3wboxvLG/McGxxDHGwclBy9HOYdDh03HWA
+ dih2zHd0eBh4wHloehB6uHtgfAx8t H1gfgx+uH9kgBCAwIFsghyCzIN4hCiE3IWMhjyG8Ieki
+ FSJCInAinSLKIvgjJSNTI4EjryPdJAwk OiRpJJckxiT1JSQlVCWDJbMl4iYSJkImciajJtMnA
+ yc0J2UnlifHJ/goKihbKI0ovijwKSIpVSmH Kbkp7CofKlIqhSq4KusrHitSK4YruivuLCIsVi
+ yKLL8s9C0pLV4tky3ILf0uMy5pLp4u1C8LL0Ev dy+uL+QwGzBSMIkwwTD4MTAxZzGfMdcyDzJ
+ IMoAyuDLxMyozYzOcM9U0DzRINII0vDT2NTA1ajWl Nd82GjZVNpA2yzcGN0I3fje5N/U4MTht
+ OKo45jkjOWA5nTnaOhc6VDqSOs87DTtLO4k7xzwGPEQ8 gzzCPQE9QD1/Pb89/j4+Pn4+vj7+P
+ z8/fz/AQABAQUCCQMRBBUFHQYhBykIMQk5CkULTQxZDWEOb Q95EIURlRKhE7EUwRXRFuEX8Rk
+ BGhUbKRw5HU0eZR95II0hpSK9I9Uk7SYFJx0oOSlVKm0riSypL cUu4TABMSEyQTNhNIE1oTbF
+ N+k5CToxO1U8eT2dPsU/7UEVQj1DZUSRRblG5UgRST1KaUuVTMVN8 U8hUFFRgVK1U+VVGVZJV
+ 31YsVnpWx1cUV2JXsFf+WExYmljpWThZhlnVWiRadFrDWxNbY1uyXANc U1yjXPRdRF2VXeZeN
+ 16JXtpfLF9+X9BgImB0YMdhGWFsYb9iEmJlYrljDGNgY7RkCGRcZLFlBWVa Za9mBGZZZq9nBG
+ daZ7BoBmhcaLJpCWlfabZqDWpkarxrE2tra8NsG2xzbMttI218bdVuLm6HbuBv Om+Tb+1wR3C
+ hcPtxVnGwcgtyZnLBcxxzeHPTdC90i3TndUN1oHX8dll2tncTd3B3zngreIl453lF eaN6Anpg
+ er97Hnt9e9x8PHybfPt9W327fht+fH7cfz1/nn//gGCAwoEjgYWB54JJgquDDoNwg9OE NoSZh
+ PyFYIXDhieGi4bvh1SHuIgdiIGI5olMibGKFop8iuKLSIuujBSMe4zijUiNr44Xjn6O5Y9N j7
+ WQHZCFkO6RVpG/kiiSkZL6k2STzZQ3lKGVC5V1leCWSpa1lyCXi5f3mGKYzpk6maaaEpp+muub
+ V5vEnDGcn50MnXmd555VnsOfMZ+goA+gfaDsoVuhy6I6oqqjGqOKo/qkaqTbpUylvKYupp+nEK
+ eC p/SoZajYqUqpvKovqqKrFauIq/usb6zjrVaty64/rrOvKK+dsBGwh7D8sXGx57JdstOzSbO
+ /tDa0 rbUktZu2EraJtwG3ebfxuGm44blaudK6S7rEuz67t7wwvKq9JL2evhm+k78Ov4nABMB/
+ wPrBdsHx wm3C6cNmw+LEX8TcxVnF1sZTxtHHTsfMyErIyclHycbKRcrEy0PLwsxCzMHNQc3Bz
+ kLOws9Dz8PQ RNDG0UfRyNJK0szTTtPQ1FPU1tVY1dvWXtbi12XX6dht2PHZddn62n/bA9uI3A
+ 7ck90Z3Z7eJN6q 3zHft+A+4MXhTOHT4lri4uNq4/LkeuUC5YvmE+ac5yXnr+g46MLpTOnW6mD
+ q6ut16//siu0W7aHu LO6470Tv0PBc8OnxdfIC8o/zHPOq9Df0xfVT9eH2b/b+94z4G/iq+Tn5
+ yfpZ+uj7ePwI/Jn9Kf26 /kv+3P9uY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAoAC0AM
+ gA3ADsAQABFAEoATwBUAFkA XgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAKQAqQCuALIAtw
+ C8AMEAxgDLANAA1QDaAOAA5QDq APAA9QD7AQEBBwEMARIBGAEeASUBKwExATgBPgFFAUsBUgF
+ ZAWABZgFtAXUBfAGDAYoBkgGZAaEB qAGwAbgBwAHIAdAB2AHgAekB8QH6AgICCwIUAhwCJQIu
+ AjcCQAJKAlMCXAJmAnACeQKDAo0ClwKh AqsCtQK/AsoC1ALfAuoC9AL/AwoDFQMgAysDNwNCA
+ 00DWQNlA3ADfAOIA5QDoAOsA7kDxQPSA94D 6wP4BAQEEQQeBCwEOQRGBFQEYQRvBHwEigSYBK
+ YEtATCBNEE3wTuBPwFCwUaBSgFNwVHBVYFZQV0 BYQFkwWjBbMFwwXTBeMF8wYDBhQGJAY1BkU
+ GVgZnBngGiQaaBqsGvQbOBuAG8gcDBxUHJwc5B0wH XgdwB4MHlgeoB7sHzgfhB/QICAgbCC8I
+ QghWCGoIfgiSCKYIugjOCOMI9wkMCSEJNglLCWAJdQmK CaAJtQnLCeAJ9goMCiIKOQpPCmUKf
+ AqSCqkKwArXCu4LBQsdCzQLSwtjC3sLkwurC8ML2wvzDAwM JAw9DFYMbgyHDKEMugzTDO0NBg
+ 0gDToNVA1uDYgNog28DdcN8Q4MDicOQg5dDngOkw6vDsoO5g8C Dx4POg9WD3IPjg+rD8gP5BA
+ BEB4QOxBYEHYQkxCxEM4Q7BEKESgRRhFkEYMRoRHAEd8R/hIdEjwS WxJ6EpoSuRLZEvkTGRM5
+ E1kTehOaE7sT2xP8FB0UPhRfFIEUohTEFOUVBxUpFUsVbRWQFbIV1RX3 FhoWPRZgFoMWpxbKF
+ u4XEhc1F1kXfReiF8YX6hgPGDQYWRh9GKMYyBjtGRMZOBleGYQZqhnQGfYa HRpDGmoakBq3Gt
+ 4bBhstG1QbfBujG8sb8xwbHEMcbByUHL0c5h0OHTcdYB2KHbMd3R4GHjAeWh6E Hq4e2B8DHy0
+ fWB+DH64f2SAEIDAgWyCHILMg3iEKITchYyGPIbwh6SIVIkIicCKdIsoi+CMlI1Mj gSOvI90k
+ DCQ6JGkklyTGJPUlJCVUJYMlsyXiJhImQiZyJqMm0ycDJzQnZSeWJ8cn+CgqKFsojSi+ KPApI
+ ilVKYcpuSnsKh8qUiqFKrgq6yseK1Irhiu6K+4sIixWLIosvyz0LSktXi2TLcgt/S4zLmku ni
+ 7ULwsvQS93L64v5DAbMFIwiTDBMPgxMDFnMZ8x1zIPMkgygDK4MvEzKjNjM5wz1TQPNEg0gjS8
+ NPY1MDVqNaU13zYaNlU2kDbLNwY3Qjd+N7k39TgxOG04qjjmOSM5YDmdOdo6FzpUOpI6zzsNO0
+ s7 iTvHPAY8RDyDPMI9AT1APX89vz3+Pj4+fj6+Pv4/Pz9/P8BAAEBBQIJAxEEFQUdBiEHKQgx
+ CTkKR QtNDFkNYQ5tD3kQhRGVEqETsRTBFdEW4RfxGQEaFRspHDkdTR5lH3kgjSGlIr0j1STtJ
+ gUnHSg5K VUqbSuJLKktxS7hMAExITJBM2E0gTWhNsU36TkJOjE7VTx5PZ0+xT/tQRVCPUNlRJ
+ FFuUblSBFJP UppS5VMxU3xTyFQUVGBUrVT5VUZVklXfVixWelbHVxRXYlewV/5YTFiaWOlZOF
+ mGWdVaJFp0WsNb E1tjW7JcA1xTXKNc9F1EXZVd5l43Xole2l8sX35f0GAiYHRgx2EZYWxhv2I
+ SYmViuWMMY2BjtGQI ZFxksWUFZVplr2YEZllmr2cEZ1pnsGgGaFxosmkJaV9ptmoNamRqvGsT
+ a2trw2wbbHNsy20jbXxt 1W4ubodu4G86b5Nv7XBHcKFw+3FWcbByC3JmcsFzHHN4c9N0L3SLd
+ Od1Q3Wgdfx2WXa2dxN3cHfO eCt4iXjneUV5o3oCemB6v3see3173Hw8fJt8+31bfbt+G358ft
+ x/PX+ef/+AYIDCgSOBhYHngkmC q4MOg3CD04Q2hJmE/IVghcOGJ4aLhu+HVIe4iB2IgYjmiUy
+ JsYoWinyK4otIi66MFIx7jOKNSI2v jheOfo7lj02PtZAdkIWQ7pFWkb+SKJKRkvqTZJPNlDeU
+ oZULlXWV4JZKlrWXIJeLl/eYYpjOmTqZ ppoSmn6a65tXm8ScMZyfnQydeZ3nnlWew58xn6CgD
+ 6B9oOyhW6HLojqiqqMao4qj+qRqpNulTKW8 pi6mn6cQp4Kn9KhlqNipSqm8qi+qoqsVq4ir+6
+ xvrOOtVq3Lrj+us68or52wEbCHsPyxcbHnsl2y 07NJs7+0NrSttSS1m7YStom3Abd5t/G4abj
+ huVq50rpLusS7Pru3vDC8qr0kvZ6+Gb6Tvw6/icAE wH/A+sF2wfHCbcLpw2bD4sRfxNzFWcXW
+ xlPG0cdOx8zISsjJyUfJxspFysTLQ8vCzELMwc1BzcHO Qs7Cz0PPw9BE0MbRR9HI0krSzNNO0
+ 9DUU9TW1VjV29Ze1uLXZdfp2G3Y8dl12fraf9sD24jcDtyT 3Rndnt4k3qrfMd+34D7gxeFM4d
+ PiWuLi42rj8uR65QLli+YT5pznJeev6DjowulM6dbqYOrq63Xr /+yK7Rbtoe4s7rjvRO/Q8Fz
+ w6fF18gLyj/Mc86r0N/TF9VP14fZv9v73jPgb+Kr5OfnJ+ln66Pt4 /Aj8mf0p/br+S/7c/25w
+ YXJhAAAAAAADAAAAAmZmAADypwAADVkAABPQAAALA3BhcmEAAAAAAAMA AAACZmYAAPKnAAANW
+ QAAE9AAAAsDcGFyYQAAAAAAAwAAAAJmZgAA8qcAAA1ZAAAT0AAACwN2Y2d0 AAAAAAAAAAEAAQ
+ AAAAAAAAABAAAAAQAAAAAAAAABAAAAAQAAAAAAAAABAABuZGluAAAAAAAAADAA AKPAAABXwAA
+ ASsAAAJ5AAAAlQAAAEwAAAFBAAABUQAACMzMAAjMzAAIzM2Rlc2MAAAAAAAAACkNp bmVtYSBI
+ RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAABIAAAAc AE
+ MAaQBuAGUAbQBhACAASABEAABtbW9kAAAAAAAABhAAAJIjAgAqqcBCT4AAAAAAAAAAAAAAAAAA
+ AAAAdGV4dAAAAABDb3B5cmlnaHQgQXBwbGUsIEluYy4sIDIwMTAA/+EAQEV4aWYAAE1NACoAAA
+ AI AAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAAoCgAwAEAAAAAQAAAeAAAAAA/9sAQwA
+ CAgIC AgECAgICAgICAwMGBAMDAwMHBQUEBggHCAgIBwgICQoNCwkJDAoICAsPCwwNDg4ODgkL
+ EBEPDhEN Dg4O/9sAQwECAgIDAwMGBAQGDgkICQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4OD
+ g4ODg4ODg4O Dg4ODg4ODg4ODg4ODg4O/8AAEQgB4AKAAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQ
+ EBAAAAAAAAAAAB AgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhN
+ RYQcicRQygZGhCCNC scEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RV
+ VldYWVpjZGVmZ2hpanN0 dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4u
+ brCw8TFxsfIycrS09TV1tfY 2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQ
+ EAAAAAAAABAgMEBQYHCAkKC//E ALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXE
+ TIjKBCBRCkaGxwQkjM1LwFWJy0QoW JDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZX
+ WFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWG h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5u
+ sLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp 6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A/Ie6uZ
+ LZoIYXSSFWZhjkgn1NZS7Y4I4yQS5woHUnP+Na MsLq7qIXfaMN22nrTWmbzIWeOMzBmckLxk+
+ gr8+hZLRH9Z18KqM3KhBK/wB339SvFbQrNGluD50T ESbj96QHjHHT29qeG3hT5bIQ/QnoQc5+
+ lLayrFJuBUqSWb1PsD606OJriMIiFwpLZA6nv9aqTd9T PDQlBuNlyteX5l3yTvExmWMFjGjbS
+ wORknionheOeFHDNHHGVyvBIPpke9SWrJJp7XJjdCj7QrHI DdTx79qhfe8yF43TswJ556CsVe
+ 7TOujOMk5T1b2a0/4P4knkhYYpX+WM5wpPLDtiro+S2AEqMpcP tJ5OOPTjipZGtBYxwLcKzxK
+ FZjkhjnkj0A6VXnaFEa3KjeAfmLHll5OPwrJSctzahOM1zTXlr26f 0hk8iCYCVGcRqVBU4ySe
+ vTp2pYrkRWwhijf/AFo+Y/wDqc+vNVgPtE8QY5LMNuOy46/gakjAdfOa VDGSRu7buw/OrcY2s
+ zOc6DlyzfL2/r/gFuaWzkib93I85kZyScDnv+lRbBFYi6iuVE44ZCvKhuo+ tU3SYNC/lERwhV
+ nXbycnOKfI5iu1yI2Z3JAK5XCn0pKFtEzCbpxg47rzas/LYfbWtotvHbxyOpLk M3ufT8KhY2q
+ zpGqzOrEklTyxHA7dKgaaJpt5+RnLeWoHOewq8lqy6bFNNxuAxn+PP8Q9hVyvF+89 yeWMZKHM
+ 9dkun43IzEtveq8b5IXdDIP4hjmlDKvlvETvRQoOPXmmTpDC6qsglOSAy5wABn9al8pX 2BiI/
+ l3Kw/rS0aTZ2wjGcWra9dOnn1J2kkmuVeY7nmYvImMY/uipmVv7QYbvNlOQcDA9DT2SBZys gE
+ gLsQ2/G4AduDVgNbLIk+/y1VVDRHJZuOSD+VYOVtkd9GEqauruJUt3QXscZieVHbaXQ42rj5jU
+ gtiqQBra4WJUZt2RwW/+tUhVTEv2dgiIjIzH+Jc/zzUKwSN8gcyHesZBORuOTxSb1vsTWu5c83
+ Ze fT0CK2NytuFOCAoYMOpJOP5VVuYLeLWY4nR/JbkgnlsjqPbNaEUUn9pBY5Nq43ynHCsoPFU
+ mE11J GDJHLM5CxqUx26dKqMnzb6HHUjJVZRcvdtuPsZrpLee7eMwCOQ7kdeST0I9qqJMG0Z1U
+ Au0gOQeB k/NT4nJmW3uGZU34I6cY6n2FVot88oQwi3UDa7MOhxnn61ooq7bOCNOFObdR6rrbd
+ FrdNDFJCu4h ZMwZHQdzUxluC5ijmiETHccjOCKbaW1ybR2mjwu7y3DDLKx6CoYU3/ZpJy0aJE
+ yOgX5icnBz071L 5Xc7FHC1YP2cb37atefYltoZbefa0sKJJnJwTkZ+lOhSe1v7a4BDRupywXj
+ nI2/U0yGTyFikJVZj 91X+br+FaG95VjXI/wBWcpj/AD9aU+a77M6amAnUklF+71v0+5Ic+nH7
+ RB5S/Zl+64kOTHxwD79a 6OGOKz0xGRxFLCqou/n5S2effr+dV0s2uAkCy+fEBucr958D7wPoK
+ fLJcqvmQ2zpmUK5lAYFuAhH tjPFeXVqOpaNzzZJSfspPZ+Vv839xZuLO2llZyfMZzJsVTggdS
+ D796ykkjjihZIZVlaMbGJ4bDcM B6ZrQeeSO2l+0OivDdFXkC4BYentg9Kz/wB297AY3zuG2Ln
+ gj2+nWlSUuXXYKUavspKb93p2fr0L Cwtc6oZWmj+3RAxt8vBPVjiqAkjltpc3cCJJIX2Eck5+
+ U5rcmtjLB5UkkeXk3l4/lOPT61j29hbq zxoj4VsBmbIUkH5frmnTnFq7exyuLk71Hr2026a/8
+ Ay/7PimJlW4WUcg7ONp7VlH7WI0AiIWJGXd jtnk/rWtdpcNNbm3QwTR4S6VunqPyNVru5JulJ
+ ZZHYnzggwGbjkDsK9KlOXr+hrTryvda22XbzMq 4tJmuEKkxwqWXLdx1p/2SNba0eeUwPKDIwY
+ ZJIJAIx2qaRNt8n2hxIkjE7o+MnNSfZX+feduyXY5 bqpPQfSt3UdlqOqubXn19PyK8kCKiyS3
+ MbTkEjjAb1xSwRSecs0Ubl0BGBztLcc1ry2dssrm7R2O wl1XA2noO3bvToVaDT51j8uSZ5Rhg
+ Oox1+lZe393+rDlUUYuPK5X6tW+/cyhCfICSyxxXG7ALZww xx09ahgjK2oiDrEHO9lYcjjH8h
+ V0Q3Hn7Agk3bXDAds4yKlubf8As+/iJQXAZHVW7Nxww9uf0q/a K9r6nXSjTU4xb5uy/rVGZHA
+ Yrf7xYMwKsBxjHI+tWHUNbKwR/KVgScEjd9alhVo7dI5M+Wq8ZH+e tRT53feI3HLIBgLVczcj
+ veHlBLmh+bFgsYLeKMl8ySSZCg8px1NSwzz2lzHInD71/h9P/r0yN3ku HVG3SEEhcdcelVgGG
+ wZYZOWbr+P0FJxcr8zuYuh7kqcndPtbT5WNGa7+03Jk2vnYRIw6Z6k1qxXl ta2kA2s/7pmyD9
+ 0HsfcnpXNWl00drJtVJfMcktjtjFSi6aRSoYDAC4C84/8ArVnPD306Iy9gqqip ydlt/wAAvLe
+ 2UlpHbLBLaOxG/wAxs/vAeD9KoXN5IU8yUhJ5Zw7nH3iARx+lN2ESxCSaPC8hthO7 3HGe2Kpm
+ G4nMD3JO4hmjAGMDkf0rSFKCdzjlhnKahZv1/r8CHYgiKMwUkbhk+nUVYxJcQqszIRt+ cKOuD
+ nj6YFPjhdrYZXcqMAOmcH39KU2zGVUE0RILK3BwR3IOOlbOSNZS5VZp66WV/wAfIqBQqBYZ Bh
+ cgMeg3dqgjU21itvHIAryF5UIyRxgc47DmtGG3fjy9jKcn7oIB/KoVhgMNtGyuk4Y5JP3ge9Vz
+ o4sRgnzRm4Wts1/wxLGyyBlk3Pt3AFeAw/hxUi3ziwt1kGXRtkQAxlfX8DVUKxjjEP7xdwDYHQ
+ DP tShVLlQ4TnKp/Fn/AA71DhF7lV6PtUnNv1/y2LNy141xG926uWRmygxnnBNRW8+9nTzRCjF
+ d4cZy vfFSSTb512QuVOflYA5AHHQVGro+2d1j2wZAAQAMzDAz6ikl7trDqKcafs6b/wDbX92o
+ 15GMwC4E THAyONo6dqRY7aOSBo4pZCrBmAPQjmm7oxb2ykFZo1KsWOQ2TRE4K7MFFZwVJ64HX
+ 86trQmUE4Wd /nv+RHOZGYhV3KuD7nnINJCwi/5dJ0yCSSQce9OdpQ2duOPm/OpCkbuzM7uEHB
+ U8PV30sdqT9ro3 fzt+bRRfyxlllUlgMYHfpUaOzop5aUZ3Nnj2GKsSqYn8wxOQBlRxxjHP51U
+ SR1kDKm4nOSBxn/Jr WOqPKrt+2tK6S7X1JXvGjgCyfvS45UDsTTPs6i7kiRAPLyrHOee/8qHT
+ McYuYsbV5IH3v88U64ig Z90TlCARjPfvmmrLYhqrUfNUs1HZPf7yqi+ZIFOYgSCM85wDVyNFL
+ EBxtHK5bt6VT8lpJ1VXwcjy lOeR9anWSObISKUuQRtUe9VPUww1aCk1PRrXV7r8iUw70kYXCg
+ LtzgdyOn1qtHGk1mJVnHmqzOR7 4HFNDq4fZG9uORhzktgf/rqHygVRh+6KtxnvTjF9zPFS9q0
+ 4bLXrr95LGt9IV/eRKVBLHb0TuPr1 qw1zI4kXzV2bsKSOoqKNlAPy/KxYg+uOMVZtI2kMqYjG
+ Yy4LDjCg1M2lq0Vh7r3ud2e+rexBHKWU +XukPm7sg8DHb+daUkMbM2Uk4J8rLDG09KywrySwF
+ nS3TPI2/eXv071LFvGNisMhiwkOfWlKPZmt CX71Jpv8n8tSREkS2FvwIgwLE8jpx/M08WpQEx
+ sWIX5lU4NNijaWBsFiv8BA68frWgIklbyw5UMh ZnXtjms5TsddGjR9nJvRLs9eu1inLKGg/eb
+ ywA4H5imvPMTkElWAx8vbuakVf3JlVMZkAOQG6DIP Paoo3Kyp5hcbpRuKgfdOeOnftQrEzxk1
+ Fzd7eW5RnEk9wjZSELgNuHOMVLC72+/5FkweWHY4/wDr 1OYraR5GxK64BHPTsM/lVa6WMzliG
+ A6nB6mt4yTtFo5VGUE6yer8/wDgWR0NzDKtzEqGRwpwxwQP XB9+aHTY0KSJISI/lAx8oOTz61
+ El6r7Y2lDGVioYEgA+/HepfJDSKiv5jlQWYnjODwP89q4NVa57 6rQdTmVtfWy+8diFLfeqhxt
+ 4PbJ6dqVHk8uOFoyjpG5XaMFgOpqv5DmGN5oXiMZ5wcZ9PypIJriJ ot77pIQyL8vr1BoautCa
+ 1adRrkitNr7E7TPBB5UaFsKAXA+UKcEk/wAs1I6tPcbIgCXOTg8rjnB/ lVRblJIiSRgHaDnrU
+ sckksJkASEliNpGTgd6ORo3pQp83uy37L+vzNK9juJIBcT2wjhdyVUIARk8 /liqUELXNwsfll
+ XIZyS2dzf0yMUhlaS4WNlYnJ3dunNX4ZYvPE/ktHvJJZSAuPb2rF3hGxzV5+x0 STfSysvu/wC
+ CQ+ZNBIj20QjVkztdQSTjBwfQVloI5ImcYIU4JU4y3Y1cG1PKywnjdt5APLYP6CnG ONt6b4kQ
+ kyBVXb8x4A6dquNkVSpxcuZQWu7/AK1M+B7q2X7KXzFJMWm3c845Ge3FTsXi1AGNcsSf LDYJV
+ MdD7+9TvZPDLEZhmZVcMo6Agf8A16bYgjLNLF9oKBF3rwQepH04FW5Ra5kccYJNuO3boIUk vg
+ w8qFHV1KsqAYAXrVwPc/ZYkkClPLPlnbxyen1yMCoRtW6RpWAZNygKcZLcDPtV8xxxXgidyypG
+ RIQM4bnGOOnNYyltobYOnL23M1a22jbX5FORrpWe2WEcnJURgsoC884qSK2d4kkDAITsBJ/i7D
+ 8a sl7gRIU2RKdqNLt5Ax606dY0+0I86zmObKmMYDLtwMD1zUc72R6MvbRqfu1pfXTX9EPSxii
+ nME4k bGWV93+qA+8G9TUc5R4cpaMkZbdvzznHH4e1SmeGWO3ktzMJlUocnOSRj9RmhIJjLbxB
+ dmEypccL z0ask3e8maU1Je/zX8u3ys/1JnNx9ntwyxw7oecxjghsntUgKyXKvPewIjOXGFwdw
+ 6HgdKinmSRp VEbInneZuJ3bTjGD7e1Z7/Z4SHjDuq4G1m5G7t9RSjDmW1mbVKEpU/fVn3snp5
+ XW/wAydFE9/JK8 6Rxl9sjZwCSDg1lMpjjQEPxyDu5HpV2DdLbPabdpVvMXPXj1PeoI2228hIP
+ mAEdM7hnlvoK6IaNn LOkpTbe9vNW83p1IFKjzGZwjhsktzk/lW5pywSwj7QQ+3fFIqcHcT1/C
+ qyfYjGY8CSUuQX7NjnOK nfLmJ1gKOYZDKqjq5Pt+FZVpc6tax5uIpyxElGKs++zGuzCaexBMo
+ 3bQUGOR3oWKI2DCPDO21pSf +WbZIx9O9VYYdluJhKHCuoZQTknB4q99me60yN4X8yRVyFQYJX
+ uT64pStHqei6c6XKtEu67+Y2K3 SV900tuAgYhiv3wDgMParM9my2SzC6tXULtXYuCecfzqtBD
+ G9ypuIplZZQqIMDcCM+noK6KOH7Pe Szq8XltIpEbrnC45H171jWquL0ZvUquDvGV/u1/yKMMN
+ 1azxMtzFG03zcj7pBxt/HNasst4yCBQj G3baAF5YZBP49QKrTOJHjYSRbURgeOpIzkfSnhkaz
+ WWK5V5JkJi6/dHGT9O9cc25WbX4f10OOpyy kpVlr3tp82tSW6EE1v5e8O+M+XnlvmyxPuBUds
+ PL1k3gh3RIAsW0Arz/APXNR2k8rt5DRb5UnOJV XCuCOCPbrSztLZeW/mqwRHUccHBBB/Wps17
+ ncy9rzxdBR+L8fQS5upbbUSkzoyIQ2AuCxX0P1I/K oIpDqdvcTMjIyEoqx4G8sfvfnUpSwYXT
+ zzK1usoUEtk54IGf50lxcSWz+dCY3G2RWVEwMn+orRJa KK17luMI1oRowfP+H4GVqG+P7RF5i
+ J5LxhmP8TYBPP61nS8Xlw8ULOfMbew5HzDqPQA0s7b4YYQD vjTLHOS/vVgRTNHZKh+0bY9s3l
+ 9ixyM/hXfFckVcqvGVGznBJ32X6/8ABK1rYx3tpGEbLNCzKpOS WBxke1MeEQrFGRLGshP2jzD
+ nJ42kelalvttryDzJY8GIlAo25HO7FVkjEbRyRMXAUlt3OHHQUe1k 5Pt/X9epxc85y5VK3a2m
+ vqI00bM0cwIDL5cbt/c759TnnNZCRrMojMpEqNjcCQCfUe2BXRefI1rF LNZ8gFHZkADMeePSs
+ xLfc6K1tIZBtDhBggnOCaqlOyf+ZrSUuTnlt6poIQLQh4tw3gsm9s47gfh/ Wm/apLlvNkgkmX
+ cF+X+DIwR+Oafd2c8W+JQxij27mPc4zkegqrHPcJeBomBmfd8qLxnHp0+lXFKS 5luUuRw56du
+ bv/W3yBpm8+EzJHt2FQMY3EAqPyphWNre1aMOx2ESknOSOc1OJw6mLCTwsrNlV+YB R1B7DOfy
+ qmsrSBBEqqWLKBjO4AcmtYp+h00qsZSUpOz+eo1EM0wliO11IfIHXB/lVpHS8nkkZ0Tc TuCr0
+ P5YxTJBHFEoCSxuQAVJ7cEGpfswM7bWUBHCsw4BJ5z9M0SaeprSgm+ZRs+uln+oxRmLyYzH Fu
+ kHUckjsPwqeSJ7edQI0CliXjIBZCOACa0bW1hlTzDFIH8wsqhumDwPzp32JZHmVRJGWcNIHfJB
+ 6msHWXNqW051GmtF0M1YVmslQQyi6DYBByOegxVEFTkfPmMlFDHpnk1uJauLjz7aGZoSGaIk9N
+ 3A ye+Kz1GYAtrt2jmZ25GeRx6Zq4VEOKjBpL/N/wDAI4EaZZUWGRwSASDwuPWldpRegSRxwsm
+ UbKjO WGM8DoK0vLZ77yYysUjvsUjox/x60kihYZI2ZfNaUm3BGS6fxNn8OM1HtE2YVKkZ1OS/
+ 5XXmRyxM LY28c9lIkRysoj+9gc9u5rF8qdbjdMgZt2WCDGwZ5B44NakqolqwKywxcmFnPLEe/
+ pUDKqR2srF2 Mineu7lZBxg/zq6bsvU56kacIr3t9NLfjYqrLBDc4kXaG37EHHTpmnW5865hia
+ AEODkouCCRgc1M scTQOrgxyrMIzvGSCTyfpTolKSPFGrozNuScnC7VB56d6ttWfc5+Sm4Nyf3
+ 30/ryC0+zlhBNG5Ql dpDfMAMhuf1qGe0iacFAUhZG8s5zkL/F9DVqRoRLbuCJ0jiKDbxtPO4H
+ jqM06O2As0kadCVUDC9W UAk49OtSp2fN3KhGEZqb+F6aa39Oxm29qGuIlwFG3fhurY6D8aI7J
+ pLnzImSBgzbUc5IHbPFXGtT PbJNbF5WwPlXkg4yf0qncvvKJCSY+gI6kdQa1UnJ6MJ041Obkf
+ y/4BXFv5bKHky8ZJAYE8f3SO5N SYkjjjWMKu6PIUg5FSwzCGaS5kiWYyHaoZchgeC34UnS+cS
+ MDHl48hcDbj7w9hVOTvqHtYU3JxVn bp/V/uZlssghVJ2EkpUkOnAx6fhVeWWTciIhcZ+bA6L3
+ q7HdvLAZEaEBSYz8mcj/AOvUjwB7IzGS N5A4UxgEELjmujm5X7yOOUeaFqcnZ9df+D97KE8v7
+ xkSVX3NtVj0bHpVULJAuwsMMTnIzmtjykct EHhyFLA7euBn9azpYj5ce4kblDDn3q6c1sY14O
+ Tb3a+RXkaeZoyVyBzlONoz/iKcYZ3BPCHO4np3 qd/JiLhldweFC1Ahjhk2K2/erKMnP860Um1
+ ojlqUlGTcndvfX7ug2VIphGGkMuwll2tjk9c+tW4Y vMhYBh8rZJBz26VF9mSLT7Zt8UiHPCDB
+ B9+KWCJxs8ncAPv5PXmlKScdGRg1FyUuT1SJDGHk2ylU VQNuxeTnmlW12tF98jblSPTPf8asG
+ Jhcuj7mKnBKjgelapvJpLe3VPs6rtZB+7+9g5z+PQVzzqyV rHdOmlUXu3bfUznjUlhOhV1lCK
+ i8E8ZOP0pZ7URyLHcDEinDkZGD17dulaNtaRbC9zOvLqSmfmQ5 7n+dTXEMPnrsdxIzl1aTlWQ
+ cbunTNYe3tKxq5e+1O935afO/+Rl7pgv7t4oI1m+8yjAY9R0qREba 77CpmkZlz2Vei/nQ00Vt
+ cFFT7SN3Ddsdc89aspELmWLadiJueUsPXgKPc05O2ttDGWHSrKpb3eun 5ozZo7iWaMzZQyP5g
+ TGOvf6VApVQxjjJ3Nkkjg4PUe1aSxzpOjeW6FZdnzgHB9KrbUQsSDGM/Ip5 IBJ4rSMtLG1ClD
+ mfs3p8tBDG+2TEbRHuOuDUE1tsQCSJsYLo2efx9avWscb2SyPMytliw9QOg/Go 3s5nijZSXVQ
+ Bx2B6/lTjNX3DmpV1zKO3Vr8hwsxa+Vb+X+82szHHUjn+Rp0Mkf7sCKWTcAF57k1X GJCsiyyP
+ s4Bzzk9/oKuRguD55VG88YKJtAU8Htg84pS2u2drxCov91H3enW3qKuILh4Rwwcx4zn5 h0P0N
+ QxnbCfOkCS+crDKkhgBgnilkSWOTZhWfqWxwcUwHfPE0iYc/KBjoewI9am10XK7ilzbbdEP Eb
+ GPcDCEX73y+/H86mDBbxVSSFWdiqq6574xVJFLkAKyEA8N3NXI4h9kb7s2clW9MUS03NFzTg4x
+ W6/rqh8cjtG9w4GwuwXjsOM/nU0RcwDJUoGAQkcKCOatgFLTyDENzMNy4yBn+Hp1NQPH5byBV8
+ r5 tzK3X0ArDmudOFjiPdVTp16/cCRqVaQSBpY1JxtwB+GKZEF+/JltykjAAq7bxKw2yRSO2AZ
+ Npxnn oKkEcflwq1tOjMhYjd0yeD9MVDnZtFRTjUd2/XS/5lCJNojdMMPLLEZJyc4x+NaElnY7
+ baMLKrYK ctyG6kfWrUdvBJNFMFEEEbEAuf8AWcHDD29qYGFsSdyNKiqN7cq2T6euM81hKq5PQ
+ 83EU6lad4dO 2n5f8Eo2FgzXzbwBhfmLj7uc8mrcFrHHO8UiSuyx7Btb7xIJ3fnV9JSzXaxMqq
+ kvljIyWUnAOfal jkt5r3EkcskuDsZeA+DgYqJ1ptts7E6nvSinGy/pt6fmOtDbRrHHbwvPcOo
+ ZyxDBCvVSPXrReQKs LxxWbKJvmQ8bmAOBzWeUul1W3iWCSVcsrNEMc9zn2PH4VoPcXtldW7yR
+ 73+ZYlP8Kkc5+hNZSi1J OLu35nL7KSq88Xd+r/zKB0+G3+zuZ/tEkUg3JESCdpyT9Of0qS4Fx
+ cWqzzI8aJuO9OA+48H6cUye bz7iLYzCRR5hC85Zf6Y6itOSLzdPee4BVS22NAcAh8H+daSk4u
+ LluelSw0qVSFSUU9db7/cY6yKt oDNBKT5jBwpALcDJ6fSniNGkSD7K6xjO1jjI6ZJ9eKrJbTT
+ 3CRKQZmIyp/vdMfXirNxHMk1qof5j HLKMevdffgVrKydk9R4vmg1FSu797WMmRoortpEDBVOI
+ wW556Zx1pbaB5YHlkkjk8qUZSMYJGMkV YkkQwruiGXG5D/snGPxFaGnxOlmZBEZ0dyx2d/X+l
+ aTqcsLnHWnKa5pRtfTff8SvC/kyLIjQxM8L ja65xnv/ACqJpWlhkBjZrltgG09Ox/E1It2SYL
+ nckDueY2XJBAwOx4rQlhkklmR0E4wG8yEAfdAI 9KycuV3aNVUSp891213/ACV/vJVkijS4Rts
+ eydMggHqMUxYxa3H+onit5MpG5bgg9R+dUrBZL9Vj YeQxYtM7/wARwSD+VbxtLifTEjVPMR8y
+ Y7gcEL9a5qjVOVm/U8+M6cJW773/ADRAwu54t62xT5i3 QZQ4wAfc4qQXrLoO+6s5VYS8oxG7A
+ x8307U4JJHDClw/Mo3SFeNhB4U+5pt0Ymt7m4hhuEkBIdZH zsyRgfXqax0k0rdTohCNRwUYvf
+ 0/G4ly9u9wXhjeZH3bERudoNZNoXN0yMjOoDMqqcFV6gfh39a0 rnU7FLOaILvZ5FYMnGD6fTi
+ qktyHnit3j3ZDI+zAPJBz9Pat6Sko2sd1KVRx9+DS23ennb/hgmvF GqfbIZ0MbfKoU8Zx0qe3
+ gi8pmuvNmRGCvl/uE8bT7nrWWI0lnWHymOWEhKnA+XI4+tSwec8zR78v PiWRD1Vl6fpWkoaWT
+ tb+v8yMRTlVk9bNL00JLmSG3ln8sLHtZYyj/N1HX61SuHAiSOJZkaNsYds4 9j645zTZZJZZ5G
+ nCrlt2x1+9kcEVIyxy2cM4LjHE565Yenpwa1jHlSudCp8yi5X8rf0iO3hCSs15 kxE8Opxux6H
+ 0qe3ke10+OdyJY2I+WM4O7ORz9K2ATdQRgWrS2rRF1IwNgHG0++ax3hmMiCZY7WIE Id4OMseP
+ xrNVOdvmOJ0/aybqvRb69P8APuMuLiV5YTcSQGRZnkwkeCORgVblZ5ba6khXlZywKL6j PT86W
+ C2tlupYZ7232wvtEjKTuBBzViDy7ZYonu4XiaEMyDruGcc/SpnKK+FbeXzMXRo0rcsL211T e/
+ 3GNMjzW65L2ylvMBckggYGPrzmrVvZpuVJXklaQMAyn7/Pyke1PuLW4khgRTstjbGQOwzu29cf
+ jUTXoSM3USZZcRkHoCw4I/WtOaTjaLIqxqxpr2Oj9dCdhZxRSW4eUMXVWd2yNxXg/QY6Vlrata
+ Sx BicSvlZB1QKCcH3NLJK0izxFMSkneCOm3p+OKrO0kiS+Y7NGzq+M9DjitadOSW5UcLNpcrs
+ 3vcWd 43uifOjiHllAuMdV9h602PdbWFsgik2BS27HO4n1pscoLtsWN15Xdtz+PIqaKCN5UVhI
+ wPLKD0Pr 9K2doqzOicFTiqmjXp/X3jVndoyskamQ42uUyWXByRx0FXQ7xg7fuugVNycMT3Hqa
+ q2bBp4w8Duw RxheORyD9ParttNvKbpYoV4Rd4zgnms6mmyN4zVKm1ZW31T/ACLtttggZQDdN5
+ 5QtGcYHGPxp9xD Ld3riNDahGJZnPQAdD75/nVRkQ5kil+RZCWjz8xx1/Si2uJWlLgtHbysXO8
+ 5JA4PNc3K78y3HRjF XlGV/v8AwRfSW4tYFkKfIZFj24+4CCSakCRQvLJK8NwrcKsa7cjsaZNe
+ faLVXe3fyVdsHONw29fz xinWcMQS28yeOFBGpbzed3JJxWT+G70NVFSpubXrotV2Wl7kE8UbJ
+ bhJogxYs3tjk/jWbc4F0rvE YoJmYoSM4A6jNaE0LER3EAZvNHmtJwVB3YwKzpXnN1biVlABBG
+ 5eAGPP61vR8mKlF04t0no/v/D/ AIJbmu3jVRHGkkboz/MARzxx6VmWYW1uobggSxpzIeoLNxj
+ nvin3EKeepEu7HIweOPb0J7VJHujt Y55SBM6syIF4PbOOnrWiilCy6nFiMDCUbKHxfL7+q9SO
+ Wa3MyKqM8bI24Dgk5+XJ9afBbO8byS3N vACQ4BzlgDxj27VJbi0EEZO5H+z7SDnJPI3Z9Paqp
+ aWRkhDBV+X5m7EDHp/nNUr7LQinQai7tqK7 q/5ofPIkjj5GQzHz3YdAewwB0pkJuJJGtzJGq4
+ BGV64BPHFX/IWXUCZImjhcuzRg4aIgYwT7dadH BFbtaTupEUkBIlBOOuMn6modSKjYxq1MOo8
+ kdX0/q1yhNPch42lUQu43rsXbjPGeO2KS1ma21pXV YbhWOxiEGD2B56cVchghclppGjBIUM2T
+ 8g+8PqT0qNp7Z2eFYtkLHzowPvDH8JPfvT5k04pDqqMq UowpuzWr2+6+7KbkLem3FuyKXH2dm
+ wcIMk/XNMktLq5d5ZlW3t5SSHcYAHccVoMsFzcREsyokLBC OPlJ6/zqt9octDGq4VY2UFjkMS
+ fl4qoyl0WpwRoVXdKNlbqv6X5lX7DbWV1Bu8uRWi37kHynAOeK ijkY2ashtk3MA6NHkn1q2Fm
+ iKPcwbT9x+ANue5+nFUp9n2sx+YGXcQJVGAcDrW0W5PV3G8LHnfJK +nay/wAiG4jS0uh5DLNb
+ fOiPjPbIyfxqmsiGHe0bsVAR+RgN+XpV0pF9iRFjYmRAyHcBwCQfx460 x4UVy4CoAwkwec4re
+ LVrMKeGrqnZO6XyRXeGH96RMGBm2x4GT04H4/0qiI4hp7+aU84TqyHB+YYw fpg1dVF8yFzllQ
+ ZIHBPOalMa/ahmFmLI+fqe9aqbiclfB1JQbntHW/f16fkZkRCiIRE7Sh68jrkm pLZJJt0bzxx
+ sCWBI4Ix0+uasMR5sEMZSJCn7xmHK56j86cUnhvCjLG4VsEoNvaqlK5goR9ooRbT8 l/wdSdXl
+ +x7/ACnhm37SsmDle/Hr05q7bWjFyTE/l5Ii56joaqWMc00u1tsKLJ8zscgAjgfU461t W1xFH
+ YC3jVpy25vLJ+YZGOD7d64603HRHXepCCs25d30XfyEFxPbrFAPIjiKjLvHuJ/rUy3EYhlL we
+ cUxGj5wFwM7envmp5tPmexEm1vPQLCseMlivVvpioV024W4khCPKMBl29/b6/4Vyc1KSvc7I08
+ O6ammpd9bfcKytNZmRbeABJAOIxl1xlselI1tcNpweOHKSMXJUY2gfdB+lVIrm9hlPAYFhlNvc
+ 5A q0t3cnfD5oCGZcE9MHjP0puM47WMJYerSkpU0rLXr+WpmzWrRXcQEgO+RSVHJJA61DIWm8r
+ DRhWT Ifb05/xq/cLAmqrcCYqYZwqjOQwYcEVmxb0CJcIxw20qDgqBnNdMJNq50Rr1IzlHldml
+ stf8iqlr FHbDe0jyIxKhScEHv+FXbVCjw3QYtFHG3G772Ov86r2sbyPCkTAOww5c8dTz06dK0
+ ZbWQsIVt5pG SIquw8A9wfU1pVnrZsxn7Hk5NEuqf+ZmrFiRY4AQuCXyMnHer0i5ulitz54ky4
+ CjJUYzg+pqOWZ0 fypRFHKVwy7cFjknjHTjFTo0wthdTR+fHIefKAU+gYH0HpUyk9zor15U2nH
+ 7v+B/lYosS37wMVXh T6564qxPsnufM3BXaQnZ0wVGcj2qEmN5dkYMg35ZwcA46HFXkgWRSYla
+ 6lYCTKDhSeCKJStZm8W5 JSk7K+t9iASpHeCbiXcCxwf4j0q3b/Z4woLuWYlXRV5z6gkYxUyQw
+ vMYGi8s7dysewHU1ONOhawt Z3k8xtzPiPgt789qwnUhszSdoVUotpvt/nqWRa+fdokaSGFYjt
+ bPLvjg5qt5ZXTp5HurdyZAsigZ bd+XFaC+ZFe2rElIS2+MZ67Rjd9PWqmTc3DbEAj3h5ZgPkL
+ Lnbx79K5oyd/I6ZVZqs/eVl2/zf6E cBuIzEBC5lAV3XuoU5z+VaNwGup3nWeJpGLNEEGPkBya
+ maZPtab2Te4cttX/AFfy8qfx6VWkDTab GwuIpHjiSIBE27cnv7mo5uaSdrDoRU5+05Xrpqrp/
+ gkMjgDOkiSQ4Me5sDoD2qBZp4oZETyywkCb SgY8DIrVYWK3lxHuMKCQLhj904x+XWksYrO3WQ
+ efHclGyNvYYPB9z2pOro21+BWKxk+b3o38mv8A gfqVI5pDf77qaKOLyysi7QCWYZA4HXOKhUb
+ bS3EJRpFQqx287geRn8aFjtpLfaI5nkfawTdkrg42 n3pLdZf7Ut4A8QdnLkEfcGeVPvWmiuwl
+ WjD95JWXbYm868ljg25LoqeWijBbrg+/vVeYyXFgZpLh ZJEm3LjPzgDqPYGtGa5kN3tAS3ihl
+ LAleYgBwGPfJ6VWia3lkaNgBdyzeai4yBx93HvUxl1t/X9f 1sc8KylO7gl/XdrYRbea8ZmXy3
+ dnDZVcZ9SPYirElpI9zPbDd8qlzluM8FcVXGousKskP2aRiFO4 cBTxVkCO1u7ppneVi4SMoSN
+ ydz+FJ86f5HpUZSbbS9F/W5Xulijt0Rfmnum83cp+6y9vx5xWWl4X hJBH+sznuOxH5VrXIdrp
+ BbxO8ZbIfr+I9KorOXhUpBHAoZ1eMqMtwMHOPXP5VrT+HVXJ9k5Plcb/ AC1CztlfUBEWKQ5Yu
+ SOVUcitezjlRdkcTxxSDc8h+7uHQj0HtVG2aOQB7iKSRiQp8ttuT2P09aZP PLatJahZfJLqW3
+ NnGPQ+45qailN8o8TRdWTj0SW9/wAFfX56Gnd21rCYhK0c7spYqnGQOSRUD2sR kSaKK4ZZUDC
+ MSc9CDz7danZ7K7WRo3y7ThQuecY6j0FRW0Zee1iZnclBllYjGScj8MVzxclHVs8h OolJp7fL
+ 8CS3keA28cKpKoUHIHbsf51pyTyXEf7wtFG0hwqfL9Bx6077IZ5GiVT5bEspXgsp7j2F Qm1Js
+ 4Wk3PCV2OQfXowz71zylCTv1Ob2dPmVRuz9LsqwRPE0Jud1urxMVaVsg7Tiq7yTTTIZZEb+ Jw
+ owCemPwrRFpKkCR3SSXHlSbZcHgDjP07VJcJFKyiGNvJBYNg8s7Hgj2q1VXNc6PauT1fz0sUpI
+ 55A0VrBBKBIfnMYO3GMZPr1ouLeQx3O+DzFSRQ5jUAn3FWU0poneRJZYvKVo5kLnl+uar2yoE8
+ wX gZ1QxyR5J3l+jD2FOM1unt5GuHc4vmUrpdtPxK0lvLJAq2s8AVVwqkfMFA3Ek49aaIJbiyt
+ naWJb jDKSOM7uc/0p8HnWt5aoJFCMuZWcZCODyD9c1anJniMUqCNDIxhIABJxx+FaOTTSHLm+
+ sR5tt7+v y1+8zLSwWUW0ckUjyNESvzdgTk/hU8kUK3EkYAjfysBmOVyR6Y6mrP2NURRcTlZUT
+ CsrEDb/ABVk 3apJFHIgZVX5QSc7we9aRk5y3PXwik5Pm1vtuv1sWDcPAYltn+7DtcY4ORnI+l
+ NWbzdQsjdobiIo wQJxuJHDfnVY5t7oeW3mqA4YnkEAVJFHvWLfLGSsY2Y4IXOf0rRwja4sRha
+ c73VvO2v4ECRRrbJE 0qK4ABDDnOSTz9KtzLasqeTnzZZPMXLZEZA4U/UZNO+zRuiXcJQxrPsc
+ MMnpgn6c1QjJ+1IwSSSJ GYqQCASM4Ge/pRfm1T2PMrynOFqU9F6flpcspLNLexwREh/LZEjbn
+ aoOTn8Kbv0+2tmWVtrSTAWw Y5JGM/j9e1UFb/SbabftZlLMcnII6A0x1aa4gLI1xDFExDKMYP
+ OOSK1dJXtfQxxmHnN8t/d06fkN 2oXSRkcjAJAOCRnnJqKYASptGwIpXkfe96crPJDEpI2rEck
+ d25xUs7eYib0L74wcJ25/xrdaPU9K Eabp2m7P+vuIkSXzG2hQ23cPlGOnIx71YRg0EnnREfON
+ p9BjoapwFn8xmjliZSVYk9M9varMtzMU ghVMrIQM7fTvRJO5FoJxqJadO463kmiYTKECsD8+w
+ cHHAzSfafNtcCFWllbexAA2npxTB5scLjIK LJ6ZAB/rV5/tEVuDFFEsYLbiEHBGOPxrOVr3tq
+ czd6ilKKTv94uniJtTEbqYxjBU9TgZzmtWJpks 7dBp8kplXOQAAOTuFUreS8lkTbAJG8t1d1j
+ 6hhwfwrW+zXIs83TMYfKby9nBU4wM1x15Lm1NK8m6 nv2T7f8ADMryNO8u0252LuCxgcsRgKfp
+ mqLzyS3G4oowAJAR1Oecela0XkLHZKI7g3MSYK7+SoPJ /DrU8ULTSIoSMwYZiwXnIGefr1FZq
+ rGO6NIYunST54fozPupC2kSrJEYsTD92ODnr+AHpVCKVDcX TmLzYyQc+4GanlYOiuFJCKeG5z
+ u/nVeSRvs7wFfLEeA7Yxg4zg/lW1OK5bHTD2UIJOOj316FdTHM lu9wdptlAQKMbwxOSfpVe4l
+ ZnUGUbI49qjHJGeoojbzwH6yMhby06jB5/TmmxTxSFYpo82zOozxu Az1z2HrXWo2bfY5Jyo0V
+ KUE35ak0MkeZGby92Rg7Rhh3A9OKc8quXkSEDzNpiCjHA4z/AJ71TeOb MqymPMbkbQMZIPX9a
+ lku3jRFhhA6bTjI2j72KXJd3RxpSlH2jTafT/h/+CSyXRQb5YpYpJZc89Gy MMfoKcbSeQJbxu
+ ziJBGnPDLn7w9qh27L6QIfOCEomRn6Ef55q2i3l9GSWX92WVSo2gk84NQ/d1Wh MKMoPm0Ue/b
+ 5Fh4YVtnt1kEjeb5ipnJAHUZ/Ws6QK1zFDAylI0ZY36A7j+vpTUed7UxbWWRCAMDJ I60p+zyw
+ l1byWMi+XlumSTj9KcYuO7uEYypx7t7Pt52H2kUlsJUkBjSRWBLDow4xn8c1DOY5LKxi t4XZ1
+ ADuOpOcA59K0CZLQyCQNcoTuGOrMRyR7Cq0lvC0DCJiZkZUCdd64+99KUZXldhGc5zip6Jd tV
+ 8yocbRJMs7gMyStv43nv8AhxxTbiS0MUdtFGTKmUZ853txjAxViaAWdvGVYOrSkgEcYA6H3Pr7
+ VVaO6BVjEwkLgYAAJYd/yrWDT1uc1OKac29Lvq7fdchMLiKQLbywFWKhJDk8nlen41XKFrtdrR
+ gv NhMjjZj+uKs36m4lS7WUu0U+0qODjHB/SqyRRC3hVgytt3Id3Pet4bXOaeGqV17OOke+uv3
+ lkJFA HABYNkgdwPSqIQP5aDckRXLORyuD3OKvgqLXauzcQPnY/mKpyJKbqWPOIweo6DvVQO+v
+ QlKiotNJ bWtcj/dHa3mLkqdpwPWljVVijaR2YFmO3dlgSO/HeqBNulvEqo0pYnc2cbD2zVm0W
+ JI3nfFwqnYN vTd1/lWso6XPKVeFSpF8vvL+t2vyL4hHzS+asfQOGH8eOFq7EBbiWRJbeVklVN
+ q53EdTjj8KoskE lmrBXjYjeGZ8hsHGcU44F0G3M4znA7DOT+Irnacla500ZTqQbk3u9NNf68j
+ X8uNrm3X7aUadZHjj YklPVT7miZpreFEX7REduSS2SrdMfX/Gkjeymvo/OkYbpDJE+cYHdavy
+ XFvLYi6f/SVdi8oQ4Ikz wPpjtXE5NSSauZ08RKNRRnG66K36r9SigvnhEks0LNJltnlgMdnHY
+ e9OvDNDfwybUysbKPl+7xgZ 9acLuSNoRAFGVPmbhnPzc49KbJEkt6R5NxHAJP3bl8/L0z78mm
+ rqV2tA53CV6isu3l6f5alEcm2R 4WaR4/nPoT0/HHSltZrWJth5ZiW8x+QrjOFP1ovnBZYY4mM
+ inAkLcEDio2mFuohlEZAY4UKNwKnl T7nsa3tzR9SMdVahZ3XlbX+vuIrOTa8dysTFEkCgD1OT
+ ileSG4VnzLFIzcgnqTx+n9arW81tLdLP skSLzGZ1EmQrngHoOgqKP9/CgK/Z1TO7J5fPQ+1bO
+ HvXegQU6tS8lq1pZrbz6GvFFE0cklyqtLIN 0WTycZyelJ9ilktoGIKLnCNuwqg9c/U9Kmjl+0
+ QPLJsklLYAjGAqkY6e3WplsPOYQxSbmbHlyk/I VHBPTPJrndSz1djtlXjOKU2k46/CvzKJtTb
+ XEiuMXCOscfHGW7EeuM0+FLWS/aRRKlsofG1iMEDG M/Wp4o5IL9YiDcoW2xrjlmAJU59qo+TM
+ kFukkBgm2sJMjAbrjA7VSfN1HQlKVXlet/67r9S1GzND HMCUeNAkasMkoc5PvV+2hU2tlFIk5
+ dly5D8dSQoB7kVnpHJJLBGIGeRY8bB/F74q9GYWvkdUaJwf vGQlcnoMY49qzqbaHozpTjsrSX
+ W9vvS1/M6GSa3ZYEdPs6eWzs7444+UD60RLCliZZQqhx80fcn/ AOuMmqFxcWElmu6XzH5ZlUH
+ tjFU2aP7P5zQXEbM52s8ny4A5HH1rz40W11Rw4ag5zV002/k/vZam J/syVxEAIpcwuy5BRgMA
+ +tTobUKGkCnJLOkfy+UQMBD6n0rLaVZpPMtnAkPDRMchmA+8B0wBUwu3 ijlNzBujdgVZV28Fc
+ YJ7n3rZ03ax2zg+XkW67Wu/vf5MkdZFtN0sahAVZWK8yEcbvoKczxPpbFxs Mh82EoNpKrwc46
+ 81nm+jMIhmk8mEYVA2SSepUH16VOpguppNolKgiNFB5j4+6feqdNpXaMnCjTs5 PVav+r7jUuT
+ au/kRlmLqised28ZJH17VCt5NOiReULhVkCymMYZjzjBxxU1zJbx2Qs4cxRRzhiXO 53wMBgfQ
+ dxT7SQwSCQxh4mV2aVFwsjAEAj0Har05XLl1CU5Onfk19df69BzXIZZo1jZAXy7NzgqM jP1qB
+ Im8tp/9ar4kV0HcenHQZxVa0ZLiNVtw80+zDqB1cHOfoB1+tXfsssUzfvY9oYOQM8LnJ/wp 2U
+ XY3w8ox0ST+X+T/Mkjltb54zJMsMxZvMkIyvboParvliaWVYVF6SwkRVHKY6g8d/xpdOtIbbz5
+ ZXgD7225HAPUDFWItQSI2/CSSzQ7n8lMFuTkj0xXLOer5NbG6dveUW/L/g7/AIg63LT75k+xwy
+ Rl 2yvbODiqKafFbS/eS6tG3eW45ywwRzirE+2GysRHdLcElxIxJPDHr9Paop1+zRQxSSC5hOW
+ ZI+CC Bwc9hSg3bTr+hVOcqkE1Gzbta35dn53K0QzayS3dpLbSSTCTOMDaOoAHTNOlNzNbQyIy
+ PG43QIEB cgHvxzj60599wYlKSsVQbjnjI54+ucVatoWbTVmhdbhxIFaBOGUnrjsBWkpKOrMMR
+ VVCC9o7u+z1 X/AK8QK5lcRw3KSqjnb8uepbA6VrQ2aILqe3LEzsZEJPRB1x+dY8KzxzRTMVtk
+ jUoWlGQ/PLf0rc VVluPLWZZ1IwFjODj1Ht2+tc9dtbM893jUdRS0W9rteny9RcC2tIlfzSzQg
+ xtuxgZ4H54zSuYRE4 a5T7SsgQJk4PGTx9avGWC0y8LKYdshIk+YrnGOvY9qzphfNBb3cDW8gl
+ iZjGIvmVhwQT61zQbk+x eHqutNRS18+v3iR284h81JCzyjzPmOcBf4ceuajSNXggmlmCOFDOq
+ 5G3JyeParP2KT7Ku6R3ZIvl CkjgY/nmrMkyqkkRCK+/93Ht+Ypx19ap1OxvKpUWy2/rzKSTxu
+ ZE/eujtlpFbhyTxj6in3NrIoI2 R28Q3I7sv3WYgKD9R0rWSSC2nkZ7JsKzonTGD/8AX4FVZp5
+ 005V8n55CDscAlNg7/Q4rJVG5LlRn GpUdRcqt266nPGG2+2tbtdKDCGjZiSdxwTuHsO9GZoYL
+ FXkRkcI8cuOFAznP1qY2sBtt5mElxMFk lAODnODj6iqk9vsD+W/+iLMIclskZ53fQV6EZKWlz
+ 2pRhJcs5aro1+Rblle5V1itnYvKF+U/dX+I fWmynT48JIjARM2Bu6jI5/Kp9rCSdzcRSQ+cpP
+ lcc9x7cVRP2qRxNtWGFV8phIuTkkkfj0qYJGbi pPlUvdXqtf68iu09ldmZYfkgDERjv07n271
+ Elq/2dZdwdfJ4IGBx1FaVvYQPq1pCwGDGQ+3gEjOT VieCW2t5Y2ddvBicD5dg6jHrWrrRTUYs
+ 3hiIUpKlT95rX7+3mYlnPHBJCBGZIirRsoP3i3THv/hU l40IsIoIyDtx0OOB/U1cRIDI00iNJ
+ iNgI4yFOOzfgOaoMIfsX7u2mXDKvmO2Qxz249KtNSnexk8P TlX5nF/kr+jf5FNba2k05RG0xu
+ dwZFBz8oOCKlKFbu48wbRvwUHGCeg4qyzrCiDyg6OCTEgAeNc9 z+tUrqGRYxKQ8WJQAGH3gRk
+ NxW0ZXerFRcIcyau+m/53/T5kSCORLYQ5FwM4GcjaOp/DmqbMHkjV B8zKc8Z3YJ5FW2VwyyKB
+ kjAK4AUNkEGpjCsZjVA4kH7tDj7pJ+nvWqkkzKOHkpTnzrRdX/V/Qpu7 CYrEpJbqCOMcYP161
+ IFltpxLFNCzLvAyM5HQnB9c1OHhkihtMjcCxMv949KiQPIYklgk2qjN8pAP HWlzdzk9tKpU5Z
+ K3l/w7/wAiXzJTakzwmNFHlxqy8kkZ59TVyWK4mhgkkyFiUqwTAJcjg/j/AEqu giaWykWG4eK
+ SBiPnz83IzWhYi4iEG2WMIsbb/MXIbGcEficVhUlZXQ4zStZXaelv+A2MSG4WKN5x IGfBGw4D
+ Kv3jQ7xxXwkVLs2bSfIXc4P9DzWtAwEdrJdyxSvEhiUJwDuHP+FMkmE2nLZxxH92/lbC MsnOS
+ T+Arm9q3LVBh8TUlV5asb33euxT8m8EE7tguW4bpgnqv5Vntc3ioVVWR3cbmBwMjgCtSFd+ po
+ QXVjbsyBjxgevqfeqS3EUC/ZmI3MQwc8jI6D861g99LnfKNvdSWnlb7xN1xPcKkieWrg+awXjd
+ nH4AVmY2xlZFke6kbEW3ptHUmthrgs82UYTuMMOMAngjFQyW8M0zRRxyRSLOq4c8qP7v145rSE
+ +X dWMKuIdLr+GnzM5FJtIdqsswT5COAVLYz/n1ojhjOnzRxyQNmTJGPmUjoM+laRithfOlncR
+ kM25N xztxzj+dOmFnHKZ12t03qhxlT/F+FP2t3oeXObcly/l/n0MiK2JlxIWZv+WhU981sQW8
+ P2gSCSOF 9sikOM4UEc/TNU4GtVeQRbxznc7E7mydmK0bS3lFqs8zxowOWVhzycE/QdxUV5vq7
+ GOMrVeXlba8 rb/mTRxQT2StIV8/cdxXjJPRh6DA6VjrC80aLbxyywuAyFT0Az19T1Oa3IQwin
+ id4UMMwiA2+vQ/ lUkUQtL53hdXBXb5S9ieN30A5rnjVcb2ObDV504Slzarvf8Ay0MKS1X7L5s
+ iSQlFKoCceav94e1M t4hJ5DRvEspiIbcuQG/h/Tiumh+0rai3eKOchRl9uQ2OGIHYYrJs5Ekl
+ VAUWOIFUbbjKnOOfXNaR rycX5FrFVZU27Nta3vp9zRHayTmBbe7CyMs6NtAAZB3BqvcOm+a43
+ KjSox2Y5ByBj8OtWTAQkW+K V2f5iVOMDoQffNZsVrdjWIZnhaCJUYnzOR0PP8q0hy3cjOlUVF
+ udt/Sz/r0K8xMcbxorg798xfnD EYIHp61EFWOWErKTcZIB7HsCMirdhaXV5BAgG1Sh3O4yCSe
+ /4VpNp8SXF2qIT5NxGQp6njgA9vet 3WjH3X/XQ7VXpezcUtd7Xute9+nkcrBbiaaG33GBXbd8
+ /Odp5z+tXbpITqNxJ8oCy4iRBjC4/pXQ XFoilfNjadt26UwjbtJ6AemaomLakl3JbneGO1Wx0
+ BwQfehYnmdzmwlV+2UpL0WhhNG8l7Dl0jjY cs4yvHJNOu8C4HlkbJAWDHoR2NaTWbSSy7djbC
+ qsRxyTxj6jis6a0uA9xGbeYMk4TaRkpz90+9bx qRb3Omo2q0pup8tLFK3tlkhjnLQywxkiTYu
+ OcVGJhEYkiURKPmCvzub8qsMpS6kjdNpUlWXbj5um KesYQrJNE02wFVAAwMD5gffmt+bW71PP
+ +r+z95Pmb/ruRxXM/wBsjlgMTMqlMFMqAe2PWrtmZBIz Twqux/njdASRjBqg6qpDoQGDYDKMA
+ jtx61VkeO4uEKzDOeSWzlhSdNS6EVKLnJzmkm/vN+Ke3MjP NaSiBcquGxtOOn40sU32p3jZfs
+ 3ntuDEfKpVTx+NY8UUwgdDcIq53iNsknHXt6UxvMW4jaKZDEWD lcenb61HsU27McY1FTk4r3v
+ np8n/AJGr5scqwzufvxElAcfN93P046U0eU1hFIrTLIpKMxYlQCM9 KpzRzSSlslNzl3UJjA74
+ 9BioxLGttNHvXLykxtnqOAKPZ3WhtWjJxip6d3/X+Qj+btj3FZFcH5mJ xxznp+FNQN9n2idEw
+ /mAMcnd9aTyn+VA6yMUJXC4GM/1p25IzIGUPwMAKMj1GfrW/Qv4qvLPX1e3 3f5j4lX7PIjsFI
+ +YHsVHJH1z3ptuPJkjmmYSRfdcDtnlQfrVYqk88Kq+QB7/AHh0H4014pXVCySh nYn7uACDiny
+ 30b3POxMruUYz+9/18jp3kWaQ/uQVlQunlrjgde3rWlayzskUslxAjMykJswSB6eg IqtLHHK9
+ vktE0RaMoAQV3cih0t0tmWfzEkldCDnG04PFeVPllGx6VdqtS5Ze75dfxJkETass0roY mV3XZ
+ kEgdKyrhrhdhIJBHO4Z5z2+uanlh8uKOMSNiFSu7P8AF1P+FQMJpLZJ4Y3eNADKSc4brW1N Ja
+ nqWi6XPUfvPRfIdsdpynmbHXKBCuSR3H1q9A1zBC2yIRr56nzZFyAx+6DkemaoiOfyY7mRQjOr
+ FVz8ynoM/XNWIA94nlSloZhIBMjnqQPvD09KKjutdjDFV6dSmrbLrq/vWxoTrDBDgx7xvZMgYK
+ rk bgff09qdJa2ksRgtGkdDKzJls5GB830ArLuiJSpy6w7Mx7j6kA5Pc1UlX/iYeTE2ZtxETBs
+ Ar+VZ wpNpPm1M40aipKftPhd/I27RYY7RRJeWse+YOx2+33fxFOknnmMETp9ms2jMmXTOecVi
+ JDGzhWmK oZBtAPL89R7dqvTSlNTkbdhHVwFbnZjjbSlSXNfcy9lBt8z5uv8Aw3n6oqIr5VmKM
+ ypuUFOw789a dHalfKMTu5MiuGTPK5wfxz3p4SP7AjXKSlAzKhVsZA4qRUCusdufs6Bm3PK2QC
+ P4a1c9NDrjiadS m7QSW1/6epYuZo2S980pNtIUYGCSTnIPYDGKyreIJeJCvmnLsGXd0P8A9f8
+ ApVhJlurdZLiLaytl BnGFB6H1Oe9OAtpNRaZo5WJjYqySEAnHXpSinFNWJWHrSpX5bX22X4bl
+ WNZliVJZ7dJI5mjGxMbg er8DnkY9a0Vim2F5C8sgmwdvRsr0/ACqkMP+grMkQniU4Y4ycn39j
+ WqlmWkRWDJIyu0gPQkHAYeg 5pVJpdTWhenFKUv1/KxtRW9td6OptldoU4J3ZJ29TUEbyS2Bhi
+ tDCrsCrsBlcD196itre7+zkNHJ FEiBNq8ZOcdvzPrU8kMcUbeRFchoWKySM+V3g+noc15+ibV
+ 76nbQahNJT5ne68isZ5Xs4RHCIwRg hhn5egPTtzUjqs9vEk+54oodsUsZxnnjOeuenNW72QDS
+ kSRV4DIrhQOMjp9c1T3I1hDE1vMdn7p1 U4KkHdz9P61UZXiml1PRjiYSoxaWrbX9aXJ2s3WGd
+ mmEN4swxGTzgDmmxTyfZ5P9GkRJJUYEcc9j 9Kie4me/kliUsJJo3IbkqT1X8RUV0MEpLDO1vG
+ +yMqSBg9BnoTSUW9JHn4mPM7TSdtbu1/0uWzbM YLVrhiiuT5ise+7GParwjtbeK8tkSa4/eM5
+ eJsFsEYCnqOKy7V76MbPIllPyZZuQmeD/AJ9auvDL l7dbG68hA2FVhv4Hc1lNO9mzyXRl7ZRb
+ 09bfk0XYY1kndyrWSzoWQXHzcD/OPxqxaTPPLLLG0TSM p3QquPLOMH/GqkTWsVis12ZI2mIZQ
+ 7Z2jGDj271E8lsmnLcRCSRVYKGRsbgep9655Rcm18v6/wCH NIRlJtX301S/Pf8AE25ZrhHjLy
+ ReSkflEeXyCRgkn071UgLSXiFZ7e42RnYyJ26H8T2qH5o79ZIp cIVLBJMtkqeP0Jq1CWMjfab
+ SZUT5AUO3JJ4P0HesuVRiarDuCklZ6b6L8P8AJkl5cTWkFvtMe2OB hEWGdxyMk+vXFZsswXT3
+ BYyTp/AD8xQnJb6DvWxcQkaYzNDJhm3BmPygAjcPxqjPeCYrHHCsscpY 741ALAfxA+nalRaaV
+ kOjOm1GSXXfb+vvI4HRdTu2u1WO389Qvy4OcZUZ9Kx3u72K/QosbGYlinlg hevBrVMv76DzZE
+ jQJudnHAboD+VdT4i8Q3/jHxZFf65FpkDWkEVsiWFqtuAiLtUMF6uepbvWvtHC fw3TWvy2sut
+ /U6pXpzc3FO6/q3Q5ZYYpkg3zxC5dAzBeFceoFRm6d52QGI4beFC9SOp/CiSTN3bC GeBh5Xyq
+ F+bAyM59M1lXE9wCkV7GHSSMuTF8pY9Mj29q1hTcnqKnH2tS1r+vT00RYvPtKRxRTKQX OfNQb
+ Qy9Tj9Kou58yYxszTAmXy2+bb/eHPGO9RwSzRs7NBJOGkOHHRQvWrEV3K6TsQsgKbnVUAJY 8D
+ nHT1FdcYOPY9DD0eXmcEml1/q41ne4t7jyImn2sE3x8A7un4cVUihvVgkjXC+SwCRtyWz/ABD2
+ FRJNtj2tIYycq2DjeR0I9u1NEi3VmrfaPNmGAMKRsAzkHjk1uoNLyM6vNLRNfd/X6DSN0kj7wF
+ En lgs2cf5FV/LfyJICSqGUMDJnjAOF+prWjb7bvgMPkOGErsehIHyjpxmobYeZdxy3qhJGd2Z
+ TwMBf T2NV7Syd+hhXxajG01drorFQrAzRqqSR7o2KKxyeT096favJaR2+4qrYZmMq5Bx/Dj19
+ 6cwEssrN Iql3jKEcAEjoPSrMk0T2MisFndZMsmOVPcZ/CiTurWuY1o3tTjC73+/8DOMwMTK6R
+ 75QpUouGDZ6 UjtAjHG4uEIY5wc5ois0KxP52+Jst5YPz4ByRz3xVi2U/bk/1ckksLMAy5GTn+
+ VaOUVex20MQkpK Mdkt1/X5BbRPFYyyfIdj+WqkZ4I5I/OtGW38rT4EM8TQZDK654H8Q/HikUN
+ NeQ/aIZJ4kQKwh+X5 m4H5ir0KhLQ2UUbW0gJJW4+Yrg5rkqVHf+v6/A46mLrJRpu1k79NP1/A
+ pz20K2MhR3Yh94TdkqM9 D/OrFxaSqUEUcgdonkJz6c8+9Mis4LnJM26V1ZwVzjGM8ipYo5PtE
+ RacwMSI1aQkgKycnFZuduuw 1VlCEWp6pt9fyX+QqW8k9jbF5FWCaIOnHzAjgjOO9VntIAj7YJ
+ jJJJGQWIJGc8D8qswGaJbYSq0s PkeZGUGPlQnj8aVryZmjOwQQvDvLuOxPUVKlO+g3iK7Tell
+ 20X3LVsUrFcakIyyRyRMqoD1MZHzH 6jjmnXJtZroQNbS27RyHZuf5mAXqfWoY3ni1aQCNLiJZ
+ FQyIv3jj5QD71cYvaaotzdYTcjK+R0cE dPzrN6NWfTQ4akFzys29LpJ316kUEUD2UefJWZURW
+ ULyCW6H3NVTbPDeX108JeIuUVcdeOMe1aSL Msk5a3Z9rEZUj5eOAffNZ8mmKloUYXMLljuWR8
+ 5I5/rThNXd3uc9GvGDak7J6ar/AIYZDJCIgJrV R86bNqgEjPzfrWxPBFdWoCoVMgxkHqWOAw9
+ sDpWRAbgXkm6LzJMqWCjox4WtG2tLpZwv2e4gVNzT lzkK2CcD04qa2jvc5selTmnB3fS3+TGS
+ abc2czxwSpJlXZyR95h8u76YzTbe4RYLQ/ZpHMdpIEYH mRT/ABVPHLcLZRSeW7RKilNxyQAck
+ E9zin3+pNIs8lvp06ySI3kEKCAhwCQB2qFKTdpK/nsZQ5qr UatrPrdL7zNigjFtbsxuHC8RMs
+ hHmLtzke2f5VCkc6G3uSYVE0Bk+5gADjH+HpWjZyRWFnE7I00a ryueSR6eg56Ut3uvltjKVSF
+ yrIqDBeP+LFaKo1Jp7EwlKDkm/del97+SMCGR0vRFAx5ZWjEhJ/dj P6mrQjhmljt3uVHmxMYz
+ k/KobOD6k9M1oLPDDq4RZLUwsrC1cr98YyD9M1E1sIrEzPC0sjgeYU4w cY49BWjqXfYqTU6qi
+ pWb2/qyKCW0RvJoWuVt4ZYw+4k4hbsh9yaty2c62P7uRVLSbpQc5VwBx+Iq 2sYVSuxduSjhgN
+ 28Abfz5IolmllK20REUTYkkLjJ3LgYz71DqybVjSpKTaUXtve3+VyKG1uPtVxk E+bOoOP72Ol
+ STW8htPL86JDtZWZkz83p+NSPqFxFDMUMcryOXLBeFY8AflSCzuHjSOdxK3zBgowX C87x7Vm5
+ SveVkcVab5lUmkn007eRTeWCNHcsk8oYIkcYwX5yD+GKzJ7K+utQW4mKwS3SvJhsjDDs evJxx
+ Vy4LzXtwi+Tb5dE8wrwWYcEelQz6XcSPKnnSSXUXMYVjhwp+Yiuqm1CzvZs6G1F25kpPurq 3z
+ 0RhanA8X9nv5ixNJC7sHGfbH1rP87zYlXz43iUlSdvQngZrqbv7LfwurFYplAMG9v+WZ5YfXjO
+ awo9OMO1YQZxKPMBjUk7R3PFd9CquS0tx4NX0qaPXW23muhRnja38t/LDtuKsATwfy9KSCzU3q
+ RK 0WcsWJXvjIH1xSvL5IgguonVnmXMnQRqMHJFW7iJjdA28UwV5XZmAzkge3TAro5mlbv1MJ1
+ 5TrOm 9+70/DZjBaxMiFpViATDE5Jk75X2xS21rbPKZJX2RYKgZ/iI4FXbWKGfT0kuHCTFcbW4
+ yp6EfhSC ezhv4yIGdFjbzCG4Jx8p/DpWLqSd0ric6klJQk5SW+iRHaWVwdQWUxlNwI2OM5OOR
+ +FULjS33Isc MrIEz+NaDwzyNCAjhERUc9dhbqTn9aIiI/tQWUyCNwkTA8eWec/Wmqkk+ZMuTk
+ m+eV21tbRfO5if vE+0bFaMNMp5PTGcD6VDsZ7uNFDlmfn25rTktRJM8M0iwsiliTnsQapSNBL
+ f4EjxIkvX269q6ozT 2KxKp001De26RIYdt5ttiJWCMQ4HDL3I+lQLDLuj4LKEIGO4PNSnzRLN
+ dW6uI5C4HooPUfrTreZx ClrIishkDBioyBjpReSRzVJzilJw5l1t/Vjoo2WFZRNDLPIpJZkOO
+ x6/n+lKl0o05UDI7FSU3ruK jo2ffuKWJZYZYxZzQ3SKGQsFz19c9T6VGVZd7CDJztI9Mfxf7o
+ 7+tedaLev9f5HqNUue+7Xz/P8A yKH2OST7ivLtycqDg46896kTYSoEcqpySmeT7j8K1bKFbV5
+ TvYxk5jyc8Y+99O1QxNH5m8XEO7lm JQ/MMcAenvVus232O7629Woad7bfqjPe4VYY1w6AnCZP
+ 3u/6VE5jlvYIbeKaWQuwMitx0yrU/Y82 9vK+8+MkfdOMkD3p6Ru/ARP3hVSduBnoBWqskP2F6
+ XxKPX/h9dRi21wumZEE6qhA+fPOTkkflQyc tIJI2ZgXUqvKhuMVrS6eVmERkJEX7uUjpuHIx9
+ adDHYpFlGIlSI7AxzvB5NZe3W61MqfIkuV3+Vv zbKAhaWz852RCZTuGOd2PlUemetNRFmkPnS
+ eSzjIdhwQBz071opa7cyAbWaQDY38Bxnn37/SorSI PMkcEYkVshsjdgnkip9qrPUKUlaT9orL
+ 5fduZMgMssWJgwALAAHAz1qytuHcRI5MahpA56YyOTV4 2U6sFW1Ko7MyuBwoA5H41FBE8a7wj
+ hFAzuPO09vzq/aprRmsOSUHyavpbo+4WvmQC58qS2mgaQfv dgKg54HIyAfStBLRDqrH7JOCJN
+ rMCNoUjP8An61YOnXMt0IRAURiTKw4UPj5f0qUtFbW0c3mkSCN g6s2S2RgfpXHOtzP3d2cc5q
+ o/Zp+8+3+dyGOO1kvmtYLaZI2/eKQ/G0DJNPjt3EZuVlDSvEDAjdR HnBz60skUz2hiSRAY22L
+ tHKpjJU+pzTxCstrD5LFInjY8nJTkArn261m5ab/ANf8E6acvZpWdk9G nr+ZYjdbaOCNmkkR1
+ aRcN+hPtUd3fGaZY7VsNu3SHqrYHBotrNBqcoecRbJESOR+VAPUEepp89s0 GsRfKixO+zdjv2
+ /Lv9az9zn8zVKhGo03dpXSWiKpu4pLCWafMkjMCyLxliOCPQVG0s0dpiQGCdDg hhnb7H1LZ6+
+ lTysgvxE1v5hRC6hfp0I71nG5ma8C26b5ePkZd3AGST64reEU+nmelCFoNyVra2bW v+ROZLgX
+ MjxvEpEnOV4YnoR7CmXksL3scEXmLsbYCzZDZHB/nzVy2e4XEpiDo0ZwwUYXJyQff0qm BBMI5
+ VIgwmArDJOD14pxaUttjlnyufa+3LqWx9qh2Rf6xHKEt/eCnPH4VoSXCxXUoEc6QOzNlnyR 3H
+ Ppms4AgQRxP5mCrq/93HQH69fpV6G2mbUpI3zKjNwR/Gx4JHsPSueoo7s55UotynK2i9H+JLNa
+ pcS6fiWNoxExkBHEpxwV9ADWnDZW4s08vdFIIh5ivyAMYPHrWMj6p9sWWONYUkUvGjqDtUHbnp
+ 07 1agsbydSJxPGwIThsBsd/wAa56iaSTnoJRcbRdXTfT+kTSQQ/YvJjkKW6jaJHOccZHP51It
+ y7Jh8 iSR02g9G3DHH0qF90sgtzNFCHbeA4zn2H5VdunumUvBHGjRnKhkBJPHSs30TO2jKo4KE
+ bX6Xdvns UpftaxwWqymQRwlmQ5JXB+YGsZjapcQyvDcRxyFWQq/3B3B+tbRe2iCefcDznYZwc
+ bs/0NVJoLFp mDzbreL5AFODnGR+Z6V0UpW0aOuE1GMoyjb0X5bDnezyrBXdVVmZN/K4OFz9Ot
+ VJnH2yIMJ5AsJM rI+N7HoPxHSp5bsKVMcaNM8ZkPHB4/lWU6B7kvLdxRK4UHk8Ajn8q0pQ6s5
+ KdKKg5u67Xd39yHyQ TxQWrW8MytJ/rGLD5WB4PsKkiu7d7j7Net5tugJEkfB3AfLg+h9Kg+e2
+ tt73a3MI+RyufmZjxj8K bPEILxEGyVYlAbaMZx3/ABrdJS0ZFKopR/ePbZrf7/8AMkSSBUR4h
+ Ise07gWyQT3NSiaTbAITBLN 5LD5ExvP/wCqiO7T+0vLlEUapDLtAQABiOM+tQRW3kadHcQybn
+ ZR8vfjHI/Ok0upM5xhpb06/wCQ k0MyMjq0EXG5mKZx/wDXOahkVSWhsYMSiTMRx95F9fU5zQR
+ fQSCCQ+YVBK/KD781FDZ33l+aI5F4 YhvYDkVqkrXbRqqa5b1JJN7Wf5rqbNhCqvLdX0yW4zsb
+ K4y38B47VlmW1ktlaRvtjq5wYiU5z93n 1q8siR6DA6p5zDHnBju+Y42j8R0qoklsbM5gWJ496
+ IwGA248Hp1FZQT5m3f+vxOWjGpXq3ld306J fduR3MsX2TDhI5pGDbMYKEev17UksU/lykmLNw
+ N5A6qV5btxioZUNvPChKOpQhWxncM849/etdl0 2f7NbJM6LIS5YsSenC/U1rJ8iVtjtrupQgu
+ TVd0k7HNSNE3lFElBYMwYNwoPH9K2IYX/ALOuUlgA Pmr+8AGY/UZ9D1xWhaWtlFp6+XPFG+4M
+ vmnJPoKjF9b272UkmXBiYTYPDMCeMetTOu5aRW3/AA55 31icpJxhd+e/4/8ABKcDPBOtz5c21
+ GA68NjIP5549K0Q7XVwqySLC0swXBHzFtuV5/n61Etw7okk M0LRoNgiK5O7OT+dRRy+bqMcty
+ 6w7ZVZVxjnJx0qJJyu7am1bmqRlVWkkun5WLkENpcyRI/mwZfM yq2CWPQD0HtVojT1iW3Nyok
+ 3CRy55BXp+GOKQ3FnJLJvI+0vJn5eNvzfrxmq8UUMetXW+VIVWb5f MG7dwSPwrmd3e91Y5XBy
+ fM1LTp1v/XkP1I28sLNB5iDEjDL8YYA/l/jVeBUazjEV5BGpj3kOu7y2 B4Qn3OaWK1tWhQzzG
+ QeWNwVsdG4/StV4Izdp5Nvtt0RhIMDOTz+lN1FGKj2O5csaai09Nf6v/wAA iLw3FjKZ5IiJSZ
+ AkY2lZOyfXjis1YruCWFJZo4z5DPJ567xGQeQffpWnHst7ASwQm8uVKxIV+64b knHr6HtUBkj
+ eKJ79SvkwmNU7shbkn1IpU5NXSWn9dDKivdajDT5X+4UTi4sXjSTzD5uAyt94dd34 d6zgt3Nc
+ h1n2xuoYGQk84p4FtHE7RhobJpdsTMeoPv8A561KtzYTT7lL7zJsgTfjKnqfwx+VWly3 5UcU5
+ uCbjt3texEYI59IneJnL5CmTccOc/LUstrLb2zol64mllJKsxJ4A/TtVuRryN2jIidAyliq YB
+ brkegqbzWuZ5VIQs0jYbb1XjJHoKzdSS9DzcRiK0ElGWi1/r/IQDybKaVCzsx2qM5CqRjp61mN
+ p1uWiX7Yw8iFlPzngjBA/Gt2K3DObUP5bZZstzuCjlh7VB58clgrHy8SHc5C92GP5VnTrSi7xZ
+ zx xtWPurV/13RTSVDv3xtgkGfn+NuRj0AHUVox28kkcSYUMbeXqPu7e/0PpWWl0rytawotxuc
+ bivVS B1+mBUYtGW9h86eSOCQFkBcguvRiD6VU4edhzhzTT+Hl1tvclhsYJ7a2aZWYKoZGU42B
+ hgA/zqGC 2uLTyh88ttvKyEnOWIOOvr2psFxC0zRafcCNgQEEmWAC5wD+taSu11bRpcN5CMQQR
+ xs7Kp9STVzn OOj27Fz54NX+5p3/AAI547f+ybOQ2t0ZGg37RJySvC/iKiu0uX0qNoF2zDBkBG
+ S+D1HoKmNy6acI GUCXcpYMOjE4yPRfatW4kWRIA6BmS3dJzHwNxIxWPtJRa0vqTCdWHI3G+vm
+ 9PO/QxozJHcySXMO1 SWymANxGMEegFQzJLN+9SO5S4L7Qd/G36dsmpQWuPMjmkWRWxKu3g4x/
+ I4qyVuis0ovbZAW4Taej Dkf19q05uV36luElNyej/roVioe2AUrbXBlDCKUZMij+MY7AVGsar
+ MxDvEsyFkmckrg9h6Z/rWi2 nXCabJFHjyovlSRlyVJwApPqajiihMslpdB43J3MWPAK9VHpx2
+ qVUVtHc5rRgubmv5X/AKv6HOrD LHJGd0UNsnlj51yfmBHWqsFkvleXH50siy7XMb4A2tyPoRX
+ YyW1iZxGzGVZlDhA3Me052H3rDl0u 7N5G9gsjrL+/YZztC/wn3NdNPFKV9bf1/wAObTxUHzJe
+ 7deiOXuYrd9akZFZrUBypJyW9D9M1XIj /wBHdTLcKIyJdrEbH/HsRWx5MCXMUTXUeAGEJVfvL
+ yT/AFFLbRRR3RWK6gLcuQUzgqO/rXo+2SR1 1J03CLT97qulvWxVtQG0iGWCWMx+YyTlueB9xR
+ 6HBp94k8iaYosZWLQFGMQxnH8Rq4Z0h0qNE+zy 5bMaIuCFPUH1J5we1QRXFu8Rmj89XTPlKZN
+ 2E7/lWalK/Nb+vwOLD08To46a9X/TQQWs8GnpdR3S 8qUdG/vZ5FZptoVuIlMjmRVDPg8eZn5R
+ +XatWJ9Rlt0DeT9mYhg4QYw3JX/ePrVOeCC1MMyMW3vv VS3JX1zVwk+ZpvXyOiKqTj7ObXM9r
+ fkyvI9xBqVx5iDzBMFbeuduO35dqpMVcvLtYj+FUAB29d3I qwytOymabLq6KBnllPLE/QdzU6
+ pYvcXBG7yon2RsW4K//XrdNRW2prVcabsrp9bLf+vIwS0gjVd6 hd7sx7EEDA/SrME86P8AIgV
+ iMfdB2fXIpzAb3aOARxsC2G56f/XqCU2yGMs7NyG2huWbNdN1JWsY xpclOdlpvZu977nV+ey/
+ vjCbeRWw644OeCMeuMU1LZpXUyXUaoke1m59eB9TULGaZTLJDIY2kfJH GOBkH9KsW2nwskZkn
+ 8tZIi4BP3mB4/AV5ztGN9vxPYp07U+fl+e6foxxt44Y7m3hguUkeUMUkfJQ D7yn86pysn2ZY0
+ 2sm3ggdw3StMhRCnmXQllizuYA4Oefx9KgaQKqzC1ISZc4OOcnGR6AH9amEn1/ r7yqClF+/dJ
+ bX/4IkbCOe5SaNoUaQMofqBnn9KdcRRhVS3vIZ0dtyRqp3DBqWG1Z7g26ROAhMcnm HJDt/hir
+ C2lmtr5UxaN1kwWz+QqJTipXKqOmqi017KzX9fMyY5JItzqsqSyTfNubgHnK49T2qdLC Z75o/
+ KcquUAAGV2jp+HetARRRlEuNsaBC0bHtzxn1I9aoXSXcCQkM6IhaOVgf9YzcnH6VUajb93Q Kc
+ p0pXste/6alo+QLCOOC6UOpG5mBwM/1NPtxE5lMit5MV0kYKNg57UyO032FqwiZ1TdgL1ODzk9
+ 8fpTpd0V2LqFGW3Me5Q3Ic4xn8DWWjukxQhOrTkqctXfdobPdXIubl1LCUXB8tQM7lI+bA9OlN
+ gQ vBgAh1mX5Tz8uM5PtxSCCK50yCaORmuIyqRop5zz19STz9BVh/OsQXiCh5lBfK5OQcZHsc0
+ 9EuVb m1Kh7vJ7ql6b+r7F+Nbi41WKQMxWWIzvsOArAYIP86ovGZLWFEdJCrRh37A9vzqSNY44
+ 5LjModJF hChsde35VcNoq6vMbe0n2Rt5TEtkMSRj8RXPzKL/AK/rqcdVRUpS5tvS1/1KUpeyu
+ yLcGbe7Z74P /wBfNbUy202gBEXaXdXjQH5sAgH86yJYb2wV38vlZdh3DOxs4Cn3INXY72eG8u
+ FdoGaORYV+ToG/ z+dRUi5JSjrb8S3S5oxmkm12/UqTacvn3X2iYv8AvWYIpweB15plrF51t5K
+ M9u0jCZTM24v6sPYY 5q1LcGaSaORhJGjlXCDBBPyqCf1qhJPqfkJbJCryoTHKQnOTyNvoMdq1
+ i5yjZs6I1JWSlq/w/wAi pJBKwlVJBJhhIze3QCh42guy8wZZWUqxBxtbGT/hTZYHHm+ZIseJA
+ oUn+8Pl/LmtNU+xOIgyzMbZ pGLc5YHtmt5Tsl1O6eIaS5NfJ9f0sZ6xyywRP88Q2qPLz90dCx
+ /GpJY8vFbBg/kxhCyj7xJzxx3F IuoTDMgjX5Gx0zjcclT71bSaI3SGSJ5ZDKCY1O1gV6H6c0p
+ Oad2jnnOtGSlOndLVa9flYpKftF4E UNHC2CyA8kdCwOOgrZP2y0nKQSJPHEjCNgPvA/eaoolH
+ 9qecAsK7hjI/hwcj86jkWGSBHlEySu2A Q/ypkYAP161jKXM0un3i5ozq6r3X87f18x7yyT6dJ
+ P8APGhQqi7uQuRmtWG6jjtXlR3ZhIDMNxON y8/TFZsyvYwxqtxGfs4MWCvXuDj9KjjSaWSONf
+ 3jyxSSlV4C4HQ/SspQjKPkdMXGVNc2iTeu34WN CyDfbE8ueKdI7faqheQTnGc9TQ2o3NvJyVe
+ FU+UEfxH/AArIgSTfZyEOiOo3Nnjdnj/CpXmtE8xL mKcPJligbBjOc4P1qnRi5a6m8nQdVqKU
+ o2XTX8CXD3jW80sLzgR+WqxnbuOSQ49h0qC6n8prmJRv 81g+7HA9f/rVZN9eRNE9vD5cQVsbl
+ BwT1qv9pVFtpHmguyImXCJjGDwDnv8A4VUVK+qFOrONT3o8 3az/AKRTgvIxdsXBEewqrE/dUD
+ gH60eXNN5TwvHc4wr7V+6cdDS20PmyvEGgjRW34K9R1Y/QCpFu YY4XELBVBJVQOSc8HP0rd6P
+ 3VqYShOVW1Na9nt+S/MSOdfsxhnaM7ZVdV2YLHPX8K0poyUkaYBv3 oRGXjI75/GqqzPvmmkjg
+ lRZUCzKoAX0B/Oo2e7acLHmSSFWDei/XNYyjd6aHLLDSjV9yKsvMfOYD BOwifzFbYwJ5XjnPv
+ UVn5n2CadEcohAiOeCpzkfnV20t02r5sggjnchRIc+YMYz+dKYfsf7h0e4D KC5jOApXp+FL2k
+ UuVGk8VFRcEua3m/8AhiB7G4uGt55LS7CheTu6nufoPSnyQTiITRyB/wB2+zaT gjcAPzodVkn
+ MdxfGNXDSSDJ+V+m3jpx2oQWbWlsod32QjIVyNuW6H370Xlp/kKMKianKPytp+JGI 0uJriJoJ
+ UeNkVgGwN3/1qrhHt4UTyGdJXDsx5Abv+FWJIrtpXhhglUxSBBzySfU9zT3tmguJUnlM NzGxG
+ 1+ijAzke1UpdL/I2s2/ea9N7fdr+BC93JLFBJ5EbLFCyA7BkE0QiOSGPcnl8rIHHADDoPp7 Va
+ kM0wjQRo+JMII1xuU9G9wMc1Qe5khnYh4nzvIULkegFOOqskHKnDljDX5/1+BKJIJZDhZJpZ0M
+ gCHG0joPxqOFQlrEZZraIxtsCyLkgNyW/lSB4Y9OUKcpImFVRhg4PBz2HtV57KFrSBZ8xyMuAM
+ 85 B5B/CiTS3Oeoocq5m/69V/kZlvagsY3u4Y5Fk+TKn5gvJNMVDPdIFni8uQfIzDgnnA/pWt/
+ Y9tIF WJLkKX3I2/kDPANE1rJBptzIwV44rkFNgxz7HtzT+sRb0e4lmE3VXK7y87aencdHCEtT
+ E0LtKG38 /eIX/CqcTyvdxzzRtsZQ5PYFsjn61Izz2YBk3G7hLQ5J4Ibkkj2BrRSAzpOks0f2b
+ 7pVRg8DK8/h mseblTb6mkW2nKfXrbUpLsZo7Jka2BwJC55YL6Gp7lk8mFIZjEs4MsgZsnOMCr
+ o09pNl07G5GcAx 8csOn14qxHYSpdwiJ4bciMszzpu2kgjb9fSsXWhe9yY1YSd3K/L5/wDDlBY
+ Z5EMsz/Z4QAPMHCo/ YfWopJFYsH2tkEmU8qB0K4+vFb9pbpILVJp4ii2jq/oDnIz7+9ZDrbWt
+ v9r86J0kZXRPRQMAfXPN RGqpSsTUnRrVLNO/TRpf16/cZgR28xoGGwrmONlzgjgjHrUFsY/7N
+ kuJNqyLdRgR4wyZ6j8e1XpV sp51tjMyTPIrK4PGf7v49qfEl8k7JPBGQWbJ8sAZ7fjXVz+7qZ
+ 1qXuNSirrdbO3r1BHaW4vGTckS TKrlj91ieAamFmWBhRnm2EqZIzjeq8kj2rOkR7cXEW9UIkB
+ mLDhmA4H1NadtfTJAgkKJbylWJK8s xB4B7D2rKpGSV4nJisNVjS54Ky83+Xcc9pmMsPPAbLJ8
+ 5zt7nPpVtLCOK4ciOQxhWIQn7uB/jWDN qL+WI/MHmJMgGD/B/EKtz36Q3HnQrM6P5jBi+R24/
+ nUSpVdF3OCWHxEYqM+o3Z9jVZoE8xvLAfaP vs3BI9uaikSSDT9tk27a5WPzDuKqpA7+pJofU4
+ /tEJnRijQvt2nAG3kVWW7spktWZpOYnaQq2Aec n9a2jCejaOinh5qpFqN/lv5b9CNobiz1CNV
+ 8mK7lTKoU546j61dg1NEMSbo5C0LhyE4V88Hn0p01 yktqZhBJ5o5GW6ggZx9KC9v5VswtARty
+ ygANuJ+UE05e8vfWpo6ejq1Y3vp9lbEskkUmlWyR3UT3 L7V3f7p+9+Nab291Lbunn273QmLsE
+ TGOO4+nNc59lmmSRmhdZy4VEHHGecfStbF9BNEjTxSRxrIu FHzEHGGzWNSCVuVmVWF4Rakm09
+ tPxtuiMM8QSQGKVUX5nVcLg5H5YrTtoLY2hQ3UZZXAZM84Xr+h qlC8Zhj80jAAXbjG4A4Y/QG
+ iKAPBcNBcxSqCUBC8t3Y1nU1XY5q9GlK17p9+j8tjbu/LNpJFbziJ GcMN+Tz/AAA+/FZs91cC
+ 8t0uvIjmdW3Hy8Yz1/Gie12QIzXAOeAvcn1psTyGYABGZEKjeufcn9Kx pwio9zNYei6Gmthqx
+ piV2Yu7OigIeQDkVjX00sNsypKyyvIrlgxAGO49j6Vsz3Eql3sgiYmViWXI A25C/U1lSi5ur8
+ XEkW1JIWE8W0ZDEcY9MZrqoXveWxjTjUvepJKPbS/3GM6tJPdLCiSThw0WxfzI 9s9qdYi6m1B
+ xcRiJ3bcCUABBBBH41pW9w4s4EneDEEZjDogBfnKnPfNKLiKW3ISeBJHkWSMMOUDD kH6YrslU
+ dmrfM66s+ePJGHz3t9yMq6hiHlGJlA2oIVJ5jXP3W9W96Y6TQ3U8s9p5UXnbAdvABBz+ FX3m0
+ 8RP50Es4QbY2jbAZM/epXjmuYJjbRud02/LjI+7/wDWqoza328y+WomubVeen4mbDOFtTEo aS
+ OOZDHGAQxABA/WqEhY3dvAdsPyoR5o3K2CTke1PFjPHpcUhWWJ3XchkP3gOv5npTyInu5XEcoU
+ YMbHoExyPc11pRV2tTR4ai6TdPr89fLZfgWzY2cjG6muI3UxsrpH8pDdmHtisqxjmitlkZ4VZD
+ 99 l+V/7px+OPxq3cLHLcwJHMGhZiY0UEHGMDJqrKhjmInSVUQgZDEA4HH50oJ2s3uedChUkn7
+ XV9v+ BomRMn/E4jKTxiZgcRkE7F53A+9Ytu8ciQvHE7jzwgfqI25xnIrTiEswiAbzp9rLiNcE
+ c8A+5qqE tnvIFVGUq3HO0BvU8V207K6ZXs27yjNbbNar+vQ69EfzZYLp1QkhpCeAp5yMe4xVi
+ ya5tdMtQiCN VG4TTKGDDJHH51npzJN5jGSYjDKOCzHPTg9Bip1lkiSKOOTcN6J5bjJ39Mfj1x
+ Xl1INqx7+Nw0ZR Ttp2dkvlrf70X4tPeaGUzMke1xHwuO+cH396jha5SCWMrEVEm1Y9nIBHJHt
+ irV0oIZZ1mSASssrq 2Ar4ABqnpSRrrM0qrJP5J8vy92S+c/N9MVgpNwcmccZynCUpu6jsv+CR
+ LbRxX8TefldpDndyCDgZ PrWhDJG2oIrRmSMMYwndSeASe9JdPY2/2aZVdlH7tOcgqR9/3wahQ
+ tbWyRQ5kKnLS4+8V5yPqDTl JzVy515VlzRur6a2K5Rft4hc8xxYG8ZGz+L8ff2rVMFt5KpEzT
+ 7QykhuCeAD+PaqZilvEku4k8mP 7sRPO5cevvVtZLRtJFrLOsCYZgp+8nQqCe5qakr2t8zsrVF
+ OUeWWmzSW36lM3VzDFJGzRl4pkUoF xuGeSPqcVaRAbO4cQSRS5KoHOQxzxgfnUbXVtDBGZDHL
+ NMpaQIOS/wDCR6D2qMzyRQXNuJ1GJV3b 1yV2j/E03FtaKxU6Kk06Ufwf6Fa1NoJVd4J4xjBw+
+ MZ+7+INWrXylupH3M4EmxtxyN204qrc+fKF lDxOFdRIij7wAzxWhYvZrqs2Z0jjdsszAkZZTj
+ FVU+FsiULU5Sjfz3YBGmsxFFGRKoy4bklh3/Kq lrhmPlvOTsBY7+CTnn8K0YI0tIZU+1RyylQ
+ 5IJGQvJx9QarxSSSXAmcIttgKsaKASDkdfY4qFLR2 2No3hBqMdPuf/BFFxIsHlqrXYOG9c4HX
+ 655zSwm5+02pWEP5sJldccsQfvfQUR+ZNcSolpMm3AVw funHQ8VbAgaye6j8yO4OWUbs4QcEf
+ iOaiTUdLbmNblppQS1l6P8A4Yql2aaOVraRYgmM5A8wHv8A X0NZ6ht8ckU32dZWEhMhJ2gkgZ
+ qxDZJFELh55JogNqKrY+Ugn9M0yRVNtI6sBHHLGiuBkFdvWtYt XsjalSja0Ov3fjdDoLJo3Ju
+ cs+4GIZxuVev9Kp/ZpzPsiLNJtKBGOSB1wfrmrsptiLUO0rJEjRFg /wB71Ye3OKkaWM26xsCY
+ 9oLqp+ckcDn3pqc9+4QjiXUb5r/LT/L8iKa1aO4txBG880oO1E7KMbif 6fSnbNt6ELpEspacF
+ uSdowpB9D6VPE98LZpoyEk8xioIyVzxj6E0qRX0EOJo1doMxu5XhQecfmah yfVr+v6Rk+aMru
+ af9ea/IhguS9r5k1zC2844XiNccofc9qpxCB3iaRmuNvEcMZIJHPJ9/wDCtCIx PbbruB2DMPM
+ WIhdj7cAH3pbfy4rRHjtZCIEMZbgnceMf1p8yV7IrDyTbtdv5L/L9B8eoqsTuY1XK kuHAYhxw
+ p+mO1SBVlaO4BaOQx4HOCwK/MfwPNNksLh4YmBhdUQJt2ffIGfzNOlsmlljPlTRYjJkB fgEnh
+ R+FZN0+jsdsoUo2Stfv/Vv1Ik02OBY5ILpZYo/unJwSejfT0pLxmaWMyQ4LfIjEffPQn8Kl W1
+ thPKheSSKOVUCq5BGf8K0oEjkmEZUYRmMbE/d9vqTSlVcXzPU6lUnQleyb726fLr6mCtrMyqsQ
+ eU8MNp4BHX9KtpaRSWTGJlbegJA7Ed/xFbHmmSENGyW8jlclxnkA46etVZZCqzg3EH3FZgq4Mb
+ Lx il7ectNjSOIqVpXpzSt5P8d/zMtkkRI4/IZnijCFl43buao2sSTamsbQecPLO9F6lgD0rqk
+ W2mtA 0kolU4VVj4OV6knuBWBMr7A0A2mSTcSBhk7Ek+hrSlV5rrY4qVf2kpQuvx3/AD/L1Egh
+ zo0weRYw XXMZHzFiM7voKkja1SBPKLzuRhirdTmrtvb2cd5cySyM3ly7FGeNnf8AHnrUdxDap
+ GVs9ysMxg7s 8kZFT7ROVtTGEoqpy6272svw1IkPm3O7y28hXEUS55TOf1pz3rxXS+aUAGWOR9
+ 5upH5VFbxyR2qP JMjE7QmB1ycZpJLCaO/YFhiIFCjDJJxwPrVe45WZvHkm3GaWv9biPKsN3I0
+ USSR5OI3AZjkZ3fQC po2m+TMSyW7EPHsXBZQPvA+grQ0+1EdxELi1fyXXMsh7seQo9Owqw1tG
+ JriQxyRuJgjjOAoK/dA7 VjOtFO1jCq4RnyqOvfT9HuVoLW7ju8bTPskUbh3Pb+dPniie9Jt5Y
+ 3O10eRzuBHUfj1qS1g1VILw wzRySLPGxbZwxx1HtWc6Bb9JJLmORRG0aCMYABPGfc+tZq8pt3
+ +70MvZSlVclJJ22V7/AD6DLd2n v2mbKR4WIdssehHsMVWubX7E3mN5cx3FmOMhW6FTn6062Js
+ J4mgcMUXZKrDIVycg1PYRwPqEg1CK dwiFDhsDPr9ea6m+VuXT8zun7WLdSWqS7a/iVZl86UeV
+ EwjbcoYDAUgYqxbRytZ28iyLIDEVbIyQ xOB+NbEVrZ2sNvHCZFghDIzu+4OzHO76Crwi8nS4V
+ YxgSHzCVXAADYK/WuWeJVkkjzp43nSjb/P7 ys8LQso3llBEaheoJYYH1zTJGnk1G8hRUbdMpY
+ be685HtxViaS0MkqxOZo/MX5VbB3bsq2fSmXZE TXEiONwlIRh2HXJ9ec1zxb67/wDDHGkoSs3
+ q9romhMEs8clx5LSujOflGMMcAY9T2qL7MhWGAjaV gKMo4IZgc596lgaRdUW5uBHIkgDKqJjH
+ GPy5rQjTzLhUMkYDDCjHzEDOTmspTcXoJy9nJyh0676/ cUxMILRIYInQLtyXwQWA4P4c1TSdn
+ uZlvsw/MH3dAxAPT2reW9AXHkp5DBWUlR05GTWRc284ijkK faFjxG5jGPmB6fiDSpyV2mrXNa
+ Lgm+aOr/r+tTLgk8/U3CuIVnj3srf3iDwPapFht0RYmQzyZTcB 068ED0HeqlwCJhOrxxkxsEX
+ HKDODmtSE+QUJuIEcQsWZlz05/rXbU0Sa/qx7mKpS5VKOqatbX8dD NvYkF+QRGJWJkV1GAxXj
+ j0z2q5bWtzC0zTl/KaYNGp+9gDJ59s1dxc3tspXyc5CBwn8JGWA9+ODU +IntAsjOojhIOW+5u
+ HAPvWUqz5eU86opOHJHfr1+4zZk09beViVaMMI3JOS5bgOPpmufuIpEkFrb q89tAyJKQejD3r
+ pryWb+yUeIQyyFMyAJwxGOnpxXNrLfy226J02GRdwVeTzjmujC3te/3sinBql7 z083/wAAr3q
+ LNJA0YVNx3NIPUnCj9Kr3UTK6W6brkmRzII+MHjcPalNptsRERJ56SFZELZJJbqPQ YotYHi1f
+ E2YmCPh26Adya71ZLR7XM1ShUp817OOvX/h/wEaCGKFraOGZ388s6k7iowMYx2NU4rgQ X6FoR
+ sUsNu3p8v8ALmrhCSQtEiyxyFQDK0hOG6lTxRDp10IZ5FgZQrAAyDPXqPrirjKKi+ZmkaEY 0+
+ Wa19df8v1FsxbmCBmdxJIFI+bgbc7l+pqxIheyjiEgLIMiQdAo5Off0qC0tJFnxBPC7biEGM8H
+ gHp9abIJbYykMrEOEx6gL1+lQ0nPRm1PDSlP3anvdE7/AOQsZ/cxXKzu2Y933iCoJwc1ofaobP
+ TG kjkaR7h96MxyNq8HHsc1TMN6lmit5UhZy8qqmCAOgHoO9KhLwnzot6rGAAF4+Y/LgenHPrU
+ SSlq9 UZKjOrK+um+yv5FqbUvKMvm27FpLhREQQMKACTTrO+ZLy4le1kjJfDLkYGec/wAqz53k
+ dJFmgYkY AYcckZqeAieNPOlVQz49MBeGB9zxSlSgoaowxFKnTu59e2/4HUrMJLWUSeXI8kgMJ
+ UdVC4JHtWRd XHkRRRxlmJj25zzu6Dn8zWBc7AxigklZ41P2dt/ATGSD6k1fS2mGirctMAc7lR
+ uSuR3/ADrCOHjC zb3POU4UeV8y1e1v8i5hcRRAkSpGomdj8rYOCR6VkXEzwaxJJ9oBO5kEXOe
+ V4oK3f9ns81xHOIX2 yGJcbjj19OlVwjw2dtJPIszOm4qB83Odx/DiumnTSb1uY02nPnWt9LXu
+ EyW6WFgziaGRbfy5AzE4 cZPb61bszbyaX5kxEUrsj72+78vBwPyoSa3TS2McJuYVkTzi3zb27
+ EZ6D2qCKySa7bbLHKMsXSMY J56j2q27xak2v6/rc7aNKUqbjUbVu35f8PoX7+8SeKZIkU2yvh
+ 3QDqcHA9KLGV5IZZ5C4tyQwI7F eMceo5q1cxzGxePfBsZg2FTB7Y/E4qaGT7FZ3LXSKsTT5ZA
+ uNu7jH4Cubmj7O0V/WhrUajh+SENP W/3eZi3TtLaLNENivbFo0bnCg4/rmqE1shgQXE6IgdeB
+ wSMYrduWG2BbOBpPJ3QM55Vh1Ax71gTw PNPapPN5anBG7sD/AIdK6qErrt+YkvaUbN2t56/dr
+ +YnmpDHIyPDlWZYjt+4meR9c1VJkltfnEig HcxxnlakuIooNyAhgh27gcjcecVSkhlSOWRUkC
+ LN5ZQnkMR3rrhGO5FfDUaLjOc4y9dikHmEbCNA 0gl3NlR3GT+tRiUDaTbuzseCGwE9AfXip1J
+ YyseGBAPbIHBH1qooMbqgyoeYAE89sYrsVjilNU0k r8t32t8kdUlsVuoTFIrsVMgwSSCp4z7V
+ rLJd7fNktlU+YJTlRyQfmI9MVNGIYZVkluLfzIFZBIq4 VgecY9TniqjLci3h8y5iTbuEAI+8u
+ fmz647140p871Or2sK1W84Kz6vS/wB3+RrjbdXL3AIOSef4 BuPcepHQ1mTR/ZEEkUiiV14I6A
+ c8mnGd2sWZZY0CzqsZUYyjHv8A0pzzXCNeQmBrmB5cK6DoD2H4 1jCLT8jehDVtPTte35kqzQX
+ GlqLgxyRYUKFXBHOP1pkd1DaxxIwM7S7nB7Haxz+B6VVd9Si0+YS2 pikZ/nwoAU/T8qkdYY5P
+ MmXIVGTav8DZBCn3NPkXXbyMuSHKnJ6Xen/DbEs89y/lSIvlJIG3KBxu x0Hpjj86gjtjbT2kV
+ yBI6RO0idw/UqffpVNbuGW5SZkkdBjzQrdJD938u9aE8SmCKaVi/l7gxHVn zgNn0yelaOLhaL
+ 0Npy5XGHL6f1djkXT8xyurhpommyTxnH8gaqbrIyQId8L7P3nmtnJ681cgtylk rzj513QyA9m
+ J4x6Ais+aeaeaWHy0iRiWO5Bk9Mc/hRDWTs9vM2oSUnzRbSXX+ty3Pp7SqsxVzIso jmVCOWPO
+ R6ACoBZzRSLcW+4mKfayOufM54K+2KlijvWe6ltyZMlgWB43Y5wPX0psEdzdaLApdonY EgN1I
+ U9aalJLWSsYutPmSdVcr6FgzzedGtzayMLdtrquAy5Ock+gFWpbotcyLA0LpEJN4Vfv4+bc PQ
+ Cqcs7z2NwVkUtJMrbMfNntzWmjKkJk3RGV2Ln5OhPG0/XmsJxSSbRdWlTjFT3v0u1+g2W5uJ7M
+ +eq2cciBmlIAVm4wRjt2/GsqQSR3LIgkdWbEqqeYx6VekkkUvHLPAkQO2NWTqfUe2eKpWN3Mmb
+ kj lNsUgYZwxyOfenTi1FtImkmqbjHTy/4O5enjJZ45InMaodgQ42AkZU+pqaC2jjm2CN2gydk
+ TEEhT 0z+NZzieHUVXLeWu5CzfxIR1+ue9ajR3I05fLXdK7AiMctEq8EN6+tRO6SV9zplSbik9
+ O3b79RiI 091ZRmHASB1AI68/MTSzwwErLaRSxXEKlnWQ5BLDjj9auLcTW86yybIpnZkJdchi3
+ TA7ZrR+1JHY sWWMTMMsuAMkYCiueVWSaaRlKq1OL5fknb7+5k2EktqC0xTy3ljxuHscD+tRTX
+ d08hjSNsl0EvHD FuSfyrQkiZ70htsbZLbSPvFeQw9h0rHnE0kUEsQa2kYiYmQ/eG7g/QVUOWc
+ rtDTjOUpWV+/b9S1e 2rnT5vtUUkSrJ+67ZQYzn1PvVV3IsZBHG7xKwOFPOAQeT61YlZ/LnLah
+ FLILjLA52gDoMe5p6wRz 2Db5lilcgynsrD+H6mqjKyXN+peFa5V7V6X81+DLVvHFDdTXCOVDh
+ xtds8tjBH0pzXsLWht5JoVu o8KzEYDH+8PbFTzuscSQMgcxp1AwAvGQfU+9VGa3m1a6FsiCNp
+ N29hnA24Fc8fe1ZpTpSm+aSbt9 35CNawy6a5jcKZpRJI+eFI4K/U0lrFFDujTeu5SGLN/Gen6
+ UsM/kwKqWsv2lwHZnOUGD8xxVu7jR 1JVJJELFS0ZwNxI5/pVuT+F7Hou7ioN2+f6f8H5EFvCp
+ W2XzQsW0Nk99ucVaWN5pJDJCiGRlO8qM L8pyD6msiWXy2ZYZAkkZA2NyV7MPrVyOWZfPLMSIp
+ ECj0OO9KcJPUzqwrOL2+4pzz2tvIVKSIykK hDYByOf8aRgrDG4FdodGUcNtHH5mtNprI7S0Ik
+ kdPMjPXCg4OfU1H5cCXieQVEKIwjY8hkB4P5mq VTTZnEppL4NvPcrxNehIpZXt4WX92WaPhj1
+ z/SoGs70xx3KyxS4AyEX7rBsAH3NWJnuY7xZCnmoI 3RgBwG4yfwFSRqbgHdDLBChKMd+A/fIp
+ 8zjroOFWUW2rfd+BTdCxuJLf5JxcFIg/TB4PHsc1OGuI IQ1yBNtc5KjmQgfKwPpTzaW7Lvkkd
+ pXBkYK2CGX0/PFNvINwaVp/KcltwOSFJHTAo5lJpHVGPtOW Mne/lr6dyT7QPsCXE1vPGZXRkZ
+ m+UBe+KmeSO43TAMZCxdQD9854bHpnis37ZdR2Sh4lmIdCrhfk K9CMe5qSVriWNo2spIY/NVV
+ wRkDOSKHSs/8AghUw8IRTqaa9/wBN/wATShvN9rcK6skr3AcDONoz jafcnpVRUabUlSeAr958
+ jgAZ+Zfr3HpUEccaXL/aIp4l3n5WfkAg4P4VU+yqpRFuDCxUMA75Jx94 frmiNOKvZi+r05J8r
+ aXn+mv5izI04k27VgKAmQD7zZ+U/j0odbopbSy3lujPCxddmDt3YYdOvvUr xRpZKFl8obtrK5
+ z8x+6PwrTginuojJdQlvIfYuBjjow+prR1FFX6HVGr+6TWy6dfxLtoQ8c8X2eT 7OkyeSx9O4P
+ qfeprmNpLxljjkjWM7cOchQT90+5I602SZ4QzbGti6kFW/hHcmrlu9r5EihyAWDBm OThTwf61
+ 5km0+ZI82cb+9GNr+v8AwSsjW7xKrPGyhz5aIMMFByQfU+h7VBHpc8eru0dxHLZyOZEB GTtUe
+ vv/AErQC3GLmQJEYmkykioMHI5xUNtdS24hi8yJkRSACvKg+tSpySfKcSlVgpcuvf8A4HZ/ Iz
+ 3sofNtpGlYxmDLqGOck4XHpWqQ8MUv2dhIS5IBGSoA6VmNcSPJKlvbmWEbTkAdc9KlN1eTSNLH
+ H5cu04GODu4PFaTjN2uzqrUas3FSlp6qxpwSvI4Wd4drRMyoqYPHU/TNF2sc9rCXmEbOvmSkHA
+ 3q OMCoYpDECJ4jE8b+XHuPJTbV+Kc3S26SCPCxkAhcY9j7nFcsouL5lscqoTTvHZHNCKMooME
+ ql2LO XIO1gM49quNaQTWSTw/61lO5Sc85A/KpL+5jgjiT7LNcJMPMZozjcemR7Y4pbeGO2mmd
+ ILhTFMUj DyZGGGTn8a6nKXKpHe4SVPnWj/P8b/gEsSy21xAW8opdGPepwDwCuKx3EFpcPDNI6
+ CYhiznofT8q 1kHnRndIibdo6cZHc1HJN9uecS+SUaQFDtGFGOR9cinSk1p0NMLGFNuC1XXXVG
+ UjTzvPBaspjiKq X25Bb2qi9p5UYt0mCxKrHaoOTg7uv6VrhJoZWeFQ2VLsij72Bzj6ViPE8ln
+ 5aiTMLADD8vH1Jrsp yu9NEOrDnqe7FL03+exERCZVu1czcFGjB5y3IJ+hqfylluXdgyxRYTzT
+ yGJ5J+lQ2lpH5zXMtzGk RdQuc/Nuzg/hSSSxQ3JktbpWicFgCchmXjj866Hq7RZHs4qbhGV2+
+ rv/AF+ZJILf7SjxSLKm1o3d eiEDof8Aa96iS4nuZbdSxiTYAE/vAn5vxz3q3BePFgxRRu543b
+ fllJOCwHpiohcyGVEW2zFuCJtA znnHNSr9UDpTjFxdr921+H/DlGCxVbi6E0rwx27vlsnnnGK
+ c88aSRTiHzI1j2qpGdxI7+pAqw0N0 IpYxbSZZjLIzHIBTsfrUbpujhuVjK+Y6FUx93J+Wtea7
+ u2b/AFeDSd/x0/r5kSNBLbRx/Z7rzEQq H8zO7v3FSxzTK9qIpYtz25Z0KZbIGdv5cita68spc
+ KIDGiSq0kx4USDgL7fSpY7ONIZLiUokxLsr Y+Xb04H6Vi68bar9Tjq4hNezcbLp1/H/ACOUMk
+ LF0McksKjEJDc7cZyT3piQGGO2mjk/cmPzJmxk K5zgfiK2IraBr6KQvHHaNAAueoPZT7ms9ra
+ K1tJo23AvMHkjLcgg/d/CuqNWL0RTdNz9lDVf1tcv wS21vZtLIY8TyLhyPuqO361QnfL2Yhcl
+ fIkJzyCVOB/Om3TRXcSBW3K8YCp6MTx/I1SVolZISxQC N1aUscHBzwO1KnS+11PIjl6hLmb6/
+ wBdmagF3KgiSMQxMS0e5c547/Ssk3l4t5AMQSBLchMx5BBH NaNtcJ9lZ3nWSE4MajIOAefzrO
+ iWWK4SR4XKgMoyc/N/hz0q6Ss2mkY4WlBVXF2t06a/PU1bCVfs QlaSJi0iK7BPlj/ugj1P9K1
+ ZYIbi4SNJovNicmIxjb5qLyT7jPrWJBNFFZkeZG7W7hCQuAQPUdzz 1rpDOv2bzYZYJFiKoSq8
+ juR+NcuITUrouvRlF7t32v8A52KsmosWeQwqULBlPGNp6j61UWSG5SdJ pUw5fqc8Yzj68VOLy
+ T7S7xpDGrqzr5iZDJ3I9MHg0wWc19bQrcyQRzCMsDGu3GDkqfU4xUxUYrXQ 6aapQa5vdfe//A
+ /UZAtumnyyW7MqvIsgBbOzj7p9zUEtrbzxu2HkllK7kDcqWPT24zUsL28jQlIJ STGfM+bhSTk
+ DHrxVi7zbTlkhIjfDD5uQFP8A9c1fM1PTccm1L3b3/MxbpbizkzDHHIj3BJUqDtbG Bn+dUpIJ
+ YLaWQyorMweTcM/MOnY8nrWkZJbWZZfNRhjzkjcZJAJH8jVR57O709AxaAq2JWz94kHa foK6o
+ OStpocEsP7KSm43T3dr/gc9crbgL8yKwQDk9fr7mqgjWBZlIyBNk4PtzjjiraqstpLK6bTH KA
+ QcEk9M9OlV1imS7BWFikZy4c/qa9WLsmrl4qUXeUUrLa17/wDAOhS3idrkROWiVxtYEkYx9PWr
+ X76ZImeVJV2NIVHDe/bip5kWSKFrGSKS3ZGxtTOecdxTzb21rpjSeaY7xNqKrHOVyNxxXmOpdL
+ v/ AEj2VOM6NN21u/Pv5XXqT/Z4r3S4HRXiR2yuT1wMAfnTIEjWRPtNpd206Sqkm+T5ckHAx65
+ rVilS a5dFjK2aTO7ODgZHQD0HtWJqCi5htsSMJJdshwenYA+/vXJTk5Plei/I8K85N05PS+//
+ AAb/AJml HLMk91ujIlR9knmjI3EZHHtVFoVluoVkP7lwfPfP3ZAMqPxqovlSPKDK9xlT5SKfm
+ LN6+uKvwyQW liqG1uHR49wkL4Dkdx+NaOHJtuegsBOLUqT956WVv1ZVaW28i38qLY+3bMM9WP
+ U/hxTGtpDFKEn2 Iku0yMcqVxk8fWpzfxNaR+TAsOSnzNzkscGnPLK32y3NnO7gtsVT/D0JP0q
+ 1zJ7EUlUhO0rr5jJm uLZpJAj3KSyqUYH5Qdveqtuw3Ol+6KisAQPvMcEjB7dKfarC58ss8LjD
+ RSO+VwMgnHua0T5uIoo7 ZZJYsDO0cHHOfU9vxoclHTr9xq26TcW/efy/HYLWZrlZhBiLePMVs
+ cLkfMD6nikiGYo7gMDH5REc SnDEHjP5k1HFfvLeQSyRi0gVDHtK/wB8kfpTbuxmmkhCo7xJhE
+ MZxwO9ZctpWehjFxpNptL+u/8A wRIbG6MqxG1mhEaFXY/xMORV7SxdW0EqSRF98yy+WR8xJBy
+ QfQelJDPMFkR4pogTtDs+QST1/lVK ZRbXFtLcSSblRl++QGcHkfkaG5TvF/1+JT/2jSdr9P6u
+ aEnzTQ7UCyJC8RmZco2DuLY/SqSQKsfm WQaSVnJXccjGe47kc06K5dZhcX0TvG5DeWnGMcMPy
+ waksJY5dQwgEEQlLgscjOCFH09qVpRi/L7j aFOvCLVk4rd9PTq2W4kuPtL74SY3wVfHAIOAP8
+ afLcXsQe4VPNLviUovRs4A9qtQzvDb2gkIklEB 2qB1HJb8fenpqdrJFbspCRSr5nPYqcCuVyl
+ e/Lf+v+AU61Tm5uXTyJD54M6ytC3lybfucqQQSfwz RPLK80uQgWONozIVGCx5zj6Uyb7MZLlo
+ JDKJL1fM+bOHHQfjVq5vHgtC/wBncu7FipUcnpWPVWWv 3DpzfMmrO/TRW+8pvJE+nRvKHcfZ8
+ 4DbWfoAQewqhNNcxDy4YTIF+UbhnIzyw9h3qaS6uy7pGIuQ BsMeTgc8ela0cSzzM5jc5YlwP7
+ uM8egz1rS6p6tXHUgqfxK9+n9aBaWVv5k7GLzlUlUcdJVB+Vx9 ecVcT7Mt0ITblRJHuweoxnm
+ pEgRYbe4wzDyP3m1sB+eCPQe1WDPFJamKKFt/mNnJyRnGPwrgnUcn 3PLnV5p3SuVv9FaCAvE5
+ +T52zkEnnH9Kom3RXXZbyKBGfMjBG5DnOD9KsraSnWopI5VEPll2BHCl e31q39pkkmW5ZFMTK
+ wIC9WPb8TTUuV+67nVGXsp2i2/M5mC2aW+mwWI3bkTPO3vWza27PNOyzKFM 65UjO4kdR7AVY8
+ 6B7u0aTbDstnjePock8k/Sr08scWnOPNgMaDYsqDAYsBz+PQVVWvOVlbc66let Oy2v3X5abmN
+ NCdrPMiXAlPm5iXBCrwxPt3pqxzM8pBjWJ5FBbb98spwR+lIryqsizXturyEMkeOY x0Kmo4Hu
+ ZvLjjZRIqcKRnvyPqAK0s7FTjUS7tddkhs2ltBpA+0TIo8xVQnIPbP4UwRLE26FWuIw2 GZTxk
+ HgfjUbSPNeQFXaZvL3pk5UYORkGnia7hiWVpYHdgIwipw248vWiU7avUuMJxjac1d/L9P1L hJ
+ DpI0J80Psk5+UsevH0qA3EM4ZEtppoQwSNo3xjjv6mrsYSUtCt1DJIkiqzgcO2cAj8MiojLEru
+ LNDglh6hecY+uM1imr2tqYuUIVLPf56GRskMikSBlBRDgc4P3m+lW5IofPWNLa4uY5d8keHyCA
+ cL +dF2YUQhd8RiiKKCfugjjPqafGzC2i8wNskw0YU4yE9Pqa6HJtJ/1/XU76kuSKneze3T8v8
+ AMy4I HjkmsGhneUKTjd90jt/WiyEkK7r5njVxvJYnHcZ/lTb67vWuDdeQ8UUoYqcgHAAB5+tW
+ bcSJbtdS zQsPLKiNhk5BFdEnLku+v5ndOpJ0730fTe79dbfcLFfLIzSxhXjT5UDc/eHU+vNVj
+ cSmfa0lvMI1 2nan8RHBHHTtSKY7uSeGYpA7EkMi7VA69B6GrL2MCWMsjh0MjAvLu+VSeSMe+O
+ Km1OL1WpjH2EZJ TXvPyX/A/AzUWzaxjlh3mdm3bGbOzPAU8dfetlPMjs1DXCgRnbK2ThzwQR/
+ KjTbRYZWmdR5ckqSJ nogAPyn3FRy2NwLxXhmAKYJLDKvzzx9DSqVIyly3HXrqS9k3dLW7tf0v
+ 5fMvvtvrq6kmnVVSTZGT 0Klen51Zt43kntRNGwLxlpQBjaQpB/AHH51lzSWa/wDLUSyqGEZQ4
+ G0EZB9W9DWnAtvA8k0XnhGy V3Pu9MD/ABrkqK0fyPOxMWqVrvXb19ehBsd47Yq0hRYQow2Bub
+ jNPQl7x4nXyGVRtZ+c461LcP5d vKDHJGuVeJ88bVOSPeny6fmae9SUSjcVDA8epI9qjnVtTOD
+ hHSW729fkTzf6FaFlCFuhIHTnJX64 70W4jw0pwskThGTPIJ6H8jSP5aWocXMUgB29M7icfNz2
+ p7wbtQQgNcbFIdYuCGHTPrxzWKempnCE akL7W666+WqJhMSssZ2OQ6lGPPANSPKRbuPMiHmfO
+ WC42lT938azYS0gQnbEDAWkdhw2T1FXH+w/ YZD5hKyN50eG+8FHy4+pqZQSZ1SioOLStf8Ar0
+ K017KJPO8geVEAhXH3R1xVhVluWX7RGwjdgz4O CpXufYcZrGaRRbiZriL5tplXHQt1P4VoQXs
+ sUyxxEeVENg387s9K1nSaj7qKrUajheO/4f5El3Dt VHBG9Q0bleFZ2xgj+VZPkJbm4nud+2OQ
+ RuqsRt68fU1dlmil3iSKaF3YSmTf8oAGNuPU+tVry9jF k0qrneA0isc4f0+taUudJR7jpzlC0
+ Hd839b3IDdwR2iraXC+YWG4P8xGRyPyqvEbeJ4zI4RPn2lu SVIwaagt7qEGK3kSSRW3ZP8Aqy
+ TkZ/n9KpRXzs8CPEt4FQjfEMAnJOefpXVGlo7fMyq4eN2438+9 vUW53w2UfmhZYQyD5FwVOOh
+ 9+lVbtPPs9oEcLRO3mLjld3JrWVpZURoYtxjDFiVyuT2x6nt6U5Ve ZSssAgUx/vC4+9Ifu1pC
+ py2b6f1sFCm5csnDZ91+Wv4FO0lkP2VXgLb38zCjBYA4wPTHepLu2kij gMsn7ndIHK8YPUH8e
+ gqMTC1dI5UfzfNUO3/PItzj8qY0t3Hqn2lIpJYd4yjcg844p8rcrrQ2UHOq 27Ra1t39GyeOcm
+ 2lHzI4uN7BznjHSrEt9bHTohKoDbQItoxxnk/h0qa6aKG4LDYYEYxbx2PUZ9fe sc3MDCRZGjd
+ 5JF8jAwGx1I9s9qiMVPWw4uEoqXLZL8zQdI557p0JCGZQqs3bb/MUskz2LGUt50Yj 2FevIxx+
+ tRRPFdGVlina53kgxnClj0IHpxUM7XE0GZrWR5SNshU4G8cjj3AoUbuz2FKLqe7KVl2/ pjEu7
+ c3XmpbTJlsIHbKsDxkD2NYz2TmeYtdR/upk80nPLHIJ+ladzZRTzI0YkjGd+C33EH8P1PrV SS
+ BHtZ3Ln95IHIzjO3Oa66TivhZxR5HUcU3d6bf53IpbB1uYYUBlUgHzE4A2nj8+aoKlu08quJEh
+ MxdVJ5GOhz6Gr/2KYQLMPPMTAMpD9CORz6YrMuMpcyTtufcu4lRwpbtXTSfNpzGcaaqzbdS6Xb
+ Rk DLEsyqN0rvtKqnGWJ/kOla1zqEaSToskasrOrgjq2BjH+e1YQh3XrEllKOwVc4YbR8p/E1a
+ eKSaB ZWCsWctK5GAGx0rapCLauY1pxqVouT08/wCtSxZvBJd2ql0KgFWXH+szncTV1PNKyeQ2
+ 2MREyoeS GHGfyrIitXe8hd5UiD5ZXxhffFXY2FrGro/zAb2JORJ82Dj2rOpFX0dzedOTk2nfT
+ b+tP1OgWT/i UZbaJFJjDkcRAkZQ+57U37JCHRI7o70jZGXeST3H6Zo+8t/JJGTbNciJE78/xf
+ nirEXltHKsIC3O 5TtbrgAg/n1rzrtbHBR0jyp63e2y9W0Urf7SQscEDKe4YZyOoNF7Yl5PlMx
+ hRVZZA/AHX9e1axVZ obHZPH81u0jEcEkfKD9MdqghQG4Ehv7cRFSAMZBwNuKSrO/MtDojimov
+ m/BfqYd3HFFdrcRuHiki YZf5s5xjHtUVppsrW0bQTWzlSSVCfe54P4VpzW9tcae9ujDeg3I2e
+ EC9Aapz+abBIVYBpR58hiO0 oRyV9s10xqPlST18zgxbVSmrXu9/T+vMyXu0uXmkcxQRhXQpsx
+ 8x6E/iKyklZZnmEgEj4Vwy5Bz1 NaV6sKziRrZ1idcnkDg9jx1B71nypHJYRSLHIGUlQikbj7n
+ 6V6NJRS20YKFKlBK10/JfodK8UElq 6wyOJlYsoUlRjAHSmmOK3voBJvS6nQvG8pBQZ4xjvnmp
+ FW2jluZEY3OHOxIzjC7evv1o+0tJZWbM Ix5UJGxly5HUHNcSb2W3/APUbcY+yp3t0vv8/wDgj
+ jBciM2rEq4bZtBwQBySfXHeljHmyC4Ks6j+ FTjfk8EegB7VKfKnh/1jtO5G1QeSp7/l1ojTTp
+ kSKJblZTGH3+ZwNp6EeprNy01M4RjKDTbv2tt5 7leO5jZoJriKOO5j+Rwq7QGJINXL+xiCQfu
+ p4lUlGLP8vr+HFNheT7agMlvGFVivmx5xu9fUj1q9 JmJGMVwkzW6FW3DIJx1qJzcZqxnKFWlU
+ XItfV/5f5mNcwSWlmiwtDPBvyzBejLyBTS+5JJgksDOn yFnPzBjy30BqxMsdxYqROFgMy/N65
+ HLfSmzSrbPFALZ4oWdkidzkBDjJ/A/zrWMrpLqdtFJRV1eV 9/8ALTVjEV5LgrZKtxNHIVXAyG
+ Xb1H41YRJ2iImtrlZpVBQA/fUHnHvUaJNCzSQQyOJmDxlDjIGf 5HrVxms4LaLzXlW5KsQ5ckL
+ xyuPfPFROTvpr+ZH72FW9PW/rf8HsVknji2IkLRQXLh4Wl5A4OB+d TNpkku1pPNG2LaUV+WOM
+ 7h7DvTIHeS1SV7dzBkLGpxlM/dJPsev1qKWVxdXXnmSBvMEMkjMdqk9T jsP8aWvN7un4mNOb5
+ 2ua3fS//BIY3ubuztrfyZHZoWmQr/EVPX6DHNSyxOGEs9tJciU+d8hwMjg4 9BTJT5AFta7yYV
+ MW4HkEkHH86da29691GtuGh+R4nMnIUsen171b0V9EjWtRhThzSklH539X1RXc i41S282KWNm
+ fIUtwTjnj04rahtrIW7SSwyxRJOGbEmMjHB+maptZXH2qO3hbNwsR/fNysijhmHpU TxXVtEoE
+ c1zBIygOG+VQDgZ/Opm1OyUrEyp05zT52vJP8f61NcLHBYxRQM0beUwfzTuKv1xn6Vbh UCyt4
+ /s3nTGAhGQAKQei49TT9gF0yNxcrIFkJHEjjqwHYAcVPPNGixi2t5S4Qyrls7AOgPvXnym3 ZI
+ 1dRNxhCN7df8+5UNusskccLranIEofna2MDPv71PJbX9sSrJ9sXaQAg5C45bmkE/2lIPIZEO8j
+ btyQgOSSe5689q0rkiJLnEFzK81wJoiH6xgcge1RKclJImNZKdlq/P8ARsWxs/tItjHGViWHy3
+ kb uwPyjPvXQWunTRzKzRs+IWLIvWIgcq3qcHNWbQRCVLiCVIkGY0BGQQ38WPY55qaEiHEby+e
+ w+UFC RkdyfWvIrYmUmzzMbj5Oo4rbtZmb8jWcSRQMsbIrKzHO7HIx7VOkAmWSVmiEm8A7RjKk
+ 8/4UkxtV sA2HTceDu4UHinXSmYmJZo3hDEsYhgnAGOai76aEwckk07fL+v0GSR2ttdTPIrJbq
+ pC5bqvr+vNV AlqYQouYWCgcgdxnJ/rUpWEW6y3SycKQkecce/8AOqRikayUzyQ7eMKi7TKAeW
+ B9K1grrVnXCPNr KTv3/wAt9fmVWgjlulmKtMoXbD5Zx5ikE7v05qpLdwtHG8bKWmgEkkY7t0y
+ PQD0rRt1s3uTvuDkb hEVYgHGaq3AspLm0El1axRtCdyqMEljkYPpkdK64SXNZp6HRCvFN8zbt
+ 6/1+RmKYpWCHKMw2+Y/Q DNWJLSJLhHt5wylJPMKk8be31NQrLIbtX2KiKv8ApBYZCzHoPb6e9
+ ayXcxiJuFhWODdHIQgGGYdD W1SU4tWLq4mtTa5Ze6+l3/X4mNbllTdEolmli85IQPmAX39B3r
+ TTyzbNdSyQJCZBIGK99vAH41Ri vrWOGJmjaFzHtyT90McYNS3rF9IurePbI0UwChR0A5A/GnN
+ SlKzVh+0nWnGLjp3f/DWNKSSBHtnt kVSYnMuRnbJkEA+9c7LdzvqLRbNiDIdlGMs2MVPdS3U1
+ kB9imYyHO2PghiOW+g71KksNskSzTRNM snlv/wBNGYfeHpkdKdOCgr2uzeKjSjdLmf32K/8AZ
+ m7U0Ed0paNvLlDZbkHvTZmSOW7V5N/lyHy9 v8ORlR+dXLW5Es/kraTlMA4Vvm3DI5PepBOss0
+ YjeAyLCQYyuW57n3xzVOc+b3tbG9T2/teaetku 2n3f15nOzsGjh86YMnkgTqB9yQcge2atW5d
+ pJPNVZGbcz4XhG6Yx71VdbaNykkcjR7Fw4PDHPytV a6kuBEQJBIZZczsgxsJ5H0yK7VDmSS/r
+ +v8AI6qlLnSSW/loWIzNHqJ2wGOMxHzN3Pl+x9yeadvm VY4btWMUICMc8FuWH4ntS3n2iF5Xt
+ juLzEqMZyu0ZP4UtpPGIkjvJY95ZDAccMncn1PvQ7tcyX+Y qk5L94o3W3mrFkjcYE+2Rwqw3r
+ GwOSMZakvZE+wLIkrPsXaWV+BuIIH1xmrS3cRnjMUSFER9pwCT u7D8OazJZbCKyYW0oeR1IjD
+ cgLjv754zWNNNyV0zPD0n7SN4vXorfj1RPbJFNqiyFCsETPGiHqAw 4z6mty2sc2v2eAtNswy4
+ J5VRkj6msA3jtpaRRQP9pRhuUdcFeSfpVmKaeyty32pIs/KuQSX28hhj tg4NTWp1GtHYmthcR
+ J6aNuyTV/yNCJctcrIkquVLDzGyAD7VMZWOivbPcwxokiguQcOeuR7VSGo3 E1lFODEkyREOpX
+ +8ePy71NLeyyQwwBrc+c5ZW8vggCsJU5XV1/SM5UZtxbVrP8fmhyJPsYRlZZnQ sPl+UnOOBWm
+ rSxyTysrsqvh0XggheTWa0837mfckcaRNhQvLBiMVXlCxz3iolzJL5n7tRJ95QvJ/ M1Dg5bly
+ oycXG6Sfb/M2J5IDY2j7WMZhdWRTgglhg/TFZsdzG7/Z0Xc0LbAfUPzx9MVFDNdyafIk 15av8
+ 6gFUxwetVJLuK2uCgdBKpKSP/tbTkfUVdOha63ZFPDxUOTVy+f9Mv3cy29rEWaCaRxtjVVx lS
+ Rk8+lQ3c5js5oyvy+ZmCQHG+IEEsPoaxnhiFnBPHeASBBhXJJx6j9aZDe3YuUjhQ3LDOwlcgIP
+ Ue9dMcNomtbfI0WEcEpJN27ppFm4u9QDgxbPlOCSuQSev5dajeW+NySINyZVJSRkEZxkVHNKUn
+ ka WGVYGLgNu4JIGPxzUFpBcRFC8u6dkYFM/c55B9z2rdQSjeyOmc3Gm5NJX7f5pluVVW9lSW9
+ S3jjk ZIgVOcDkZx19KjkK+UrmaKIgESEJwHOCBj6VTa7K3EMXlIUCfMsq7jke/wBOKszzpc2i
+ iXbbAOzy REfMxXoM+pFVySTVzmk5qUVKL+VvyaL9rLEhWZYpzFMTKxD8DA4B/DmonKzhV81ow
+ ULIxbhj2/Md KwBeh3jyWWIRsAo7Z9cVde33WzSrcoYUKqNvcgcfzpvD8ru3Zm8KPLJOctXt1/
+ ployKlt5nkTIZH BMjtlY8cBT6sfWozvkgaSAkSmQgJnOwD5Sp9z1zSERGSzHnfNtj3J1yDnKn
+ /AGj2NTbYrbVCZCwb DeWOnGO/qQTnNLb1Oec5xk1zNW/ru2KLq7j1CO3kUJbxKxl3LnJXpz69
+ Kr3ZkS7t5YIQ7EBmXbwp H8HtU0rl7WFVJDxoVaU8qWHr9etTKXWwgxLHGOfNaQZw/b86Sai07
+ A6iSulZy0tr+lyzZpm+keSG W2mlckZbAVQOePY1SVIoLiKeQzGMx71ctlW4NWR9rNgkp+aSWQ
+ TFwOEwPmX8ahlkQ2wQxyIrI24u 2QpzlR7VlG/M/PQ5YSnKTUldS00/4JRk2/YfMS6XmMKUYnO
+ abb28jwWrNPHejawW3hPzEfxdqc8g WGJnUGT742jhR2BHqRmpJlu/sYLIsXmHMRjXaVx2/Gum
+ 7tY0rKrLljJJLpzW/TVfeijbxzPcJaZk gRUfaHyfcCqSR+feO9427LLuVBjIPf8ADFW1t1Qkp
+ cExfKZctzkjgA9uajuZJEt5YJAg2kCQFeck DC5roi9dOovYTm3GLS032t5ruZpk2agZIysqI5
+ 8wj+LnsaS6jl+yvMsqxQs4XY5OX78fSpIYmkae IzRQqCMswIAI6DP51AiRlBGHMs/mFozngdu
+ hrp0T9DmxKUPdWr6v+tCS4kYmyWORXYKWCqMbue38 6sCRTpxcTRyTEkyYHA5xgenrVaRvLuFO
+ 1WAUJuC8Zx0+tOjjWR1jlkS1cgMA3Yj1pOKshQpRp8s+ ezWun+a/yNpLactG9pL5yR7lcjoWx
+ xx6/wCFbKb5Iw8vyXQAPyjHTr+lchBJKJZwJFjZiX9MgdD/ AFrRg1OOGGAtKX2hg8hP3nPQj2
+ HpXFWoze2py42VZNe957a/MkDpPBFvv7dEKFIwoPILdP61cgtJ bdblYrqCRIpFiHy5+90NZNq
+ VnhdECl1faJAOCO5A9hWr5klhbpOgEqJ+7wf4snhj6nHSlVTXur7t DpqYia5Y3u+istya6S4h
+ uJIIjGY0QgELyWQDjPuaw5lultvlcCbzQsh28JuXhTWq2pG8SVLUqzRz FI8jqrcA/hg1hNNIy
+ l4b2CaKI4AUHLkHntRQhPqtTzpRlN++kpf18iCeRxbrHNbSkhRGxLdz0OPp WSscsUJaUvEQAO
+ mMcnj6966S7ufOhVZbZ1kSQkkHGQCOPqKwl2/bY/OLtCGLvHnk7T/9evQoSfLs JSbV+W1ul7/
+ dZnTNeNFbzKluqBZgWyvP+zz6ZzUzXl3EZHkaBi2cBYxxhgM9OlPuILq3PlWuyfzX V5AV3E7T
+ x/OrOWnlMV1ZOJtkjuVwNhB4Brz24WTsmvxO6nUpQs4QvHu7N/dYoSTiRproJlWlYAqc BvlwC
+ PQe1W7KSWOKNTPaW7RgQMkiZbkZzn3qNXtLWeASq0YaFlkLHKrJgkcf0pVFxENNkhCSzqg8 9C
+ ufMGeo+lTKzjawSq3hpv6f5k5trmCCI3SiS3SIq4UYYMTlVJ9apmK8DqL0eSGQxsQuOpzg/wC1
+ itIkuJiyyMokJJ3cSFRww9u2KYriW6HmyJmJVKKe27hgfU1EakrHbhq1SVJpfr+C7+ZS+y2jzz
+ /Z pGa383aELdFI4P50XKQpaRBVcDzfLAdsjkjj61ZkjhuLF2bFuMt5YPGUUjB/GpLSzmVXKXd
+ pHhw6 iRMjAHT61TqWV29iKtSUaampu/8AX9bGfHebrgxIDIomC8H/AGuMflV+5lFrqsTAQfZ9
+ hDiVd2/J +8PQZqjdtb3Ea4i2Y3LG6KAJAT19znimxRQPdRLdPJBbDCLFK3zg+59iPyqnGL1a+
+ RlUnT9m5TXy 6l26kIt5S6mTMhwsfy4KAY/Dn9Kz1xc2yKjCOUxESLLyGJIy34fnS3ZjEc6rIZ
+ WlYPIQeFJI/wAK fHbbyfsuN2HQhuSpyDg04JRhcKMKdPDqUtLvT/gq2w24triSC0bG4lmMmwY
+ MhHHFWLWKMX8qXCXE McUy/MZMbDgkbv5VVNtqNvbRtLudFfIC9cdx9TWtJcTXFlKgVI3aQCRS
+ vzO4GQ4/2QO1TOT5bJ3X f5hTs6Tho0+q6fn+Rbwz7rqBiwdhtQHDE4wCPRR3Hesclor17e6lY
+ pEpRsNgNkZU/hUTRPa2L7pD LEZsIQxAIPP61baGCS9SRrqG1x/BMCSejDP1NRGKj1ujehTVKi
+ 6knfpp5en+RHAL2c2+JhPkFW2A 7sHhjn2rZjuXs794IrW4DJKGVnbIwOpPtjtSabBDLJLMZ0d
+ pJgz+WdoBHOAPT2rZM3kKZLsxxq6E oxXJA6nPrziuWvWTly2uc7xidRwUbp7b3v6LcoXzSyvu
+ tzEkqnZGqr/A2PzPfNbCQusUJuIZv3YZ XkLfKp4AOPSs2RJrmzhbg74S5KDBBBBI/lWpDIjrZ
+ ySCXzZo3Yqz5BI6ce1cdV+4l2v/AF+ZtWqR 9lBJdXtv8/8AhjchV7e0iRNqiMlWZhnacZwaUs
+ 32i3DK5LwuGkXgZ7H6VB5T3Jji83ZuIwSevHU1 qOYIwY9rI4BIDH7hIHJ9h/WvLbs/M8rSMny
+ u79CnbQw3CwbW2ybD9/kA+mPWpt9qrojq4DIZDhsH J4FV4TCb4EMZMHcGXjtwKfI+6RGCjzNm
+ WyM4A7USu3qQ8M3O8l+NipaBJJYi+XdI2JBOeQDz9Kbc CCaCJF3uJ4TchlOAAABge2avwm2ba
+ pV03LyxPXNUL0R201vFFHJEOdjPyAgH8s1alep5ik4Kr1uZ MMNs7uQdkisNvPG053Gsm+2iJl
+ FjcSSkB7eRWGAg6j61o3UN1FDHPbzwgxPHHuZMg7vX6Zrnr2S5 knMRt7hzbuYo5I3wFHUqfUm
+ vVw8OaV0z1aVPmqJ328/+G/MezQeZcl5hHvl2xqxwWyAA34VKY4Ss gSSaeRkIWNZOZFAxn3Oe
+ c1VeaRlt5tsUMMhxh1yVBGAM+oq/9hhiiWKKC5M7hN0m8fIwPK/1P1rp k+VK7N6mJcY+9Udvl
+ /wH912YTxQp5dsjyRfu8yLI2SzAcEe3t71bt7jVPskKRRrMWPmSAL82BzV5 NPsY7tzFvlAZzE
+ 5bOAex9cnpTo7M3F48ipM67P3hjbblm9PbtVyrQa1/E7KTjVpvW6Wuv9Ir3N5e nT55HcRbrg7
+ WxjAwOntUomhvrJ3MLN8xMu3jL8BcelTNbuLefbNCJBMPvrkNxyAPyq6ZIksWa4tZ Cjy4Pl4X
+ aeOPqOKxcopKyHQdKnytxW/R2/D/AIJSVL0pPH50UUyFTKoTlcct+XeiXYtpcNBPDeP9 oBzCu
+ 0le34A1ckslkW8uFuCG83ZKcn5sjjHpVBfszaYvlH7ZuTa6wHaykEYpKSlqvyN6kaU7TSe+ 1v
+ zf/BMp7l2ZCQqqI5I5BjqScZHsDT7UyyaUImjMilt7FcAkL8tWWaKW/eNDDEFQhXddyk5BNaIk
+ Z55YkeJEO5lkC8bSMhfrXROVopWOuvg5WjHlt1/4bb82ZVnbWkNva25lmKMkjuWk+6SeM1cY2t
+ vJ bhZYXuVRvlIzjjj+tWo44IUiZ9sJWHGJOcfWnC4tLnTZVKpcZUHMQwxAOKwlNt31aOL6s9I
+ 3fL/X l+phxahJmOQRoFVc4C/eOeSPapkurZp43lFs5ZWCgRj92PQ/U9KW9dxO0Nv5SBZEEa4z
+ letTXTXD q5MMIlEu8ARhcjv+VbtRdtLXOmWEp3Vla/oVbeKK3vspI12PIcuqNyNo4qHLJZW2Z
+ o5IjGu4Hkrk jI6dauXCEkTQARylW3EdtoHB+tWYy7i2nmmtWUl96rFgYI6/hQ6ltdxTxnsVzL
+ 3umu+nbQozFRP5 CwSiMtu3bzztH3enc+9RLcyQPFdXGxp5l3sgGAOcDA7Ag4+tTCVmW9uIyAk
+ ZEa7udw/vCoDBMzQz KyS7omH1PqB6CrSj9o1UKUvebsn66mo95b3GnNFsks13lSJD9zJ4U+9U
+ Li2eOxMyieLy28pizZJG ck1Tfz3t4g0DhRuG89HJHWlW3mYuIZfN+UERHJyD+nFEKShsycLQk
+ knGdopu63X3/wCZZ85/s58p WKvIuQOoyeB+VV5rKb7YZXhkjZZywRuScEZzV1rfzLGdVtp7aS
+ OT+Ju4HyilslmUu80wxIoMu/kr Ic7R/wDWpKpZNomcpcjkpK35kN4Ynu3+zxqdoKy8fKWzkAD
+ sKqo0RDeZvtJScE5OBxnGBWtcRySF EaAzziEtOIgV3MtZEu0DYCIzNiY7xnHHNVSacbGkJNwU
+ NYrq9391/wA0WYXuHhiijMcjIoA3LkZJ ycjvVhLWV7QR+Yq3CFwXPTg96o/ZX3maDe8Xlneqn
+ 5iD0IqOWOSG2th5joDAXkVmJJyfvfShxTfu s8+vh0q0ZU/h9F+P/BQyWKKDy4/OWSeYbSpwQT
+ jqOOlUXiuIxEzxtDuGQHGenWtT7Cjo0rFmiDKE cH7q5xj61WvYTFfqJGJXy3CIWySO9dFOor2
+ vc2dSU1yOrdLo/wBGU5FMke7yEy2Wyi4BPXjj0q2b HzLT7XGXSFkZgm77uOn41LBaXEcW1yLh
+ iFK+WMcdhVwQNLa2xt0ljlEJhCO2Qx3HPH0zUzrWtZnN KrGEocsklfW7v99zDmgkRIudkkij5
+ Ccscen4VLHHJjO8SERs8Z6/JnB/OrVxZRqrRs5meINgjPX/ APVTrG2tklijIfa0JIJbqcHd+G
+ KuVVclzrrynGl7WesfSxBCyy2DkoyoB+5Qnk5P6mtQWUV1b2TW rneEIcFsjcTwf51Xdke1DR7
+ PLVAFA6/L1Oakyy20zRo1u0rBuT0GPvD0ArCbb1WhhONSdOEovlV9 P+CiFI5YrxYyzyuoDqgY
+ /dU85+tNMspke8iZZirmJQBlSCOuParUVs0aoySiNVh2O7jOT1BB7Crm l2s728s1zA0ZNwGQb
+ cZC5zUTqxinJkYiqlK8mn36X/Az0s5fPgYSJJCIXjOOrEdDTjAJtJjledky N7ZY/K68Bf8AGr
+ Lia/ZER08txuEqDCqc/d+vGKz47e7lmkS4heIOCyjphicD9KFJvVuzRwztOfvS St+RkYJExI+
+ 8CWAOPmHQ/Spr0rLpY8weY7Yw68BwMfN9B0q08KxQxpG6MxXLA88/wj8cGql9HOsc DiLYjuzs
+ uOIyB8qn9eK7FNSkjoxOIpzUPXt/wCO2kaC4fy/LZgjbWIyGz/Fisvyyk8RdigjHQjBb vitq3
+ eb7RGSkNvmNkMjr8vzdO3aqlzHi6toHcOIoz5jr0c47foK1hK0noYctJtpU7d3e7/y+5me2 Gd
+ S2A75YA+vYVMd0YlKxsZAWBJ5wMDI+oqJ4gm0eW8cQbcN/LD2zjnipXWUopiZtpGVXGSFzk545
+ rdu9ipSc2o29F3II7hpNNWRVUMoCEEc4Jxk1ahGx3DvCPKk2hSuc+/4VTZ7hRbCEoEU5YLH97B
+ z6 e9PRJGkcDLbe/qDzQ46M58PSqzvSl8tv8jQNw22NBH5MRjZ2XHJyMf8A16FuLeK1iAlaVlK
+ sNxO1 yO/sMcYrMaHyzCil2HIXqTgj+vNLBFLhEdssdwVyhC9Pu8jrUOlCxDp007S0t0v/AMM/
+ uRpxXUUc MhiURL9xR1Lbjy34VD+5O6CCPyZTIIyWOQxPcflVR40WLdMjxSGQbEJxlRye3rUQz
+ O0g2NGjOZWy cnIHBz6UKkt1/X+ZhUoJtSp38u33atl/UY2F3taC4G1Ww27jkDBNNhndrUySRR
+ 25B2EPHk4POfxq oEu2AnLGVGiJEnOMHqPrmrMMUd0lsJJGjRQURievPQ+9DSUEn0OWrKmoJz+
+ 9f8E6UxXE3l7bedoo Ytow2GLlsg/QVNCJtt4tzOvmtdRsXAwAuPm/Cp/PaZYVEMqp5Z3OrYG4
+ N7e1XJbaJrFgQxdSowDz IMckewrx5VLaNf1c2q16Sdp6Lytp+hmtBFc3F7AoMkTzMysOvAGBQ
+ v2iK1Vtiyl90nAwV2/0NF3b CJZJRcK1uJsEJkEKRj9etMtEktLW4lcPOgk8uJgeCh/qau946P
+ 8Ar+rFqKqJO910TWj+b2JPtZgW 3lLqsc0bSlWXO8njK+gHpStcQtbyOQFdJApI4LKAAW+maGK
+ TRM4TyYgrIyyc43dh6VWNjcCKOYwT LE6AYJ+/2BH9aIqHXRnRTjh1G7XK3+I9s3F55iSI0RBw
+ gHQHj9DSQx3dtYBQ2wAgNuGTG2eAT7jm pWiVdNVYg29JgiAHkqTwPc5zzWlFKsOoSQzxO/mMz
+ uc/xDp+VTKpZaL+kEsReKainbo7GMtpIyTm R0PlyKvTGQOQR7VFciS4lYW0BSNW3NK/ONw4Br
+ d+zQX7xzoZCZox8itjBIwB+VVFO3S9szxrBEBG iDhmBOOT3Poaca93fqbOvGpO6d5Lps16W3+
+ ZV+yeZJEv2CdyYyqMrAAjPBPr606KL7NfSzStl4Hz IRwCcenv2rWtdPEVn/rzAys+0OxO0AYG
+ fpnmsxnKpJi6t7oIEEjKuQzE4FKNXnuk9PmTShHERlfV duv46Ed1IL21jMKzRSlfkQv91Sec+
+ uAKvxQwCNwjklgWiycliThWB9B3FV5UmRprdpIpFJLkIuGX aMbc++aUxI3kq04Bh3KQDjaxxg
+ H8KUrcqSehM6UYQjGKsr/1qPkVlsV88xvIG+RwvyFc4JA/l6Vn K0kdxLJHcW0zF8RnZn5AOv5
+ fyqNvtMbIRHI8Rk+6ecqOv6mtC7aJrSKWKMwSJLznkMuMHj9K0UeX Te50wpSppQjeSl9xHLbk
+ WqZmMhAOHh+UMBgk/jV6CeXUbeaO2uIQN4ctKmQSOoGc4Bx0qOwDzqkM 3yQkboF7gLk7Se5NJ
+ FaOz27xK8McsGWI6Bycjp9Kyk1qpbo1pzpRTjUa5lt/ka0dzcW+l3Ml2wLz TiTKrgRZxiP6mt
+ VbyZYonkEKeXmNFKcjJ4B+tYqW7pbK0sivMXHynoDnOCPUVqPb5uLpnmVZPMCz AjgucEMPQAV
+ w1YwbIlhFOC1vr2NNHZoFa5ilTZlTtON7Zzx+FTvcNJ5hjOzfIo3OM/Ke/wCFMAkT Jdh94EKe
+ oPTH1q1LHILci6XY7ZI2jHAIHFec2rnAk1Llf4f5Nk8sFjPaMWYjDARbGI3ds/nUcUip qEIR1
+ /1LLIWGdrZ6H8KUbftJhgjM0ZZCSO2OlRSyY1DzY0CiQFkz/wAtE6Eisopv3SIPSVOW3mST Qp
+ NIB5ylSMDbkHJ+6ao6pc2lvpUYnmywATGeQ+4YFMlu7qJbiDMWxv3ocJjaF4xXOajOGtZTc28z
+ FZVWPBweO/vg11YfDuU1d6BDCSUlzPT+vQdPcSyambWK4hDh2ZlK+nP6npWXqbCNEkAkjuJYsl
+ 85 UKfvZH973plyrTtJFbRskrMm9mPPXrn071HsL3jQteW7qp8v5kJ3qf4h7V69Kmo2fY9CjRV
+ NuprZ bq2vrdfqadnHC1pbOZBcBg2xR3Cjj8upqKNorS682ZLqOB5QzSOxI3c4/A1lCO8SaOKF
+ gsRxJESP 4AeT9McGtC7R73KJBLNC77wUOMeg/Kh0/e1ejMYYHnquMp3Uvlp+RaE4lkjlALIpO
+ FXghugz9OtM mj8qAyMJhsmVXkSTCuCOmPfPFMjt5Q0TXFrPFFP2VsF2z1B7DpWhb2dsk0xlt7
+ gMAymKR+hH9fSo coQPXpLD0tnt26/NP9Bkd3FcXC/ZoHGwFULHIx7+p4PNVo3luY5gbG5a0mv
+ FcuDjbt64NXVhSyWW 4t4mcB1Aj79OT+RNOmeWOCOa3jeG1JLxs3IKkYH61Cav7q+/7zsjGLl7
+ iTvs3vf8wNvEJsySPty2 3BwHXru/A1nTW1ta2VvLHvjZ0LNh+M9h9TWxG9vskSW4jJU5KnqpC
+ 5C/iahYWz2StOrRuQSu88Ed ScexpQnJNbipynGcd7X/AK8yOGFpIbQ23kRz+UUdXQEq56Z49K
+ rPZyQSSz3cbsiKqkRnG5/4fwqe SK6WxthCyuoIMkyDhH9D9at/vCtyslrPKfNPmANx04FPnce
+ v9XNqdWcNJWcX9/36Ff7d/aMqI6xx Ha4nDJnLHjj0HFNWzhs7a3fyZplERiIjfGSx6/hmpbZL
+ f7GrGNuSiZXgknIzVhp0s9UcypIY1RlT PIYAcmocrPlgtOxhKUVJxpJ+hlXFjaNZNEs2y4jkA
+ XLHI+v1pk1sJGH2i1u3kTduCuBuyOo9s1YX zJ0haaCUwsyGIjALjPJz6dKgiW4bVnZSY1eQzO
+ JDncBwAPTJNbRlJLfYHOUYtb8uu/4aFk6cIo/k LQsQQpc5BzjNZ0rRkqr4uWCEEQnbgnp+gpz
+ zyxXxDzeQ0S+WEk5yxOc/hVW6uSZZJfL2TedtMqj5 VOOBj3rSnCd9XcIKUXy1Hfqv+C9x0890
+ LIOFjhSVWcIUGSOBTIZQIWnSVZOARCv3s+o9sVOJbkWp a4jWCWP+KRMhezKR61ltcWjxOkI3l
+ 2+RhxtQdsetbQjeNrfcOKiocj0T6rVP+vvNW0uGOXcZw+UX HDKf4h7VSniura/iMMqyuh2r5Q
+ 655GRiq0RlvrjMeLeJAUXPYYxj61K5uI7a3jvE3iL/AFbr8u4A 8/0pqHLLp6GdKmqc7Rad+mn
+ 6lqS5eCIqm9Z/OIfec5J5B/KofNEeoQXdxKHBRjtUYBJ4H4gc1CJR 9rldv9YV83cem4f05qae
+ 9lURxrai5TecPtBCjjFPktolua4mCp+4o6Pf/h+xctLi485jHukVv9WB 1I6daoPGkljcmV1W4
+ dlZFIOVA/xqSGWyaISeY0MiuqMNx46+nvUM4uCqS7oJnRwsgROq/wD1+lKC tPsZ0ptVG7NL5K
+ /zehfhaWOAXqlXckiRVHHIwuB29asQWt6tslwjQzPFGsWGTPzMT+lQTLd3d0Y1 hMMsbkwxqMf
+ u9vcdyPWtQXUwt7dIEUJIhlcgc5BAX8u9c1SUkla2p59R1U+aMVq9U7PT/IhW2P2O WCS2mLx3
+ CK2DjJHJ/DNNkFzJDPdYt4WSRY0MkYPyH7xq/JBcurJ5ojmy2+T+FiMEn8R09KrKUl32 7N5kY
+ K4wedzdF+tYxm3qRGnOMG1bzVtv0Bbq5jKIYEmiThVjQBip5Xn1qvIkLWUN1tktVwNqueRz jd
+ +BPNaW4HV5tP8ALbfEjh8dcheCKzLiS7fQ1iUwlJY1kjhKfvCF4PPoDzRBaq2hn9Wipxjbl792
+ n96+9L1Mq5EVru8yZLptjJhDjuM/jzVKRo2ztjltyIyAWbPTA7CtWYJNLa+SVknjhbY2PlZj7d
+ yR mqK2zz3rIwChFIOD3xx+dejSmrXZ6mBr0uWUZy+Hpf8ANbFhPLngi+0yI7mItiJduARjB9y
+ cVHm0 t9Mtfs63DTq3lyo752ueRx6Y7U6GMtEv2sqilMxKowSAc/0qKXbPMbyaQQeajOIuc5PG
+ cAfjSS1t fQ5Hg4ydoS07a6/gX7v99by3ShirLkBTgY9R+VRxXBh8u6inJEh2APyEyfun3NZst
+ 5NFDH5U6yDf ukbb8o4+7j3qAyXLmIACNkBYqVwFx1z7jrTjQbjZ7GijWlScJfj1Ld5DLNOjQw
+ zR4J3Kp/j9MD0H Wm7oRAkrPNFPGpHzvkE9j9M1JYSlQ1yrgySEsqHnPBGfw71EsKC6j8qaNZl
+ gK7XUkEEdfQ1Sdvdf Q56dSq4OLWi8nr5PfQqWgh8xEnma4d4z5jJwEY5wOR1prsoji8xAHKAY
+ 6FCTwD71opFFZwRtJLEW GSQqcleq/wD66wiEvLyWSeQRsvzI3bHpj16Yrem+aTfQywmIxKlKS
+ b5f72qfyJyRb24QRPK8bkTf NkcjPSq2+MW0iKj+VIysjM2T8vUZ/GhomEy7ZlmcHJRM5bA69O
+ g71JCY2aS3kPEkm9SOMe341tZJ XM1FRnOa+etvwK89074aJkFukwBjYbmORyM055fMkSOVUIi
+ JBKttBU9v0qwqqmpxFoluJGjO9FAG DzyffHNRm1EUfnTwyiAnCKGwX4659BxmnzQ0Oe2G5k38
+ kna/4lKJRNI5iljK5wWJ4XP8PTrTBFho ZGE7gMcBWwpI7HjmtRYZora4jUW48pwrIke0u7dDU
+ OEtmiWVHklti0b7ThXB6kD15xVe17GUqtSS tKN/JP8AXT9SsYrhhHEyPnaNmFx8uc5+nvUQjZ
+ ZJHaKRDuyqsfu5NaE92ViEETboADs7sAeSCfao Y4ITbs84mCK642MAWHeqU3a7R0bU+aUfkv6
+ RQnVLvUINs3kRQlgTIxPHpx3rQEMDoLhJVMCtkr3y ein+dVldBcylFDJvLAMoOSO/0pI5YpXi
+ neKRlX/WbDtDHJ5pyUraHD7OpG9uutl/Wn3sluJIhZok Uu/BBTbwozyRj606NHmvpTHZy7PMC
+ yIpGUB7fWnWEjW2n3Ea+RLiUOPMjDYAppdUu47i78xi+XUx nYGJ7cdajVXS/r8jKNOpGjJJW+
+ e/l/wzOus7MJp0ixeZIxw2N2c7W5I+g6094SmomeKO5Z5cyQLv yNgGCMfjUtlfMdyOm0ySAEg
+ YwRk4q5JeSyzK3lqfMR3aNBgxkAjb7fhXiTnUU3dBPFTVZwcLrvff 8TMgVQkRW3uJo3UEgtkf
+ 72D2FLDFcG6SVpo48IymNh95ugOOmMc1FC1wLHTGETRNFblgG5yc4H4Y qUGVbUywXEE+2WMBA
+ uTjNaSvqd8ZVG37y107/wDDF17aRNPYD5jHLHGXPRuOWqjZ4F6Uk86YEAjD /Ko54+uOaciP/w
+ AJOss8jtAyOxKkhVODwaWFbC1tLAQ+chlx5ckj5HOQT74zU7Raet/6/Q5atWUF yuV79uhKkd3
+ DY4DoEaPzPNZcjjgfzojSN5Lee6V43+6zbsAuQRinmS2geO3aVihVgYyclcj/AB5q m9kiWFqs
+ cdwU8wOCzk5H8X45NJa76XNIu6UZOz7liwSYR+T8wuQVBUdQQcEfXFab2rpGXkEca4yy uuSpz
+ gfzzVd5UmuoYoYpPtETFpCD1Yj730xmoJrqYwRea4QIyhdw6oTzn1PpWUlOUr7FShN1NF+r Jp
+ p3j84SsjvGGWRlGAC2B09+tZkkVrEGRZ42iwpi29SByM+vNaBhvjqaNGiz2sm4ZC5x2GfpUaW8
+ 1u4t5/JjWKMIJ2ThiOeK0g4xWjO2lRp0k0nr6r8inOQs0ki3CCTC+aSONwPI/GrD31o09y80DO
+ BI AXj4AJGQD78Yqd7WO5lXzHQs0ZZ9gxtIOdp96fmHy41Elqm8MQGT7xxwf8KfNFpXX9f0jpl
+ UozUV JO/zX4lL7SbnSwY1VZjggY+6CckH3GM07yppEl/d+aZW8yNsfKB3OPSpbO4MUojiaDbI
+ A6ErnAHH 8+Knm1HyVuEmAkmjuFAEY24GOR+FD5lK0UQo1qErU43e+u5Xgto7j7T5k4VlZY9y8
+ cdTj69KsJdP taG2lWN3kEr71z5RXov4+1QEW7SuIHKTbTkseGwMjj3qSWayfSYEMiJclFM+OC
+ xJz+lTK8nrr+hb nKrK87y+W3quxNb+fPPubduddxQ9UI/qauJJILyN5FcxFOWz39D74qOGIqZ
+ 5/MQr5pVUxyMjufQC rd1ZgWg3b9kUgSMqeCMZJNc85x5rEPGUvhlK99Lf5GiRJFEHO8RxsIyz
+ HPLEc/hT5biYWz+a+6Np C59QAfX0rBgRZFZVeUxqwBLOcepH196vXepNDYZihKo8wLhgCYicf
+ Kf51zOi+ZLc5IR1Vtdf61LI uWEe8kyRvESfLOCrA8DPvQ1zcvaxSJJHFLsZY2dcqysRkgemeK
+ r3NwEucMyy797L5Y2jAwMfnyKy p75lSBDGxZVXcB/snk+w9qqnR5rNI6KaVVXiti3dXl9BaTe
+ W8IAk2zl484YjhR6Vg3OqXQCRsUUR 7UbcuSSfm/pinRxFtWcPDdSRyKzyrv754qrezRwxsHgb
+ Nwu/LH7pz0r0aNGCaVrs74UKDajKF330 X3EjMY2vLmOZJy7bmRDyoPb8BVZd8k1zHGYSyzHyW
+ VeXXHHNPvmlNkPKeApLlnVV5LDAxn61Xtp5 I7+2id41jcHeuMEBff1rphH3L9f8hKpTnTc73c
+ f62tr+BMHYWsAuG3ThTDGqccnn9D1roEuZEt5g GR8yIr4XuOCR6CuVjn23IaaJg2QSM8hs8H8
+ jWw7izM0VtOl0FOAByQf4s5/Gs69O7SK9hUbUJNWe 2/X7zciYT3TW85aOBJcqSeSo6Ee2aVWt
+ 767ZEaWUTK8uxW+Yds5/DNY0d3NJbiLz4IkMTOSV5+U8 Vr2N5i1imgt1ZlQwhlAGd3f8O9cVS
+ lKGqNlhPYvnvbsr9e+xJa3VqscEUayxlIvLZ5GyMnpn9aYt y0dqq3iCZVUoNgwGz90j6d6zry
+ 3lS8cqymAMhyv8ZQYGPqTVqG+hEszzrtd3aSNW/hA6j8T0pulG 3NHU9OGHp814av1Kaox0mRn
+ iaB0b5pHOQCOin3NaOnqbiPZclYFQSZDDJOB29BSkrd2cdoqlWkTe M9VwclT6sexq7a2lrKsm
+ Le5Sdd3yGT+A8mlUqrld9wdSMYrm3T+75sq2e7YjGOS7gG1EihOC5x97 PtSzRCKSVkjui7Ocn
+ zPvYxVcLcWgVYklKgBh/vZzU8duLi7tnuZJYTKhlPzkdKUtG5X0DESnTi56 Wfa/5Ji2V3BPMI
+ Zyo3nzC6cKOwH48UOIJLZxIXgUPuxM2SATg/rTJI445MleH2EsvHQ/4moL82ro jSvJI6kRNEh
+ wST3pKMXK6urnH7OCkpRbjf8Ar+rlt4cBjch4LaIeWjbsD5iMkfTp+NZv2WRvOXz/ ACssuS2f
+ kAP3fqeKsPfLaXEttK4CKxYGQ7s4GSP5VHDBazQGdpn8zeCYtxyR3P4VcXKCuzGvOpQe qtf7v
+ +H730KitZSah5kqTTu7F9obG054X3PFVpjE07QpulM8hdwvTPYj2qW5igi1jz/NCwgnao6q D6
+ +vNZ7Yhu9rSiMb0eRWHzAjrz2rrgk9U3sdNS2s03ey8/yBp7pdyPE5hYNnfyckcc/WqSw7ba0d
+ WQlCBIoGCAT09yTWhPHKYJ3U+egnJUqOpPU/SqmJkZQmwNghht6HHGfc9q3g01oRS5J0vaXs/L
+ b5 ixTyQFY0yrSMRhgMBwOn5U15JXaLfDNIWwqEdMHqf0oFpN5ClsfvVEir1OORmpGuStpbRtE
+ 2Y4yu fY1Wl7rVlTV7ONm32Vv1uS3VwpupYo4xGjlipI/h45z6cUttJI9kZ3eNwrrGCBwPUH3x
+ UMZZYoXh ULGCysZOS/HQelSxvCmnMu4LKrKGP8Jbk5xUOK5bJGVanOpRUUrR+/8AHUZLCU1MO
+ kTGMneExkbj 0rQF8ZtqzoE2D96AuPmBqratb7fnMpCsEDbuOeoq99h8lk8mRG2IRISMh/8Aa/
+ Cs6jW0txLbklHX +uupYslukl8zaSjLvZmPKkZyP1rQkgMttcJgTbXC7Ivlbpk49qpOk76SjzT
+ o1tlVAQYOWPr+ArQl jdLuY4csx+cqcAHHI+vSuGb9699TKVL3lNNL0/pMtfYJobBLhJ1DFirh
+ 8nlsc/QiqzWrjUvK3Kxj VsKg5bA6/hTysUVpBteRnO6VAXJAjyAQfU56HtSCG/uppoXUpIJGU
+ soxhSMkfXgVzxbV22cULwTb ehVMV5aTwlXCMIWR55BnzM85/XFUJIrtQC0TBYSpAPUKOo/Dqf
+ WtcXCo8AkuEEJXEYfnIJ6/nUrg LctJI32gq58x1OFZivAA9/6VqqjT1RFWFnfkun/X9bnOIsc
+ tvJE48uVbhRFKpwoUjJbHoT0rQnlk jlgVogMRMLiRVADknt6YqSWXyNLjhuERhtJfYuCrZG3P
+ tVCETSaw0jW8qouYrhmOVVz0I9Oa2Xva vZXKo4eLhzVFbsuv4W/UzJIXFhiKGeMpIoRpG3bQP
+ vmoY/PjVwqLcxSAyoSmc+4z/CO4roGit/IX zEuA7OFdA+MsOCP8aqXPlKoVIpo4gQjvu4zt4U
+ enp9a6IV76WNKdWHa/9etzHlillZVkaGKNxmRg mBkjOPqccUSpcXNnKRKmPNC4C8gEev4Vdku
+ VuJYoUs5mEcWwLu5B9/cUW81tbARTho9y7gCfvAHj 8a255Jba/IVSLuuZO/bRmR9knc/ZiyyS
+ JOdskXyqNw+7+OOPxq3mYSgQtA1ycsqrH83pz7HrioZ5 Yo5YZYSWjdd2QTkEHjPvV2CVGigaQ
+ iHzLd3DDrkdOfQf1rSpKXKm0YYmPLG3R9H363Kd40kl0luB 5rIrAbR/rF4JH4VSWCVr+OK2KK
+ fKI+cZ9+aleORbRriWbaBKFGTyCw5/Co5TJDcsWzsiOzKnB3AZ 61rBWVkJq9JxhZeWv6/8Agk
+ tLqIK5xbrkKSy53H0zUohQxmGIlZJGeTy2OSMdFz7c1CgmMqmOQ3B CFQoBbGeSPrzTrbZEVkl
+ Ei8mSJMndx0z7Hn64rR3tuYqNorRc62t19VroSuVjsxM7h53OH2nAIYc EenSpnmigEEkEwbYC
+ HVxuCk9OPfmkuUMaedG8UsLhWKMOwPaq5uHfUd8USH5SChQEE54P4ZqEuZX I9i3T5pLRd3+A2
+ 6+zo8ioZZxLhwVboF9c/jU8zW0ljcS27FZzeY8p/mYll/lSxp5qzJPPBGkaurD HzBvwHY4rPF
+ qJJYXWVERoy5kOcHtkfjVJJ7vY568Iyak29Oiu0/68iK42SSQQRskrSMDEE4YDGCD U8Zht7i4
+ dYpCY5Qq7myNuDuOP1p0Fi/2xZJIzOIQXPl8EMDwM/rUEjxXOJkV4mE4WQZ4cv3Hp0rW 6fu9D
+ n9qr8s/h8tH+hoW8yNZQIixAxzb5cr97j+XqKylkS2kRoVDJjnI3BOTwQR19Kmc2YnIBkiQ Ag
+ nOdxzgEVItudnkNJD5O8sHxznPTNTFRje/UyhGjScoq+u9+3luQQSzTzRTsUZI8/ukGGc9PSod
+ 86XCB1TeBu+5yKsvCrahKWmhgbdljzznkkADtVXyUklt40kMjSDaoxyK1TidTlTo8yUtGtdHb/
+ I7 KZI547YWjkwqMSuD1Zj8vP6VqssEZkbf/pEM8aICezDBB96rGVjbt5NuU3uHRRjlFIJ/HOa
+ v3M8F xePKAoUPuIA+9/tfTH614NSUnZdP+G/4YyVGTgktUZDy3lvEyBoikbrsi25dlB55rUik
+ jCTT3Dww xGQqMLjBPOPqOKcl/G92y5g2RnahKjIVuv1qaeJCdiFCigRxjH3+cg/XrzWc530kr
+ ET1fK4cluv9 aL7jlLm5S7uYYhFNbzSFjIxfgfQf561pWdur2ygyK3l7vLQ9Rg5/+vVtklmgdU
+ SF/MPmsVj5DA4V fx9KuyRoLxpruJg4Zjsj+UISANp9zW1SuuVRWh11Z3UYr7r3f4laOeFGKFo
+ /PJSR3dcgk5zj2Aqv K6vEXjkB/csS+flBBw2BRbxo8Kuq/vQ6DLc9G6Vca1Z5JVCMJHVpI48d
+ FH3gazvGMgoctOreKt5M SGOCCB5oFmuX34wrcnjrVULMQoEDrGQrOz8jr0/GrouEWJhCY7cyg
+ bUc5JOflYe3WoXt1huZpJbp ZgCA0anbkjuPbmlGTTd9zspTVHmc939/+RLHte4QhbgpbP5ZVZ
+ MHJ+YD8qkd3muZmnkiWFrhDFkf e4zx9TxVa2nsYplZ5Tl0aSbLcb/uj9KfLfu11JHB5aiJ9ql
+ lztGOfxFS4S5tEZulJ81S11br/wAE ZPO0VmXWe2WSb94yleVx/CffmpUngkgkhupreLbIGzsw
+ QF6dOxFQu8UsqxMEMbByCR6Y2/map3Uq q15mMTM+C0gHy5A4wPQGrhTUtOp00cPTqxUZNprtb
+ 82NvD9rmYwosaTFpom6AAYG3j35qaxsgbjy bpjJ8xbcDyMDkH1NVILtUjt51uIXlj6psyD13c
+ e/9Kn8u8igF7HIGjbaJABz+H1zW8lJR5b2NJTn y8rdl0et2/X/AIIs80iG1Ft5bM0Ls5xnDA/
+ 4VDEWkjjnZUe6Y4UqoAC5yVI7nHOatXRaVGgkUK0b 4XYuNw7j8arXFvKliHmuYgQp8tQuCyn7
+ x/DilBqyT3MaTb5eeyu/X77FporWZlkM8kaTuHjw5G0e /v71Y811uZUguhNK0mDzkDHbB71QV
+ 7a3sxAtzFlMpIWyfnOMMPRcdqLS2E2ni4hV5JM+XuRuGG77 w+gqXHS72N/rLUZKUrJ6K60/H/
+ M6hZokuZ5GBjbzAjg9M9z7cVkzTTG4bfE00bzqGCfwtjgH3Ip1 iuHZ5SfJeQsrOcjJyqt7ioD
+ BcQIJGuEH2dgrErkEjJJ+uDXNCEYyauYYeb55LnUn/W3/AA5o+RaR MbgmVEyFBd87M8BT7nrW
+ bOBb6nKxbdDHEYyzfxluSRWtJJbixiIuIn8yBiFxn8frXP8AmWsixRMZ ZJJXIR1fhlH17mqoX
+ d27mlGvDmcpN9n/AMC9i1a3cK3ELtdwmMpuYY5JGdoz7is+/cSyF7lHDK6t C2OMY5U+tS3Rs4
+ 7SWRFEOZo2jBHVfT9KT7R5UjSXEBmiJdkQf8sznO1vXiuiEUpcyQoxXtPacvNf rez+RWtRFKy
+ DbJ++yevTaOR9TSSSZ1CzxbEMSXKHG4Dvz+tEaXDndbRkRtC24d1YZ49s1C08Spa2 13L5bm3K
+ tJtJ2nsDjn0re15aGtShGad3p+RJC1xNdD7MhdlyGOAck529R37UguDKVdnCSrDhjjGS D396l
+ ikf7T/elUMrRRjaQ2MZpUS0hJN8rJlVAUHG3jofc9Qad0m9DuwmJ5INJbeWvz20FgvYjEkU hS
+ N9gUOVz17VpSanvtTGhWAqVUKV/M/gapR3EEeoRLPaFoSCxAwGjYdMn24p0NvE8p3zwymZfMYI
+ MMp7jPbNZSUL3aO2lXjGV5wemqe5pRW0kgtgk3mykM5wTjAHJ+n9akspLeJgJ7WWQzIph5GfLz
+ zn 1571DCzxLFGiMo3GMHP+rycgH602YyQ3JuJmyrZxt4AxjIHpXO05XTM4znKMrt67Lr+hqwN
+ ZHUyq szNIXkLhuBt6fQZq2Gu4YYrqcrmTKoFGPkP3vxrLfybkrboCrAFlKnoO4P4c04vdy5Mi
+ P9nCnafQ AYx9SK55U0/+CH7ru0/Pf5O5dMd1O8ciypDGqeXECueD3P0x1oiZIJJTOTGXIKSOM
+ hF6EY96qRSx iHbIk8ULKJYSX7AY5+hpbxvJtt3nJcs0m/avB4ABH454qeVt8pz1qslU5H17b/
+ ft95JK0FvctdLI s9s4+RAeSBwKquwhQoDG8sC53EZ3Y5NV7ET/AG2KBIzHald8fm/NgLk5zU8
+ TyOQ0jxtMclDt4ZM/ NxW3Jyuz1/r+rluEVU/eavvf9CvLdQ3YcztDHayMGj3J8z47g+gI5qGF
+ trSMkiyF2ZnYDAVgPu49 6Y9xJdwLGYY0hd8CQKMIP4R7dPxouFke1eNXTz0ONsa4IBHIPqfet
+ 1FJcux0xUJRUUku/axXnuVk ESKhMrruK4BPrSpCZ7NwGjSWOVVYyjlmJ4P0x2qaJg9xEqWssj
+ jJj56L/Hn1xUweOGRMGOFGVvsz PyCv94+p96qUuXRI86vWqQl7NW022f8AmV5oJFkaSSaPD58
+ xEJGJM8L0709IEYebHHI0k0pkMW/5 htPAqqxLQTfMzNDKkYPbB6k+p96jYXsWqF7csF8tgoIz
+ jPT86qzatcVSM6q3Sf3J/cWb5MRSbZMS +bhuf4c549BVSR7a51aJVyokzI5J4G0fdqeNp3soy
+ 0ZaeBypXH3R2VvUnmqPkSAqpw87/vQiA5AH UdKunGys2PD0Zyp8t7W8/wCtPUlS4ZbpVaEMjp
+ yhAwM9D+FT3FrEqiFGEczOCzNyvTAH49qjsY4L a/cSrLHIM7GdshB3BHer32d5PJjUiVUdR5i
+ nqxBK0VJ8stNDpxVepGom042+4SzUEm3l8s+YwcAD mPYOAfU1ftIzdXjLBHKWUKuc8EfeIx6n
+ FNgWRLyJHjUGFCPNxw4P8X4Go7gSxW8zo5BadTGyErx0 I+tc0nzNruFJybdOT1e39I6BIlJub
+ tQCDL8kJ5wCMdOmRUtzMgmUM6nETngYOeBz+FZCSx/aLcNP 5bksdjE9M4zVzcxtmKOk6LMFDq
+ OoJ5FcLhZ3f9dDmp3Tbldtd9B0U88jLiNFcIyoWXIZepNMaG4Y ySxziNhGq7T/AA56598UrCK
+ e9LDfDJggLu6gHJxU8ySeT58Q8yNiHVR/CvRgfU0XszWUnG/Ilr36 /mZdvZOuoxfb9vlvE7Dj
+ AXb/AI8VoiH91lg7tsbeUOB5mMgflVSZ786nEsSh45EaRl25MfGAtNju Jfs0iwQT+e7jYpbqC
+ OW/LNXNTlZtnJX9p7Vc7V/69BkEjfabXeyBWtyGjcZJJycn6VWNsIz+6Z4A sTKpkbIcdd9WFi
+ e3817WGSdZHBU5zs2jhST65NUDai5kYsLi2JkJIZ84X0raNrt30/roazVOMuZS Vvl+RWllRZP
+ OkjuLkH5nMb4CNtxj696ogyxtCyyrMY1I8vB+b+6/5n9KdsiiDAiQqSXjJfjaOCp9 +nNNWVUn
+ 82AEgoIkHXO/rz7Gu+KSR0XpuDcv+A/68rFzy7i6W33lfMRTE5jG3eW/i/DGKjaOOMGT 5WkaN
+ izMMgMo4WqlwsNo+ySdhKn7r5SfvDp+eagtUje1it0huXKE+YQ4O4nPIz09KFD3b30PPhQc bS
+ T930/zewNfK0tsrpDbyCArHlOCfTGOtNAmNrHvVtm5ZFZRgKBwQfr1qOaAbkIUIxUuC2DjA4H6
+ YqRbe9aw3q5YqygAfwg84Pvn9K6LQS0NsRyxaVl6/wBXGxXckKF2jMtqhyAQDuJOFP0qnPbM08
+ qN unkSYybl6Px6fWti4lmuIJYvLWRjJgbFABI5LD2GKxpwGkLhZPNYA/KegPXNOi7u9rM4IYe
+ lNup9 rtr/AMALW48m+juSpbKFnRRjk8U27lE01tIytEFQg543sT2pk8KJeNHFL+7VtqM2Tkev
+ SogigQ5Y HzBlVzynOOa3UY3Uh1qVJT5ndPvqa1kpTVP9JglEP3QT90D3/GqbzzPPIpeKBTMok
+ O3G1vwp8t3d W0vU8t8rEZUnufoav2yzyyS3EqwlPNAeMIMlwPlNYy918zOLEy9lJyk07rT+rW
+ uYk0YnC7i6OOcZ 5PYk0rW9w9rbkZELuSVXqDnGB6ZqeRnNjFIIJo5GygyB68dB1NTIZ5bm23I
+ YiJAr8cFsHpWrm0gx FWlGmnTd/wAH+enyJLCUPOsAhmGYpHUh+vv9OKrXLNAIEIiETkOp28se
+ uP50LiOWKVRJDtTZknIA yd6n3NQm633yTImzy1ICvyApG38+9Qoe9dLT9TgeFhKo5Rimrde/r
+ f8AzK8zN/aC7kxFtwF287Ty OfX3qL95b3Ufl7jGgwyvyTkfzq55LTJBGJEdURotwGd+Odw9qh
+ AhFo6sxxkGPI5IPfPtW8ZLY7Ka hiXZ9PXQquqGSMsrFFX5RvwSPfikdlR5iwG4t0A6e1NYmYR
+ naoDFV3dOe3SpQzBJ5JCFuCSWTHIP Q1tsbQnC/Lf5/wDDWPQtNDQlYLWKXylYB2kO4tk9R6Ad
+ x3rb33H294hYFkXJOFGcA4J+mKxgbZb2 FJXeJMPvKvjLdVxT4b2W9iNul7EkjOhdyCPn54+hx
+ 0r5irBzblb8zzoqUqsny2XXfT5rcubYRcma KEJAq4hUgFtpHf1NZ++ZgqxywSLCrLhRzkdT+G
+ a1riNra1ZFUCVz5sYIyFC4JU/zqo88F156GLb5 7faCyHG3HBH49amnK6va6/r/AIJ6VGEpWqc
+ l0UJZILazjiO8LLGB9/DbgflxS2cErXU7TSnypDgu zEgtggH+lTy6YssMlymfs/nI6knOBnDC
+ l+yLBb4iEgj83awZskFWyPzBrb2kOWyerN6+LjCm1Cbu /wCvkKCLO0VjazRjMZUOwyoB6n15q
+ S7iM32gxXaRusx8pv8AZ7j8802WK9bVhNdwvJFGxSIKMBcn Jz69qe2pKjzR2yAsvzK7AEZ4rN
+ KV046s5uXmanC0pddV+pUWy1C6uLV0ubYqi7Rtj5UN/wDqpjWl u8CxPL5kxQtgNzIecYH4VDc
+ G8eXz5IZgsk2+NYjtIAGMce9aDSRC38+9gkhEcq74hw4kxwM+ntWz lNW1+6w1iakJxnBL0Vr3
+ 69v0CygP9iWgQRxOsLKzSpu5Lc1bW2CIskUOUVdsink7jwvP86iHnGAF 3RcI/nLjmN+oBx3NU
+ bYXLQxtvMathgWzxt6KfU+9YNOV3cqLlUp80ZW1ZYuvOit7uFogjpMqxEgc 4A4/GoTA10s8Mc
+ sOxTmIbeWXtz35zzTxeTx/vXw5kbeARnZ25qKO9LTRyHyxb28PlNIoxlyev0rW Kmloj0KM5uE
+ Ukrp/1pZjzBJ5EFuq2wkWJfMJiB2ZOSD74qERySySwRyBY8jyvbI3EH344q1DOzNM YADdGaME
+ HngfepbYfZ7mZLd0mkE+5Vxksq5/xx+FLmaucs5TTajFX/J9zNmayiaCRorrMkL7C0nQ DkE/j
+ Tmkku4FgmAiIi2O56bsdvQdK0J4DNBZXGxGtxbuT8o4w2R+fSs+7lLXUd3FC4Z13bD/AA7h jn
+ 1xWsJKVu+pNGfPCL5m2m+vUhtrCK3Yfa5I5WkbCL64U5P51qQzx/2WqxAKrIXmVTgq44X6A88V
+ m232OWbfcSMAjhFfdgBcYx9T61qmN/7OjgjMewhg42/NkH5eaVd3l724YhRVZObb+Vv8/wBCs6
+ Sr aq33wyAxBe69WP4ULeGd5EmxBHu8x2boTjgfjWcv22O+EKAxyLgx7+flHOKt3PmTBJg8cjr
+ KMIgx 17Y/M1TppOzOmeEhF2l/l9//AA5PeQt5ANy6QKyqAcYHOOn0pzzwwIYIoCZokdY5cArg
+ 9eKpedNI k0V66FTmVTt4baeMexoSWeVJEysU81wJUV/4F/uml7N2V+n3Cq0nHlUlon8v+CRl4
+ Lixjtw6QgBU TzBkkA/e/OiK18rzkeQl/MVJPrg81B9kEUJuZgS8c6rJ6Nn09B0pJzLJffuxKt
+ wsmwc9d3St0t1F 6Fx55XUJWj30sSym3+yjyLqPzWUZUoQc56A4qnA4aIJfeUjiYSRlkyVC9Qe
+ O9aCwyrBcI5gLLIDK ioA4IOOtQzwILzDkukAxlemDzVRkmrXO2tCpiaVpzbt979NP67hmS4uJ
+ Ag8t5nMjjGCGHIGfpVq5 hurpbePy/nkVn3kcA44H1qta7JIp3kjlFj5u4SbueOBzVRoZnvJBC
+ 0rqn3WBPODU8t5drHDTpt1P ity7f1c1Y5lijRZ0KlEVVZhnC5+YN6k+taFq9hE91LGytD5yhS
+ edqkcg1myxrMZWuI5IkL+YjE9F /iz684FJm3NkrQspkMgIXscA4zWMoqS9fuOudpRs01f7vvL
+ E1wV1F/IlWOAY2Mwzu4xmnCRbaG3g m3TuylMH+L/a57DvVaWeKWztCWWIhAhDDgZ6/liqkhMU
+ bbMkn7ztz5ZAOV+pqowTSWx0SlGq4x5e Xz/qxsxh2mhJuoZpY0kQtGMKfQ4/SlElwmnOZ3Bif
+ MhbJG2QDCj6e1Z6uY7KVWR5LffGx28MB3Gf rUlw9nM6WtqJsFt+CxI47fiah09fL+mRKnOE1z
+ q6XWy/P/gFiG4VGj89JI5Ik27mORjuMfka0yk1 ywNuoYzQl2kxxuzjgduK5q4tpLYw7pcyL0U
+ 88dyc8d6Yst1FexRp5imNCEQHkoeT0qpUFL3os2lR U17alv8A10f+Zr3LzWiCORxvCMin0BA4
+ +ppbGNomVJd6rErbHc8EY5H49Kjt5XMSNbp+7WE7DMN+ PQH1PXmq0ySXt+Fg37mVfKAbA2dST
+ 9DUKN04vQ4788XGbStu+33afmTz20i+Q8cy20Dw73LgkDIw F+tPsfmt4y6NJLbxnyiD99e+fX
+ iq0Ya5uLnzpFCPIpB7fL2FadonmzS+ZC6sgZTsOAxxzj9KVSXL Gz/r+tjKrVpxj7O7l+X6GXF
+ dtbFJYSPPRCE3Lu/dk8n6+9SlxLqb23mL50T+XE+Pl2kcnH+eabbx SJbbXspkneHCBjn7vapo
+ WZLuFvKEcrRfMxGQ5PQj8eKqXLq1v/X/AARfu+VuH+f3+RVhEMazr9si hMlwPlcE7doIzVu4S
+ WKyuHkYTvK6lTGcbRioRDIrmL7N9rZVIbAH3yOKmaJJYYQ9yiTouyVDn5nb GMegxQ37ydyqUX
+ CanLbraz0+SuvvIALdLJEkS4h2cFi/3t3J+tW7KIygxIphlEZ3O4ySRyPoMdqs XMFuJooIMTS
+ 7GZxn0xgc96rRSlJSzK0MJYu5Y8pg8KazcueN0VUvODcE0/P/AC6ilY0uIYbgxyXM kTYwPv5H
+ 9BSQSRyXSwqkkCkBgzHgqOAaXyJbh7meK0nBkcPHMSMDsQPaksILS2keVpQpBZJfMOcc cEego
+ fLyvuKpD922n926ZJcBQyKS6hx2PRV7Z9ScUk63tzbJFJiEGJn2FeQV5ozaMIEVJpEIBLb+ GG
+ ecfTvT4ikmpXSxXUJiklGwk5JYggY9AaSulfsdOGlKnG838Ouv/Duw2GLzkgnZQjSqzlj0PPb0
+ FbVhKLiOZIU4SVURfXJyT+GKyXVo7aSCSVY5Y/nXjpt/hqGzvIZXd4IZ1Vn4G/7g5JB9T71FSD
+ nB sdXnq0m5v0N4+fBfSm0MboQxAKZLDuR7daswXH2q1+cCCLpF/uHqDjqeM5rPuJUZ5tysu2N
+ mhKNg NHgZ/P1qrC15HcI0Vu7RNjcuQeTxx9BXN7LmjfqZypJ0+a2q79S+IWUyXErFmRkRdvAO
+ 7v8ATpVG 5+1W9uzLG4uEUur4+UADBFXJdR8qcrHPbkKwieMpksW6H8KxLu4dLkW8CzNOA5Ys2
+ QMHpj6VpRhJ y1RhSd6n7yK+f9f5kVvcI2mvcKZDFhQED87wOufQHrVS6uk+3w3CSGSXb5rYYh
+ Wzxj2oN3HGFgO2 IKu5Dt4Hcg+pPaormUyfNF5CIkbIfl6Z5Cn3r0IU/eu1v+R0RhJv3oavzaV
+ umyIFluHmCTL5jfMw 2rjGeB+Ga0IZoY7QSEok6tzuGVwODgfXisqERxQC5lkMUZGI8knecgkU
+ 24cyzTJG28FywAX7o6kH 8a3nTUnboLEUlVkoQXurdp/g+5LudmVmRWmADMXAPzA8/jzVkm3ht
+ 9sTb5Em2ttODg84/ClimvZp raNbJmjJy+EwWY98+nSorSzmXUWh3KLjd5u9h8uB14+hqXbW+l
+ jJrn5rWXKujNJYtMnjucM87glN qtyMfdI9qzpLZbS9S1j8yVmJWRN3L8ZBHsKmit4JrkySLII
+ pHdwUbGVH3f1rOWVRfRpJcpBM3yq7 g+vHOKmmnrZszw1T2kJv2jtHv+WhZmQRyhHt52i4ICth
+ gSM4zWbds7XBJ2xkk5xxu9CPatAGVLto rpzKZyJW2HG3BxVUN9sugYouJ/3sYPITaSCPxxW9N
+ 2d2RCrBTd1bu9l/XyM+OMz3TDcI1MmAWbIG egpGheOY4jkyDgHHtk1NPbBbsxllhUL1IJ5xnt
+ TEWKMDZIXVycY6jiupSvszeUZOqoJ6Punb7+pJ iOS2VmnRmlYs/GQp4qOB54xLItwjHzQWIzg
+ 56mo0RQpViqvuUbj93vS20pkHlsm0s5bKjA+v0qXH Rnm16UYKSvr1029CT7XGZz5qkQBWSMd8
+ Z4b+tRzJAjKgL7h0O7/WN/eX2q1Z3Hm2Hl+RbTMWd8CE E9evTp2qCZ1ubeGW4jcqke0NHgc5y
+ Ov+eKS0la1jOlUmoqXLZdrp/hoVSgQBlYyMflAB6MTyPrUv 2S4juLeaKRUUbyxkGQ6j7uPqeK
+ gR4Ycy25MTCQkrL82/PHHHFajRwz71cTu0TbFUP98+306mrnKS 9DlqxqT+J2X3fLcmtYilmFE
+ 0SXCAqVZehYZAPuTWVe2zxpG8jAttw2BhYyB9wj1NWLkmBZZTFIpk kVgWPDAjqP6VHDPHc3ck
+ jyxrub5S/Krnggj1x0NZwUk+dbGMaNWm3KPw7+b+4I1t28OrcJiN1+Xa ecnsfwNCiK4t41Y4l
+ Q7ZHHb3NV/NNtGIoplaPaUT5AQyk8t07VLaC1tS0aSAKJAGJGS5PvVyTSb+ 4wdOpBXb130f/A
+ O3SYS7kkMcjvKrKir83XB/SnXOnW0MwktXJLuWiYE4yOgPrnnFQJYPaRj7Mr3E xJbg52heo/E
+ VoWotpWLBzGFb9zG5ySjjgn8e9eHKXL70XodSw7ilOL0fl+auNjtLxftF1Mzpifyi jc7c9R+P
+ amy2cKSBFD2uI28wyN905xt/KtOewEOlpHHM8p2qJFLkkvkYNVkMWnT6isgZ4HuDjzDu JLL1y
+ e2axhWctUz0cPiZS1Tu/JW/AgtcW2/96zRsVAJ+7kHnimSTvJq4ZUZY4YjG2ejMT6etPWKO 7g
+ tFwZRCFiOw4yCcn8eOtWPswgaRgJFtpJCyhjksOm4H0zVOUVK73/r9CcRXvJ8+rfyGi982J2EU
+ qsZcgscjjqPqcU6W2jmeQNC7JM5lRo8DZgfcPvWlbWyAKEiaSZtzKvqBwf8AGsgwy2kUKO7TAq
+ 37 xTgEg8YHvWMZRcvd0/r/AIB5PtXKWyVvPX8xEmuI4osFI0kw48xc9PT0qnDPOV3Xmy6dgSx
+ QYC/N 0Of4j61atf7QLgTRpPEJFV0VPm5zgD0pYhHDPIhUhmOTnu/PT29q3ulfRHZTcY3en9fi
+ XJZ7p2jl toMSOrtsKA7SDgFvXvWB5sxkt4TIslzKn7wpwMDPIHarcz3kH2RIoncmMLuB++M8s
+ PakNrN5zOWR cuSzY++o6lfQZwKqkowXQ1w0uTeS8rNX+fclhgmeN47iaGNdwEYZOSAPvfTpUV
+ tGkhfDRS7pFEgA +UkfeYD0rRguopCyi3kJchuSDtGMMKqSRxLbWazRSoiJhirbcgHDZ98Y5qV
+ N3aehcHUTcWt/QuGG 3tpnuhIhQOCBnqB3z+NRyR7buN5HRYyhDOo6Eds+9WltpJtQMVo0f2YA
+ iJXXcdnfPrgipXsJFsmc zxOElRRJt+ViTnOPTtWHtEnqw9ooz5ebXz/4bT8ShIphW3lkjcRxw
+ PG0Stg7mP8ATNZ627QrNErq JIpFgjD87lP3j+tauLhLy6NxIpE7eeCV4XZ979cUtncyXNi8iG
+ F2adJXOwcH0/CtVOUVf+v63G+e m3ZJ/l+RWNnZ2zRpIyPBGHCjHTHUn1rOWST7JEu9ApXcDjn
+ g5K/XpzW20UEVtc3UqSSsbgKGDfKF /u49e1VEht57ny1tJ4N5LqjPzHgcqfcmqhUurvUinOct
+ WtPkVLS1uJrSRVYCZZifmGSo67frirRX zdNhBtZY7cqPm4zyeDn9KmtYEigE0UrK77N0ZJJjY
+ kjafcip57rar2m9GiPIXHOV6HPpUzqNz0CL lOquSS06tbFeKI/ZrdIYQgjiZAZQGO3PP45rPu
+ bV7qS33W8vkAEPIuBhyOp9geMVcZnmado4ZCBK jKqtymBkg1o+bbta3UARyrSFzGG+bpkEH0H
+ enzyg7nb7GVFJ3u+/b8TjlW4ntxDdZzGcFQMc9GJ+ nFSk21tKSgaVgOG3d14P+NakLpe6fKGM
+ cSK6oJSPvlgefpxUU2mQi1DCTyXRWWUsfauv2yvaWnkd tOvFQ5Z7Pok7Ge/mm8WOOYC6Zd0gI
+ 4zj5s/hTn0ib7FC63cd0ybo4xHn5xnvnrxT5YrdWeZZ1WRN qkkk/e4x+Wa0Y9Pia2dcywBJ/L
+ ALHK5IwT+FOVbkSa0+RlicQqNSMrWXmv8AgFFNMmbR5I3lSE7w QjA8flWlZ2FxHfPJDLE8aFE
+ zt/1h67h7VoBoI3eJ23xGXKt3kI4BB9M8VIXAWMrhZEDeaF6GTPHH pjtXFPEzkmu559XF1Jxd
+ J7P7kVX08yPi7ljERgYQsoxlAcs341TklhlQojwW+xgRleqgc/4VqQXH 2tbszJseWRWGT90EY
+ AHoMjpVC5itRbGRbaZJiMEFumeP07/WlCTvaRp7SpdQm9trWsUJo4ktg4lg Ikw5i2/MCOKha4
+ thdRNbRSSzONzKTkAZxtI9cZ5q8F32IhWAu8bCIMOwY5yfyqOZLmS+uVEaQt5g fbs5TjlT/nv
+ XTGS6m0KkXB3k387fgihFcHbJ5kkUayT8K4zuUcAj2qmziI23lxlpMlXkToME/wA6 vxwQtN8s
+ yrLje0TLyAvoen1pzyQzwxRIoTE6hnzwdwyf/rVvzJPYVScoNXu119P1KMwMskCz7wjQ 5MgOA
+ v1/L9adbPbRym483cwUoV7kHqf6VpS2yy3KpyvlMYxnkEt3/Ksi5V45YrZRG6hg6MigblHU 59
+ zVQmprlOjD1VVTipW7pdvuf5lmaBdkjxpMsDSL5ah+ijrTxcBIzNbxNGYN0asxyME8D69aikik
+ uru5itJSys+8nPG7GcD0zUkK3QEayshcy+b5YXpjnB+vak7curKquVve963S/TzJYpI0itJ2kU
+ Oh yy/7Hv7n1q/9uFq8cZSSeSZ/3LIcZTGT+Oe9U47yC4uJDHaySBpzsUEZQY5U+tSNZXKXkct
+ ycxOp AK8YU46elYTjFv39Dj5Kbi5S0t0vv5K2pm3QMmp2WJJlUw7mG45B7CtiGKDb5sRZmjm+
+ QM2SykYG Pxqo8MUGoJmOWaHbuOG7rnaM+9aWmT776WG4iWF5U+0ZPG0pwB7c060m6d10OrE03
+ OlzQTaS110+ etySygvgXNwNgikCYx3YfMT9Ksi4g814Tbqp3rIkhAy4UdPrRb+VPbFi8jM0uL
+ k7/wDloeOPSpXK pbyieJ5I1AijKnBO4evtXDKV5O6MVyTjzaLyWn66kDyWtxfJOkTMkqMylWw
+ VHYfU1BG9vBam7lid 3YBNjHIIzg/j0FAgS3WCOEthEdMHncTzx9T09KUwia1topEe1jYFlMh6
+ Jj5gfcHvV+78gclKacn7 r0a6kMt8qwYCuHQiN0B+65zio4EsjqDRXc6FmQDAyN4wckVKloN0Z
+ 8xE+QI7MM/MTwT6kY/WpJzg zSLFHclB+9eNfuMP4Pqa1TjblidKqQUJUqd/vsx6CwMcsoBSKO
+ RU5boWrPCxxXG2RQ/lkEmPjaec GrJhsxp4W6tbizjkZZA5l4fBx0qzdRWdxqJWOUNN8xCIT8w
+ I+99BUxkk+tjNckLc3M777NffqZv2 cSadJcKWKOyqznnLg4H59aWO1Np50MbJuF4CwYcj0X86
+ vfYrZUlDF3Rm3fK5AJAwMU4IXs9rFY5h taRzyFZeuffFU6t1a+hrVqup7t7r+uhnTRNDqD3s8
+ oUqsgCEnrjhalVt9rb5hu5HaP5NkmMDHIPv 71baOS5SQuoQSEypkDjjgH61TFvLa+XeM/WDH0
+ znimp8y1eparua95pNfiVHCw6PG5t5wQw2sWzv To34iqlxK6ySFGY2m47STluRgAn1PWnvJe/
+ Z7VVDBPKwu4A4z1PSneRLN5qmN7gtKAsUWAzKBw49 hXTFKOsjLkpQXNUafdq70+eifzGQBhDI
+ JHt9+5hIXTJDgZX6DHanokU0dskZSVmgKTlTxvPINOlI W6khSN4bcljI7c7iR1FY8cclsDKZk
+ kYTCNdvZSOv1Aqox5tb2Zlypu0ZNPpZJ/kXDa7LuOKArLsT c0bLncc8MKjR/scbmCSF2LlW+U
+ ZjB55z1qjKVM8rQtKNhARg3UDqac9xIzPnZsDEABeSP7x45xXQ qcnvqb+wqOd07p73Wvz0L8s
+ WLRPJuT+7GNoY5ORlj9BVO3jurbTJJon3rkB2HVQTx+BpVtRFEJWk aTYwJ2HA4PT8afcuJGdo
+ pAUmbPljgqegBpK/wrVCoyV7Lb009P8AhyENc3DLATvVWIVVAGcntx0q nKEjuSLkhz5mFI757
+ j0q0izrceW37twu0joVz2PvVdEmuZI12KZNw25UFiSeK3jZPyNK0eWL5bKP 3W82ORi1tFJbEy
+ SqjIwz0Gev5ZpskczS/u0cqJdse3+EY4P41f8ALMF3PCkEsUjPwD6E88e1RXNt JbLA0Eh2SSk
+ ZIztUDnNTGor+pwqs4S5Oa76aXb+7oQbJZWmA3BiN4B5IA6D602GB54gAoXEvDEcK jfeB9we9
+ SAwi6liEu/L/ACEDHy49x+NSXEix2lulnJ54lVlTbwSFOS386bk9kTjsRFqOr5vnp/Xm jKIxO
+ Yyrud3AHU4p6t5yK7MyBVJfA689R7dqt2iwQXQkQTTMqsDznJYZ/wAaRzaw6cEjl8yVwAM9 Nv
+ X065rR1NbWJWJ5pck20n1X6joDHDcK8ToxbLeUB8xA/p7U2Uo0MZWCQg5yQ3B79Paq6wkwqJWE
+ LKArKwySSeufTFNXayNJFHLJHHMFByNrBep/GlZXuRKvClUU5J39N/yX4Mmfa1uqCEMyJy2OM7
+ uv 5VWRJwkpkmjBEu3KJ/CRwat3F+0stwiW+3c+SVwMen4UrXDvE6LAC6j5iQDyB7inHnS2KhG
+ rUd4p xT7P/gFaK7gjt4YtwEhO5POG4DngYx9agke4VVljhh8k5LmOIBeTg/lSn/WCRooZBGhQ
+ nYMDcMj8 fQ0ExbEgYvEsURVhnv1A+uavlSeiPMqYd05W5eu/UjWYRXcUs4jni37cIMH5eAOnG
+ anjluIdQBji VnVsyIY8/Mc4p8c0ZiaGUxqZ5lmZdv8Aq9vY/h6VEzCG5MqRzRu8oaIs2QAOoP
+ qaN7po51rzqS1f f+l+B2llMxska5nRWZlxH0fhjkZx6VfkurSG8imgmjCKrjDDIznAH6mqVpm
+ 2vtsiDgsmGHVtpO4e wGKlitpZtKhWNobjYUMhVerDkD8a8OoouV3t+B3ynT9o+bVfcvysi9+8
+ mhlEaygs6uATypXt+Hes 2NZLieYNKDJIWYMQcL/skevFMf7VBPNcTHaIpPKVRxuD85rW2Tr5j
+ w+XuRykI29j97Pqan4Fo1r/ AF/kehFzi/dktdv8imlm/wDZ00bM8W6aJmA788kelaQtZElZtz
+ QmNXKeaxYHPXA/L86rSMRaxTWu RLt2lXO7cv3dw/DJrXtYRFfsTcLMY4WhhB5DL3P19/asKtV
+ 2vcynWUkrS+XmVLe2uYzbKrtJhFV2 U42E87fqaTasGp+WY3gzEziSZtyLjtj15oW4aWztkMcu
+ 0xlmCNhnx91gao287SSYkV0UDZK0h3Zb B/LtUqMndv8Ar+vQ8xRk5ObXy6/16otG6uTZAPsWR
+ gHyF7rwahW0lnlwd6MCUyfzP+NTPbXLWP2d mWRSo3FRyR3x+HNSxypAojSZQJv30LvyGC8H86
+ fNZe7uPmUIpwfvGch8m7JEU07qAD83BBUkEe1R /aHazhmmikP7t2jIONy9GI9qutcx6jBdNar
+ 5cjSxu3sp4K/UU0soysZSaIkiIDn5QcHFaJ91qdSo QlNSqL3u1/1EhW2/szMcheQsNuDyF9a0
+ yktxAqPD8uMFvXJ5P8qW1Jd3tkSLaWywwNxPqPRQOoqZ poUtItsy7fKcKxPUMeP8RXLObcjL2
+ jUlFLW/rYhit0/tFCrFjHHJFhSRjdzk/kaGtvtVsRFMPKEi gqDyw7MPbNUo2voTsFtNcyhfma
+ PgH+9+lXtPaOSWWO1Y2t0doiMx3L5XOePz5pzUormvsdk4VEnP m27W09ev4GZeRyNqgUyGXJw
+ Qh4BI5/AjtStBO4jWBH+zCM/OnHLdKu3wzZxxuQiOpcy+oyMVVj06 5uDJLHOYDgZkfO1Mfw49
+ e9axn7qbdjSlV09pOf36r8BdLtg0iRzOwY7S6s3TGc/jU5tyuqxXUayS wupZWU9z3+nAqZ2WI
+ Nl1Z2cFdowVXHIPvjmq1tatbqDbSM8GCIAWJ4/r3qHNtuV9zKVS6lJytfQb FHkxvMrgSFXBHA
+ JGefz4olt/tN1biWSNopEZpIkGHU9Ov4CrTwxfYZCbpFMkqzhsnCBSPl/GnSSw RXjebbytE0h
+ wUIGTwQfoCeRSU3e6ClGVlNKz6dPzH3HlWlkA43NKnmNsGDkMFz9MVmvbW7I8tpIW aN9i/MT5
+ g3Y3D2HSrSpbSXZkkSWQFGM534GfYdh04pGjUERrYXCFXKffH3CMsfwODTg+U6NIpaO/ olf/A
+ DKEr20MVxFKu1TKuwLxgdh9ahkt5vMuoo8gKdspfnL7f6Zq4+mKkhKsbna2WP8AexySPr2r Su
+ CkVmpjgknadzMVUjcAMdfw5rR1krcutx1cV7N/u1dv8PvOQitVDQxRwzTDaFnYNwzE4BH0rq4o
+ 7qOzkjitpGJDEM2Du2HrWbCmL0T2YMX8IWT5twznd9B1rSjjvLvUjsLEhyFK8BxjqPaniKjlu9
+ F3 FjpzqNLmvFau9/8Ahh0Ane5mknWOKBnVk3LypwT/ADqK8RhZWiSxMshJAYcYI9ffmpxAIrc
+ tdSEg Iqtg8ZOQP6VflMk/lwSwPAqRu0hfHLgAcelcbnaSa/rQ82rGTnGS2+77u5gw290JIti4
+ J/iI9ODj 8elRYmiMYlhlMYQqxb+HBxgn1NXltilmwS6BAwXOT8m05/8Ar0gu0lhuXlvLaYm5G
+ 7YuByOP0rbn bba1GnUTbi7p76NW+ZFj7dI6wzRxgEeYoHIfOFH5CrjRTg3SECSZpt6uAMHPH5
+ CorkQwz3TpGSxl VZthwGOARj0xUUEp+0XT28zFzJtQuchRg5H1zUvVXW3/AAxpXhBpOCv69zn
+ r6KSPU5PL2xXIJXkc upXkj2qs8e2VjKGESPsUA43YH/6q17oXZEMsUL+aqiMhhuOSOP061SmU
+ RWSApJJdRBUdc9zyDivT p1HZI9GnXqStZJ306XXz6IpPs88AecJyN8ke/lWFDW8lvvljI3tMr
+ R7+T/u/rUTNJNtiCfMsLJLJ jktnI9/arEMkzyyJ5yRZUuodc7eOe3auhqSRs6U5Sdvne70+Qk
+ 0kkL3CMPIM0sZ29GVe/Iq5LNGj 71uYpUVHWJFB3HJwDn8abZQGc4klVkEPBIyX5xkH6VNLLFH
+ ZxCGITREEblAymD0J9qwk05JExmva KD/Db/MzbhI83CKrAxEDMZxlsYJrRFx58SPDL5CiUcTf
+ NtPQA/WlaCGJZLYyjYzeZI7dWA6kH0NC GxaXzSJCgIRAp+6G4wfVs96JTUlsVXxMeXl5Wvy/E
+ 2r20NxE0DuCylgTGMZxg1BbzW2VkMbvKq7d in5sMfvZ9AKhaZZI7iNJDJNFdxqI14YhRgjP+e
+ lSwXJ3T+TbMsjuphDgHMecGuFRko2f+R50lKKa k9Pu/wCGH3gSW0IidQqEI23jzGJ4cewqmlv
+ DJqMZkM4iVGH3zhCPX3PanG3eC/u13eXEsgEYY5xt HQ+5zWsjzCIAQCR41KthRwDzg+pI6Gm5
+ 8itFmksQ6KUISvft/mytJPFJppUPGRuyQv3lBAzz9RxT 4b3zIzFAMRuR5bv8wxnDD9M1Uku5D
+ AqxeRBHJC8gDplowP4T6n3qlNNG9jbnzEgjlXfuHG09hx68 0KjdWaLVOpGEbrr6/pqad9DcXU
+ yW8GxsRM3mAYEhyMEVnb9Ta5ngRYy5U5AXGTjrUrXlyLx5HzEs cwjLEYAJ6UnmK19CFuVEkQX
+ J67ufmP4VpBSirNI0hKdOD0TtqvX+uhVWGCSC3+0Q3abmQqHl4UDI 2/UmtZdRsbK/INvI7YOV
+ UjKY42k+vNUbrL3f2hWE8MTeW5j6B2Py/lSLEftl24mha5QnfxkMRySB VNRmve2+ZdKFOpFqT
+ vfZXdr/AKEkTxXV/NECYRDIApdsgqByappcmaQKsokTaG+TjqeQfUnpSCeS SWWeaL947oSUwo
+ +bgjFUv7MuIZ99vIiIFZH3clGwflPvWsacFe7sXKGHjNqTs7adfuLSX88mqbxG YGLbiWORGAc
+ YIovpHMzwbmLRLhXB4fHPA96itwohjC7pCoViOrMxHHPpntVq4V5I90jxwztb75lY fxeo9ABV
+ +6prQ6aNSLrptWT07/8ABKzvI9raFkdZHVmUnoVPGfpUTzPbSTNbbnmLNGxH/LJemD9a Y8jwX
+ NpK8q3MKpx5foB7+uaq3DSCFSm6Aw/IMjls8kn1+prWELtdjmjSndqOsW35X8thY1cXqecs vk
+ yL8zk9fRh7VXcSRXJZ4+REwYkcEnoRUiTXb3MKwSRHCO7Lt7d1plyxjsEL5BGIwG/iOM4+tbpP
+ msy5VZqraVlfTf8AIqGCSVbeKFHlmwQ6ge/FWo5HAlt5Io1Eis6uVwVHp+YpYGmbe0OItkgXOO
+ Tn nNNFvDILePbI52Oxw3KlTnn61cpdH/XUyq15QldfLun+ViwJbn+ylQIJMDG8LwT3HvVSxjm
+ uZopi 0YhjYCR8dPr71JbzTw2xuBbyO88jAgdFz0OKnt7gjTJlVQhZzn5eGx1NQ7pNJGdKDqLk
+ TV5X8vzu RXweS5jKlIlDHeSMkjsayZJZGnQqjnOckfwntWlPHELCAo7lpOChYkjHf8qjy8cu6
+ Hy4x1CuueM9 +OtbUnaJ00YzVJ8t9Hb7vkLEIyWSdZ43ZS3mGTPOOTUbK8mn28yszRBQshxkKe
+ w9s0wvJHMjocbQ VAbkc05i0NzJGfly43IegK9M0Wd9BVqMo1PcWi1syFTJvWdiFKMVbK9Djp+
+ NV4IxIAzYj8s4BJ6e 3HrV24jaWzhnWGRRhlkOcjORj8ag3MkBiZAJiWMuR159O2MVpGV1ocUJ
+ e0nzWu+t7FhDD5kZIbck Rf5TjkZP49qekME1qtw0iwsVdSrDp6/zqKAv5EskEWGEyx4b5icg8
+ fWo/LdIFikBRhGwIYn5uefy rNq70ZVaUqtoUrLvtf5+Qy2e1iy5jlkhUNH97JJz6/jSS2bRws
+ 8BdEjk2ybz9854x+FCBUsQ0S8g 4k+XIGen4moAsko3jayxnbNhccnpWttb3OaVKCirv5f09Pu
+ Hs0RikCh423ERqTy2DwatSQ3FxcW4 hjwrgKTnjpk5rNjiENpI87Kk8c4AXHOTz/Srq+UksCW5
+ lmnCNvCE8EDNEtNjF1alkue1+r6evl5l MxsbyzXcsm7JcIMYHfPvgVanmtnnDph1bIUA4KjHG
+ Tjk1FH5jzwLHJGzuhwqjnGOn1okiS3ZNp83 kF4/4l+Xk/mabtzHHNxjUum5SXTa/wDXctQShb
+ HyktgWcqS5ALMp4bB9OBUoSK1ncEnEPzQyPyrg df51m2sP2G2SdnMi5C/7xJ6j2FXEdJtRBu9
+ +1W/ebc4z34/Lis5x1dtjjjzTlJ04XW/d36qx0mJI YoGaeMSIrZkbnDZ5/TFNit5BNnzcKcbl
+ jcghgcqD+HP0qOyjMEK26AZWNmmZ/mG/cMD8q15khfV7 ieQSTAsQqwttyAACfwrzZz5W0fQU8
+ Q6dGUZW18l/X4jF2m8kmAdojkvuORkDIpDL9ujhMEc0oWIE Kr4MmeMj6HrTpJ4ltQsDpHsmSJ
+ S/IJPr60sVisNxFFv86VS77YTg4B6j256e1Y3ja736GUa9JpTc dfnp93+ZTtIEl01oZZGt5I5
+ VJZ2PzAnqPY9MV1SvNb37TxlPJjJjkyucO/QfhXIrczi5UPNBHHFG FLMmc+g+prZa7uotQKKU
+ MLSYPy/eJ5P49qjE05SZpjaEX7tlZ9/00NGS2mLvsUiQcEjgAL149xUU peKWGCG7tFMgdolaP
+ 5iB3J71I01vkZS5QvhnPmfdPv8A1qbT5Z45JIJLUXA3j5gozjknB7A+lcd5 JXfQ4Zzkknbbul
+ /wbk1s9zBbQyzQO6xtGkjADGOf8ap6hdR3MDwQLEUjU7NqgEBSDTbm2vXKokhg GFJDfxc4/wA
+ KiL2kF/JIx+0SwnYY4uCd3b60RhHm5t35Bh8Iub2srN72X+b2EVoy93JeWlwqSTll WIhCwwMk
+ Y7Cqypbx2gjimFsInC4lOTwcn861LkC6WdJswtET8/Reg4/HinpKwtI2je0VppRK5eIH Cgcj8
+ 6r2mn9W/UiUpRkua+r26fqZ1pZzzzCeItLNIoIKHAXJwRWvHCY3kiNxbNF5mCSnfsR7e1Zo eW
+ aUEK1uxfEQU4yv8XTvnvV1pIBb5lvIWtw/mMVGCe2c+lKq5SZ1TxMpSUNL+Sv/AF+A27zD9pkc
+ Sk7gpCNjJPYe5HIqGNrGIRbFltTs3J5j5IHVQT+dTXd/E5ZVhkdGmCtIDwW45/HoPeojfSS6i0
+ bw oI43KOpXlc9j9AKIKXJqvxOxVJey5eVu2rs/01Qtx5H2GCSIPdAx5ljVudwOQR6AelWbG7Y
+ RTBri GMySrIXZflyB0x7iq12zI0k/lEIW3bBgFhjGR6AUs8ccKRoJog23OTzuyRzSsnFJ9TJw
+ j7O8ou3f 9LDbi1nlGzzFMoZWdFGCgU5Ofwq28Vo8M4M+N7CcMHICr0P4YqTzJ1WScqLhwHRTG
+ MZ3YFZNpbTR 6qEeVUQBFk3gnaQOh9jzSi+aOrtYmlUc6LlN25dv6szYntYI3gWNHnt1gcsqNy
+ W/h/DHNUYmQ2lt JHDMp8rJ3tuDHPJH1FajTwRASuQ0ZQ/KOoPTH5VHBb2qTrBBLulSNiIy2dg
+ A4B9+9ZRm1HW5WGT9 nZxbXfW3z7fcUbqZSGGxiVyqRqcErjPPqalWSS5szugnSOQI4Jbrg5b8
+ DV+OG2hsoGkIuBIAQVOC +eMj2qNrMCKWBVm+R1ULu5UYyc/zp+0haxvGtSlBJ7973KzRl9ZaE
+ EtGwfeFODG2MgH8KznkWKS3 mnt7pSVww38bm7flVxLEFFnbz5N2HiZXxuHOfrntRLcQtZwyRT
+ RQtNwiT/MUJb5Qffg1rFq6S1Gn T5+Vaxfrv8v8hph+x3TKkMvnuxdSzZVQq5xj3q3a6jK9lDc
+ +TteWMtIqqBh2GOPQY7VWYmdh5kou 5gvzeUcc5pFWCNJ3iLRSk4G85X2IH51MoqStLcirTp1H
+ yPfv/WpNFJILF0wIgkqoWlG7cU5/TvVv CXdzdebeI7ySsSyEgEEdvTpiqsBkSNFZfPUHcSPXt
+ mnRXCrNI0mn3FiPOBeSQggFeQPy/nWbi7tr f5f8OeevaRcrLXuv+DqUTDGdoil2wkAFCST055
+ p7fZjYtE6CJ1kCJ8uCwbGT+HrV3c91fyXG2ImU NMiIuMheCR7UyVtLk0+RlcpsdFikZ8iQP24
+ 75q+dtq9yo1Jykk38+3yM+6nl+1xW8LpIgjbLAenQ n3ogeSW1hiht2nkj4LR4G75t276VA8qQ
+ ube3ZEniOHdvmBwDnikt7SRrqO4dnjcxERhGICrg5B9T 71vypR1DEQi6bctLbX6v5WMe6kv7b
+ UWulWWK1Mv71pOQx6jHpUMaNc3MckrEbrZnXDYIKk4B9TUk 8M/2K0CzLPHcASbSCcEHA6+9Ub
+ m3kju4wXYXCMXlT+8wIyB6DHavSp2asnqdtGrCcLxfvbdfyZLI bIWoYmRZnVMpv+7jgj8+agc
+ R+fcxKkkhD7Bg8qR/jS+UJr2Qh1hhdycuc/KD1q0dPu7NIZNpkGHy VH38dG/WtOaMdL6s9GnU
+ jBqCqczl3enpctIxSO0uACoERzg8HdxkewNVY5723sMFAVhbycFOpJya tjbPbZ3iKRYyqs33S
+ oAyMfWs1pgiXWYJA00wcAvwFxg/jWUI811b+v6uVQp80mlDm7+X4luW8vhN bS+XGrCBsZQEbT
+ 1J+varcNxZLpyGJtsyKqENznLZz+FZ8TQ2jPm1m81W/d+ZJwVxxnikzeyabZGY 28ysrZZIgu3
+ nIBpzpp20sv6fmXWoLminDlT7WX6M07qWEIsYKNsBLSR8ZyeCT3JFVTf3iyW0cGwk rnbt5AXk
+ /pSBUgsbeVLyFZJfmfcpbkHjseOoqNrW9vLgxrEWQzDa6gDaD94VEYQS128zhdOmoOUt I/3v0
+ 0X4M0lvLoC3lleKWFk4VV5yTwSe9W11SFY5JZbuG4KKVPloV/n1J7elcxIJFvAVimhkUgkO ch
+ QeDx7VPMkLRK+1ZkDsIfLG3egHBPrnsfaplhoNq/4GU8JHmSavfayS/H/gpmrJqFg93HEEYxcc
+ nsAemf51RubssLNjbhjP++Cj/lmd2AuMY7Z+hpLVHisprgRqqEkB5ACAeMD8aDqFwyuCkUUp2n
+ DR j5SowR/WtacYQulG/q3o++htLDQi709fV7fcJefa5LqNxMirFceTJleDu5yfpWjBiGZDJAx
+ fa4Zi OAOmPqTUCR2H2eKNoLy7ZNrkxy4z1IP40xHQf6Q9rdLCylipk5JHf6CsZaq1v6+85Kan
+ zcq0Xpa/ 43+8049OS18kwM7jbiWLdkh/U1jLdTwyiXaI5HObgMMliTzj0xxTp5LloI5ITJbxy
+ WxaZ3OQW6Ae 2f61nQzgWke2VRN5ibo35J54H+NXTpSablqdcqUoxu9blppoZLeaS33yFSqZXo
+ CD/PFWEAjvwrPK SY2bhvvAkY/E9KWWGVbmfzWigRpG34XAVl5B/HOKq/ZUEkbXF4kb+WVZDnO
+ 7GcVScWtyZVoVIct9 ej1+75E3leY0k8EcsbIdpg3fNGT0U+p71YkW+RkN1F5khhcbcDPUbs/h
+ xWcst4IFdUJdUDTcdW6c ++OafZpK1/se+QSpkRFskMvf9KJRaV3bQVRVFC7Sdvm/vW33Er/Zz
+ pXnW0DxxRNgCU7gw6j9aGKT rELn95ggt5fy4b0NRyTSS23lKCLO5w8TY+6B/CT68VVMrrM5Y4
+ YOgZfU+v41UYO3mP2EfY3bSktd 29yyLdDcR27q8IWErJJnqd2f/rVTt/7PmmRJFljdpCWkd8o
+ GB4bHp2qWS6nn1JLeN49rI+Pl5OOp qqyQ8Qput/kG6RznnqoH1rSMXbV/cYVI88rzbvbp089d
+ /wARC9xbPMDGGiMh8zHHPYZ7U+3e6eXa 0RVW5PGOp6/Sq5t7qdGRElJR13J1Jc//AFqha/ZXJ
+ jY5V/lP93HUH1rfk5lZWubzpp0nHRy9UW3l ZJiY3WZQpB2jjHTNQx2iuin7TGuwFyCTwMfSq2
+ WmkaV1G8tuOOMjPI4p896jo6wwtsJCIVP+rHXk 96vkktEdPNZJ2t935Dw+5U3OoTYwXI6dqml
+ Ahht3ZPNi5A2Hkntk47URCc20E0LwtKWWNY9mTjqT zVOWRXupd8wH7wmPB4Zs54/lSWsrI46u
+ NVSTjTaS6/8ADdCeGa1ICybS0bsOv39vIP41LFsuJdvl MjyZbnk5J6VQ3SpMSIQBv3FSBkZ7U
+ z/VuFG/zFYjBP5VfswhGpBOUrrs+hYkeJd8Rm8gFgAjdSQO vFSAI+9ndGM6E8DlW3CqBVVkia
+ RopOucKTwO9StIZAI/MjjCHKMBgNj/ABzTcexyzrVU2lJvza/4 BbaVob9oYATKZc9M846Y9aq
+ AfJPJJJvZCEAI6ls5qwsTlP38gWRm3JHn5yR05qRLqZmkiEcaNLvI VkGRkfz9PSoTtsZUK7pu
+ 1k+7/wAylGpEsSNA3mJEwBBxu5yMjv7ULDJMziCIorANOc8f7P65q2YI 18mZdSi85YwCNhOB3
+ zxyapyzvDelrcq28MuMdBnIzVpuT939TJwTm3Tjb1T3+6wWot7mGETHyiqM rk/xMSdpqCJFVI
+ w6SRtn52Z+p6enAqKC6la5QxxbHXJORkNjkGopZQIozE2fm+bqehz6VsoO7MqL hGc5Nt2Wiff
+ 0t+ZIXcruaN4m8xdgHGFH3qr+arTqQ29GkzuJ4C/wk+3rT0EbDDSn5Ry27gHtmqwR zDHuPlfI
+ VII+9zWqSFifaTqXg/Xb/hjaEsks0UciF0CucoMKfVh7VmebF9njdJ0bCMMEcsM/zo8y eW0jj
+ dGLxJsiKHGVPUn+VVYYTJuU7EZpQFVhjrnjpUwpqN7nnSlOF3K0Uv6uejyfZJJIIpmYo6MI 9p
+ xj2PqxPT6Vct2NrBI13wVcqzHjLY7e2Kz3vLR0hlMRmdmyfLOPmzgY9OKuvHLcRXQMUodrrPmM
+ cpgYycV4Ek7JPRHqRvzLndovpdf0vuIWLtfqY/LC9GDAHDgAj8cZpbGS5urzzvvTmUbWUYCxHO
+ f0 5qNbe3ublVknOxVkZo1YhiR0OalhnU6arAqqnl5FOArEcL+lOVuWyWo685JNxuv6+9mpeWh
+ eVWgj VAU5JUENjG2mrJHJMWuJI2Zn80qoxsI4I/EViNeTyXJVplCyDzMAYGewH1xUkdwlwjef
+ PFGzAvKQ uNjY5U/Ws/YTUUpDnQm0lUlv1SuzpZfJuZZGRhErO3LHhRgZP4YpAZZZNyxSxpFk+
+ YDw2ev5Vn2U tsyQSwndMIBEATkbWPJx6irEAuAY4mcnzM4IPBABFcrhy6du5moxpt8zbXS/T7
+ v1Lkkm284aQJuG 5mbhHHRfxpGjiN0UYpkShy6jGVHX8amSz/0LyDIr+UViyf4wxzu+vvReS2i
+ zsJJE2cRIVOMqTz+P vWXMm7I2nONRNpP5Fie5iivBIkR8vyZNxcZCE/dB9T3rCRXtUjkQNPtI
+ jkPbI+Y9auhp7e4JjQsg uVDbxnB6DNTT3jXH2mMrHHH5nyybflzgDH1p0046LYqhTjLRbdWVG
+ d3gd0tZo2mcyFyeEzj8uOfx qzbXMLRRySxKVVWjQYHzB+Fb6Usst0kSxBoCVBibCdAT83446e
+ lUIZY4bySIgyWUWBAw6vj7pz6V XLzRehHs+aGnutee5oT2aiO2i2v50RLMFPDOnH5Hpj1piR/
+ 6MwkkWQlgwVRhiCO57kU1r61aWVjI UdF27y2AQwyRj1J71nvcXUjpECkm6RG2IMPtAznPt3pw
+ pza1O2nhpxhzS6fL9bGsZDJA2AGjlILs P+Wew/dP1pl1bImoteSyKY4o3RohwcnHP4UyP7XJq
+ WWQeW7MyqgHy49fXNP+z3kzT2qrucsCHIyD x8xqV7r3sCUef36mnXW2n3Dx9o/eNIwhtkQ5J/
+ iOBluvTpUsECDSRtulupTIrsqfeJ9c+maxWiug yqzMVDAGM85Rj839Oa6ATIkMqJE4hwS7LgE
+ MD8vPp7VNVWSsa1qMHFKK/L/hx7SQz6bKDEYi7M7u 33S38IHoOMYq1bQyujSSSwb/ACyCiphu
+ Rk80NYh4ZzAHebz1CEn5SMA4x+dWI2uFkczTW7qzZASP ByOn5/0rklNcvus5nVdOl7jt5df1t
+ 95DD5pie2ZVYeYhYKPunBIwew46VG0VuodpLoxebKjZYn5g RyadKzreTbSFeSQNHkdPlxg++a
+ p3dxM9kC8kMEhIVldc7d3X8qcItvtc0pX57LRPcjnMAEkSzPLb hiUWNsNgjIAP1qO1vLZyslx
+ beTuQuY2xu3Abcj+dEkMu1TbFXlWEnAH+sA44/CqcM13EIyEiEZcq xdAcfL8tdKinHc0lGKpu
+ z/HX/gfcXfOki2Ss0T26NtaONMOx7HPoD1p6X8TuivGiqEGxyBhic5xV ARsJomu33yxwYkiQY
+ PT5j+HBpkTTC4LxXVo4hXy0zFkHd3/HtTdKLRz1IRcHbfvdr8ja+0/ar25g QCQF1wiDDYC/zp
+ ILazR0ncziQpuxJJlW54JH0rNF3II332kiSmRfLZQBgfdJP0PWnOziZ4JJFkRW dJAByz4DAj0
+ A9Kz9m1onZGcnLrK0Xvr/AEie7+1LYvMRzuwxQbQrA5C/T1Hesze0cskjqsTmfId1 +QfL0xRH
+ crJefv5SYXAWQZ4EhBwfxNWnuEhuIES/sFWMMjRyJubdjOD75rZRcfdsFWPKuSKTa1vZ 7fcyB
+ N8bxreSQTQuE2+WmGcnoc+gPX1qlc3kS3Hlos8FyIyCzt8uCeTikuJkuYdOdEf7YlvuZQeu Dx
+ xULDzhNcmIq0xBZDydwHOPQD0rohBXvI3jB815Oza22/DsZFpd3yW8EsBSUq33GXJzu9PQjNNl
+ 2SanMJ2dS83mIQ3Rf7v1PWtKVnjtIooQkryQliETkn+8PbGarQQOiG72NbrHlA0w3AA4wenvXc
+ pL WVrXPQoUNHVStJ6aeXe3T5CQ3dtHa22YJSEXEjE/x5JA/KrjI0UJnn87fOm+Nd2Ain74x69
+ KnEyr oqoIlnJk4KqPmGcZ/CoIoLiW9uYoyymLgCQ7jz1rK6d3sXhaPNBt2i+uv9WGTGAWjrBO
+ qKzhmDZJ Vm7Z9B3qF7WeK7/fxuiKjIHPQnHFTBElgMinziHVJEQYyRzSvb28dvBvmkkldwSik
+ AqCcgdOpqoy UdLnZTqUqV4Qk7el/wBVb1ZVUMJYZTIjJEgZo3GS3GPyzTnEcYkllRlGAihWx1
+ H+FRgC1uRI1vMG 7BjkDrgH8ancSmFoDBK7yuG3Y4OBjj9a06m9Kynq7J9bojR1IiWJEMSSCEL
+ IudueQD79asFb+NXj gDxwvNuHru7c1atrhkKR3scccKjcvygFmHfPrV1J7VbdJPOVYiu4gnOx
+ uoU+5rnqVGn8N/xOGs3z 6U1JfejGkl1CDzDdIsuJv3pMYHzN/D/9aiVZ4B5FzEoiR8DauMkHo
+ MfhVy93/ZEklkRJWbZGhXqP 4mPrgd6rTRmTThCkcrB5so7vkMBjafxqoSTs7IwjUp80JOCSbt
+ 1t/n9wk96r2cYEZSI5eM9Q3/6j Tra+ubhts9ks6glm8tQp3Hrz/SpHkuEsLj7Q0Fs4dk2vHnG
+ cE44OBVIQSjzZ7hwsAuCWdDjJIx2o UYOL0F7KjKN0km27av8AD/hxZJvOiUbHhTap354BHf6e
+ 1SOZ3MsVuDdKhWLCjqxGc/jjpTJbqKGV TMDHIynygRxt245H1qCGFVtgrTtFPsBZuSAQDkYH8
+ XatEtL2NqNWT+z6aX1/P8SaYhLQSMsyyEDY rNkMDwTj0FVZLUz3AhjngkIUvHtXBbaPpV6M/Z
+ NLDAw3O9AyLIu7aAcAc+5pqWVzcC2ZbWXKxYwg A4YkE/rRGfLrcFJOF5JaPdr9P+CVUihnNxJ
+ NKyszKck9C3Y+tXIoB+4M13DNFhi0ajDnBx1NOazM EIjkKQSo6LGX/i56n6Vbit3k1N5LmIqS
+ cB14XeOQMe47VFSqrXTIxUlyOXNb+vT8jPjna1ljGxrd cBQ0vzAqTzn3qcajbokiwRo8oz5Tj
+ HT+79TVi4hsZpLRrmRk35V/mwFc5OfYCqJBjiiaG3J8tWDY 58wEffHoBUrknq1qcMHSqtcid/
+ w+8j81JmkeZWtkVCqA9z2xTNQCsVaO6hcunmEKvJAAx/WrErwT 6Zbopw4X5M/xAkAmsqVTHqg
+ j80SqqvGu0fwj/wCucVvSSbvtboddKpCO6tJdOhDM0nmxu8LnzBhN q/dB45q4xS1gYO8Z8wAb
+ tudu04IP50x0eDTkSJHaRic7jkocfMDTG82cMiSeZlecJnfjnI49ua33 S7FU/rFWjfmio6/P5
+ sgn+3pO8UZcsjkEhCN2cD86rvE1tHKjJyjgMGj+4wPANWhc3KXhmyWcxEBi vr1P1psb3N3HHb
+ yyROpBKOQBkepOOee9aJyS1tYxqUqlKVpRjyv1uvO1jOEk6kyeWcs+FG3r6ipT GjJcNvFuVO1
+ FZfmIGDn8qkMM8Cxx3Mi7hJvV1U4wOuPeniWVYzI1utwZCx2bc8E8GrlLseXVxddx Sadulv8A
+ MzoXdQBAX3MzNweQP4R9etKSq24Blhdh8oOPf+dX3tJtjIqx28LPuRto5x3GO1Z32Znj leWaB
+ nEuGKAgA5z6VpGcWysPWgpOKSbt3bHLc7lMaKJY93oNwI7E4zTkSKe9DeaLcRkMu9uWwelL Fa
+ qkErySpLI0xKiPgYPQ9O/NMaMecEMErMCACvc9qfu62NYxc6EmtL99P0ZYQmS8kbIU/MqLt/TF
+ RMhEm7EixgfddefpnHWmGF0uoVWQu046AYPLdfzqyWuHtpEOGCykDj7wPBb6cUr2ehtCpV51Ra
+ vb tfT5oa1wUu4JW2rNj5MJ3qz5swkWZvLWZZN2Cv3OxUiqXkNOwfZJjGFbrViK2H2+JXuEhyp
+ ZzICQ p9xUTUbGePgqsZTdml836P8A4YrynMxKxkAADA/hBPf6VE63O2N2gbBVuR147/StKaSG
+ SwV4ZUl7 ZVcHOcc1lF3N2+9cBWwwI61dNtoxo1Jzpqzsuy/pNEkc0sEUiKUULIAm5eSp/iz6D
+ +tVpJY47h9x S4TfxtHbp3FTQqbi/tzIFmTkSRIMMwA4GfWmQBPMMUdvJkgklz9zGc5q0kmzj5
+ KMpyXNZd3/AJLX 7ypgeXIY1cLuYEkVJ5RSFBt3ZUsDn17U8m1eCJ5QUkYf6scZwfXHtUCwtLI
+ zGTIV87cfeHXFarUh Jyn7sb2+V/k3+Y+a2kKKYX3KuN+0HpkcVUkjeS4llfchMvmDb2rYciWG
+ WW2Cshk2hUHKk84PrSyJ EYTEbaRZliIdw/3mz1xjgVMarXQmcY15OSp38lrb+vI6d7SHyo7TD
+ QqVaSNyfvYPanXl1bGysBIl 0rlSxRZMYy3zZ9cAVopduW2vash3ncWwfn7Y9FA5I70RWwv3TM
+ 0MrxwtyF7d68L2lrOfTzE1FWdR WUddHcjtkt9zeS26N3bAzyRnHX6VWY28jSWcbbYxs8pgfvo
+ OrfhVmHzYjDHFBiKMYDEZ+g+tZslz AZLi4gUJOspiQMPuqR0/PNEE3JmeHrTvJNN9nfb1NdGg
+ +0XEolgl2zbIzjhoyByPpT4rNbS4uT5k RhEnIZeR3APuaxwn2e2kmmjdmFwoVFOC0Y+8RW3DL
+ bSa0pfdNESwi+bgqRkZ9TkcGs6kXFaO6LjK avOL5k/QtLNHLFE1pHGxRdgRQMrnk5+lR2y6gi
+ Ncy42wMEK7e7cZqaxh8+SaKONoWldZd2e2Ocex xirssZiuo2ihuFhaPcdzZCk8BD6t3zXJKai
+ 3E6sPZXi0n1d7DnEcdmCgfYsTbBnkg9CT3PWs37Je SSW8fk7EZA+9xnIHBxWxN5l1axWyBo5t
+ jqxIyGwB849FGOlQyJLHa25WUPujyoH8Kk5P+NZU6jS8 y6fM6ajDdt79CF5LhbKVUMagziTLD
+ O3HrTEuT9uBQKfl3jK5DA9xVRzdF3McqyqZhIgUcSKBjcPa taIuJDLKq2bI+N0q/LgdBx/nmr
+ klFG8YU4wtJJt+n/Dlbzrh5SEmgV3lU7imQcDrRdyyBF226TbI 9kbIAA0fBLfnxUjG8luXeGS
+ 3kVZVBjWPBTuwPvirYSaO6iuI3iuI1R1RFXkD057nPFRzJNPQy5Ve z+S1/PoZ9wy+TdGPy2Pm
+ lom28AYHBHc9cVRSe5Nx9sS0O853HAxgjnj6dKddW3nwxlnMEsiK75PA Zc0kRwIo4nN5NgyMs
+ fGG7Kf89q6YqKj3PWiqXs1bV9d0RxBjGqrM0EZYFVkyWAB9fep7+SWO8naO 43RrcRuETIbkdM
+ +3f1qO3ZppVkmjeIhB8x6M2SRgelXrmQhbi7URyvK6gbE4TgcH3obtPVf1oaqN p2klrte1vvE
+ txOtzG026XClJSO8h6Y9OO1X7OO43zJ5f2iNAE2qOR8p5PrVK2iaZWil3gSSB4W6f KvJ/H3rS
+ WZIQJwzrK0W488NzjP4A1zVm22kcs6kpScUlf7whup4ESJIpZcRjZtPMvHLD6VYiurh7 ou0kK
+ Z3YLJw3HUfyrPE48kq2YtihWJ6ls/Jg9gfSpAgnnneeVYTJJ5hHQRYGNmPWspQWraJVJJNy SX
+ 9eo6dg8MMkrfvYkZJVXghm5/QVDDO7hI4Wh+V1L713EHsPxq/bXNpsaCORGaSMyOG5YN1UZ/Cq
+ DS77dLown7VIELqvAAPXj19PSmuzRM4pq0ovy0/rQtSC9innaW5tZDHcCIrHHgjcM4rNuLq4Mi
+ QR RDlWwSucAHk/X3q3vgneQhJIiZlU7myWPY/gKyLuC98yVFdFjw259v3QDkj8qujFN2f9fcc
+ lOEHP ldr/AHfkZ83kyS284mk8t4H80lzwM8fjV03P2W0E7IArH5iR17ZH0FVXgeWGHLI0Usys
+ MLjKDqR7 dqnuDK13PIAttDubJmXcoZugx/nrXa0nZMIwhPeV7f1p1BbxFO/7QssaZT5f+Wn+2
+ PYfzpEnSVD9 pmQ4kR1C8MFxzk989Kql7h2uFhgUOR8yhRw/YD0759arGS5+zRo9sdyxKJDgA5
+ BJ/SrVFM66WGi1 yvWT81dG5MqRXF00RyGlVkXHRgOB+IrLB3zubsJamaQ4Mg+6wGMH371VbVS
+ u1FjL75hJKxHH1HtT bq7u5lZCglgMzksiemMNn0qqdCa0ZcI4ty5ZRS83v/kTxQzLE8oxLJlS
+ rJ3H8RHtWi87NaSGOWFX UhQdvAz0P41nrMv2WNJw0blHLyA4UsCOAOwPHFSfZvNt7mUSAxyzI
+ Qo4IbGMfn2pSV3eRo5VKslU qO3S7XYcun3P2ppPOjJiby2Kg8secj2xTjp5JnzcKkDIXwe+0c
+ f41FcpPZ26qUuHXd+8YtwGGOtX p4FZzbHcjSTtLhj02gHFDnJWfNv+h6ClXp8slPR6aJFWyhS
+ VTunV5y6yjaCFCD73Hv1okjf+0DLH e25jD4UKCCw6g+9MgvLgXkjwiCKSXlFMY6dx9Kcy3G2K
+ eV4gpXcE24LHHOP51UoyUtX/AF9xpUw7 jUak7X9L/kW7ZFF+u5M+ejSOq8c9AR7d6ou0tjaQr
+ 9nlVhhQ7gNjnPNS20aNPbubgAG13uRnjnit BkV7me3Eocq29QfUjpUN8stdTWdBxnd2aS6r+k
+ Z0qbVmBkimnnl3bsfLhe4HpUqs0FnFJFiW4jY+ Vx1TrnHvzVoQRNbwyXPzSJExJU478n6Ypsc
+ 0csEiCaIlySkm04CH735Yqea62MlSlV5U1pfXtb03 M2RElTfMHDMf9Hx3TGc/0ppeNLW1RYjb
+ mVC8zy/MpOcAgdsCn+Xd/unaI3VurAKsXoBwc+lV7iDI Vmy+CJCg67F7/SuhWbs2bOz91v4dr
+ flb/NE9xbNEI5rrfLAqMigNjpjHPvVOK0WVVE100crksgLH CAdc1Ok4urtsxTyxGTzUi3fe68
+ /SqQMshlgwI3I3lWGScDt+FXBTtZuzMFGrUnaUrNden3bFqA87 1PnKSN+85ByCB170yUKWidW
+ WcxwiAoP+WjHkMP8APakniWHTrCSK4jEgiI293JORU9nEJraBhhZZ jvZz93cCen4DH40m0lzH
+ FOUYx55yur2/r/gEQQW908+Y51yy/OMkn1GegqOK3jfzhcNLFNGpDHP3 8n5WH4GtWWS3lngSB
+ 02yRtKQRnYc4Gfp3qvFbPbLJvjeV9g2yBuGAyTUqr7uujNac3zc2ql9xYEU cUEsVvKkciuBKs
+ vzcjnirqXDSbHS3n8wNmNlOFVemCO55rMhmRmU8FWIKKPvKP8AaPc571ektWUz SrLtnWRfMPR
+ cA88Vzzir+8TUoc8rS/Hq/kZ9w8wjQ7HVo4yCZOcjP9DVy1uZri+dpLSaOUk/Ox+Q DHPHr6H3
+ qyrh7gwzzQMGYuWC+/8AKq1xLN9te6kjZkMZA2fKpB4/Q0X5ly21Eo+3vSsk1/XkZKzx rcx+a
+ CRIQVJbiMkEAn6d/Wr0L3L6itvbR+YsTbJ5Qvyl8cAegPTFWIms5dFUtA/nQMICM8kn+tZs tl
+ Khe3t/OEzSDZ8331HJP9M1reMrpq3qclSEailzaPbXXb5oi+0+TfszW7RLtbcrYO3jCgVbZfPh
+ iVkEzn93P5YwUOAP/wBdVZEtCZJCXWTzdpSRs4BGcH3ppmjmvnyJbYNzIhPIfHB47DFauKeqRN
+ aE J01Kle662/r8yMmC3leIxuJ4wUbe2RJn+ID6VVSFzeRRorSxyQlgyenc81YjgMtteebNEhW
+ aIq56 learyLY29w2VnkiUOqsr8fMOnTtmt4vdLc6FOdOLjF697f5/oTx/ub2ONo9qqDlnAyyn
+ qQfaq32p RdAxWxlzGEAU9Ewcj6571CkFxFbo00UuyMlWOcD/ACeKvwpbSWpkKSCJ0OQDypXqM
+ 02orV6nLyp+ 85N303/4O5WMM1vEbgKscRjZAJl3enHSoXnuXcweV5sMbFMImCARnGce1aEUEF
+ zdopnJjERY5PCq BnJqhNBcIlvcvFKF2byduATng59OnFVCScrPc0aVWTUtZR20t92t/wAwtIF
+ lZIvNcrjKtu4UkUGF fteLhTKYh+7CDbvGPmPvg1Iu1pPMLfZpwW3uT8jEjjA7Clhed3sY5XUR
+ SMCxZeWK5yoP5UNvV3PL rx5FKUtu3Vej6/eRFriC3EoWN1kQMxVeAM9qYIo7maJpX8hUT98c9
+ WPTHp2q1ckwtFIssXnoDCyb crzyePYGhrUPZRyJFLL5kRyUYcso4/nQpq19r9TSlWgqS520pa
+ XMv7NcxiNpYmTjHJ5OSeR7VItv LA6wNNHKsrMEAXczlecg4zj2pryO/l7kWInr8vOPX6U62ga
+ e0ZmUiQSkDH3l2jJP8hW8m0rtnTXi qU1epf5NX+5ldIo45l88svTcQMHnn0qz9oimjieSCSaR
+ VfZGBgqBwNx71F88l1byMARMNxyOG5wM VYW0NybgF7cRQO2XRApfAxwfTPalNreTOPHKlKa12
+ 6X0/C5meT5LbAGIVG6fxd8/1/Co5pxHcK5M W9n43LkOcD+ea0o5LZDI00ckiEDABwckc8+nbF
+ VSscrAgKqEqEU8sB659q1U9dUViW1C1rfiQxPI kgSC1kkuTI6h1bhOOmMdcVVdQiWYMxilkyZ
+ Cc4Htx61Zni8iVUeJ0Bz8z9x6023k813liSPdG4ZR ImduOo5H8qtbXRwywzmrKV29kv1fYI7V
+ IUKxxzuWJwCclW7Dp25oeR0kVUaFlEyIzbcjHr06Vaju HkeNZ0JN0jyKy8BcAjn8qht7tksYE
+ PkyKExuVB8vPfI5PvSvJ7oVKc6kHTi7fp+f4Iu3NusF28iQ uxjuTsWI7Qigc7vWiEIL1wkQJz
+ x5w3eYOuRntViFx9kObK7kvuszE/LgHOMfStG0vtOvpnikKwRS MW9CvbAP4VxzqSUdr2PPrS5
+ IStd269fuTJ20/wA+KeSMTxgToIwz5x/ez6nvVjyEiuS1is0oQneF f7x7Eegpbszx6a8TSLl5
+ MqyDG0jBP6YqvatcHUg7zxso+VgoxlWPP41x3k43b0Pbmp1KKm5K3bo/ n1LF2LuWFGYMgVWEs
+ YGDvP3RWAkVxJdslwoiRgN4xg7sYX9a2ob6KHU5o2indMjcS2clR8h/Kqtz qNzJayGPyTHs25
+ MfJJ6mro88fdSKoOvCXso2Sev3/eTyxKmmOyrLKN6RFlbo38Q/E1pWV1KqxrFH CrR7UcMuSpJ
+ 4NVpJAmlnzEJjWVUYDgqxAxn1NWW8kW8CHcZEUiQo2N+T/hWE3zRs11JiqkqSjP3r N7frc1mu
+ DatI0sLFA21mQ7RyvBHtzSSWxa3ha2nfMcJCB2LYIIwD6k9qzxJpiy3UX2iQAMBGsshO 9O/41
+ pRpZyBZ7aR5FmYlsPwmDjafc9q45Lks7P7i4KOHs1e/mrp+VtSC2trh7xGuRJbupwct2I+b 9c
+ Va81WmjUQTTytEVKo2MkenpxT2uf3UipaXEqyzeai7ucLjP4U2W7hMSyR7djjfIy9ju4APbIrN
+ uUndo6qdec58yX9fmStBsRirJbRmRfKEi5/dnjj8arCZ01Z4J5AYY45Izle55GfpV+WQTrLPIP
+ LP 2gPEn9xc8qfXPUUySdFnmuPKA3K23f3OcbvoOlRGTe6IpVXKUkkn29fxZBbRrDaefI+CWCy
+ N2zjl vwqq0l9bm0W3YyKvAkA4ZTyf06VoKIHtImZxLtUCQKcAMAePxNRyT3H2EC3lhEhG/wCZ
+ M+WccqRV Rk29vvFTlUk0uX79v8xJC7adIyTRNG1xvUleSB3B9B/SqbanapKiBo3kZQymIbd3P
+ P5mponme0Y3 AUxxNsUouAAwxt+vepDbW9vbwwuI47oKCrOuf3ajDfzqlyrSWvoOnXcFyyXXpt
+ 8+pBI0bA3KrJvZ wxGeDngkewp8MtxgRPbuYSjMCV9DhR9apmWFbuI/62NcIqqcbtx6/lVp7+P
+ dMlmrsvnjgtnJHce3 bFXKLta1zonUk0oxV/PoMLXSywuY2TeuenAwcfgKngjuGinN9BIio+2N
+ AfuLnlT7niq13dXjXrtI 0UNurHcCnVgM4HpVjcGW3lmvI4oJ4iy7s/N83B/MUmmorbXsNwcIr
+ mas+qv+HmTBJTEVQAhpFYBu u3JLH8KssYPmMUm6AYIyclgenNYJUhGmaZ3y2x0UkY+npVmG6g
+ VwFxIuCSA3TBwv50pU29imnKK5 btfcarG1P2mQwyF5HDbUOChx0pjWcq2R+1SqpAzlRjcR1I9
+ uaha5LzRAhQ7IUkwPvNnJx6cVfuby ONViWGV4JJyXLNnacDCfU1zvnTSRy1qzjaMdb767GRbx
+ Q/apgJt7u+8c/eGPvD09KazfbZlTeYl8 plCk5LHr+dXfsokmmkVTbyqdqo3XCnP9arXVyrzyI
+ 1nIyySeYRFhWBPHB+tbqXNLQ7It1GvZ6+b6 f16lcwgWmWtLnfHLkAPjI9BSPpzyXdribZCS7O
+ kmSQR0zUUwmgWKSRZYyrKz7zwSM5P0Gal23J0u RzFOGFwoikJ4HcA+ua1vJK6ZzVoWio3Su9/
+ 6uir58pZWR4y+zMhC9Sc4I/AGo4p5g0QHlvHMu9iV BMYA6H3q41tbTN5k0m2RH5CkjJzx+B5G
+ KpfYIbczCOK4TZK6sXkznI6fritE6bViJqjFcqWvf+rD obeGOS28wxGQRHYCox17+vNVGsrae
+ wEkry28u05+bjjq2PSlkKNPaW7tgFi0ZU4MaJ2Y9yTUn2uy 3RII5C85M0gZujA/dH4dRWq507
+ q9/wDhzOnKaqLlb/r1GRRQK0kC3UTIVwHbkMSOMfU1ckV10YQS SxyCPB2qMMSMFufaqjTBY4p
+ ljRAsLZ44LMeo9hxWjA159iX5I2lDqwJXIfAwWHtipqN6Nnqc81yu VrX0vpr62K9xcw3ssCsc
+ Kys2A3RCe/qRjrVQEW+o/LJJPIjkZJJHsamXEksUVttMqxuoO3ONxzTE ZooTaPEJLoRlVOBk9
+ 8/lWkUkrL7v1PSwtFtS5tF5vRee2w2V7YeW8cEgmBKyuD8qZ9vpSxNbtqEY 3v5aj52ZuN3t6C
+ nW4lcxSgIZtwwNowQOScfSr9y0BaCVoC8fzNGUwMKByp9T70pSSfLv8x1HTpz9 lBuV+qav+N/
+ zBNQiexfEItnk+b5wMcdMe3tV0XRigt3keCKWORY3kZeGBGc/hWdMI3t13jzYyF8k LxkD+H6m
+ nXMSy6WgKEzISzx5+ZeR/KsHTg7K24pUKdVQppWTe99vX+rDrpJplGyaOUFvnSNcEZ42 fUjms
+ hkMaqsSM4zt3A8Dnp+tW5wy+Z54YwiTflDgseOR7UyNZRfNLGVcIpZhjAYnoR7V00/diejF ul
+ Tave3b/P8A4BYlldknR1aErMFUrwFQevv71nRXNs+2KUmMIpVZCffgH61HFPLcRFpSoKnYWHR8
+ HP8A9anRR2huna5lAD5dgvBVjwBVqCimn+BwVOV+7q+unQjheOS9cM4ijLEvjjHsKgkEKNEY98
+ i4 JQ7sHHTrVtbp44CIYoisbKFdkHfg59SaaGLCeG3VGjLHy3ZeNo+91HarTad7aHPGo/ae+rR
+ Xn/wN y7PPZtYRKE2RFsBm5wx7f1pPsot0jlKSi3gBjdC2CHPfNZawBLRJBlkYI5IPC84596uX
+ OotMfJiR zGjYVs9s/eY96z9m1ZRenUiOFlFpQlo3rpsvJ9yylkY7aKR3E2+MqNgxuGcZHtU3n
+ pD5FqkckZfc FeVtwVD6/wAqoPOHW6PmsrGQIJM/KFPJIHbOK04UErTSxIQ8bmJd43bdw4z9Ky
+ mnvIxqQl9uV332 X9fIdN8gaVFSMwusakjgA8Ekd8VNZ2TpMZDexM8YKcqSoAPRh3JzTYWsprF
+ rf5p5mYeZsfHzAe9V x5hurmNw6AuquF4wxNZauLV7HZRalSdp2a30Wq+ZbmZWJaSF4XWRYpG7
+ euP8+tVZ3sriGeTz2kTz QibDjaD2PqeKs3Jiud0ckv2cRNtLseGYnr+H9agnGLSTyZLeXzyp2
+ Rrj5s4/PFFPS3QmnJRa55Ne m33hKtpHZXDW0qguWkTJJ3Dpmq8Nve/YUWM75HK7GxnpycfhVp
+ ZJhmCX7OwhfayGPBA6Af1rOLzL CD5oL+WV3A4XceBj6irinZo5KkajpuCVne+qvdf16i3VosS
+ tcorRF2O3zGyCuRzU4uIobwOLOS6W eRpMpjlV44qCG1dpopi5ePyismTxyMZHpUgh0+wsVi8q
+ 6uFDEFll5QYyT9DVSatyvV/15nnYh6Kn K7b9V+v6lDZDPKfJPkyGMsfMORkN1+mKrTLCDapeI
+ 8gt0JOzjfk8H3xUksTS+SLWTyT28w8kHrz6 CqUsc4d2kJkWBvJLjo2eRXXBJvf/ADOmDjWSg3
+ a33r5/8OaD2zGOSSecLbhhtbJwc/1PWnGOFtPV IGEMbFgN7Z3E44/HFVAssis94ssUEkg3OCB
+ 8w46VNeQEKypGxRgfNXuHUcfSptqk3/kQqicopVE2 nppp/wAOQxW6+ckUj7ZGQExr97jqPwFI
+ sFzOVti8nl28ZAIb7wOfm+g4pZEjZU8y4ETOpd5Sp+Zi PlIxyAa0obbyoGhKyXC5O90ONvy52
+ /U1U6lle4sRibtSk9Vt0t5roZptI0trEvLmJod7PnIJU9Px 6VDHJpqPIxt7pdzEqjScrkcVPH
+ qTq9mPISTJUKm3O0E9D6k1LMbf+2Z5r0qY4nMaxxjBORyfw4p3 ne0r/JnC5TlL95e/ZP8AQyU
+ KTwJFJgzhVjjPqeevvRBbpcrAju8PykrubhT3yPoM1cWOedA6w/ec EsP4V6Z+uf51VYFIgY1O
+ RJuifPCqOx9Tmt+a90jSpJykowWvS61v+IxoHLPtljkJnTy2A6oQaka0 uo9NmkmkSWdZlVtg4
+ 2sOB9asRpLLaSTDEfmOWjGMZUEcj2qpLBsvJIGuGiXcGdmBIJHOcUKbbtfY pTqS9+Mr8u+5ei
+ aOK1jXymd1DpGncDOR/jVaRrdUidQ9wTGfM8tyASep6fh9a1khOx7hpoYopZPM Vip6D0rJ4tg
+ xkuIZFOGARcZGc+lY02m20edRjOabir791fy/pox3tDFYRMjOA5PDnJHqfpTgYvLl NsWlIlGG
+ A6Keg6dfWrtoxt4rm3WFw8rEuZedozk052aAXci2f2aPIHIHGR/n867HUd7Gnve7Buz/ AA9DF
+ IfGzeHYEgMRwQPT9at28ai1t/OubeBZFyDs5AyRzjqanhMFvcpFIiyMFOeenrxioGZHuS3l +V
+ FvK+W3JUVbk3oVWpyu43aa1utfu1f4kZuIJ9UtApKQRK0bNz8p5NXYRb3c9k0UkNyI90bQwxlP
+ MYgnIGO1NWJonUqkQYHKRPGDuUckn1NXw2kO7y5KSGUBvKGxcHqwGOlZTmraJ/1/Xc8tvm6t/e
+ 9f zX3lqxMSXFuSGtnW0KM0rZEhwcN/SnW1ktzoUMUM1usYGclPmPrz7VZSOyWSTdcpAJGKIXO
+ d+e6+ wFNjkBeKOWNsRv5YCHGM8lfc9K4XNt3X9feYymlUVSnuv66mtFEP7NdlImj8xPqBu659
+ +n4Vm39t eSSEJGJACSEjGGGTyCafEGTQBEsjHzJVZZB0XB4H51PcKyyN5sc5lkyzhHxt2nkfU
+ iueN4zuenT5 FG8tf0/JL5DYI1huhb+WSHYlZTyMDJAPfmqqRI6CWaKQ/LtkC4ADNkgVHPbm2u
+ Z1ijuCA4VAWyT6 H8M1AJY7h5LRWeBWJkG5snco4z7DBreMW9Uzr9i3PmjL+vk7k8MN1E+5raa
+ QFgGjByZGXnePatSz uY7uVhLEYysnylu67Tmo7QSg4huo3llkVjkZ2gj5j9KZme0vYt0LOQpV
+ FUD68+uKyqPnbXUmVR1p uKav0eq/MtTMnl2xtI43X7MWQsuT14Ge/erfmtHAySMiuyiRlUY4X
+ uP60sc7+cTIq7mGI/lwpB6s PQU+SS2lEiSssksUioqrw3TOPzrlb6NHdFctoy1a3t+pXnXy7d
+ ZYZZDJIhZzvJA56D05q5BbI1zc yvBMTk5Ct8uR1OPYVJFLJCt280tsQs6CVdnfGRj0Ge1W1uZ
+ Jb4s7xDefMZFXGeOR+P8ASsp1JJWR NfGTpwdr8vfuQMi7j9n3tFMyyYB544yPY0k1pIb6eRm8
+ qMy+ZEr84UDG0/jVea5k3oxeNV3CNFC4 JUjJx9e3pVeTU3kDxxwTBWyYtzZwgIHP40owqPY5v
+ bOony9tf6/4Bf8As7BlAilZF5kCtjaw5AP8 6RlRJDO0MyQMgLOW4YscAj2FZllcLI8qxJcsRO
+ cAyZJHp+eav+YRFbpOSIiCzZP3eeAaJQlF2Zk5 Si/eV/K5Dexf6KEVZGdZU37WxuK8n9KgnEi
+ yXZF7AirMwjdxnCsNxXNX7m4Riw8+J2dGdNq4/wA5 7VmTeW2kh3+duQFB54xyfp0NaUr2VzWj
+ OUeW63f9biqYmhmWJC8wKsIgeVU8n8utXBLaN9q8xGdW uFVWi4zkZH51jLOwvDIhUF4+FHVxj
+ HFXvtVstqEit5TKkmWG7+7jH861qQd9jpxNSTmko3Xr+ZLc aj5spgSzmkYksy5B2k+tMedo1i
+ geEhdg8hXGflHf6ZqQPpxvXOJSwASRlbG0k5Gfesl55odTEk2W i6ZI+8RnAX05xxRTgmrJWNI
+ 4mM4unGNrd3+Wp0Fiv/LScxqRGcIf4euc+561nPArmNtwaOBEibZw ck5IPue1MkdjF/xMNyKy
+ AyFDtKP3B/SoN1gyXCxXW1XuVl5Y8gUQhJNv8loRh6tVNrX5amwypp8i ThXZfmBRjktzgMD+N
+ ObUo7C3ijSB3ZGbZv5ySMgnPXFWDIJtUuwAGi83ace68Eeg71Nb2CyRKuEm WKMRqCMk5GS3Pp
+ XJzQ3qFUVRc/36bt+KKEeqXJsre5up0YL8pUJg4J+YH3IqWI2ss00q3MSpx5eT zuB+VfqalWw
+ tG+zrIS4dQyYPHTmpZZbVIJUhiVptyeVtwAV6v+PvTcoXtFHVGpS5uSMdX91uhXFw El/0oK4M
+ RMiY5BPBP0Hemxq9vp3lR3KTRcSEHJJYdSD9KsyXCPfzeWqMjLI6naOoxj8O1ZxglujI OI5tu
+ fK6EY6n6dqcVffQqph41FdaFYPM175gMcls08ZVlXqOauNEsl0yAPJEZW3MpPyDqFb1YnvT BJ
+ bCSRUuYflJZVA7AcEVkOb6K4MqeaFypUn7uMcg+/PWt4wc3poP6pUqScnaL/P5D5LKOXUmhhkE
+ Nw0e5/M52Duv1NPMv2ey88rFPAZVYqqjcMcdfQmtHNw/mPbIiMqMAzjJxjr+HNZHl3Bs9skkdw
+ fl 3+WuNoPQfX/CtIy5/iZz1E6sl7X4eu3520+8ry3P2l5GlUhBnMSjBBP9KtrIqJaNb3IjwCw
+ 3nOV4 yv1p52R3bCe1ChG8tJccMpB5PrzSTWMccixGZXk8psKowRgZ5rTmg7LY7F9VkuSTcbbb
+ Nfht8yRd qX9zcrnyFzhwehPO0+9RNdxvBJMtu0U42tuf64qujy3Uc7rcwNvwWjCkE8ckfQVfi
+ ljs4YpYl/d5 KAuN4AznB96TVt1dm7lF2Vm326MrXAnlkeaOMZXcJ0Xgp6D8qglWSVLaNZBhY2
+ 3nJ5yM8fhUzwwr M0yNLLFcO2Nr8AHGAfU1TiufsrlbYbnUmMhuev3h9T0FaQu1obQxcpxUVun
+ 8/Q05lgXTwWWQHyyY WzkEcc/jTIr+CyuXuEPm5UKQ/O7I6j8arm4laSziWIYjhZTG/OFzzn1x
+ 1qGCJFspo5IWaNJE78vj OSD6dKSguW0v61D21qLhNd9L7/16jzPKb1ASPO8hlbPQHnIx9KbFJ
+ Hc3QkkZhEYdpCnHIXgfiaqO rQ6hHNKd0bkPkHG49OPxNRRlrd5zEDGsUiqyvzlhmt+RNaDliK
+ krwpu2nf8AUfLHJHbwowaJEALM e7dcVYN1HHHDJbRL5w8xZFkXOAemf1qBWeRvOdWl2xjcM9e
+ aqossT9dyiUZcjjHb88/pV8l9zlq0 Vo6i08tn67kqvcMkk7cmOSPbtX5cDPBHrV2N3RXkI/co
+ 5jRRwSXOc0C5EcojZQgRiJkK8sazraQS 2rT3mIyS2yLOC2P/ANdTbmTujKTppPmVr7bu/kX3d
+ 50SN7aUhJQFKHAPv9KYDJYXjlkATftcMOrD nH41H5qoYnimJ2ybio/iO3j8B3p0SyXhWSd+do
+ BA6+5oSstdjKlC1+ePuv1/zGRvs0+feNs7SAMj fw47/rWhDewwh5JEkNw7Kw2tgHjb09ealDW
+ cLw7rmDAUq4aMkliMAmqBjS6vYVKmGQJjeDxxxkis 7qd7rQ6aNSNSnJSg+VdX289vwNK0t7dc
+ TwS/vYZChJOQoGQSfU81YbUbq2kh2wLIuQGbb99v/rUk hjjsWihhfIYq7g8Mxxk0kNw7xeVPt
+ RmJbzCML8pwcfhXM/e1auZ0o05q8ld/p0sTeUhuGcoFjKEs pOTnr+dVmCMYQ0qJC2HZFyD7kH
+ tg1PE3laxczFgI1Yj5uQuR0I96alz81rmDcEjO7HYvxj8KWp01 IuS5Vt3Wn5kk+oRQ3IItjIj
+ 4dmGMt2Bz7U2OG1ighFy6hZk3Akkb8N2qEQfZvs8T289wAGXKng84 P86tF4L23isjZ3MXlkx7
+ nYE5Az/SpfKkrbdWcFSrSi1ON0utmR3L+XbpNDl7eQCVwvXcpwAD2B4o cmbTkYbWYxu0qY53b
+ h/L0qhPJcWI2grycmNhk5bByPbtWebkkho5gJG3BlAI2ZOOfwzW0KDaTX3k zwqlZv79QZ8osi
+ RyBpCDEM9s81auppUgYxRYRZf3pdcjfVqeSzW4iiimjZEcbWB6gcgj8KzZ7mIt GQHSKeB5CXO
+ QWz8v8q1j7zXumFPkqVUqkNPO4Ti7lKO21YmRn2sOqnrj8amsbwR20Fv5TSyqNif7 QOfm/A1F
+ DJa29pDvZpLlvlJLZCBhzkVJO6GKJbcxstsuNyjBbn19x/KqkrrltoTVXtkqcaeib6NW /wA/v
+ LEEVlsnQt9qKg+YU6A4+XHoBUCyz20dvcWkgLtBmVWGd56BvoO9NLz+VKwCW5UfL8oyytzu /D
+ +tN2Ty6MS0L+bGxRCOAA3LA+tTy93oZum4uKqStF6NN/oE0rCaK4mkhOSGQImAyqOv4npTLgCe
+ yile5gVZmLFtuMMM4/Oo4rO5PlxFPMETbAmMkgckj2GasLbWEsmFkwypnlsq4PO4e1W3GLVnt2
+ MH JKakparsk9CqqqVhRfMk2xlHkjbAZ2OePYdKt2/2lbG5S7twUkuIxKdg/dE8fh24qVI7fa5
+ QgtuU RgHG9eu8ewrOEsyWsmZBmdt2WzjeDz+lK/Pp/XcxqVvaOyaXrv8AInS8SC9uFcgxQ5hZ
+ Qv3u2R6c 1Sku1ujH9oXbtXACjBPH9akltbZ7V5beR2LSMwQnJYAjLfQc5q/PPbwaXNPC1vPKz
+ EgBfugkYH5Z NXeKaaWr0CdSnzx5U3J6dV+X5mUlxPLLJC6OsciHykPO09BWfJt+1qJIZNsJCH
+ J6EdjWje3UjmRB GkAJOH24Z+nzA+gH86zfKcxOqiRzJJ9oXJyQRwQfWuqnte1jatKVrRjZev6
+ 6E1zPFJLKodnmLk7l PHQZGPoMVG8TSwW1wkihPLYgE54B4J+lQuGZFkmVVMkZIAXBJ6A0WUcs
+ V9bTsDFD5bsA4yGHTp71 ajaOj2OWpdQXJq107+X9IuxJNcaTl2ijkO5i5TllB4YH0xWbM8TR2
+ qqNrhHyeMsO2ferZmJt43Id Sp/dgHA2n7yn1qi0QjhEKrnOGB7r360U1rqcmGoVXa8LO/f/AC
+ /Uv2awCVVd3jgCtvZm7kcfhnHF XEjtn+z+VtOUK3Hy8I56D8ax7ZjHOrPIi7RjDISMHnmnzTM
+ 1wHjDRMwO9ccEf4980TpuUtGddaDn UbgmrLorK/mdPcxRRwx/aoXJiUoCDjA43fiOOadKtt5M
+ rBJd7tkYk7ADmksr6O5tEieeKQRRFSGG S5PJbntxVmLUIrS0vH/dyTb0c5UEcDoPrmvMfOna2
+ v8AwTx41qqlyRT5+urtb7i7ZRBoTBHJH5DH JJ5JIyVI9OaqzXM8Ytp2/eTFFYvj5Wf0/KpZYo
+ 2DkrKBHKRuR9oHy5FQ3E1obaPaxSTH7lGbJCsO p+hrGGsr73PTw9V2va8PMoz3krS2txcP5i7
+ d4CDBIU4B/XP4VCbi5M8SW8SlpJciXaMD2/GmTwSS zW6Rt5swty0hTowB4IHYVEzs0aedbywj
+ a/mnOAGP3f0x+dd0YRstP69DrnQpcqlbX06ely8zSxpN HvSFtwk9Dz2/PFPmWRoEnd3V0VhKC
+ f48gAD061HbXGm3NpFLPHKobAIL9wMY/SrP2GUWgkhJDuQz Rtyc5/p1NZuSi0nodeCr0YOKWi
+ v1W50Nus1vbODA11MisSq87Rgcc+9QwlNyugCXMh6MM7Tjv71U Nw9oywz3CSCSNpHdSeo+7+B
+ pYHk/s4eXcwkD5ZAyZZXboufXFcDpuzfcxSUbycd3uXdQMk1l5bTQ KLn98zBfvbR1Ht2rOhju
+ 0iuD5ckvluoGDgrkdD+dThmCeUVwyp5aI3PH94ew709lkguYYTKoGxvL bJwyqO/qT604Nxjyl
+ 08RKlT5W+byaLVjcLbzSSXTRSKVGeOrEEDHpUXl2Uott0U4ZIwku2TGw5OQ femRW8XlBp2zGw
+ LKAcFSPu5/Gqf2bfq7QC+jhUBRITnlz0/PrUqMXJtOxPNGo5VFLla9TV27Z1+z BYAswXzDznj
+ Az+NQzQ3rTJJIoe3izE8YGGDnkZNVbotBLJgmZNjeYUJ4fjj2PerdhPDPFdNNcFC8 qyKpPTav
+ Q+9S4uMedanPWo1Ir2kHzX8l/SMi1t5Li+DyLLbyL0VjwVHXH41uzWhN/CyRPcRFZJ5V jOD8o
+ wBTZILe9szNb3KxyOyquSf4u341Pb2VzFZyW7u4aGb7OTz8yscmlVrX1vbyMcZjYS5W5a9t Uz
+ F+0FDE4WMkR7sFB064/HrVdobZ7mI7pZ5XV5MRPgEAdfp/hWpcGOKeWNF3M43lcdQBjj2FZuLh
+ oYdpiESIYy4XlApyQT710QldXWhvGrSUk3dP1HxG6hhRp7WRoTGA7AAfMRgVnSDybmeKeQpsmS
+ Mu /IC4yfx96lee4k+0JCWfcN+M8YBB3fTFPghSXzXWCVw0scoLNnCdwfUit0uW7Z0z5qadS92
+ +3/BG pDmwkEjSkDI5fJyM5H16Vo2dhb/Y4Y1w0uV3g8k4PI/rVaWd7Z32Wsgh+bypG5DqeM/n
+ SW4vJJjL cKyJFJg7fl6L/U4rOfO43vYiNOs6PNL5K+/3G/dxNv2BXSGN9pdTjdznr9Knhv7Y3
+ ds1sszYR9yh s9fX6VjW85HkQsxtmmPztM24MR1I9B2qxaEfbZUMfmKswMZj4MYUHIb17Vxype
+ 60+h2U4XptSVmv UvyO6x24jjfYFU7s5zt649OtOnkd4dtmI2lLMSNuSg6AH8M00XLl5ljCvk+
+ Zux8qEL938etTw3Jt rSBvI/1sS4bAwM9B9cms2mrO2p3fVpwjGX9fiPjjKw4SSKQiRQ6qPmOO
+ hHoPX1prQqNQmWRiQjFW wTl2Azke3tSsbpkeKRo41jOHbZjcVHGPqTTRJcLA53xRzrMmSyZ2M
+ F6H61HvdyalOo4tp7/12KVy Y/It7lYGjMcfzPxtUnnBH0pFW8aaWVGj/e7QkTx5wRUF/DP9g3
+ PFI0CyjcFONoAztPqeetTXFoJk S4S88mMxOQCTwcDFdC5VFa7/AD8ypezhRj3lp3T8inLczoS
+ Xy7OGbbHx8o+Xj+dQLGsttFBPcoeM fJ8pJzkE+2KIC8Ee62kSeLaMoRlgSM4z+pqjDLGl1bTP
+ l41/czFegZs4b6V1Rho7f1/kS6cVCXdf P81oLdFo98Ak3bcgHPXBB/OrgmhuJmW4SUOZWdSGx
+ yB0qwkMSynZLG8aHyWB5Oeuc+prDuEhWJwj mYqxbYMkgY5qoWnoZU3DESjTbtbW+paiZreTyx
+ NDArK6KrjLEsM4qKWa5jtYw4XYgQoGQENx15rL WUhxKsifu5AFB53ZGMitOK5vIxMTGWljyrn
+ aGVScYGDxmt5U3F30O2M6lKfI1Fp/L+vuZHIlxHcR hI2KtExRh0IHUioZpQsqExsVVAuBgdR1
+ zjrTXuFGnwkCQSOcyEtxjPCj0zzVqXc4kLRbEjZs5H3W IGAcVabT1R2UMZKcveVr6X/ytr+Qv
+ n2xsgYmKygqMk9hwAf1qQRCOwhmklJaKMhUyeRn/wCvUEdr KY4o0VCZAJWGMlWUdKRz5qONks
+ Yd1yWOcORwKhpXsmcHPSc+Xm0W76/jqWYJjLHFK0BMUb71J5AP Py/U1Uu45VltXT5nZP3qehP
+ c/hUiRTiyaFj8kL4nPq+Dge2OhqB0dfJ8+YSgfM0aEhvzxRFJSujl p0UqjcVa/wCP6fiiwFVL
+ YxRxy5kLBeeWAHQVBGbSWxzJMd0qAgAk7McYPvTIm8qSKRSTsOWU87jn HH509ImjupgqIfL+U
+ 7kyoq+Vrr/X9WOmGFxCfLKVktVrb8NSoGJWXzJkaQtuYhetWoWEljLCQrYu IykgHA4xj6Vcnj
+ ki0yA+XBL5n3HRABg8HNN8m2huHQLIhjkMe4njHbPvSdVSj/XQqU/b0kkrtP1M uS1ZVlXEhli
+ nCDHQAg8H3zUsQnUpsDCKC42tnrz1ye+KvzyXeUjJjXOOduN3v9aW2ZVeYQRuXMgY h+e/X86b
+ qScdQnQbp2aTt/X9aEb2Rd7jkMBIN6jqrdqV4DLIdriWRWCtsGMk9x7U6BGgJjYtI0r+ YVB5K
+ pkn9asbA5edQxEqgqqcEZ7/AIHis+dp7nXQq1Ixeune36Ec7XEQBlw5DYyo4JPIFaTWsAgM Zm
+ VbqM7NhPJ3DLfnUsziw8gGHz2l5U9QmOMtnrzU9tZ3Mm9J4wud0nmbeQ46ZNck6uiexyzrQnOL
+ ulbrt+n6mQk0sMokiZVwArRSDcSADg/hWskk8mlQIhglEqpIzKnRh0/D2qF7RxpxWcq028AMox
+ we tTsst5A0EEiQlTuChMEAf0pVJRlZm1b2dSmmrNp6t9hsc9zcJcpHG0VxLIZg7j5QF6gemao
+ TzTbk dHQqUICAYZQ3TJ7nrzT2jleAmebKOSyyJkBVLYIqN2CagySMq+TmJAOwcZyfXFOMUnoj
+ jknLWCSS +f4/oZ8sCzBI4bgONrGPk5wOAT+tE6LFpM0C/ZxiY5fbyTxjn3qIK0M5kZTNFEApM
+ Zxu545qxIft dzcNJG0UDNuZ+yt2Fdeqa10RpiaUozTTuo6303IY4YhcCIqXVSGDA/cPYH15p0
+ oiVDayQFpI/lIX ggk5yPYGojIz237wEuU3yBePnzwP61CxhliLrP5cvmiNg5O47uapRbd2ee8
+ N7/tJpq+ztpf1LbGB pZXtmiaU4GSPlbcOw/OqN0JY4m8sAGErGGA4YEdfc1bispk1EpEyqY3G
+ 4Hkgj/6xNW5raGSVFjDA tvkV2bI2g4GfpS9pGMlrcdavGlU5ea/9f13IY5kMc8e8IyS4DtyBH
+ jkfhTbeGK2u5J5DJLGG2RkE AAY7+p5qKFZVlGCnyk4BTO5e5P0qzJdTRG3gkltvsnmEZ2cgD5
+ tpPqexqZJp2XUwxkZUpcri0nvq 9V9w0MtsZZDHL5ynDNu+VvcD6cU+a3Atrie1QyASBFA6gEA
+ Y/OqcV3cG/ZgY2EiM7AjPQYJ+lV7p ZFslkklI3IBEF43L3B9SPWmqcuZXOapRnCqoOyf33X9e
+ ZetpmZreSCSJpLfKTfLw574/lVAGS81K NEkigLtnLLwuQcr9apCO5tUSNZY8PG/Qcrzk596fH
+ O8srJcRmXch2tEdpBxgGt1Stdo54YdTUpJa 9+33ktyluJvs9rDceaR8vz/6vjODUcM0DReakq
+ ZdG8zcMjJOBgfhU0V5J5CM0Qh2KB5hTODjGD9R StEdsUUJguABtxGmDnr+lUnZWZU4y05nZd7
+ /AK7fIrQ37TWbys8S7XAQOmcAdPzqQXsf2gPMjElN qhRjHOTT0tjDpyy+Syt5Q37gMZLHBxUw
+ WVkiWWS1kYjcieWOGJ4B4+tKThrZE1I04Qumtd3s/wAm ZMitcz+bK+yN32owGFB6gVfXT34mb
+ f5DgKxz39vQCqIguXuJoIY5M+fu2f3MZqxcs5smQrITGoG7 OF59q0k27KLF7Kc1pP7t16bGZc
+ 281oIVZ1Eb5PzdSAeo9Kz5vP8APiCzDYxz908itWSWJkJjjYbc qpc7hg9OKryPbkp8mOBjcet
+ ddOTtqjVUZypPmla3qm/u0Ic/daaWMfLg4+Xn8qsecUubeRURI49y OzDPJ4wT61Uz8yywlJDv
+ 3AFM7fz4p2x5JGW2UyLyxBG7k03FdTln78bP4e7b/LRFyygViiksksW5 ZADjIPf6VrWkcUdsv
+ 2dXnDyLzuz8uDk1hRrlkEciuTEc7euAauG9JtraBQUMULKhHG7JyDXPWhKT 0Zy18NVTUYz372
+ aS9f0Okvb8ShZYwwt3jdSgONpJAGT+FZqSXFvpUYyhdZCnlFMuvfrW2tvBYxXJ tHiuplIG3G7
+ Izzwf0+lZ17Z6ozFYIWigEnzlwCdgHAz65zz3yK4aUoaRWi8z0VUUFBW0T30/9JbT X6g89wuP
+ N8os7mPcgxlAM7h7ZxVUS3dwpWWaEM7jgrgMvdxx0GKuMto2lI9zMFeSVEgXPOGGD+oq hIjW9
+ 0UM8c/2VigZFxu7H8O1a07PZam+GqXbVN3f5GjbwQ+TJCrLKi3AKhRzjqD9KszmG2niks7w M8
+ sLt5ZYnbz/APrrMi2NdNG+6ORX2pg4Geuw+56VcnuFuDbR21vuuWDArs5iGeB+hzWcovnXY7Kt
+ KFOpfmunvsvvNCLZPcSyOvneXMAhX+IEcfgTmlubaGSLq/zuWkVf4cevvjNUivlRvcNdRK6N+7
+ AB AKk8Ej37VIZbq1DzR3Nu00b4ZGTqOvT8aw5XzJxZzyo1PaqdKXpuv0tbzLcE8EEPmxhwJji
+ ISHJ2 g4BHtzzTL1Un1m2tzcCEWiMskhPDnqCPY9Kkljm2LKkW+6dS8S8YjUEZXHqc0/zCby5k
+ AjaWMhXU r1BX730xWStfmX9dBPlk25tv87lszl4LhIFBkllVgP8AnkOmD/Oo7uSEpKkmyNXBL
+ SgdCuMD1ye1 UzvTyt1tMlqUKRgH5gGH3ie/NUY7Bmw0kwaKBfL9iSpP86UKUU7tmlKlCKvKVu
+ 3/AA//AADW85vs 8z+bGYpSJRhfu4OOar3d08ojMBjhaUkPlOFJ4x9e9Ogjhh06CCRZVmFoVkD
+ NnDZBNOWMtesw2g4y UYZ2E+v4c0LlUrmMqkVPmta3f/gEVtGE06NUc/u2Csp6gjP8qum9SaOS
+ C5uhE0k24tkjhOv59qyZ UjsGWWBjcIxyCG/1ijgEfUmpNqvKJIruC2nj3mVZoycgdcVcqak+Y
+ HRdT3ld+aW35/eWrlJpXijL iPzVYrn7ygclCfXHNJFbQQu3mSsodWK7m4LHgVfhmknuojFGJM
+ li6gcxkjhT796o3W9o2Vp0hWMh k3DlwB1X2BrKMpP3djkoOpKbgtGv62K0YCtEl4PIieMhpOg
+ yBjFK0VmNkTLcNGcIHSTAJPAHNILZ rmSCOdxJvy8pBxtccZ+mO1RvBPbX8sjgLFH94kZCuFwP
+ 0Nbqze+p1UKbvLln7/ZaL/hyxL5ccYtX WWIJGTukbIJGCcfyp9rPO939olkimjILEovyjPXj2
+ plrEshJguorm7IyAVJGPTHvVwZS3EjQG1yX K7+ijgbTjuetZyaSsdUq1OLtvff+tySC3tFjCM
+ j3LybfKZW6gnoPerQtHmlkgkjdZoW8tFRsF16u frWQikPNAqvE6vj5jnGBnj8OafczTrPb3cj
+ O7NvwEYgnoP5Vm4Sb0ZvBSfvRevTV/wCZs29l5MpP zLAgKqrHkhucn6CkmilN1bQ2ys0UduVi
+ Oc5H3ifwNU7DUJSXV1Mwb5jjHY8L9a2A0ovY2SBgEVlJ z98YySPQZrnn7SEveOx1a1J3mtfl/
+ mNuVNxYeZbJJulO7G7O4NgEj6Yqo8Ust3H9qguI7cRNI8e/ DOBwDmlS+uYdLEwaKN2dXTcmcq
+ ODj6VbW5AneUHzWU5dycqvbb+INSlOGyFGUlD4bp7WetzMN3FK sEcUm1JVOfMJPGOPxNJHNHc
+ yxqXUxrCElAOMEngfWopVWV0W4iMboR5Kr8pZAPvcVYktolt7yWOR I4TIGRz3xyP61u+VKw5V
+ ZWtG93t5P/MhRre0nQjDsy/6tf4SPlAPuRUKRpDFcpAqRtFIqfvRu3EZ OfwHWh9NWW1uZrecP
+ 5kgcnJ4HWssSQNdtBK0qROCyMW+97/jWsIKV2n6nHGFKo5VFK7XxafpsUUv pGs5JGcC5kcYZe
+ AVPXj14rUitdqM/mRxJLnmQZLkHhh7Y7Uu6C31GZTbiZRc4PyjCfJkVTleS6nh VMwRbBwx+6D
+ wR9TXS3zbaIbrOV+TRLdsjSzaSaSeW3biQMGXAQjvx/KrE87S6dEfs8sMTFpJSSM7 iwGPypFl
+ maSK1jdYcKyv5vIT0B96WELKsHmXMUrOmDGoII3HFOTd7y6ETi3UVSotvX7+xUdpZL2F IEUxl
+ cxIV5I3fz61OL2VtXcw2T3cTlkwBkEDjceO3rUMsEaahJGjOiRnYCT8yn0z+tMd5I42cNtw 4D
+ ovBYkcEe3qK15YyWx6FWDs+RaND4vtJuQiCQIMMrHuq54/Gp5orqG3juoJUAcZdCuTkHkfWodz
+ JPcfvlgZJFjw3O44Iz9Kv2yOtlDCY2mWWPdJIDwCOorOpKzTOTERcZXsrPfT/MymuViuZVkYyI
+ z8 Ecb8HipWR5Bb7Co25jlyOV9zVyCCW6aZSmGBMiqFGSNuOP51BGlytr5SqMBgzHb2HU/QVXO
+ ntudq qqok4u0l+C/ryAx7LMQrAdpypLY3bieBmoY2YWkqzEhWkAYd9wBz+XGauh45J2ltpDkl
+ 2R2OVx0H Xv15qSG12WNzHMVhjdlcO4zg45pc9lqddBT7K34/qVEV8W8brIVBJky3G329Oasww
+ 2812HQS3GDn APXA60sz25gikihnQsuBKzZVselWYIGlikiWMo0S9hg/T86icvdvsaVKS5HKL3
+ 03/wAhslsyRmUR m5BT5lQ4OQM7h7DvVIIhh3NbTtuOZJEbhj3IyOBjmtFmaEETRTsGbfuVsAt
+ 3H09qfGfPs3RsIC67 UA5Xjqfas1OUVdmK9rCKlLXzTf6fqZkUFvI7gz7o43PlFeGcMOfw4q3Z
+ oWnt4XUxmKM+axPHXJ+n FPMa3FiVSFllSZV2rwWXHzEfhUhZEhuBDBOoklDKzHOAByKJTbViY
+ zi7qKavtr177/oTvObi+VEl RLcqGy65OCRgZpv2vyZpEa5E/mb3UpkAc9KLiPmCdXSFnIXbtx
+ kfwgU42luJXuJoJYn+YtGWGVyM fkOtYr2elxxhh3JPl07abjVYzyxfaJEETKXJ5HzdAtLcHbe
+ wQhmQxHbchTguSMbh6AdxVmyjlJgW 4h8hYY1QxOBuBz1P6fnVRpn826LwmJxMqNMw+VMclT78
+ Clf3rLoVU5Ze4nttbb7u4q2NlLGlvDfK h6eYWJUY6DHvzUN1bWSokkxlkUEttV8Eeise571Pc
+ rHBcvcRW0hlY78Z4XHt7E81WhuZbu6tY5EW NTC20MnXPGT+NOLn8SlocVVT91yqPkW+quvuK0
+ UUCTypGssNoVBkeVt2GB/+vTyZp3jtYwjxPC33 V5HOMH3pkEsFjqEQ8uSXEZ81G5AwOevvzU1
+ 0JglognjzKdoVBhpCOTj0raV+YjGWhJO9n0b/AKuZ 8xdYYrcW4WURmQM4zkKORVBIzMUEiLCu
+ C4YjAz1BOO3pWg9vLLIPNV0hlO9pv4VYZGPYH0qBGW2v LVJ0aR5IsKgONuD3rphKy03MvbRjS
+ vDV+WuvqwB/cRIJDJKG271ON2eefU5oljaV1Y3KhiMbEz8m e39amLSS6pIYo1ZncSAIvAIGMj
+ 0FRnfJcLJco0ZAALAYx7/n+lJXuFTC1oys997X/T/IWdbaPz1+ 0JI4l2qUGNyNgGoYXtIMiWC
+ YiDzFILctngP9K0YkVoYPMntZHRWErCP7xJyo/OlTV1ghJNuhnLDc rqDksKjnk1ypN/OxwV1V
+ qacrfzsjJQ3LXVokCKxjQtgLzIAOQKgvW+06dZtEksYVirFmyE3dAfpj NakkjvcwLKVDquNqD
+ aQSf61TffFKiRSxy/eZTjgY45Hrk1rCXvJ21/4c4K6caqaVmvN/1+BDaWTS WxWY+bcSSfumj4
+ GwZ6+5psZ+zNbmZ40Z49yx4+bgkAZojkuZ4ijzJBMWHloVwQoyG6VWa3lazjn8 xZltXEG9Rwy
+ sTz+taattSZhUqzc+Wc21/Xf9BywRKSJ7gOi4xtyeD1H15qSeSYOBFIkkcb7Q6Jgj Pc8d6Rba
+ eC+jVrWWQRoUlUrnLHOMehqKCQxXNtFImxRGY2OMZOc5Nab67nouVNrmT5rdNPyV2W7i ytGtg
+ ftMqvHPtCsxOF4yCKmF+2y4RYVdTOroQMEKO1UpriRrqZjGrGRwTxwB3pLaYNbSjHlnzv3c WP
+ mZe/NR7NuPvaieHpODcru/fb+vVjb5ZbnU2cs0R3MdwHVsdOKhVjPGipbmUScKI8ZXnkH3qW4a
+ G5uVaAOoJwFLZPTn8qqzwvGINknlhv3jZ/jA7j0raGyWwVHVpRcYaXWyX/BKsoKS+XuULvG4YP
+ AP +FOAE8YBxcgPtOxSBzyB068VJMrOHmkXyGWQY3dAOwPHWq7gM0qYUEys7benTgY9ufzrdO6
+ Odyqu XIne+9/6/UPs4s5BF5ckYYFhvJz79qQW+IzJ83UEDJ47c8VVmtZ4ju84DrkMOxqKS6m8
+ mOMqclvL Pzcgk5B+gPFaqLezIdRUItVo25dkl/w7/EvqyK7heCyHAA56dar4e41C1/eoFHUnj
+ juKaYlmBcRS xmI4f5uhz0/StBPOuRMkcaRqz7x8oyOMY/Gpk+XUyxLU1dpcvc6kzxrcWz28qG
+ WJZEkfqGJHynH4 /pWpG3mQQmW6EkcahNqkjecjJ/PiuY2W4uGihbfIW2qT0bvuFT2nnz+Qt4r
+ CSQnyyoADoT1x6A/z ryKlBWTv/maYjDw5UnLlXV2V/wCvQtX0ofVJsGNIWuNy5TOwKBwPxpIC
+ ks0kk08JBIDDbyS3A/Gp r0RItvard2rBo3D5HKsPu546mn2N1HC9tbmENcrEfOUoPlK85+uKV
+ 7U7pf1/SLUlCgqkL3Xy077C L+5nYSmJDFIowV5XPBz6n3q9b6hdNPvhhhwFZCgiG4N0GT/nrW
+ ebiOeG8OzALh4mYZ3KOT9ajjjm nlEgWZ0lQsrJwCAaiVNNXkdE6VGS9pLd97W/QsvA6zSNemN
+ FBAcFfusF4Wli1GOE5V4cnDMXjz8x /pTY1trK9bzZzL5kgePechsjgn15p1u/2zZC9j5mMNcB
+ QFYvgjAPbpQ0mveV19wOlTUX7SDkvu/B /wCZcN/LdWpllChlZj5qDaoY8Y/Gqs63U7Ov2qKXy
+ yqOI1wZCVOMfyqoEvnWPMTwJKPkUrwOv54F OtnYxRhI3JEZeOQHgqp5z6ketCpqCvG39f10N6
+ UY0oJwS/P/AIP3FnLpZKAJYW2qxaUkgMODx6DP SpltktxKnm+ZEHMiyAnB2jkn9aSPUHlumEf
+ leVJtEe9c4DHkn8RUNzFeDTbuJmQwGThtv3s9MH0P TFRZ3s9CasnKqoysk/P8rotR7Lqzd47h
+ fKMgbJzlsc4FURdXdxJE88iZnfd8q4JwfmH4DFEV9Hbx sksDJFISzBRjYRxs+uK1dOv4nRYka
+ 2ljhZ0jfYPlj6n8T60pqUE3y3OLEOrBqMY389zKZInupJYy VMPESkkgj1+nNallZLdLIPMh/d
+ p5bqF+c992fyqnLZ6emnM0UzbkXbneSORkZ/lTbCRlihk8wTxl R5qx8NjJBGfX/CnNuULxex6
+ 1So/YKdK6e2qSZoqJba5w8ciuxDGXOFzjG3681Qe7WS4SKWaKOJVK NuXkNnp+lPu7dEglWP7R
+ vJPll3z1I/pTIo7e5nlWGEzskhKqG5IwRj6ipgo25mYwownLmW738vm2 aMtwlp5dzgOTHIrr/
+ tY4Htwc1Qs3uprMBFEssMibwwyGz6+pq4bT5o8SBJRbsWR8nb8vU1ammnfT YJY7yxhcKGm2xd
+ 8ZA+pHSsVKKVluzCVKlCKT3b31Ms6beJNHIJFbehACLtKjP3T781Q8ue3lQPHN GIj5e2Rid5L
+ dB71ckJuILSRROxMY2RqxBPzcH8O9Thpv7VLjExkLOEIyRt+tdCqSS11/A7KVVRjq 1Jeegrah
+ N50kKQq0pbc6EfN6EfXHFRx3DW4L+TIHiPlqJDkAE5APvRNGkNvFeOkiIQZAucMB0AJ/ HNTmz
+ tDYsHn865Rw7Krnop/ng1F6aW2hs8RF2apvle9no/XU1ofJuMXJkjlmB2qkI28Nycj2NN8m RJ
+ WSK5MMucCRzlZPl5I9BzVW3kl/tOTZGV86f5owozyuMD0zVS5Bkt4AEmSSJQqqzffUHlvpXNGD
+ 5rX0M6FV+35ItJPvqaVw8U+mSKsyRy2x8sow6hwMfljmoI2nijmb7VbCF5VkPyH5x0Zh7CpI1u
+ Jw 8pjSQSZlwigEsBgc/WmzRXEMZtoVzeTkO6kZEQx84I/XiiNl7t/66h7ifI3Zd9H+mn3FZ5n
+ GpNC/ +kIFPlugx5g6DHtiqK31vJbrEokMe0ADdnBzjB/CrSytYqktxGZwFAjdejL04/MVntFb
+ QxGU200Z gmREy/Xkkg+p5rqhGL6F1ZRnPSGnR3/4KJ4rk+cyRMzbnBKDuR0I/wBnHaqVxeYvJ
+ HBiBEWxMp1B HQVduordWtNgaVXDiF4zjCDnJ9frSTiOWZllkgtodmI2dckflVwcL3saUKlO7l
+ KNvVf5bjjLJb6T KH2lFdvkK/NIMAZz7ZqlHFFdyRpAkoQfu1lJyHHXPTtipoTdHSrcqYrsvgK
+ iryAD0/H+lU2FtdSQ +WJIZoC3lENhQT1B96qEbX/r8Dmw0qii40klq7vXRen/AACYrE5Bjt5R
+ MHJiO774IyAfU9a2LZok jiR4o4lki3s20AoRnCk+tYAsnRbeFJGd3XzFKsf3Z6EGrIW9e+4tp
+ 1Cy+UUPVdwxz/OirBSVuYur Dmi1KasvW/4kFmYra+zG/knG5GuPmD9Se34VYBSXWFmkXCMuXI
+ 6AgcjHt0+tWf7PlWGC2lnhIC7Q 23liT8pB9KtRW26/S2urZxIwKySKSFLA9MY4z9aU60NWbwr
+ 05U5N7Ja2aTt313/EzpoxPZwmFN7F clRy2eufwFQW0a3EEUbu8XHOW4CA8j6mrMkkdrqfnxQS
+ iFEaNI93UnufpUaRJcqJJpoo23gOo4LZ GCw9qpSfL5BOo5U7JtR6SV2/nYdeWhglaSBmSJ5So
+ Jb7ikc5pli91sESQSyoyjaMdh0/OnvIsUC2 tvMLhUQlJApwB1wcjk1es4C9tBK0U+1kBba2Aw
+ znI9PSlKbjT946IRnSw37zW+2lv8vzIGt7VIJ4 445IZkfZ5bPzt6//AK6beO0SrAhBUph1IyR
+ jFXLyKdlE9soG87XLDJJbrj0xTreBrfUsT27XDoCo C/x8c1nGorcz18jqoVYOldO7XS/6sSEW
+ 66XcLLG7AXCiJd2cLkZpgW5aSYxRuZHlaNsfxtnOR6AV phbaW2Xd8iyxCYKTyhB6Gs12vVjla
+ 4haRWYAGL5c55JH6VlCV2/1LpxcXeP3X/4a/wB5K8cy6ewR WeVTwx5AB69fypGkvI7RJY/KxE
+ +zOwfKP4c+pNVpp/LaRSJDsx5YB+8uOTTbd4pmjtNs9tFO29Wd s4x/F9K05Ha7RpWpuMbzSSW
+ r6/gacswiR2tLiFpzPtVduc9Mj9TSRtbpZyrOWO2cEbTg4HGPrzn6 UxjErqIpY5pgU8xlXgnP
+ GPTNWVuJWvZGNk5iYliuBken5HrXO9F/SZwVJw5ubdLXsytfXcUjCGCN ss6AMeig8VI8JIm+0
+ 3kaNHIURtpw+eCfcA0yKMREXUg2jz0JJ6MO9aM/myRTRLHFIs8m62YgfdHc /XpQ5KNktjr9pF
+ SjFO0O779ejMuG5eR5Wn3TgFclTjGOSK1nure4QrsEZKtkNz1G7J+vY1lOGECR CBm3JkheCXb
+ jFNurNEvI4FuQsm0KAepULyfwpyhCT7GeIVGfvN2a7fn/AEiSLy7rSjJBNnzFXezH IDZ6fl1q
+ nbuzzvPdSrnft3JwBk9Me+K2UMVvpj+W0LQtKMkLjJOMY+lZshimu7mGOPyysvyMfukA ZJx60
+ Qne6tocEcXUmnBrQqBW/tLmPgoWLYGQOScn0z1qrb3E7PbCS2kuH8sSYUcggnBHpV2FWMWL Nt
+ 8Ux8+QuM7e5T8ccVqwRv5nmeXi3YhlKgAqoH3c+3etZ1VFaoWJrR5fehr2ujLiuYnla4WRVYMS
+ 0JP3yehA6ACssRBruNY7iKVwmd5XOOPm/wAK3J7R2vGEaLl2DiQLwBjB/wAaoXCzC8eNTCzsPv
+ xx 44z/ACq6U430MsNKLctenW2n4f8ABKLSCOUlLhQxQMQo5BHAWlso8kJMXJdd5ZmJDnd94ew
+ 9KvQ2 6BZTPCJJY32DGPmwMhvpVUz/AL6znELxIiPGpY8AHqT7Vrz8yaRGJrQqRaite5OLOJbh
+ zbs2USRM k5Vm6j9M1kok93I22PftdWYAc7sHHPpxV1IIoLkJcXiSW4DKux8EnHB6VmxSSiQC3
+ lXPy+YwPBIz z7CtKadnrfzM6cHyySfNpvrb5vf7jRmv2YPlUlZpFl+Ucj5eF/rVBEE6wTy285
+ aRNqIhxuGeWqK7 uX862VWSRXjLL5S4LEHr07U/7SkmntIWId3Mke04wB6e1WqbjFWW559WUoR
+ 5YKzejs/+GZlS7H8p YQ21W27mOSzE9fpWj5scek3UMzssq3SlVTjtyfwqoCzR3EoVQfOR41AA
+ 9Tn6Uryqtys8jQ3DHcJE C9T2b6V0yV7L+u4V1pHmWnTvf7ixdXcguwiSswD/AHgfvnjBqGO5a
+ DUFlaEN5UhRm25CseckVTa3 gm1GNTMqgLkSHIXjrT98ZeUkLH+82hWHJHb8apU4KNjeEI2dGL
+ 5U9+t15vYdJdGRycbd4xICOjdB 9Kngc2kz5AmkjPllfXPcfrVXa20eXypdS4xzkcAe1IrwLAk
+ bI0bFiWZmyWPRe1NxTVkVNtrlXp8i NRJyQuF3Hn2xSRSMzxzRoU8sFf3gyBnt+IqeMSrMVbyy
+ 2MFduc+oqNTtZ9kZIwCPbirua+xvaD26 33/DUgkj/doXGWJ4XnKj3OMGo5plggjii2Om5juxk
+ g45yT61JKJiyF2Csqc7uj/SqSzGO3XzmR5n GFwuQo7g8da0jG/meRjVGLTaej0ul+mxDGxZAw
+ lZmxgBzkVOGK3EQgj3s5wvGevHf+dPdovNVAUI ckBkGAB+VJakf2Y0pYk+aVUKcEHHB+laOWl
+ 7HC66cbLd6eRatYpRp8scUgOZAxQ/eycjOcVNazT2 rIYkDOYmBQjJGDmlMTSXcUbSJFN5Z3A8
+ Hf3Bx+dILJ1+zmaYW3y9G549eK5nKLvzdQbhGnyyV0+i X/A/I1ILjzTLcTKrIWAYxAL14IHpx
+ WzBJZpvlYmBCPLj8x8kDPb+dYETm2W4gbbIHlRmAGM7c9Pw NWJYIbm8kSOXbCrEQF24w3IU+p
+ J6VyVaabtsv+GPXnQkr2bXez0+W5p2bW6XOwlLto42ZnA+++eM Z9KAlukiXE0MsaPJlmL4Ib3
+ Ppk9KswC4trYJdRRvMSVMcahTyPm/SsC5Xy4rOC0aT7ORukV23HPr ntWEFzydmc0IyqVPcWnV
+ 7misksOoTeUgnXG0pt4PBGR7CrMAW0tw8Ql2qgHmM3yjJwePxrKQ3HmK U3PtjKlh2B9at20pW
+ 5jgumDBYjgg4AO8YyKupB2PTrU3FNvWy6XEV7Ga8InlGxGEcZ3fdPofpWva TW1vqRcafduGcl
+ sTHOegHTHfPWsW5soxIQq8OS8be6nGD6k5xU0aXBE8TwziFpSR83KFuxPrnmoq RjOO+nqRKdO
+ vB22atu1b5Jq5rXXnXMYtLWKSIxoEBdsn73JqhdDZdLvtZ/lUqGjbCkE8jH0q3bKm 5lluf3kY
+ xO4JHPU/oMVnm5sprsywx3LEyAwoZM4Q9c+prKmmnZLRfqRGtaXLFO0dev53JrtIbXUH uWzEn
+ zKsQ67QAOPcE1nwb2gzH59xErYlbcSpxzx6etblywnaSEoGQSdSv8IAU/nmsOS3NjqTFJ0j SP
+ dsU5O7AxyPfNa0Jc0bPcdCq6vMqkdX6/oXRL9rhPmwNE73CBWONoQgk598d6f5dvHDMiLkM6FW
+ Q4ynQn/GpFtobiwsgEk2om2UB+euAfwqEC0jiUBzcGNirBGxuGc5HtUJrZfcKjO14rm9P+CW0i
+ lR 2lhjx5ZYx7+Qy9Rx3qFJhL9nlnTbGUIRIxtyvPX6njNWZftFxGWhAj85twJ6Y4GB/OqccUa
+ MkM6s 3kB4wynAweVH1J6VMHda7/idtCrzK6WvVrf+vQsLd7olHWWNlTYw5Q98+uKmhv7g3O57
+ dJCilGMK hSxY4DfSqdpFZtYrDPDO1zHkqivg4/iB9T3pF1GzhmzHbTfNtYHfnPBwfpmiVNO6U
+ blKjFxlFw97 5foy5vnXU4pLu5jWO3BikOMByOf14FaFwM6fMyvHctJIDIsa42nI4/Cqdoz+Ra
+ BHiMphdWEi7hIx P3vp2qFp7uCFXlaFsuR5YXDMw4zwP8msHBykrdDkadWrGUZJNaWv2+X6ot2
+ 9y0Sz+ZJCgZiVm2fK hHBGPftVZJ4zEhS9t43iiwqkclh16etaXlwvpcESERkt5ZRvmJ9W/A9a
+ r3FrDKlnbugjIt3ZHAxu z/8AqqYyg3qrEwq0XLWNnfW39aleKR5YVS4kTyooWjMjD5SG5FXIV
+ 228KI6XMsSSBVTqExyG9W75 rJspoIbTyEXzBNIr7nORH/sn3yKtoGlkRmguJERShhiba6An7p
+ Pc55z6VdWGr6FSjTlqk1b7v0/M mNgzTwLMk8kfl5DRvtJIHX8jVUPdRNFOkscoCZ8sqSSAe38
+ 6tSp5ltbhfNilVmWPc2QU/iOPamS3 9tLAn76FAE2sAOu48D8uaUHJ9LjoYhyTly3js1YZNPLO
+ 6mSdENwrSJ5eVGc8KPTmo1vdRt71pDdQ CcJh9yZ+o+tUrgRTw4+0RxRW9wYY5MHBU4yfwP8AO
+ p3uJIblg6JcIWKzKBzvzwM84xxWyguW1jvV b2kOTlV+3/BenyC4W+l01ZHZZjHhDtXGTkdPpx
+ Vq7iuRNJB5sUku5yVC8lhjn6YqjLI8sk4mWS3l mYsMnCrjhhj1PalTzknt4re5S7ZlJKoPnz6
+ Z/SnZ6PTQ5HOEUm2rp9tP1/QXyb14n3KZw6bj5ePk wRwPTNLJLNfRKmIond+Qy5Kn0/SmXwRY
+ YpA8tuGGzBcnOCBnjtmr6tNGm1XhnMZcSSKvDt0Dj2Bq XLRS/r/IKtfnUZJ3d9LKyX6FFIZbM
+ QTW8yzEKQ6qp78Aj070+zigjmNvI6WrjMjPKudxA4/ADr61 VMs39nzKWDneoZ04CEdAfrVyJ4
+ rrUZXLJmUNhT1U4wq/UmtJp8rv/X9andKlTdHmqX9V+qelvkSR W1w8UDPIkuFKh0G0EN1NVGJ
+ s7qMzmVwIyGAbB3D7uf51eWae20hYZ03yJgTBePLb+6fc9qz3kjjl mnJ3MXEZicZKkjv9Kinz
+ Nu+xGEhupaJ7ef8AkOt9QuttvKWRyLdspt5GM81MLuZ5EV7oWzOglZ3B OCO341BPOsqiFlj/A
+ HZCxmMbdy9z9KijuHilD26R+azEssqhtoUe/bFa+zTV+Wz/AK/rY7XhIqD5 o+8/T/J/kTW6vd
+ TuYY3ljcrs55OM4GfXjmr95E1rpAleJoiD5QLY+UNyc/54qW0gkMMN0sTOHjY+ XEduMHIHHc1
+ SSyYMs8t6hjLYaNiTtcg8H3rBzTlvojgqV5Tqp8ytHbTd9rX/AEH2lqlxdpmL5IlK gD+Pb61c
+ kuGO5VgmV1G8KrYEY7KQPp+tYSQxwPDbrclopF3Pz0bPI/KiW6eS5ke0LQws4Zg53FwO nOK1d
+ Fzle56sKEaj953fbZGz9pkkMb4E7SOJXSPjac/Mv6UlzHJcT3txLFcRA3QdDu7HsKpQtHai Ga
+ VvNSWL7iNhlYnp+VWbNkt7+RmZYwkZCh+fYqR3PpWbjy3aRpSp06bk1Hb1s/Ly9bGhLLA42I4J
+ b52QHoAvzCqLuLTWIJHt7hICCVSST72FwD9OaZDDBEY0luUmWJGwqEhgCOpPfrTNzHy4ZLiNFR
+ N6 NLzjHQfjUwilpuiKDTTunbqtbfkatrZ2ly8Uqv5RijVCrnPX1qpLMpYj7M8UeTG0mRgE8gf
+ kKUS3 S/Pgojq6ncBgHHfiqj3Ey6eiSwNlduG7Ke2fXipjTlzXvf5lfV3Gq5wmn6Pb5lq1CXF6
+ sUJJSM7E GPmZD1b3x61O1hb2trdJ507SM2YoxIQ2P61SVdU+1w3Vqse2MAqoQfMucYqvPd7J3
+ AtbkzNKMsX4 wB2/CnyScvdehx1K8o1G9LeqevntY1keFCZkZlE0TYWQ5A9/w6fjUsN7I1laRy
+ xGacEBFiOCRnOf pWS75RZVkQRqwVYerIOmCf1NXwYotRgu4xJvSBxvY/KTjpis5wVtTLE14VK
+ d56vp/l3JHjmhinIu ol8yXfFleSAeo9smnwi6k1GC5cJORHk4XkEHBH1zVY3TJEkkhjKYUnK/
+ c7bfyNSJHEjZtJX3JIFj BYncvr+Z5qWny6kVJJUfZyitfx8r6Fa7tEmSbbeQh/NDFATg8csB2
+ Aq5bXAnACouxyG3EYJwDzn0 4xUV4tusM7SxPvEmAVbHJGB+XekYQIbSRC63C24V0DYALf8A1q
+ pvmgkzSTjPDK9/LZ2+4jur9pYE jYRR74lZ9i7djZ9u3FTRzq8RBLiSaeN/KzyM8Efj1qN4He6
+ SzSEQwratl3AJOOQc1EM3Ailms57c ufMjOcbuMcfl+tPlhy6f1/VicXOn7NKCs/l/wPzLGoMI
+ JdsbPCYm2F3bhm6hh7YyMVRgkto90pu1 dwpAbaeRyP606a1lkx5MUxEhOZZDlVOOn1zUUkOYR
+ HLFHmRhueNAoHHK/oPzq6ajypNnLT9iopc1 79rL/P8AMjfUYzpZU/vCWVgF4bA4YUfaPN1mRo
+ mSb905CKvB45I9v8KintFtZLfyNmdrE5GdpHXN Z6SJs8x5o0RbgINq7Sc9G/3euRXTCnBxvEl
+ zpQi7LR/12JLlGNvDLHbTJtXIdiCNq9fxz3qnE10J 3xGJHbLsqrg7T1/CtW5Vbi5ubVJS4ViU
+ xnHHUfjUVpJL9rnhiWOSc/cIXOUI+Y/pWsZ2hqjOo+Wh LnjqvNozXSQpG6FdrKyxbUzhW7fnm
+ s+b7VLd21uiBQgIKgY4IFXkmminhZWRYzIpZCO4yFHtkVGk 8kOqztAP424YbiPb8K6I3XQ4ZO
+ U4WsrrZ3aIGa9ZI4js+QMANg5XvT40aOJ1fazSLvUqOUHUj+VQ IJd0YZZQjKd24c568ZoSHfc
+ pHuaMlTww5+7nP0rVpJG7nSoWqRTsuutvw/4BGsgZvMV4wcgDCHkH r+VPZHM9zuKkiRixxwee
+ MVHYSxQCIXhEkIJ4ThjmrRULEfvbCzN5Tk7h7k4/rTk7SIjKdSak07/h +H6jE8poN+5E3DIHU
+ tg8/wBabsRZWMYRlR8x7gCxH5U7f5IUrbqMgFtx4wRg444zUkzvHBtjG0kd W6daFe520IuqpS
+ qr4fIjaRPJJmkBkZ+Tjj2PSoQWIcqrJ1JLdtvUfWophlH+YFchskdgOlSgyZMg TaNp2hvSr5b
+ IyvUcrJ6emtiBimAZCyqzAwlj0Hp05qDEBL4VyEkCq4bjPXninmaT7OZBGTHH8qgq DjcMZqJp
+ CD5UZAIbawx0I/ritIpnjJpycHa3q7siSU8eWyM7MzN8vT2/KrUbKY5W2rjcMEDAB7A8 deKZ5
+ EaXivEhkKksFAzhff1471IDEFdA4GZP3RP90evvTk10HScqUuSS0XzLlulxPdvC20XM2WUn 26
+ qfc02YFYUSRJPLhYEZblVI5Q++e9BkaJmkJEkqsANvHGOefrQtxgzI+JYM9ckEH0JxXPaTd0ZT
+ 9tKstPdW19Hf10LFjD5ksQeVAskLMQfvDB4H41fEq/Y2WNUDyhWZSvQ5xj8qyYXH2BlQ7FTDbm
+ HI wfu5981rWLvLNLdq8cZDbIo3X7wPAP4VlWVrtnoxcaN5Tlr07fl+hZ+0XAmfdJtkgm2ByMj
+ kY596 seVk2/lzwl4YShyOozy34Zq22be2WScpIFWTcoXBLDHP4UttfJBcpF5AmEeVmwBkk/MT
+ 9K4HNtXi v6/r8zOGI9xzhC7/AD+9FOZb6LbJDFiOPKs4UYbpz9KozpHJO7SB/M4wynA5GQfoK
+ 6Rrpv3xiwhe RXIcZxuGMVgO8waWO2QOFKljt3Zxxjn0NXQnJ9LHThazt71NX73t9+hMXmSwV4
+ kM4bMfmDkMW7j9 alt4Wi1h0ll+VIGBPZiBwR+dRbfKiV7iCeOZnC7AcDr8xA9hVi2aSa2lC3d
+ uSg2jenOc8fmKUn7r sZ/WWk409U93tb87lNRZSxbYJJATGvzluE55Dep60t0kEVyTEd8cO4Yj
+ GM+n4VO+nziZt09u8ImH miNcEEj6U+VbecRS20se9FZGGPfHPqaaqK6s7o2eJg3abbflt+KuJ
+ IQ8skTiSFs7lUn72FBJ+lTS SxbYDbRG4nAK7D83B5BoX7RMJ4whRTOuHbnjGDj6ikSUR36LAh
+ SRY2SEkAgrjv6nrzWf6GanC9ub Va2vp8xlwUbT32ziGaCREVdxGc8mo1kPnuFh82CdS8ip94M
+ PQ9gB2ptxfSDS4wEgKyc+Zs64P8zT JJJxdTXLELuZtqquMgrzitIxdtTpw8mqWi1d+v5bWLs9
+ z51nAI5o/KPzMw4xtAA/CmxfacmFpYJX 83dOQvOf4R+Ap1vaW5sEmiG7KYWHPLjozD2FSRKrS
+ MsjBJopEUEcZX1Pqcd6ycopNLockZxhzOCv b8GXI0txEFZXnm+ZlaM4wmcf/WqBo7Z7VLmC0d
+ JNu1Ucg7gGwCPahMPfPFBeRbZG8zO0/KEHT6Zp GihlngcXIPnJ5ihSQAB2/PmsldPf8zVJqSk
+ m9NWnf+rE0EdsHnRre5gnBBVHk5Ht+NMF4Y55DOFj m+0bgjjOz1U+9VUFzc2UsrXCgPKjEY+Z
+ +xYH0FWpPLSzlFrieXzVMRPzZTnnnqc55puKvZ6m8/Z8 /Lvf+tW/8i1GkZCJc3kW4xMV2ccDO
+ aoSzwx2qGPzWSSRSjl87VHT8O59akt7x2nhhVUaRoWZztB2 kHJFNmu5PLeIpDEXdQW2DGWHAH
+ pxUxhJSsznp0pqoo307X0+5LUnnK26NALX7QzuGRo+BtXqf1ow jXUrXUxEJYCURnaVI+6f8aj
+ Zrh7Zjb3UDMXVI1wcopOOfrVq4LyrID5bYYh0UYPy+/rxU7af10Om M40/3fPZvte/4ozw0siO
+ jTpwjqrY7sf/AK1Q28V3AJoZVilRdxEoQY5H+FWbx7h9OVtibXj3gquN xzkmoJA4t1ntpQJZV
+ Y4c5DKOcj+Vbx1Vu5tKMXTSvu9P+HWxBay+YwkaMRwJgMWGQSTwarz3dxdt cllEXnEyAlcDch
+ 5Gfwq2k15HYTqkK+UzD92U+YMcbapXAAntY5VZbkbyX/gJB4GPetoJc17f1ucv PGFRt2u9O9v
+ PyHjy5kmuZLjeguMB1PChjnB96kuNh1KeNJo4NzqzScjp1PHpVe3uYhFaxXCbGVGD rjG1s8Fv
+ XFPjhVLwOG5VTGHcZV+OcfXtTas3cyp1/Zxm3o+nb8V/n6FQCW5yrrLJIT5kZB4BPGPx xWlFG
+ 0LzTy+Y4hYoyI2CSRwfp/hVS4WOYW7W8oUrErhFz8oB5BPcjrW9DcIJrsBont5JfnPUk4+U j2
+ oqzajojv8AbzjD4bJ9Nn6/8MZsNxGPPCFVdpMDfyu3HLY/l6VZuTDCkc0KFlkBjCpwUX39ST3p
+ rWbw24JELs7qVUDDZHTHtSSXVzZ3LLMYjMuRjZ0J71npKXu6m1Kftbezlfvr/wAC5Zmth9kRYr
+ W7 G9SDIzg57/n71NbJCssn2x4ordjuIcZbJ9/bpVBtSvTZrDlX2Abzt5B9KrhkmTz7gtuK4VV
+ ONw/v fQGo9lNxtI6KeGrKHLUdr7W1a+8sSafbw2SyTbmMM6wyBW5GfX86fcfYY5CEjeONg4iJ
+ Iy3Ytn0q vDdG1htw7xzZlBkVhnzDnjH4VuXFsizSGSB50kfdGo6gL/B9T7UTnKMlzO5zqcqdR
+ Nu/bVK//BMm zliS4W1SWUr5ZUNu4Bxk/rVoC4S0QXOxbcRbXBAyr5xz75rOjlRL9XuIWjRjvd
+ BwQRkgCn3EcbwB mndR5oyrEkoCMkH1NVOPvevzHiWlU93Vel7Py8wtbdUFz58hZYpRFlcZIOf
+ UUkkdvHCTAXZygPzD 7gHGDxgmq+5vs8gglVYUkAAfktuOd34VZiLpLcmUpLtkEcgAwCTypHt6
+ 1o73u2dNCvLl/eyd+i6D 2hWR7cJG8sUaESOp4DAcD8aginBJCNvGBtJ5wR2PqcmrMoJ0xoow2
+ 4SBtwP3yvUj2qcTndJKIInj c71WNQCCetZqTsFLFOMHKyfkMtrlJbxJQI0kZBu3pkcZBGP1qC
+ UGW6MkTJJ5ThFwvBB6VE1s8iZS WPaMqrD+LnJx9elFtcXK292GKRsJApiZMNycjn2xVKK+KI3
+ U5ptqSldf1/WhZupHjkWO5jlJ2uAU faOvWqyzQm8iWMmE7SMzHcAfU0rwsq+ZcszFiERQfmI7
+ nmq8MipOgYRQptdCzqCfQ/4VUYx5dA9t S9lLkl739bLUs3d4HQNCzo8cvloFb+Hj5TjqT2qnN
+ qUt5JvSP7PtmbzVIySemB6cUyW4iW2RLWJl VGZn3/MeeMH3qpbovmK0Nu8jtIcI2DtIAG4+x6
+ YrSnSio3aPLcYqMZ1F72t15dNVp+BbVY3uJt4c AMzRgHBwBxn61qaWIIZoGlYxpNgh5D8vQhl
+ +tUTazknzjHGU3KQBjdnqfoKlEMMcsMy3EchjP7sD 7uQOWx6VFRqUbXNqtanOm4pu78m/xSt+
+ Ben05AytG5khwvybuWYf0piCZr0JPKLYBHDSlTtPcY9M 1FKzXjWKLeRbowwZFBBfHORWnbqiP
+ Gcbo0t2CmT5gcc/pmudylGPvasqhiWo+/rLbs/x/wAiulsr RWaq0su+IsfmyWbOQw9hViB/sP
+ 2lpraSSScecrMegHUdPeqv9omSCFoY1V0iESDaOecnH86fa3CG 4Xyo3UlcoZm3fKQRj+ZpSjO
+ z5lodjUqcJOS5k+l3+n+Qksm6II19ChKjZnOUXrg+pNSz3CvbxTWm ZRGwQAH/AFeTnaffrQ0E
+ V7MYFAHzqGcD74A5YewFR+baw2Qmt7qKOSVpNgcEjZjGcAdfQ1GjtZan l1a8bxhFu99rfnZBc
+ yywSARN5cBT5CxLbxn7w+mefWoLhg9lFcx7p42cNJsbgFSAP8arRQW02k27 W6TzSqG3IXzuPt
+ 7e1Pgtr1Lq3uYgnnsm94yo2jJ6EfrWyjFddV+P9dyKtWnUg5J2a6d/XqvX8B66 hIb65ad4o5f
+ m+Vkz1HPHpVK7tWXT7YJAzl4CJGH3Q+eB9QP51Tv2mkuoCI9kUhLKpGTtBwcn9ald PIEodZ1e
+ ab92+/5W9xW8aajZowlJRcWn8v6t+QyK3n/dxtuAAJMnTDHoCfWpZLtkWJbiCQXCxtEW Q7T8x
+ 6cDrUM81zb3EyRk7FLJhgG9OaheS8jeK4mt5eSGiJHUDgn34rXlctXYdec+TWzXTVrX1IGk t2
+ l8pt8YIGd3O0r26UlzNEI0eMofNyYyvYDgg+p96givWnvBPsiL+ZtUEZyM49KhmSRrolYVQlm4
+ K8j2+tdMafvK4vbTnOLT9O/53JbadI2YzRO2MjBPHI61WIWS7iKySIUYEKxJL+1SMItjeYjh8E
+ gA 9B+X41FEF+yEjzJI0bBOCeT0FapJamFSmuf33o+70+64scFqJV3sEycqSTyT/wDXqzJIMRy
+ BhNgF ZAqkbccAn15qgJURvmid95x2+XtThKy3SxmEkFtp9vr9abi27l+1jF8ylZLol/wNSx9o
+ R4U+YM4H 7ojoQDzxSODNbyyrIJVSYBSp6++MdKpJMHVTtRWVxjA7/wCeo70Ga5jKhI0Ul8MNv
+ Ue1P2epz+2W 769lf8Cz5jQ3ckWCQcgFhkAdc9O9VJ3kYxeTIWKZEiMD0GORx0qWNXnlIMckbg
+ c89ewxSJbTxlpk VtqPhi65ww4IP9RVKyfmcuKrVKkLRk/S6X6XKqRiWXJ8x9nKANgfjVeOJt8
+ AiKA5PmEnnPXP0rR8 uaNPljYnG0ADnrx/OqkUN3MQ/lnYpJPyHnHJraM9HqcuJpRpOLlfn7aK
+ /lrsTNdll2Sja5wq8djy aHx533ldEYBiF4NKsLKqlQZAVynHb1zUaoWARJUK7gZBg5PoOnXFT
+ 7vQ6pzqO0pu9/T8+v3lnzld ZXkRn3NncBjdxz26U23knW5R7Et8zhcMoOARwTkY4phgAI2jIV
+ Sck579KSR1gjtWjcywSStgISCu MEZNSkun/AOHGQtT5Zu172X6dvxL0QdY4nRSltO3VjnIB5P
+ 4VuwK0SWXlobqaRJCuzptJ5H1FVLe 2jlWKLyJYEVsFXblic4I9B6+tKjzRX0UbMI5S6DJ/hJb
+ t6VwVHz6HoRm6ivdNx1fb8DqZLiBNOgD W0/3N4QtlmHGT+dULgSXeryKlrKoaQ72BHHy5q3PM
+ zJevHNBJKLkALs524AOPQVcijiBZT5gjtmM Bkz97eMj8e2a8yM+RXtqXRrOhBzjo/V6fIzYre
+ SKK5K7pJFkjJIPDDHb8OazxJENWQRRysCDhlbg A9z9a0TA1pMsltchZRbner8gkDg/lxWXEqy
+ WisWDfKuHTgR84w3qc10wd7s9Jy505R2a31/Ine2m jZJJGaNGO9WkYtuC8n9P51oWSWc10YJL
+ iNJpnypwQF44U+p7UyZTBpgtpnZ4TJ8zn+HAwcE9iaqN uDqUSFJX8xsheVwOV+vcfWod5x3OF
+ /7XFq+uy5bW+7qW7q6uLOS8gVRGJZ0cOy5AwASKZb6legSG OO2ZPOY5EQ+ZWFSJNNLbRXEtlJ
+ GVjxC7kEbMfNkdz71Wmmne1txB5Z3orLtXHy1MYpqzirkKFOpZ cqvt9332LSXsMcNrHcSKksk
+ uQBwemPyPaqKTKXYSI4ztHXBQ54H88+tSW9xLc3hM0cYjkYSKSgyF wQSD6DirSzQTyC3t7ORQ
+ JFYlmBbAGQM/WnyqDen4k0aCpSlGMb97NafkQRXNm1uiuVOHKlffPDfQ UyRAwuAZFdoblGLDO
+ 0tj5uP7vtWtbwQ3FkbmMRCSZ94wByc4wB7/AM6jXSjPE0LZjdxvI7oQDtDe tZqtBN9CcPXpKX
+ vJr1s/wsUoo2WcSeTN5fzKpRuF55qHybmeRBb286OU2sHbluoz+FW7eO5srP7Q xOZlMgVhnfx
+ gsPYGmv5loPtNzdJu8oqO25uMEe1aKb5nb9T06GLvUlyyS00639UWLXy/IMbyxyJb qIkZOCVc
+ YOT35omDw3KQrJE2bZjkL1KnHHoPak8qO3jj+1uqxKWWZV4LNwQPw4q3FZLc6xKFSWRF CsoDY
+ OQMkfjWMpJNyvp/X/DlyqR5ZtbW62t8iC2gWztZvLlXDSDG7kIM/dPuc1IkD2m37UrRKuUX HH
+ llzwp9TzmrLyTSI8kVsLcv87JKAeW/wAqrdPJLFbMpKxiMhQ/PQg5J7moUpSevU56L9rZuS+/X
+ 8Cf7Ozz7YLWTzI28oyqfl+7yD7mqkRuo4438yCRVfy1Qx8jP3c+46Vqgzi3muTIj+ZcRCEJkD5
+ vv GqMscxcwW0ihg7mUMOcr0b6YqYSvo/67jptynaMk4+jf37laeLyQyI4WdnVdwOAo6c/rUA0
+ y4i85 WaQbztVi2dw6k/iKvQE3ulNmCSVVKMrqcE8/MaiS7mGozrOTNDIjSEIMEkdMegx2rZTm
+ rpbo7ozq Rva116O/oUPs4SwJa7+Zf9WpY/dbGPy71bK7J4Ty6hWLMvTrzgemOahnWcCye3tnf
+ NswDkZUqOS1 U542ihMjrO6OC0bK3BXHJ+nNbL37XZMqilDl5rX+/wDr5sjks5pXZopPtKMzOr
+ gnDYHXH8qdHI9x BE9xDIwYKY0HDFQCvX6jNakcEuz5EYuAxZU4w6DqPbB6VizvNPALiRkK5+V
+ QMfe44HpWkJ8+hzrF KpL2bkkl1t+hLdrE0KTCQSo8m3CDB3jgjNV0g3Swkz/ZoIn+TzTn3I46
+ 1O1iPs0UUbG4Kk/u4j1Y d+fqaLi0uHtT5YMaxseDzn2+vWqjNWtcwniIygqTavfe35X/AMiuL
+ hXuAtsY2LuVBA/vf4U2C6lI j8sgAsIxIB8qgDGCO5680ItrHC8QBtwASsjHOM4Kr9evNWrGyj
+ lbcZTtD8p6MDwfpVycFF3NfaNQ 5ai28v1X5DgJFjztnkYErFznCdDn396tpLJBA8UMLvMW3gz
+ DcQoHQ5qK7uHjupzg5QADacAZxkfU 1YH2x3zEgUSKWBZQSRngg+lYPVJtHp048y/eR9P+CTW0
+ EM16I5CVjZMh84z6H86sTWtpbtFIJBvc Mixn19RU9pmCzcyJ5qtKpDKMDnpj2zU9pbia5ka4j
+ eSdZWjQrwCG7j8a451WpN30RksdPn3tFeZk zRpMyhgrMgCqFGCSe31NXZL6S28mMK0jKmGbGf
+ nJwAPxrRm02Y7txjd02tIVXGHXv9AKqm2hudWM UW5pnTzPMB+VgP4gPQVKqwktdUjrlWpVI81
+ rpev47GHJHLFdRRGJjPuQOvXJB5xVk2c02p3ASFt7 KxQnG1VHAB/2vepp7aC0lWaSVrgbGUFW
+ Odx561RS4aTTokjMkchAA+bnqSB9Sa6VJyV4jdWd1Ui/ d762+epbRUs57VrieDdsTdEEz8vfP
+ GCcmnTQi41ZxERIFDLtTghgPlJqtOjTSkwxMZD80pc5wcdB 6Ac09LmS0YbZo92xhG2zIKEcE+
+ p9DU8r3T1MKlNuo3Tl7z7pfp/w5UY3K6mGwnnN8gAHD5HJA+lM jliil2eVKu1AG3Nna3UH6Yq
+ x51vdTxp5UodTuUbuSMZx+GKkmhs3tMxuRcdSO20jn8a15ukkOU5y k1Ui1fTRbeen+RDc3iJZ
+ GKGJ+CAHJ4Y5BBH61XV/tF+ZpnEbSTq5XpuIHb25rQZbmeyt7cW+1oNm G2g7jnr9AKkkt2zcy
+ xR+WwugVLDIIyDkD0qVOMVbqcjrRgnSirX6tpsx21CeW5DSf6yJiqggYB71 dSe2/dyyyxqyw7
+ XQpkk5zmqxgAvJzc8tvdnRMA885+grNG+S5hXckbBfmLDIJA4rf2cJLTQ6bUql J+7ZrdpL+vw
+ L8TrPG0Drl2OVA4JA5Jo2xRi2nZ8jawk2HGGbpQbq9itIJnktg5AaMiP7w6Ht26U0 XX7udftF
+ uIjKMKU5Y9iOOgotLpt/Xkct51ZabLzf+RUhkZ7MEB5WyUGD09Sa1I7MJZlrtm2jIV0O AVHp9
+ ayVuGxIpZWywyUUAY7/AJ1YUf6JiIuxchvLJyVA9a0qRl3sdjhUkoqU7Ly/z/zNK3hdM3lv NC
+ ZMHam3JB9PxFTW5mgjt2ifM7DzdrcjaB6fic0yIwQwyzSMZY1cIAhwSSOopJopblLVkhkjkfIV
+ G/hHQ5/KuSTu7PY5/rMNFVel7cz6+T7/AHISRJG1aNrcLOUh/gTAI9f6VZtPPMcwA8mMPnEi5K
+ sT 8o+lRx2csEqtuI2KY5FHUknIqUlRqIkWZdskbloyeUkI+UGlOSasjqrYihO/IunUn8yS2Fs
+ yAp5p ZjuGdozyv5c1WLESsIreGWJUzCSgO6MdxUMBEdujt5kxdWaQ7uBnsPTPQVnyTQTsdknl
+ RHIRSclT 12mnCldnDh6bi25W16/5dTQjnjS4FzBhY5QPLtx944OAfp61HPLPa6vKZWZlBOEU4
+ yFB5HsDUEf7 /TlkEDkruNuV4BXPzH8Kvubf7T81ldSQ5Oz58kjGetNpKW1ylzNuqo8yenToZk
+ UsTWcc9xA7KVGw bsZQkhsH61dk8w3RNqgM2/bGW+ZSmPmIz0xUxgmeximghA3qC6FchAT0Hpn
+ FUp3jmjurgJJaywS7 FRm6Z6jiqupPQJSjNJX1/BeqILgo1iXk/eStKu0A+oxn8ayt8q3MeJAk
+ gUlQy5zjtirZgjjVNkoX zAGG9uFAOMdPWmG1zPJErRuUb75PTHUE/jXVT5YrUUYqnCUZNL5Mz
+ 1MIYdWjcMfLXqp7Akj1pzl4 ZA/kOwlLID2wBy35mmvCFViZELpLtG3ocDn8jTVd0aFVheT5jG
+ zZ+VN/c/rXRvqjhqVJpKcZOy/L yJUQ/Yo8FW3qSCRnft7j2qq8saxwqoUOWGWLZBHcYx1z3q9
+ NZ7JlC/NalSY3B68/41SCPLKCBGSG wTjH3qcHF63NbOajbWz0av8A0x6/O0qugc4ypjGMD3+l
+ DxvGIjMhQtH8rFcbu+fyqZVtzZxjLJNu IJJ9OQPxp6Ry3d38zGQHhlA55HUdhjApc3XoTJTfv
+ 2vr13/P8Rm+CaUptjcMDtIOADQLFwltIYpj bv8AOzL/ABKBjC5HXNacOnI2jwSlUS4MZCgLgv
+ zjP51cnsljs7iGOQmXzAJEz3HXA7D2rnliYp2R nXxftmlJ2/B/hb9TFuFs57dGjhmh/egRl2z
+ lO7H1HHFOhsd90ZXSVLZZNwJbjHXn1rQa5RHiLGJ0 KFgu3O0d1+tI8dv9reQXqfO5KoScBSKX
+ tJJW/wCCebWhKEeVrfrvf08zDW5EN48kCrKgOYxt9uvT pVJGuJGUpbyM5UgFF+9z1+ldBLZkP
+ Ir4uZGbgQqFAwuRj+tZkQkWBJchZVRQcd92cY/KumE4tNoq MqfMuV2b7oozrKh8uNjt6MMdPp
+ 6VDGlyp/1eSTlsIBgVceS6nkWOIM+xdhxHyO/Jx1zTSLhYla4i kjITauR2Oc5Hc1upWVnYqUq
+ LqK7s+lnp8hjpiIGbzfMB4Yfdx9MVnRlkTaxWQGTPyjG0Y5H16VMV
+ ZpLZVl3hEJOfXng+tTh59q/6tgyA/d6ZrRaIz5FUlfVee5//2Q==
+X-ABShowAs:COMPANY
+UID:F0A6918D-8E09-43FA-9684-226810B8A96F
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,12 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Kawado;Saeko;;;
-FN:Snow Leopard
-ORG:Snow Leopard;
-EMAIL;type=INTERNET;type=WORK;type=pref:snowleopard at example.com
-TEL;type=WORK;type=pref:777-777-7777
-item1.ADR;type=WORK;type=pref:;;1 Fidel Ave. Suite 100;Mountain Top;CA;99999;USA
-item1.X-ABADR:us
-X-ABShowAs:COMPANY
-UID:FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Kawado;Saeko;;;
+FN:Snow Leopard
+ORG:Snow Leopard;
+EMAIL;type=INTERNET;type=WORK;type=pref:snowleopard at example.com
+TEL;type=WORK;type=pref:777-777-7777
+item1.ADR;type=WORK;type=pref:;;1 Fidel Ave. Suite 100;Mountain Top;CA;99999;USA
+item1.X-ABADR:us
+X-ABShowAs:COMPANY
+UID:FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/1.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/1.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/1.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,2 +0,0 @@
-BEGIN:VCARD
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/1.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/1.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/1.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/1.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,2 @@
+BEGIN:VCARD
+END:VCARD
Deleted: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/2.vcf
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/2.vcf 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/2.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,17 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Contact;Mulberry;;;
-FN:Mulberry Contact
-NICKNAME:mulberry
-ORG:Apple Inc.;
-EMAIL;type=INTERNET;type=WORK;type=pref:mulberry at example.com
-TEL;type=HOME;type=pref:777-777-7777
-TEL;type=WORK:8888888888
-TEL;type=WORK;type=FAX:5555555555
-item1.ADR;type=WORK;type=pref:;;1234 Infinite Circle;Exampletino\, CA 99999;USA;;
-item1.X-ABADR:us
-NOTE:This is a contact created in Mulberry.
-item2.URL;type=pref:http://www.example.com/~magic
-item2.X-ABLabel:_$!<HomePage>!$_
-UID:uid2
-END:VCARD
Copied: CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/2.vcf (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/2.vcf)
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/2.vcf (rev 0)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/2.vcf 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,17 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Contact;Mulberry;;;
+FN:Mulberry Contact
+NICKNAME:mulberry
+ORG:Apple Inc.;
+EMAIL;type=INTERNET;type=WORK;type=pref:mulberry at example.com
+TEL;type=HOME;type=pref:777-777-7777
+TEL;type=WORK:8888888888
+TEL;type=WORK;type=FAX:5555555555
+item1.ADR;type=WORK;type=pref:;;1234 Infinite Circle;Exampletino\, CA 99999;USA;;
+item1.X-ABADR:us
+NOTE:This is a contact created in Mulberry.
+item2.URL;type=pref:http://www.example.com/~magic
+item2.X-ABLabel:_$!<HomePage>!$_
+UID:uid2
+END:VCARD
Modified: CalendarServer/trunk/txdav/carddav/datastore/test/common.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/common.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/common.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -17,37 +17,34 @@
"""
Tests for common addressbook store API functions.
"""
+
+from twext.python.filepath import CachingFilePath as FilePath
+
+from twext.web2.http import HTTPError
+from twext.web2.responsecode import FORBIDDEN
+
from twisted.internet.defer import inlineCallbacks, returnValue, maybeDeferred
from twisted.python import hashlib
-from txdav.idav import IPropertyStore, IDataStore
-from txdav.base.propertystore.base import PropertyName
+from twistedcaldav.vcard import Component as VComponent
-from txdav.common.icommondatastore import (
- HomeChildNameAlreadyExistsError, ICommonTransaction
-, InvalidUIDError)
+from txdav.base.propertystore.base import PropertyName
+from txdav.carddav.iaddressbookstore import IAddressBookObject, IAddressBookHome, \
+ IAddressBook, IAddressBookTransaction
+from txdav.common.datastore.test.util import CommonCommonTests
+from txdav.common.icommondatastore import InvalidUIDError
+from txdav.common.icommondatastore import ICommonTransaction
from txdav.common.icommondatastore import InvalidObjectResourceError
from txdav.common.icommondatastore import NoSuchHomeChildError
from txdav.common.icommondatastore import ObjectResourceNameAlreadyExistsError
+from txdav.idav import IPropertyStore, IDataStore
+from txdav.xml.element import WebDAVUnknownElement, ResourceType
-from txdav.carddav.iaddressbookstore import (
- IAddressBookObject, IAddressBookHome,
- IAddressBook, IAddressBookTransaction
-)
-
-from txdav.common.datastore.test.util import CommonCommonTests
-
-from twistedcaldav.vcard import Component as VComponent
-
-from twext.python.filepath import CachingFilePath as FilePath
-from txdav.xml.element import WebDAVUnknownElement
-
-
storePath = FilePath(__file__).parent().child("addressbook_store")
homeRoot = storePath.child("ho").child("me").child("home1")
-adbk1Root = homeRoot.child("addressbook_1")
+adbk1Root = homeRoot.child("addressbook")
addressbook1_objectNames = [
"1.vcf",
@@ -57,9 +54,7 @@
home1_addressbookNames = [
- "addressbook_1",
- "addressbook_2",
- "addressbook_empty",
+ "addressbook",
]
@@ -113,26 +108,22 @@
)
requirements = {
"home1": {
- "addressbook_1": {
+ "addressbook": {
"1.vcf": adbk1Root.child("1.vcf").getContent(),
"2.vcf": adbk1Root.child("2.vcf").getContent(),
"3.vcf": adbk1Root.child("3.vcf").getContent()
},
- "addressbook_2": {},
- "addressbook_empty": {},
"not_a_addressbook": None
},
"not_a_home": None
}
md5s = {
"home1": {
- "addressbook_1": {
+ "addressbook": {
"1.vcf": md5Values[0],
"2.vcf": md5Values[1],
"3.vcf": md5Values[2],
},
- "addressbook_2": {},
- "addressbook_empty": {},
"not_a_addressbook": None
},
"not_a_home": None
@@ -160,17 +151,17 @@
@inlineCallbacks
def addressbookUnderTest(self):
"""
- Get the addressbook detailed by C{requirements['home1']['addressbook_1']}.
+ Get the addressbook detailed by C{requirements['home1']['addressbook']}.
"""
returnValue((yield (yield self.homeUnderTest())
- .addressbookWithName("addressbook_1")))
+ .addressbookWithName("addressbook")))
@inlineCallbacks
def addressbookObjectUnderTest(self):
"""
Get the addressbook detailed by
- C{requirements['home1']['addressbook_1']['1.vcf']}.
+ C{requirements['home1']['addressbook']['1.vcf']}.
"""
returnValue((yield (yield self.addressbookUnderTest())
.addressbookObjectWithName("1.vcf")))
@@ -227,8 +218,8 @@
def test_notifierID(self):
home = yield self.homeUnderTest()
self.assertEquals(home.notifierID(), ("CardDAV", "home1",))
- addressbook = yield home.addressbookWithName("addressbook_1")
- self.assertEquals(addressbook.notifierID(), ("CardDAV", "home1/addressbook_1",))
+ addressbook = yield home.addressbookWithName("addressbook")
+ self.assertEquals(addressbook.notifierID(), ("CardDAV", "home1/addressbook",))
@inlineCallbacks
@@ -275,21 +266,11 @@
L{IAddressBook.rename} changes the name of the L{IAddressBook}.
"""
home = yield self.homeUnderTest()
- addressbook = yield home.addressbookWithName("addressbook_1")
- yield addressbook.rename("some_other_name")
- @inlineCallbacks
- def positiveAssertions():
- self.assertEquals(addressbook.name(), "some_other_name")
- self.assertEquals(addressbook, (yield home.addressbookWithName("some_other_name")))
- self.assertEquals(None, (yield home.addressbookWithName("addressbook_1")))
- yield positiveAssertions()
- yield self.commit()
- home = yield self.homeUnderTest()
- addressbook = yield home.addressbookWithName("some_other_name")
- yield positiveAssertions()
- # FIXME: revert
- # FIXME: test for multiple renames
- # FIXME: test for conflicting renames (a->b, c->a in the same txn)
+ addressbook = yield home.addressbookWithName("addressbook")
+ try:
+ yield addressbook.rename("some-other-name")
+ except HTTPError, e:
+ self.assertEquals(e.response.code, FORBIDDEN)
@inlineCallbacks
@@ -310,12 +291,21 @@
can be retrieved with L{IAddressBookHome.addressbookWithName}.
"""
home = yield self.homeUnderTest()
- name = "new"
- self.assertIdentical((yield home.addressbookWithName(name)), None)
- yield home.createAddressBookWithName(name)
+ name = "addressbook"
+ #self.assertIdentical((yield home.addressbookWithName(name)), None)
+ yield home.removeAddressBookWithName(name)
self.assertNotIdentical((yield home.addressbookWithName(name)), None)
- addressbookProperties = (yield home.addressbookWithName(name)).properties()
- self.assertEqual(len(addressbookProperties), 0)
+ @inlineCallbacks
+ def checkProperties():
+ addressbookProperties = (yield home.addressbookWithName(name)).properties()
+ addressbookType = ResourceType.addressbook
+ self.assertEquals(
+ addressbookProperties[
+ PropertyName.fromString(ResourceType.sname())
+ ],
+ addressbookType
+ )
+ yield checkProperties()
yield self.commit()
# Make sure notification fired after commit
@@ -327,21 +317,6 @@
@inlineCallbacks
- def test_createAddressBookWithName_exists(self):
- """
- L{IAddressBookHome.createAddressBookWithName} raises
- L{AddressBookAlreadyExistsError} when the name conflicts with an already-
- existing address book.
- """
- for name in home1_addressbookNames:
- yield self.failUnlessFailure(
- maybeDeferred(
- (yield self.homeUnderTest()).createAddressBookWithName, name),
- HomeChildNameAlreadyExistsError,
- )
-
-
- @inlineCallbacks
def test_removeAddressBookWithName_exists(self):
"""
L{IAddressBookHome.removeAddressBookWithName} removes a addressbook that already
@@ -352,7 +327,9 @@
for name in home1_addressbookNames:
self.assertNotIdentical((yield home.addressbookWithName(name)), None)
yield home.removeAddressBookWithName(name)
- self.assertEquals((yield home.addressbookWithName(name)), None)
+ # address book is not deleted, but cleared
+ ab = yield home.addressbookWithName(name)
+ self.assertEquals((yield ab.listAddressBookObjects()), [])
yield self.commit()
@@ -361,11 +338,7 @@
set(self.notifierFactory.history),
set([
"/CardDAV/example.com/home1/",
- "/CardDAV/example.com/home1/addressbook_1/",
- "/CardDAV/example.com/home1/",
- "/CardDAV/example.com/home1/addressbook_2/",
- "/CardDAV/example.com/home1/",
- "/CardDAV/example.com/home1/addressbook_empty/"
+ "/CardDAV/example.com/home1/addressbook/",
])
)
@@ -498,7 +471,7 @@
set(self.notifierFactory.history),
set([
"/CardDAV/example.com/home1/",
- "/CardDAV/example.com/home1/addressbook_1/",
+ "/CardDAV/example.com/home1/addressbook/",
])
)
@@ -508,7 +481,7 @@
"""
L{AddressBook.name} reflects the name of the addressbook.
"""
- self.assertEquals((yield self.addressbookUnderTest()).name(), "addressbook_1")
+ self.assertEquals((yield self.addressbookUnderTest()).name(), "addressbook")
@inlineCallbacks
@@ -640,21 +613,6 @@
@inlineCallbacks
- def test_addressbooksAfterAddAddressBook(self):
- """
- L{IAddressBookHome.addressbooks} includes addressbooks recently added with
- L{IAddressBookHome.createAddressBookWithName}.
- """
- home = yield self.homeUnderTest()
- allAddressbooks = yield home.addressbooks()
- before = set(x.name() for x in allAddressbooks)
- yield home.createAddressBookWithName("new-name")
- allAddressbooks = yield home.addressbooks()
- after = set(x.name() for x in allAddressbooks)
- self.assertEquals(before | set(['new-name']), after)
-
-
- @inlineCallbacks
def test_createAddressBookObjectWithName_absent(self):
"""
L{IAddressBook.createAddressBookObjectWithName} creates a new
@@ -676,7 +634,7 @@
set(self.notifierFactory.history),
set([
"/CardDAV/example.com/home1/",
- "/CardDAV/example.com/home1/addressbook_1/",
+ "/CardDAV/example.com/home1/addressbook/",
])
)
@@ -792,7 +750,7 @@
set(self.notifierFactory.history),
set([
"/CardDAV/example.com/home1/",
- "/CardDAV/example.com/home1/addressbook_1/",
+ "/CardDAV/example.com/home1/addressbook/",
])
)
@@ -896,10 +854,11 @@
Addressbooks in one user's addressbook home should not show up in another
user's addressbook home.
"""
- home2 = yield self.transactionUnderTest().addressbookHomeWithUID(
- "home2", create=True
+ home3 = yield self.transactionUnderTest().addressbookHomeWithUID(
+ "home3", create=True
)
- self.assertIdentical((yield home2.addressbookWithName("addressbook_1")), None)
+ ab = yield home3.addressbookWithName("addressbook")
+ self.assertEquals((yield ab.addressbookObjects()), [])
@inlineCallbacks
@@ -909,13 +868,13 @@
user's via uid or name queries.
"""
home1 = yield self.homeUnderTest()
- home2 = yield self.transactionUnderTest().addressbookHomeWithUID(
- "home2", create=True)
- addressbook1 = yield home1.addressbookWithName("addressbook_1")
- addressbook2 = yield home2.addressbookWithName("addressbook")
- objects = list((yield (yield home2.addressbookWithName("addressbook")).addressbookObjects()))
+ home3 = yield self.transactionUnderTest().addressbookHomeWithUID(
+ "home3", create=True)
+ addressbook1 = yield home1.addressbookWithName("addressbook")
+ addressbook2 = yield home3.addressbookWithName("addressbook")
+ objects = list((yield (yield home3.addressbookWithName("addressbook")).addressbookObjects()))
self.assertEquals(objects, [])
- for resourceName in self.requirements['home1']['addressbook_1'].keys():
+ for resourceName in self.requirements['home1']['addressbook'].keys():
obj = yield addressbook1.addressbookObjectWithName(resourceName)
self.assertIdentical(
(yield addressbook2.addressbookObjectWithName(resourceName)), None)
Modified: CalendarServer/trunk/txdav/carddav/datastore/test/test_file.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/test_file.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/test_file.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -49,6 +49,7 @@
featureUnimplemented = lambda f: _todo(f, "Feature unimplemented")
testUnimplemented = lambda f: _todo(f, "Test unimplemented")
todo = lambda why: lambda f: _todo(f, why)
+fixFile = lambda f: _todo(f, "fix file implementation")
def setUpAddressBookStore(test):
@@ -78,7 +79,7 @@
@inlineCallbacks
def setUpAddressBook1(test):
yield setUpHome1(test)
- test.addressbook1 = yield test.home1.addressbookWithName("addressbook_1")
+ test.addressbook1 = yield test.home1.addressbookWithName("addressbook")
assert test.addressbook1 is not None, "No addressbook?"
@@ -291,7 +292,7 @@
"""
self.txn = self.addressbookStore.newTransaction(self.id())
self.home1 = yield self.txn.addressbookHomeWithUID("home1")
- self.addressbook1 = yield self.home1.addressbookWithName("addressbook_1")
+ self.addressbook1 = yield self.home1.addressbookWithName("addressbook")
@inlineCallbacks
@@ -457,3 +458,23 @@
((yield self.addressbookUnderTest())._path.child("not-a-vcard")
.createDirectory())
yield self.test_addressbookObjects()
+
+
+ @inlineCallbacks
+ @fixFile
+ def test_createAddressBookWithName_absent(self):
+ """
+ L{IAddressBookHome.createAddressBookWithName} creates a new L{IAddressBook} that
+ can be retrieved with L{IAddressBookHome.addressbookWithName}.
+ """
+ pass
+
+
+ @inlineCallbacks
+ @fixFile
+ def test_removeAddressBookWithName_exists(self):
+ """
+ L{IAddressBookHome.removeAddressBookWithName} removes a addressbook that already
+ exists.
+ """
+ pass
Modified: CalendarServer/trunk/txdav/carddav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/test_sql.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/test_sql.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -20,26 +20,32 @@
"""
from twext.enterprise.dal.syntax import Select, Parameter
-from txdav.xml.rfc2518 import GETContentLanguage, ResourceType
from twisted.internet.defer import inlineCallbacks, returnValue
+
from twisted.trial import unittest
from twistedcaldav import carddavxml
-
from twistedcaldav.vcard import Component as VCard
from twistedcaldav.vcard import Component as VComponent
from txdav.base.propertystore.base import PropertyName
-from txdav.carddav.datastore.test.common import CommonTests as AddressBookCommonTests,\
+from txdav.carddav.datastore.test.common import CommonTests as AddressBookCommonTests, \
vcard4_text
from txdav.carddav.datastore.test.test_file import setUpAddressBookStore
from txdav.carddav.datastore.util import _migrateAddressbook, migrateHome
from txdav.common.datastore.sql import EADDRESSBOOKTYPE
-from txdav.common.datastore.sql_tables import schema
+from txdav.common.datastore.sql_tables import _ABO_KIND_PERSON, _ABO_KIND_GROUP, \
+ schema
from txdav.common.datastore.test.util import buildStore
+from txdav.xml.rfc2518 import GETContentLanguage
+def _todo(f, why):
+ f.todo = why
+ return f
+fixMigration = lambda f: _todo(f, "fix migration to shared groups")
+
class AddressBookSQLStorageTests(AddressBookCommonTests, unittest.TestCase):
"""
AddressBook SQL storage tests.
@@ -51,7 +57,6 @@
self._sqlStore = yield buildStore(self, self.notifierFactory)
yield self.populate()
-
@inlineCallbacks
def populate(self):
populateTxn = self.storeUnderTest().newTransaction()
@@ -61,22 +66,23 @@
home = yield populateTxn.addressbookHomeWithUID(homeUID, True)
# We don't want the default addressbook to appear unless it's
# explicitly listed.
- yield home.removeAddressBookWithName("addressbook")
- for addressbookName in addressbooks:
- addressbookObjNames = addressbooks[addressbookName]
- if addressbookObjNames is not None:
- yield home.createAddressBookWithName(addressbookName)
- addressbook = yield home.addressbookWithName(addressbookName)
- for objectName in addressbookObjNames:
- objData = addressbookObjNames[objectName]
- yield addressbook.createAddressBookObjectWithName(
- objectName, VCard.fromString(objData)
- )
+ addressbookName = (yield home.addressbook()).name()
+ yield home.removeAddressBookWithName(addressbookName)
+ addressbook = yield home.addressbook()
+ addressbookObjNames = addressbooks[addressbookName]
+ if addressbookObjNames is not None:
+ for objectName in addressbookObjNames:
+ objData = addressbookObjNames[objectName]
+ yield addressbook.createAddressBookObjectWithName(
+ objectName, VCard.fromString(objData)
+ )
+
yield populateTxn.commit()
self.notifierFactory.reset()
+
def storeUnderTest(self):
"""
Create and return a L{AddressBookStore} for testing.
@@ -91,7 +97,7 @@
events).
"""
@inlineCallbacks
- def namesAndComponents(x, filter=lambda x: x.component()):
+ def namesAndComponents(x, filter=lambda x:x.component()):
fromObjs = yield x.addressbookObjects()
returnValue(dict([(fromObj.name(), (yield filter(fromObj)))
for fromObj in fromObjs]))
@@ -107,7 +113,7 @@
"""
Assert that two objects with C{properties} methods have similar
properties.
-
+
@param disregard: a list of L{PropertyName} keys to discard from both
input and output.
"""
@@ -137,7 +143,7 @@
database- backed addressbook.
"""
fromAddressbook = yield self.fileTransaction().addressbookHomeWithUID(
- "home1").addressbookWithName("addressbook_1")
+ "home1").addressbookWithName("addressbook")
toHome = yield self.transactionUnderTest().addressbookHomeWithUID(
"new-home", create=True)
toAddressbook = yield toHome.addressbookWithName("addressbook")
@@ -154,7 +160,7 @@
is "bad" address data present in the file-backed addressbook.
"""
fromAddressbook = yield self.fileTransaction().addressbookHomeWithUID(
- "home_bad").addressbookWithName("addressbook_bad")
+ "home_bad").addressbookWithName("addressbook")
toHome = yield self.transactionUnderTest().addressbookHomeWithUID(
"new-home", create=True)
toAddressbook = yield toHome.addressbookWithName("addressbook")
@@ -165,6 +171,7 @@
@inlineCallbacks
+ @fixMigration
def test_migrateHomeFromFile(self):
"""
L{migrateHome} will migrate an L{IAddressbookHome} provider from one
@@ -173,14 +180,12 @@
"""
fromHome = yield self.fileTransaction().addressbookHomeWithUID("home1")
- builtinProperties = [PropertyName.fromElement(ResourceType)]
-
# Populate an arbitrary / unused dead properties so there's something
# to verify against.
key = PropertyName.fromElement(GETContentLanguage)
fromHome.properties()[key] = GETContentLanguage("C")
- (yield fromHome.addressbookWithName("addressbook_1")).properties()[
+ (yield fromHome.addressbookWithName("addressbook")).properties()[
key] = (
GETContentLanguage("pig-latin")
)
@@ -196,9 +201,8 @@
for c in fromAddressbooks:
self.assertPropertiesSimilar(
c, (yield toHome.addressbookWithName(c.name())),
- builtinProperties
)
- self.assertPropertiesSimilar(fromHome, toHome, builtinProperties)
+ self.assertPropertiesSimilar(fromHome, toHome,)
def test_addressBookHomeVersion(self):
@@ -249,7 +253,7 @@
@inlineCallbacks
def _defer1():
- yield adbk1.createObjectResourceWithName("1.vcf", VCard.fromString(
+ yield adbk1.createAddressBookObjectWithName("1.vcf", VCard.fromString(
"""BEGIN:VCARD
VERSION:3.0
N:Thompson;Default1;;;
@@ -268,7 +272,7 @@
@inlineCallbacks
def _defer2():
- yield adbk2.createObjectResourceWithName("2.vcf", VCard.fromString(
+ yield adbk2.createAddressBookObjectWithName("2.vcf", VCard.fromString(
"""BEGIN:VCARD
VERSION:3.0
N:Thompson;Default2;;;
@@ -288,49 +292,280 @@
yield d1
yield d2
+ @inlineCallbacks
+ def test_addressbookObjectUID(self):
+ """
+ Test that kind property UID is stored correctly in database
+ """
+ addressbookStore = yield buildStore(self, self.notifierFactory)
+ # Provision the home and addressbook, one user and one group
+ txn = addressbookStore.newTransaction()
+ home = yield txn.homeWithUID(EADDRESSBOOKTYPE, "uid1", create=True)
+ self.assertNotEqual(home, None)
+ adbk = yield home.addressbookWithName("addressbook")
+ self.assertNotEqual(adbk, None)
+
+ person = VCard.fromString(
+ """BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-444-444-4444
+item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
+item1.X-ABADR:us
+UID:uid1
+END:VCARD
+""".replace("\n", "\r\n")
+ )
+ self.assertEqual(person.resourceUID(), "uid1")
+ abObject = yield adbk.createAddressBookObjectWithName("1.vcf", person)
+ self.assertEqual(abObject.uid(), "uid1")
+ yield txn.commit()
+
+ txn = addressbookStore.newTransaction()
+ home = yield txn.homeWithUID(EADDRESSBOOKTYPE, "uid1", create=True)
+ adbk = yield home.addressbookWithName("addressbook")
+
+ abObject = yield adbk.objectResourceWithName("1.vcf")
+ person = yield abObject.component()
+ self.assertEqual(person.resourceUID(), "uid1")
+
+ yield home.removeAddressBookWithName("addressbook")
+
+ yield txn.commit()
+
+
@inlineCallbacks
+ def test_addressbookObjectKind(self):
+ """
+ Test that kind property vCard is stored correctly in database
+ """
+ addressbookStore = yield buildStore(self, self.notifierFactory)
+
+ # Provision the home and addressbook, one user and one group
+ txn = addressbookStore.newTransaction()
+ home = yield txn.homeWithUID(EADDRESSBOOKTYPE, "uid1", create=True)
+ self.assertNotEqual(home, None)
+ adbk = yield home.addressbookWithName("addressbook")
+ self.assertNotEqual(adbk, None)
+
+ person = VCard.fromString(
+ """BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-444-444-4444
+item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
+item1.X-ABADR:us
+UID:uid1
+END:VCARD
+""".replace("\n", "\r\n")
+ )
+ self.assertEqual(person.resourceKind(), None)
+ abObject = yield adbk.createAddressBookObjectWithName("p.vcf", person)
+ self.assertEqual(abObject.kind(), _ABO_KIND_PERSON)
+
+ group = VCard.fromString(
+ """BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:uid2
+FN:Top Group
+N:Top Group;;;;
+REV:20120503T194243Z
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:uid1
+END:VCARD
+""".replace("\n", "\r\n")
+ )
+ abObject = self.assertEqual(group.resourceKind(), "group")
+ abObject = yield adbk.createAddressBookObjectWithName("g.vcf", group)
+ self.assertEqual(abObject.kind(), _ABO_KIND_GROUP)
+
+ badgroup = VCard.fromString(
+ """BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:uid3
+FN:Bad Group
+N:Bad Group;;;;
+REV:20120503T194243Z
+X-ADDRESSBOOKSERVER-KIND:badgroup
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:uid1
+END:VCARD
+""".replace("\n", "\r\n")
+ )
+ abObject = self.assertEqual(badgroup.resourceKind(), "badgroup")
+ abObject = yield adbk.createAddressBookObjectWithName("bg.vcf", badgroup)
+ self.assertEqual(abObject.kind(), _ABO_KIND_PERSON)
+
+ yield txn.commit()
+
+ txn = addressbookStore.newTransaction()
+ home = yield txn.homeWithUID(EADDRESSBOOKTYPE, "uid1", create=True)
+ adbk = yield home.addressbookWithName("addressbook")
+
+ abObject = yield adbk.objectResourceWithName("p.vcf")
+ person = yield abObject.component()
+ self.assertEqual(person.resourceKind(), None)
+ self.assertEqual(abObject.kind(), _ABO_KIND_PERSON)
+
+ abObject = yield adbk.objectResourceWithName("g.vcf")
+ group = yield abObject.component()
+ self.assertEqual(group.resourceKind(), "group")
+ self.assertEqual(abObject.kind(), _ABO_KIND_GROUP)
+
+ abObject = yield adbk.objectResourceWithName("bg.vcf")
+ badgroup = yield abObject.component()
+ self.assertEqual(badgroup.resourceKind(), "badgroup")
+ self.assertEqual(abObject.kind(), _ABO_KIND_PERSON)
+
+ yield home.removeAddressBookWithName("addressbook")
+ yield txn.commit()
+
+
+ @inlineCallbacks
+ def test_addressbookObjectMembers(self):
+ """
+ Test that kind property vCard is stored correctly in database
+ """
+ addressbookStore = yield buildStore(self, self.notifierFactory)
+
+ # Provision the home and addressbook, one user and one group
+ txn = addressbookStore.newTransaction()
+ home = yield txn.homeWithUID(EADDRESSBOOKTYPE, "uid1", create=True)
+ self.assertNotEqual(home, None)
+ adbk = yield home.addressbookWithName("addressbook")
+ self.assertNotEqual(adbk, None)
+
+ person = VCard.fromString(
+ """BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default;;;
+FN:Default Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-444-444-4444
+item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
+item1.X-ABADR:us
+UID:uid1
+END:VCARD
+""".replace("\n", "\r\n")
+ )
+ self.assertEqual(person.resourceKind(), None)
+ personObject = yield adbk.createAddressBookObjectWithName("p.vcf", person)
+
+ group = VCard.fromString(
+ """BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:uid2
+FN:Top Group
+N:Top Group;;;;
+REV:20120503T194243Z
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:uid3
+END:VCARD
+""".replace("\n", "\r\n")
+ )
+ groupObject = yield adbk.createAddressBookObjectWithName("g.vcf", group)
+
+ aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
+ aboMembers = schema.ABO_MEMBERS
+ memberRows = yield Select([aboMembers.GROUP_ID, aboMembers.MEMBER_ID], From=aboMembers,).on(txn)
+ self.assertEqual(memberRows, [])
+
+ foreignMemberRows = yield Select([aboForeignMembers.GROUP_ID, aboForeignMembers.MEMBER_ADDRESS], From=aboForeignMembers).on(txn)
+ self.assertEqual(foreignMemberRows, [[groupObject._resourceID, "urn:uuid:uid3"]])
+
+ subgroup = VCard.fromString(
+ """BEGIN:VCARD
+VERSION:3.0
+PRODID:-//Apple Inc.//AddressBook 6.1//EN
+UID:uid3
+FN:Sub Group
+N:Sub Group;;;;
+REV:20120503T194243Z
+X-ADDRESSBOOKSERVER-KIND:group
+X-ADDRESSBOOKSERVER-MEMBER:urn:uuid:uid1
+END:VCARD
+""".replace("\n", "\r\n")
+ )
+ subgroupObject = yield adbk.createAddressBookObjectWithName("sg.vcf", subgroup)
+
+ memberRows = yield Select([aboMembers.GROUP_ID, aboMembers.MEMBER_ID], From=aboMembers,).on(txn)
+ self.assertEqual(sorted(memberRows), sorted([
+ [groupObject._resourceID, subgroupObject._resourceID],
+ [subgroupObject._resourceID, personObject._resourceID],
+ ]))
+
+ foreignMemberRows = yield Select([aboForeignMembers.GROUP_ID, aboForeignMembers.MEMBER_ADDRESS], From=aboForeignMembers).on(txn)
+ self.assertEqual(foreignMemberRows, [])
+
+
+ yield subgroupObject.remove()
+ memberRows = yield Select([aboMembers.GROUP_ID, aboMembers.MEMBER_ID], From=aboMembers,).on(txn)
+ self.assertEqual(memberRows, [])
+
+ foreignMemberRows = yield Select([aboForeignMembers.GROUP_ID, aboForeignMembers.MEMBER_ADDRESS], From=aboForeignMembers,
+ #Where=(aboForeignMembers.GROUP_ID == groupObject._resourceID),
+ ).on(txn)
+ self.assertEqual(foreignMemberRows, [[groupObject._resourceID, "urn:uuid:uid3"]])
+
+ yield home.removeAddressBookWithName("addressbook")
+ yield txn.commit()
+
+
+
+ @inlineCallbacks
def test_removeAddressBookPropertiesOnDelete(self):
"""
- L{IAddressBookHome.removeAddressBookWithName} removes an address book that already
- exists and makes sure properties are also removed.
+ L{IAddressBookHome.removeAddressBookWithName} clears an address book that already
+ exists and makes sure added properties are also removed.
"""
+ prop = schema.RESOURCE_PROPERTY
+ _allWithID = Select([prop.NAME, prop.VIEWER_UID, prop.VALUE],
+ From=prop,
+ Where=prop.RESOURCE_ID == Parameter("resourceID"))
+
# Create address book and add a property
home = yield self.homeUnderTest()
- name = "remove-me"
+ name = "addressbook"
addressbook = yield home.createAddressBookWithName(name)
- resourceID = addressbook._resourceID
+ resourceID = home._addressbookPropertyStoreID
+
+ rows = yield _allWithID.on(self.transactionUnderTest(), resourceID=resourceID)
+ self.assertEqual(len(tuple(rows)), 1)
+
addressbookProperties = addressbook.properties()
-
- prop = carddavxml.AddressBookDescription.fromString("Address Book to be removed")
+ prop = carddavxml.AddressBookDescription.fromString("Address Book prop to be removed")
addressbookProperties[PropertyName.fromElement(prop)] = prop
yield self.commit()
- prop = schema.RESOURCE_PROPERTY
- _allWithID = Select([prop.NAME, prop.VIEWER_UID, prop.VALUE],
- From=prop,
- Where=prop.RESOURCE_ID == Parameter("resourceID"))
-
# Check that two properties are present
home = yield self.homeUnderTest()
rows = yield _allWithID.on(self.transactionUnderTest(), resourceID=resourceID)
- self.assertEqual(len(tuple(rows)), 1)
+ self.assertEqual(len(tuple(rows)), 2)
yield self.commit()
# Remove address book and check for no properties
home = yield self.homeUnderTest()
yield home.removeAddressBookWithName(name)
rows = yield _allWithID.on(self.transactionUnderTest(), resourceID=resourceID)
- self.assertEqual(len(tuple(rows)), 0)
+ self.assertEqual(len(tuple(rows)), 1)
yield self.commit()
# Recheck it
rows = yield _allWithID.on(self.transactionUnderTest(), resourceID=resourceID)
- self.assertEqual(len(tuple(rows)), 0)
+ self.assertEqual(len(tuple(rows)), 1)
yield self.commit()
-
@inlineCallbacks
def test_removeAddressBookObjectPropertiesOnDelete(self):
"""
@@ -369,3 +604,4 @@
rows = yield _allWithID.on(self.transactionUnderTest(), resourceID=resourceID)
self.assertEqual(len(tuple(rows)), 0)
yield self.commit()
+
Modified: CalendarServer/trunk/txdav/carddav/iaddressbookstore.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/iaddressbookstore.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/carddav/iaddressbookstore.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -20,18 +20,40 @@
"""
from txdav.common.icommondatastore import ICommonTransaction, \
- IShareableCollection
+ IShareableCollection, CommonStoreError
from txdav.idav import INotifier
from txdav.idav import IDataStoreObject
__all__ = [
# Classes
+ "GroupForSharedAddressBookDeleteNotAllowedError",
+ "GroupWithUnsharedAddressNotAllowedError",
+ "SharedGroupDeleteNotAllowedError",
"IAddressBookTransaction",
"IAddressBookHome",
"IAddressBook",
"IAddressBookObject",
]
+
+class GroupForSharedAddressBookDeleteNotAllowedError(CommonStoreError):
+ """
+ Sharee cannot delete the group for a shared address book.
+ """
+
+
+class GroupWithUnsharedAddressNotAllowedError(CommonStoreError):
+ """
+ Sharee cannot add unshared group members.
+ """
+
+
+class SharedGroupDeleteNotAllowedError(CommonStoreError):
+ """
+ Sharee cannot delete a shared group.
+ """
+
+
class IAddressBookTransaction(ICommonTransaction):
"""
Transaction interface that addressbook stores must provide.
@@ -49,11 +71,11 @@
"""
-
#
# Interfaces
#
+
class IAddressBookHome(INotifier, IDataStoreObject):
"""
AddressBook home
@@ -234,7 +256,7 @@
def setComponent(component):
"""
Rewrite this addressbook object to match the given C{component}.
- C{component} must have the same UID as this addressbook object.
+ C{component} must have the same UID and KIND as this addressbook object.
@param component: a C{VCARD} L{VComponent}.
@raise InvalidAddressBookComponentError: if the given
Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -58,8 +58,7 @@
from txdav.common.datastore.common import HomeChildBase
from txdav.common.datastore.sql_tables import schema, splitSQLString
from txdav.common.datastore.sql_tables import _BIND_MODE_OWN, \
- _BIND_STATUS_ACCEPTED, _BIND_STATUS_DECLINED, \
- NOTIFICATION_OBJECT_REVISIONS_TABLE
+ _BIND_STATUS_ACCEPTED, _BIND_STATUS_DECLINED
from txdav.common.icommondatastore import HomeChildNameNotAllowedError, \
HomeChildNameAlreadyExistsError, NoSuchHomeChildError, \
ObjectResourceNameNotAllowedError, ObjectResourceNameAlreadyExistsError, \
@@ -217,7 +216,7 @@
@inlineCallbacks
- def _withEachHomeDo(self, homeTable, homeFromTxn, action, batchSize):
+ def _withEachHomeDo(self, homeTable, homeFromTxn, action, batchSize): #@UnusedVariable
"""
Implementation of L{ICalendarStore.withEachCalendarHomeDo} and
L{IAddressbookStore.withEachAddressbookHomeDo}.
@@ -517,7 +516,7 @@
@classproperty
- def _calendarserver(cls): #@NoSelf
+ def _calendarserver(cls): #@NoSelf
cs = schema.CALENDARSERVER
return Select(
[cs.VALUE, ],
@@ -562,7 +561,7 @@
return self.homeWithUID(EADDRESSBOOKTYPE, uid, create=create)
- def _determineMemo(self, storeType, uid, create=False):
+ def _determineMemo(self, storeType, uid, create=False): #@UnusedVariable
"""
Determine the memo dictionary to use for homeWithUID.
"""
@@ -626,7 +625,7 @@
@classproperty
- def _insertAPNSubscriptionQuery(cls): #@NoSelf
+ def _insertAPNSubscriptionQuery(cls): #@NoSelf
apn = schema.APN_SUBSCRIPTIONS
return Insert({apn.TOKEN: Parameter("token"),
apn.RESOURCE_KEY: Parameter("resourceKey"),
@@ -637,7 +636,7 @@
@classproperty
- def _updateAPNSubscriptionQuery(cls): #@NoSelf
+ def _updateAPNSubscriptionQuery(cls): #@NoSelf
apn = schema.APN_SUBSCRIPTIONS
return Update({apn.MODIFIED: Parameter("modified"),
apn.SUBSCRIBER_GUID: Parameter("subscriber"),
@@ -648,7 +647,7 @@
@classproperty
- def _selectAPNSubscriptionQuery(cls): #@NoSelf
+ def _selectAPNSubscriptionQuery(cls): #@NoSelf
apn = schema.APN_SUBSCRIPTIONS
return Select([apn.MODIFIED, apn.SUBSCRIBER_GUID], From=apn,
Where=(
@@ -670,7 +669,7 @@
row = yield self._selectAPNSubscriptionQuery.on(self,
token=token, resourceKey=key)
- if not row: # Subscription does not yet exist
+ if not row: # Subscription does not yet exist
try:
yield self._insertAPNSubscriptionQuery.on(self,
token=token, resourceKey=key, modified=timestamp,
@@ -680,7 +679,7 @@
# Subscription may have been added by someone else, which is fine
pass
- else: # Subscription exists, so update with new timestamp and subscriber
+ else: # Subscription exists, so update with new timestamp and subscriber
try:
yield self._updateAPNSubscriptionQuery.on(self,
token=token, resourceKey=key, modified=timestamp,
@@ -692,7 +691,7 @@
@classproperty
- def _removeAPNSubscriptionQuery(cls): #@NoSelf
+ def _removeAPNSubscriptionQuery(cls): #@NoSelf
apn = schema.APN_SUBSCRIPTIONS
return Delete(From=apn,
Where=(apn.TOKEN == Parameter("token")).And(
@@ -705,7 +704,7 @@
@classproperty
- def _purgeOldAPNSubscriptionQuery(cls): #@NoSelf
+ def _purgeOldAPNSubscriptionQuery(cls): #@NoSelf
apn = schema.APN_SUBSCRIPTIONS
return Delete(From=apn,
Where=(apn.MODIFIED < Parameter("olderThan")))
@@ -717,7 +716,7 @@
@classproperty
- def _apnSubscriptionsByTokenQuery(cls): #@NoSelf
+ def _apnSubscriptionsByTokenQuery(cls): #@NoSelf
apn = schema.APN_SUBSCRIPTIONS
return Select([apn.RESOURCE_KEY, apn.MODIFIED, apn.SUBSCRIBER_GUID],
From=apn, Where=apn.TOKEN == Parameter("token"))
@@ -728,7 +727,7 @@
@classproperty
- def _apnSubscriptionsByKeyQuery(cls): #@NoSelf
+ def _apnSubscriptionsByKeyQuery(cls): #@NoSelf
apn = schema.APN_SUBSCRIPTIONS
return Select([apn.TOKEN, apn.SUBSCRIBER_GUID],
From=apn, Where=apn.RESOURCE_KEY == Parameter("resourceKey"))
@@ -739,7 +738,7 @@
@classproperty
- def _apnSubscriptionsBySubscriberQuery(cls): #@NoSelf
+ def _apnSubscriptionsBySubscriberQuery(cls): #@NoSelf
apn = schema.APN_SUBSCRIPTIONS
return Select([apn.TOKEN, apn.RESOURCE_KEY, apn.MODIFIED, apn.USER_AGENT, apn.IP_ADDR],
From=apn, Where=apn.SUBSCRIBER_GUID == Parameter("subscriberGUID"))
@@ -752,7 +751,7 @@
# Create IMIP token
@classproperty
- def _insertIMIPTokenQuery(cls): #@NoSelf
+ def _insertIMIPTokenQuery(cls): #@NoSelf
imip = schema.IMIP_TOKENS
return Insert({imip.TOKEN: Parameter("token"),
imip.ORGANIZER: Parameter("organizer"),
@@ -782,7 +781,7 @@
@classproperty
- def _selectIMIPTokenByTokenQuery(cls): #@NoSelf
+ def _selectIMIPTokenByTokenQuery(cls): #@NoSelf
imip = schema.IMIP_TOKENS
return Select([imip.ORGANIZER, imip.ATTENDEE, imip.ICALUID], From=imip,
Where=(imip.TOKEN == Parameter("token")))
@@ -795,7 +794,7 @@
@classproperty
- def _selectIMIPTokenQuery(cls): #@NoSelf
+ def _selectIMIPTokenQuery(cls): #@NoSelf
imip = schema.IMIP_TOKENS
return Select([imip.TOKEN], From=imip,
Where=(imip.ORGANIZER == Parameter("organizer")).And(
@@ -804,7 +803,7 @@
@classproperty
- def _updateIMIPTokenQuery(cls): #@NoSelf
+ def _updateIMIPTokenQuery(cls): #@NoSelf
imip = schema.IMIP_TOKENS
return Update({imip.ACCESSED: utcNowSQL, },
Where=(imip.ORGANIZER == Parameter("organizer")).And(
@@ -828,7 +827,7 @@
# Remove IMIP token
@classproperty
- def _removeIMIPTokenQuery(cls): #@NoSelf
+ def _removeIMIPTokenQuery(cls): #@NoSelf
imip = schema.IMIP_TOKENS
return Delete(From=imip,
Where=(imip.TOKEN == Parameter("token")))
@@ -840,7 +839,7 @@
# Purge old IMIP tokens
@classproperty
- def _purgeOldIMIPTokensQuery(cls): #@NoSelf
+ def _purgeOldIMIPTokensQuery(cls): #@NoSelf
imip = schema.IMIP_TOKENS
return Delete(From=imip,
Where=(imip.ACCESSED < Parameter("olderThan")))
@@ -1379,15 +1378,15 @@
class _EmptyCacher(object):
- def set(self, key, value):
+ def set(self, key, value): #@UnusedVariable
return succeed(True)
- def get(self, key, withIdentifier=False):
+ def get(self, key, withIdentifier=False): #@UnusedVariable
return succeed(None)
- def delete(self, key):
+ def delete(self, key): #@UnusedVariable
return succeed(True)
@@ -1399,11 +1398,7 @@
_homeMetaDataTable = None
_childClass = None
_childTable = None
- _bindTable = None
- _objectBindTable = None
_notifierPrefix = None
- _revisionsTable = None
- _notificationRevisionsTable = NOTIFICATION_OBJECT_REVISIONS_TABLE
_dataVersionKey = None
_dataVersionValue = None
@@ -1424,14 +1419,7 @@
if transaction._disableCache:
self._cacher = _EmptyCacher()
- # Needed for REVISION/BIND table join
- self._revisionBindJoinTable = {}
- for key, value in self._revisionsTable.iteritems():
- self._revisionBindJoinTable["REV:%s" % (key,)] = value
- for key, value in self._bindTable.iteritems():
- self._revisionBindJoinTable["BIND:%s" % (key,)] = value
-
@classmethod
def _register(cls, homeType):
"""
@@ -1447,14 +1435,14 @@
@classproperty
- def _resourceIDFromOwnerQuery(cls): #@NoSelf
+ def _resourceIDFromOwnerQuery(cls): #@NoSelf
home = cls._homeSchema
return Select([home.RESOURCE_ID],
From=home, Where=home.OWNER_UID == Parameter("ownerUID"))
@classproperty
- def _ownerFromResourceID(cls): #@NoSelf
+ def _ownerFromResourceID(cls): #@NoSelf
home = cls._homeSchema
return Select([home.OWNER_UID],
From=home,
@@ -1462,7 +1450,7 @@
@classproperty
- def _metaDataQuery(cls): #@NoSelf
+ def _metaDataQuery(cls): #@NoSelf
metadata = cls._homeMetaDataSchema
return Select(cls.metadataColumns(),
From=metadata,
@@ -1587,7 +1575,7 @@
Return=cls._homeSchema.RESOURCE_ID).on(txn))[0][0]
yield Insert(
{cls._homeMetaDataSchema.RESOURCE_ID: resourceid}).on(txn)
- except Exception: # FIXME: Really want to trap the pg.DatabaseError but in a non-DB specific manner
+ except Exception: # FIXME: Really want to trap the pg.DatabaseError but in a non-DB specific manner
yield savepoint.rollback(txn)
# Retry the query - row may exist now, if not re-raise
@@ -1711,48 +1699,50 @@
return self._childClass.listObjects(self)
- def listInvitedChildren(self):
+ @memoizedKey("name", "_children")
+ def childWithName(self, name):
"""
- Retrieve the names of the invited children in this home.
+ Retrieve the child with the given C{name} contained in this
+ home.
- @return: an iterable of C{str}s.
+ @param name: a string.
+ @return: an L{ICalendar} or C{None} if no such child exists.
"""
- return self._childClass.listInvitedObjects(self)
+ return self._childClass.objectWithName(self, name)
- @memoizedKey("name", "_children")
- def childWithName(self, name):
+ def objectWithShareUID(self, shareUID):
"""
- Retrieve the child with the given C{name} contained in this
+ Retrieve the child with the given bind identifier contained in this
home.
@param name: a string.
@return: an L{ICalendar} or C{None} if no such child exists.
"""
- return self._childClass.objectWithName(self, name)
+ return self.childWithName(shareUID)
- @memoizedKey("resourceID", "_children")
- def childWithID(self, resourceID):
+ def invitedObjectWithShareUID(self, shareUID):
"""
- Retrieve the child with the given C{resourceID} contained in this
+ Retrieve the child invitation with the given bind identifier contained in this
home.
@param name: a string.
@return: an L{ICalendar} or C{None} if no such child exists.
"""
- return self._childClass.objectWithID(self, resourceID)
+ return self._childClass.objectWithName(self, shareUID, accepted=False)
- def invitedChildWithName(self, name):
+ @memoizedKey("resourceID", "_children")
+ def childWithID(self, resourceID):
"""
- Retrieve the invited child with the given C{name} contained in this
+ Retrieve the child with the given C{resourceID} contained in this
home.
@param name: a string.
@return: an L{ICalendar} or C{None} if no such child exists.
"""
- return self._childClass.invitedObjectWithName(self, name)
+ return self._childClass.objectWithID(self, resourceID)
@inlineCallbacks
@@ -1778,7 +1768,7 @@
@classproperty
- def _syncTokenQuery(cls): #@NoSelf
+ def _syncTokenQuery(cls): #@NoSelf
"""
DAL Select statement to find the sync token.
@@ -1842,7 +1832,7 @@
@classproperty
- def _changesQuery(cls): #@NoSelf
+ def _changesQuery(cls): #@NoSelf
bind = cls._bindSchema
rev = cls._revisionsSchema
return Select(
@@ -1863,6 +1853,18 @@
)
+ @inlineCallbacks
+ def doChangesQuery(self, revision):
+ """
+ Do the changes query.
+ Subclasses may override.
+ """
+ result = yield self._changesQuery.on(self._txn,
+ resourceID=self._resourceID,
+ revision=revision)
+ returnValue(result)
+
+
def resourceNamesSinceToken(self, token, depth):
"""
Return the changed and deleted resources since a particular sync-token. This simply extracts
@@ -1904,9 +1906,7 @@
wasdeleted
)
for path, collection, name, wasdeleted in
- (yield self._changesQuery.on(self._txn,
- resourceID=self._resourceID,
- revision=revision))
+ (yield self.doChangesQuery(revision))
]
changed = set()
@@ -2040,12 +2040,12 @@
@classproperty
- def _resourceByUIDQuery(cls): #@NoSelf
+ def _resourceByUIDQuery(cls): #@NoSelf
return cls._objectResourceQuery(checkBindMode=False)
@classproperty
- def _resourceByUIDBindQuery(cls): #@NoSelf
+ def _resourceByUIDBindQuery(cls): #@NoSelf
return cls._objectResourceQuery(checkBindMode=True)
@@ -2106,7 +2106,7 @@
@classproperty
- def _quotaQuery(cls): #@NoSelf
+ def _quotaQuery(cls): #@NoSelf
meta = cls._homeMetaDataSchema
return Select(
[meta.QUOTA_USED_BYTES], From=meta,
@@ -2123,7 +2123,7 @@
@classproperty
- def _preLockResourceIDQuery(cls): #@NoSelf
+ def _preLockResourceIDQuery(cls): #@NoSelf
meta = cls._homeMetaDataSchema
return Select(From=meta,
Where=meta.RESOURCE_ID == Parameter("resourceID"),
@@ -2131,7 +2131,7 @@
@classproperty
- def _increaseQuotaQuery(cls): #@NoSelf
+ def _increaseQuotaQuery(cls): #@NoSelf
meta = cls._homeMetaDataSchema
return Update({meta.QUOTA_USED_BYTES: meta.QUOTA_USED_BYTES +
Parameter("delta")},
@@ -2140,7 +2140,7 @@
@classproperty
- def _resetQuotaQuery(cls): #@NoSelf
+ def _resetQuotaQuery(cls): #@NoSelf
meta = cls._homeMetaDataSchema
return Update({meta.QUOTA_USED_BYTES: 0},
Where=meta.RESOURCE_ID == Parameter("resourceID"))
@@ -2206,7 +2206,7 @@
@classproperty
- def _lockLastModifiedQuery(cls): #@NoSelf
+ def _lockLastModifiedQuery(cls): #@NoSelf
meta = cls._homeMetaDataSchema
return Select(
From=meta,
@@ -2217,7 +2217,7 @@
@classproperty
- def _changeLastModifiedQuery(cls): #@NoSelf
+ def _changeLastModifiedQuery(cls): #@NoSelf
meta = cls._homeMetaDataSchema
return Update({meta.MODIFIED: utcNowSQL},
Where=meta.RESOURCE_ID == Parameter("resourceID"),
@@ -2265,7 +2265,18 @@
).on(self._txn, **kwds)
+ @inlineCallbacks
+ def ownerHomeAndChildNameForChildID(self, resourceID):
+ """
+ Get the owner home for a shared child ID and the owner's name for that bound child.
+ Subclasses may override.
+ """
+ ownerHomeID, ownerName = (yield self._childClass._ownerHomeWithResourceID.on(self._txn, resourceID=resourceID))[0]
+ ownerHome = yield self._txn.homeWithResourceID(self._homeType, ownerHomeID)
+ returnValue((ownerHome, ownerName))
+
+
class _SharedSyncLogic(object):
"""
Logic for maintaining sync-token shared between notification collections and
@@ -2273,7 +2284,7 @@
"""
@classproperty
- def _childSyncTokenQuery(cls): #@NoSelf
+ def _childSyncTokenQuery(cls): #@NoSelf
"""
DAL query for retrieving the sync token of a L{CommonHomeChild} based on
its resource ID.
@@ -2306,7 +2317,7 @@
@classproperty
- def _objectNamesSinceRevisionQuery(cls): #@NoSelf
+ def _objectNamesSinceRevisionQuery(cls): #@NoSelf
"""
DAL query for (resource, deleted-flag)
"""
@@ -2360,7 +2371,7 @@
@classproperty
- def _removeDeletedRevision(cls): #@NoSelf
+ def _removeDeletedRevision(cls): #@NoSelf
rev = cls._revisionsSchema
return Delete(From=rev,
Where=(rev.HOME_RESOURCE_ID == Parameter("homeID")).And(
@@ -2368,7 +2379,7 @@
@classproperty
- def _addNewRevision(cls): #@NoSelf
+ def _addNewRevision(cls): #@NoSelf
rev = cls._revisionsSchema
return Insert({rev.HOME_RESOURCE_ID: Parameter("homeID"),
rev.RESOURCE_ID: Parameter("resourceID"),
@@ -2393,7 +2404,7 @@
@classproperty
- def _renameSyncTokenQuery(cls): #@NoSelf
+ def _renameSyncTokenQuery(cls): #@NoSelf
"""
DAL query to change sync token for a rename (increment and adjust
resource name).
@@ -2418,7 +2429,7 @@
@classproperty
- def _bumpSyncTokenQuery(cls): #@NoSelf
+ def _bumpSyncTokenQuery(cls): #@NoSelf
"""
DAL query to change collection sync token.
"""
@@ -2441,7 +2452,7 @@
@classproperty
- def _deleteSyncTokenQuery(cls): #@NoSelf
+ def _deleteSyncTokenQuery(cls): #@NoSelf
"""
DAL query to update a sync revision to be a tombstone instead.
"""
@@ -2455,7 +2466,7 @@
@classproperty
- def _sharedRemovalQuery(cls): #@NoSelf
+ def _sharedRemovalQuery(cls): #@NoSelf
"""
DAL query to update the sync token for a shared collection.
"""
@@ -2470,7 +2481,7 @@
@classproperty
- def _unsharedRemovalQuery(cls): #@NoSelf
+ def _unsharedRemovalQuery(cls): #@NoSelf
"""
DAL query to update the sync token for an owned collection.
"""
@@ -2517,7 +2528,7 @@
@classproperty
- def _deleteBumpTokenQuery(cls): #@NoSelf
+ def _deleteBumpTokenQuery(cls): #@NoSelf
rev = cls._revisionsSchema
return Update({rev.REVISION: schema.REVISION_SEQ,
rev.DELETED: True},
@@ -2527,7 +2538,7 @@
@classproperty
- def _updateBumpTokenQuery(cls): #@NoSelf
+ def _updateBumpTokenQuery(cls): #@NoSelf
rev = cls._revisionsSchema
return Update({rev.REVISION: schema.REVISION_SEQ},
Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
@@ -2536,7 +2547,7 @@
@classproperty
- def _insertFindPreviouslyNamedQuery(cls): #@NoSelf
+ def _insertFindPreviouslyNamedQuery(cls): #@NoSelf
rev = cls._revisionsSchema
return Select([rev.RESOURCE_ID], From=rev,
Where=(rev.RESOURCE_ID == Parameter("resourceID")).And(
@@ -2544,7 +2555,7 @@
@classproperty
- def _updatePreviouslyNamedQuery(cls): #@NoSelf
+ def _updatePreviouslyNamedQuery(cls): #@NoSelf
rev = cls._revisionsSchema
return Update({rev.REVISION: schema.REVISION_SEQ,
rev.DELETED: False},
@@ -2554,7 +2565,7 @@
@classproperty
- def _completelyNewRevisionQuery(cls): #@NoSelf
+ def _completelyNewRevisionQuery(cls): #@NoSelf
rev = cls._revisionsSchema
return Insert({rev.HOME_RESOURCE_ID: Parameter("homeID"),
rev.RESOURCE_ID: Parameter("resourceID"),
@@ -2615,231 +2626,113 @@
-class CommonHomeChild(LoggingMixIn, FancyEqMixin, Memoizable, _SharedSyncLogic, HomeChildBase):
+class SharingMixIn(object):
"""
- Common ancestor class of AddressBooks and Calendars.
+ Common class for CommonHomeChild and AddressBookObject
"""
- compareAttributes = (
- "_name",
- "_home",
- "_resourceID",
- )
-
- _objectResourceClass = None
-
- _bindSchema = None
- _homeSchema = None
- _homeChildSchema = None
- _homeChildMetaDataSchema = None
- _revisionsSchema = None
- _objectSchema = None
-
- _bindTable = None
- _homeChildTable = None
- _homeChildBindTable = None
- _revisionsTable = None
- _revisionsBindTable = None
- _objectTable = None
-
-
- def __init__(self, home, name, resourceID, mode, status, revision=0, message=None, ownerHome=None, ownerName=None):
-
- self._home = home
- self._name = name
- self._resourceID = resourceID
- self._bindMode = mode
- self._bindStatus = status
- self._bindMessage = message
- self._bindRevision = revision
- self._ownerHome = home if ownerHome is None else ownerHome
- self._ownerName = name if ownerName is None else ownerName
- self._created = None
- self._modified = None
- self._objects = {}
- self._objectNames = None
- self._syncTokenRevision = None
-
- # Always use notifiers based off the owner home so that shared collections use tokens common
- # to the owner - and thus will be the same for each sharee. Without that, each sharee would have
- # a different token to subscribe to and thus would each need a separate push - whereas a common
- # token only requires one push (to multiple subscribers).
- if self._ownerHome._notifiers:
- self._notifiers = dict([(factory_name, notifier.clone(self),) for factory_name, notifier in self._ownerHome._notifiers.items()])
- else:
- self._notifiers = None
-
- self._index = None # Derived classes need to set this
-
-
- def memoMe(self, key, memo):
+ @classproperty
+ def _bindInsertQuery(cls, **kw): #@NoSelf #@UnusedVariable
"""
- Add this object to the memo dictionary in whatever fashion is appropriate.
-
- @param key: key used for lookup
- @type key: C{object} (typically C{str} or C{int})
- @param memo: the dict to store to
- @type memo: C{dict}
+ DAL statement to create a bind entry that connects a collection to its
+ home.
"""
- memo[self._name] = self
- memo[self._resourceID] = self
-
-
- @classproperty
- def _childNamesForHomeID(cls): #@NoSelf
bind = cls._bindSchema
- return Select([bind.RESOURCE_NAME], From=bind,
- Where=(bind.HOME_RESOURCE_ID ==
- Parameter("homeID")).And
- (bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
+ return Insert({
+ bind.HOME_RESOURCE_ID: Parameter("homeID"),
+ bind.RESOURCE_ID: Parameter("resourceID"),
+ bind.RESOURCE_NAME: Parameter("name"),
+ bind.BIND_MODE: Parameter("mode"),
+ bind.BIND_STATUS: Parameter("bindStatus"),
+ bind.MESSAGE: Parameter("message"),
+ })
@classmethod
- def metadataColumns(cls):
- """
- Return a list of column name for retrieval of metadata. This allows
- different child classes to have their own type specific data, but still make use of the
- common base logic.
- """
+ def _updateBindColumnsQuery(cls, columnMap): #@NoSelf
+ bind = cls._bindSchema
+ return Update(columnMap,
+ Where=(bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
+ Return=bind.RESOURCE_NAME)
- # Common behavior is to have created and modified
- return (
- cls._homeChildMetaDataSchema.CREATED,
- cls._homeChildMetaDataSchema.MODIFIED,
- )
+ @classproperty
+ def _updateBindQuery(cls): #@NoSelf
+ bind = cls._bindSchema
+ return cls._updateBindColumnsQuery(
+ {bind.BIND_MODE: Parameter("mode"),
+ bind.BIND_STATUS: Parameter("status"),
+ bind.MESSAGE: Parameter("message")})
- @classmethod
- def metadataAttributes(cls):
- """
- Return a list of attribute names for retrieval of metadata. This allows
- different child classes to have their own type specific data, but still make use of the
- common base logic.
- """
-
- # Common behavior is to have created and modified
-
- return (
- "_created",
- "_modified",
+ @classproperty
+ def _deleteBindForResourceIDAndHomeID(cls): #@NoSelf
+ bind = cls._bindSchema
+ return Delete(
+ From=bind,
+ Where=(bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
+ Return=bind.RESOURCE_NAME,
)
@classmethod
- def regularBindColumns(cls):
- """
- Return a list of column names for retrieval during creation. This allows
- different child classes to have their own type specific data, but still make use of the
- common base logic.
- """
-
- return (
- cls._bindSchema.BIND_MODE,
- cls._bindSchema.HOME_RESOURCE_ID,
- cls._bindSchema.RESOURCE_ID,
- cls._bindSchema.RESOURCE_NAME,
- cls._bindSchema.BIND_STATUS,
- cls._bindSchema.BIND_REVISION,
- cls._bindSchema.MESSAGE
+ def _bindFor(cls, condition): #@NoSelf
+ bind = cls._bindSchema
+ columns = cls.bindColumns() + cls.additionalBindColumns()
+ return Select(
+ columns,
+ From=bind,
+ Where=condition
)
- bindColumnCount = 7
- @classmethod
- def additionalBindColumns(cls):
- """
- Return a list of column names for retrieval during creation. This allows
- different child classes to have their own type specific data, but still make use of the
- common base logic.
- """
+ @classproperty
+ def _sharedBindForResourceID(cls): #@NoSelf
+ bind = cls._bindSchema
+ return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+ .And(bind.BIND_MODE != _BIND_MODE_OWN)
+ )
- return ()
-
-
- @classmethod
- def additionalBindAttributes(cls):
- """
- Return a list of attribute names for retrieval of during creation. This allows
- different child classes to have their own type specific data, but still make use of the
- common base logic.
- """
-
- return ()
-
-
- @classmethod
- @inlineCallbacks
- def listObjects(cls, home):
- """
- Retrieve the names of the children that exist in the given home.
-
- @return: an iterable of C{str}s.
- """
- # FIXME: tests don't cover this as directly as they should.
- rows = yield cls._childNamesForHomeID.on(
- home._txn, homeID=home._resourceID)
- names = [row[0] for row in rows]
- returnValue(names)
-
-
@classproperty
- def _invitedBindForHomeID(cls): #@NoSelf
+ def _acceptedBindForHomeID(cls): #@NoSelf
bind = cls._bindSchema
return cls._bindFor((bind.HOME_RESOURCE_ID == Parameter("homeID"))
- .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED))
+ .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
- @classmethod
- @inlineCallbacks
- def listInvitedObjects(cls, home):
- """
- Retrieve the names of the children with invitations in the given home.
-
- @return: an iterable of C{str}s.
- """
- rows = yield cls._invitedBindForHomeID.on(
- home._txn, homeID=home._resourceID
- )
- names = [row[3] for row in rows]
- returnValue(names)
-
-
@classproperty
- def _childrenAndMetadataForHomeID(cls): #@NoSelf
+ def _unacceptedBindForResourceID(cls): #@NoSelf
bind = cls._bindSchema
- child = cls._homeChildSchema
- childMetaData = cls._homeChildMetaDataSchema
+ return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+ )
- columns = list(cls.regularBindColumns())
- columns.extend(cls.additionalBindColumns())
- columns.extend(cls.metadataColumns())
- return Select(columns,
- From=child.join(
- bind, child.RESOURCE_ID == bind.RESOURCE_ID,
- 'left outer').join(
- childMetaData, childMetaData.RESOURCE_ID == bind.RESOURCE_ID,
- 'left outer'),
- Where=(bind.HOME_RESOURCE_ID == Parameter("homeID")
- ).And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
-
- @classmethod
- def _updateBindColumnsQuery(cls, columnMap): #@NoSelf
+ @classproperty
+ def _bindForResourceIDAndHomeID(cls): #@NoSelf
+ """
+ DAL query that looks up home bind rows by home child
+ resource ID and home resource ID.
+ """
bind = cls._bindSchema
- return Update(columnMap,
- Where=(bind.RESOURCE_ID == Parameter("resourceID"))
- .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
- Return=bind.RESOURCE_NAME)
+ return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ )
@classproperty
- def _updateBindQuery(cls): #@NoSelf
+ def _bindForNameAndHomeID(cls): #@NoSelf
+ """
+ DAL query that looks up any bind rows by home child
+ resource ID and home resource ID.
+ """
bind = cls._bindSchema
- return cls._updateBindColumnsQuery(
- {bind.BIND_MODE: Parameter("mode"),
- bind.BIND_STATUS: Parameter("status"),
- bind.MESSAGE: Parameter("message")})
+ return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ )
@inlineCallbacks
@@ -2854,9 +2747,8 @@
L{_BIND_MODE_WRITE} or L{_BIND_MODE_DIRECT}
@type mode: L{str}
- @param status: The sharing mode; L{_BIND_STATUS_INVITED} or
- L{_BIND_STATUS_ACCEPTED} or L{_BIND_STATUS_DECLINED} or
- L{_BIND_STATUS_INVALID}.
+ @param status: The sharing status; L{_BIND_STATUS_INVITED} or
+ L{_BIND_STATUS_ACCEPTED}
@type mode: L{str}
@param message: The proposed message to go along with the share, which
@@ -2875,31 +2767,32 @@
newName = str(uuid4())
yield self._bindInsertQuery.on(
subt, homeID=shareeHome._resourceID,
- resourceID=self._resourceID, name=newName, mode=mode,
- seenByOwner=True, seenBySharee=True,
- bindStatus=status, message=message
+ resourceID=self._resourceID, name=newName,
+ mode=mode, bindStatus=status, message=message
)
returnValue(newName)
try:
- sharedName = yield self._txn.subtransaction(doInsert)
+ bindName = yield self._txn.subtransaction(doInsert)
except AllRetriesFailed:
# FIXME: catch more specific exception
- sharedName = (yield self._updateBindQuery.on(
- self._txn,
- mode=mode, status=status, message=message,
- resourceID=self._resourceID, homeID=shareeHome._resourceID
- ))[0][0]
+ child = yield shareeHome.childWithID(self._resourceID)
+ if not child:
+ child = yield shareeHome.objectWithID(shareeHome, self._resourceID, accepted=False)
+ bindName = yield self.updateShare(
+ child, mode=mode, status=status,
+ message=message
+ )
+ else:
+ if status == _BIND_STATUS_ACCEPTED:
+ shareeView = yield shareeHome.objectWithShareUID(bindName)
+ yield shareeView._initSyncToken()
+ yield shareeView._initBindRevision()
- if status == _BIND_STATUS_ACCEPTED:
- shareeView = yield shareeHome.childWithName(sharedName)
- yield shareeView._initSyncToken()
- yield shareeView._initBindRevision()
-
# Must send notification to ensure cache invalidation occurs
yield self.notifyChanged()
yield shareeHome.notifyChanged()
- returnValue(sharedName)
+ returnValue(bindName)
@inlineCallbacks
@@ -2915,7 +2808,7 @@
L{_BIND_MODE_WRITE} or None to not update
@type mode: L{str}
- @param status: The sharing mode; L{_BIND_STATUS_INVITED} or
+ @param status: The sharing status; L{_BIND_STATUS_INVITED} or
L{_BIND_STATUS_ACCEPTED} or L{_BIND_STATUS_DECLINED} or
L{_BIND_STATUS_INVALID} or None to not update
@type status: L{str}
@@ -2943,25 +2836,28 @@
if len(columnMap):
- #TODO: with bit of parameter wrangling, call shareWith() here instead.
sharedname = yield self._updateBindColumnsQuery(columnMap).on(
self._txn,
resourceID=self._resourceID, homeID=shareeView._home._resourceID
)
#update affected attributes
- if mode:
+ if mode is not None:
shareeView._bindMode = columnMap[bind.BIND_MODE]
- if status:
+ if status is not None:
shareeView._bindStatus = columnMap[bind.BIND_STATUS]
if shareeView._bindStatus == _BIND_STATUS_ACCEPTED:
yield shareeView._initSyncToken()
yield shareeView._initBindRevision()
+ shareeView._home._children[shareeView._name] = shareeView
+ shareeView._home._children[shareeView._resourceID] = shareeView
elif shareeView._bindStatus == _BIND_STATUS_DECLINED:
shareeView._deletedSyncToken(sharedRemoval=True)
+ shareeView._home._children.pop(shareeView._name, None)
+ shareeView._home._children.pop(shareeView._resourceID, None)
- if message:
+ if message is not None:
shareeView._bindMessage = columnMap[bind.MESSAGE]
queryCacher = self._txn._queryCacher
@@ -2989,44 +2885,112 @@
@param shareeHome: The home with which this L{CommonHomeChild} was
previously shared.
- @return: a L{Deferred} which will fire with the previously-used name.
+ @return: a L{Deferred} which will fire with the previous shareUID
"""
-
#remove sync tokens
shareeChildren = yield shareeHome.children()
for shareeChild in shareeChildren:
if not shareeChild.owned() and shareeChild._resourceID == self._resourceID:
shareeChild._deletedSyncToken(sharedRemoval=True)
+ shareeHome._children.pop(shareeChild._name, None)
+ shareeHome._children.pop(shareeChild._resourceID, None)
- queryCacher = self._txn._queryCacher
- if queryCacher:
- cacheKey = queryCacher.keyForObjectWithName(shareeHome._resourceID, shareeChild._name)
- queryCacher.invalidateAfterCommit(self._txn, cacheKey)
-
+ # Must send notification to ensure cache invalidation occurs
+ yield self.notifyChanged()
+ yield shareeHome.notifyChanged()
break
- bind = self._bindSchema
- rows = yield Delete(
- From=bind,
- Where=(bind.RESOURCE_ID == Parameter("resourceID"))
- .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
- Return=bind.RESOURCE_NAME,
- ).on(self._txn, resourceID=self._resourceID,
+ # delete binds including invites
+ deletedBindNameRows = yield self._deleteBindForResourceIDAndHomeID.on(self._txn, resourceID=self._resourceID,
homeID=shareeHome._resourceID)
- resourceName = None
- if rows:
- resourceName = rows[0][0]
- shareeHome._children.pop(resourceName, None)
+ if deletedBindNameRows:
+ deletedBindName = deletedBindNameRows[0][0]
+ queryCacher = self._txn._queryCacher
+ if queryCacher:
+ cacheKey = queryCacher.keyForObjectWithName(shareeHome._resourceID, shareeChild._name)
+ queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+ else:
+ deletedBindName = None
- # Must send notification to ensure cache invalidation occurs
- yield self.notifyChanged()
- yield shareeHome.notifyChanged()
+ returnValue(deletedBindName)
- returnValue(resourceName)
+ @inlineCallbacks
+ def unshare(self):
+ """
+ Unshares a collection, regardless of which "direction" it was shared.
+ """
+ if self.owned():
+ # This collection may be shared to others
+ for sharedToHome in [x.viewerHome() for x in (yield self.asShared())]:
+ yield self.unshareWith(sharedToHome)
+ else:
+ # This collection is shared to me
+ ownerHomeChild = yield self.ownerHome().childWithID(self._resourceID)
+ yield ownerHomeChild.unshareWith(self._home)
+
@inlineCallbacks
+ def asShared(self):
+ """
+ Retrieve all the versions of this L{CommonHomeChild} as it is shared to
+ everyone.
+
+ @see: L{ICalendarHome.asShared}
+
+ @return: L{CommonHomeChild} objects that represent this
+ L{CommonHomeChild} as a child of different L{CommonHome}s
+ @rtype: a L{Deferred} which fires with a L{list} of L{ICalendar}s.
+ """
+ if not self.owned():
+ returnValue([])
+
+ # get all accepted binds
+ acceptedRows = yield self._sharedBindForResourceID.on(
+ self._txn, resourceID=self._resourceID,
+ )
+
+ result = []
+ for row in acceptedRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = row[:self.bindColumnCount] #@UnusedVariable
+ home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+ new = yield home.objectWithShareUID(bindName)
+ result.append(new)
+
+ returnValue(result)
+
+
+ @inlineCallbacks
+ def asInvited(self):
+ """
+ Retrieve all the versions of this L{CommonHomeChild} as it is invited to
+ everyone.
+
+ @see: L{ICalendarHome.asInvited}
+
+ @return: L{CommonHomeChild} objects that represent this
+ L{CommonHomeChild} as a child of different L{CommonHome}s
+ @rtype: a L{Deferred} which fires with a L{list} of L{ICalendar}s.
+ """
+ if not self.owned():
+ returnValue([])
+
+ rows = yield self._unacceptedBindForResourceID.on(
+ self._txn, resourceID=self._resourceID,
+ )
+
+ result = []
+ for row in rows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = row[:self.bindColumnCount] #@UnusedVariable
+ home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+ new = yield home.invitedObjectWithShareUID(bindName)
+ result.append(new)
+
+ returnValue(result)
+
+
+ @inlineCallbacks
def _initBindRevision(self):
bind = self._bindSchema
self._bindRevision = self._syncTokenRevision
@@ -3064,7 +3028,7 @@
@return: C{True} if shared, C{False} otherwise
@rtype: C{bool}
"""
- return self._bindMode == _BIND_MODE_OWN and self._bindMessage == "shared"
+ return self.owned() and self._bindMessage == "shared"
@inlineCallbacks
@@ -3073,7 +3037,7 @@
Set an owned collection to shared or unshared state. Technically this is not useful as "shared"
really means it has invitees, but the current sharing spec supports a notion of a shared collection
that has not yet had invitees added. For the time being we will support that option by using a new
- BINS_STATUS value to indicate an owned collection that is "shared".
+ MESSAGE value to indicate an owned collection that is "shared".
@param shared: whether or not the owned collection is "shared"
@type shared: C{bool}
@@ -3114,134 +3078,198 @@
return self.name()
- @inlineCallbacks
- def unshare(self, homeType):
+ @classmethod
+ def metadataColumns(cls):
"""
- Unshares a collection, regardless of which "direction" it was shared.
-
- @param homeType: a valid store type (ECALENDARTYPE or EADDRESSBOOKTYPE)
+ Return a list of column name for retrieval of metadata. This allows
+ different child classes to have their own type specific data, but still make use of the
+ common base logic.
"""
- if self.owned():
- # This collection may be shared to others
- for sharedToHome in [x.viewerHome() for x in (yield self.asShared())]:
- (yield self.unshareWith(sharedToHome))
- else:
- # This collection is shared to me
- sharerHomeID = (yield self.sharerHomeID())
- sharerHome = (yield self._txn.homeWithResourceID(homeType,
- sharerHomeID))
- sharerCollection = (yield sharerHome.childWithID(self._resourceID))
- (yield sharerCollection.unshareWith(self._home))
+ # Common behavior is to have created and modified
- @classmethod
- def _bindFor(cls, condition): #@NoSelf
- bind = cls._bindSchema
- columns = list(cls.regularBindColumns())
- columns.extend(cls.additionalBindColumns())
- return Select(
- columns,
- From=bind,
- Where=condition
+ return (
+ cls._homeChildMetaDataSchema.CREATED,
+ cls._homeChildMetaDataSchema.MODIFIED,
)
- @classproperty
- def _sharedBindForResourceID(cls): #@NoSelf
- bind = cls._bindSchema
- return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
- .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
- .And(bind.BIND_MODE != _BIND_MODE_OWN)
- )
+ @classmethod
+ def metadataAttributes(cls):
+ """
+ Return a list of attribute names for retrieval of metadata. This allows
+ different child classes to have their own type specific data, but still make use of the
+ common base logic.
+ """
+ # Common behavior is to have created and modified
- @inlineCallbacks
- def asShared(self):
- """
- Retrieve all the versions of this L{CommonHomeChild} as it is shared to
- everyone.
+ return (
+ "_created",
+ "_modified",
+ )
- @see: L{ICalendarHome.asShared}
- @return: L{CommonHomeChild} objects that represent this
- L{CommonHomeChild} as a child of different L{CommonHome}s
- @rtype: a L{Deferred} which fires with a L{list} of L{ICalendar}s.
+ @classmethod
+ def bindColumns(cls):
"""
- if not self.owned():
- returnValue([])
+ Return a list of column names for retrieval during creation. This allows
+ different child classes to have their own type specific data, but still make use of the
+ common base logic.
+ """
- # get all accepted binds
- acceptedRows = yield self._sharedBindForResourceID.on(
- self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+ return (
+ cls._bindSchema.BIND_MODE,
+ cls._bindSchema.HOME_RESOURCE_ID,
+ cls._bindSchema.RESOURCE_ID,
+ cls._bindSchema.RESOURCE_NAME,
+ cls._bindSchema.BIND_STATUS,
+ cls._bindSchema.BIND_REVISION,
+ cls._bindSchema.MESSAGE
)
- cls = self.__class__ # for ease of grepping...
- result = []
- for item in acceptedRows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindRevision, bindMessage = item[:self.bindColumnCount] #@UnusedVariable
- additionalBind = item[self.bindColumnCount:]
+ bindColumnCount = 7
- assert bindStatus == _BIND_STATUS_ACCEPTED
- # TODO: this could all be issued in parallel; no need to serialize
- # the loop.
- new = cls(
- home=(yield self._txn.homeWithResourceID(self._home._homeType, homeID)),
- name=resourceName, resourceID=self._resourceID,
- mode=bindMode, status=bindStatus,
- revision=bindRevision,
- message=bindMessage, ownerHome=self._home
- )
- yield new.initFromStore(additionalBind)
- result.append(new)
- returnValue(result)
+ @classmethod
+ def additionalBindColumns(cls):
+ """
+ Return a list of column names for retrieval during creation. This allows
+ different child classes to have their own type specific data, but still make use of the
+ common base logic.
+ """
+ return ()
+
+ @classmethod
+ def additionalBindAttributes(cls):
+ """
+ Return a list of attribute names for retrieval of during creation. This allows
+ different child classes to have their own type specific data, but still make use of the
+ common base logic.
+ """
+
+ return ()
+
@classproperty
- def _invitedBindForResourceID(cls): #@NoSelf
+ def _childrenAndMetadataForHomeID(cls): #@NoSelf
bind = cls._bindSchema
- return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
- .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
- )
+ child = cls._homeChildSchema
+ childMetaData = cls._homeChildMetaDataSchema
+ columns = cls.bindColumns() + cls.additionalBindColumns() + cls.metadataColumns()
+ return Select(columns,
+ From=child.join(
+ bind, child.RESOURCE_ID == bind.RESOURCE_ID,
+ 'left outer').join(
+ childMetaData, childMetaData.RESOURCE_ID == bind.RESOURCE_ID,
+ 'left outer'),
+ Where=(bind.HOME_RESOURCE_ID == Parameter("homeID")
+ ).And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
+
+ @classmethod
+ def _revisionsForResourceIDs(cls, resourceIDs):
+ rev = cls._revisionsSchema
+ return Select(
+ [rev.RESOURCE_ID, Max(rev.REVISION)],
+ From=rev,
+ Where=rev.RESOURCE_ID.In(Parameter("resourceIDs", len(resourceIDs))).
+ And((rev.RESOURCE_NAME != None).Or(rev.DELETED == False)),
+ GroupBy=rev.RESOURCE_ID
+ )
+
+
@inlineCallbacks
- def asInvited(self):
+ def invalidateQueryCache(self):
+ queryCacher = self._txn._queryCacher
+ if queryCacher is not None:
+ cacheKey = queryCacher.keyForHomeChildMetaData(self._resourceID)
+ yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+ cacheKey = queryCacher.keyForObjectWithName(self._home._resourceID, self._name)
+ yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+
+
+
+class CommonHomeChild(LoggingMixIn, FancyEqMixin, Memoizable, _SharedSyncLogic, HomeChildBase, SharingMixIn):
+ """
+ Common ancestor class of AddressBooks and Calendars.
+ """
+
+ compareAttributes = (
+ "_name",
+ "_home",
+ "_resourceID",
+ )
+
+ _objectResourceClass = None
+
+ _bindSchema = None
+ _homeSchema = None
+ _homeChildSchema = None
+ _homeChildMetaDataSchema = None
+ _revisionsSchema = None
+ _objectSchema = None
+
+
+ def __init__(self, home, name, resourceID, mode, status, revision=0, message=None, ownerHome=None, ownerName=None):
+
+ self._home = home
+ self._name = name
+ self._resourceID = resourceID
+ self._bindMode = mode
+ self._bindStatus = status
+ self._bindRevision = revision
+ self._bindMessage = message
+ self._ownerHome = home if ownerHome is None else ownerHome
+ self._ownerName = name if ownerName is None else ownerName
+ self._created = None
+ self._modified = None
+ self._objects = {}
+ self._objectNames = None
+ self._syncTokenRevision = None
+
+ # Always use notifiers based off the owner home so that shared collections use tokens common
+ # to the owner - and thus will be the same for each sharee. Without that, each sharee would have
+ # a different token to subscribe to and thus would each need a separate push - whereas a common
+ # token only requires one push (to multiple subscribers).
+ if self._ownerHome._notifiers:
+ self._notifiers = dict([(factory_name, notifier.clone(self),) for factory_name, notifier in self._ownerHome._notifiers.items()])
+ else:
+ self._notifiers = None
+
+ self._index = None # Derived classes need to set this
+
+
+ def memoMe(self, key, memo): #@UnusedVariable
"""
- Retrieve all the versions of this L{CommonHomeChild} as it is invited to
- everyone.
+ Add this object to the memo dictionary in whatever fashion is appropriate.
- @see: L{ICalendarHome.asInvited}
+ @param key: key used for lookup
+ @type key: C{object} (typically C{str} or C{int})
+ @param memo: the dict to store to
+ @type memo: C{dict}
+ """
+ memo[self._name] = self
+ memo[self._resourceID] = self
- @return: L{CommonHomeChild} objects that represent this
- L{CommonHomeChild} as a child of different L{CommonHome}s
- @rtype: a L{Deferred} which fires with a L{list} of L{ICalendar}s.
+
+ @classmethod
+ @inlineCallbacks
+ def listObjects(cls, home):
"""
- if not self.owned():
- returnValue([])
+ Retrieve the names of the children that exist in the given home.
- rows = yield self._invitedBindForResourceID.on(
- self._txn, resourceID=self._resourceID, homeID=self._home._resourceID,
+ @return: an iterable of C{str}s.
+ """
+ # FIXME: tests don't cover this as directly as they should.
+ rows = yield cls._acceptedBindForHomeID.on(
+ home._txn, homeID=home._resourceID
)
- cls = self.__class__ # for ease of grepping...
+ names = [row[3] for row in rows]
+ returnValue(names)
- result = []
- for item in rows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindRevision, bindMessage = item[:self.bindColumnCount] #@UnusedVariable
- additionalBind = item[self.bindColumnCount:]
- # TODO: this could all be issued in parallel; no need to serialize
- # the loop.
- new = cls(
- home=(yield self._txn.homeWithResourceID(self._home._homeType, homeID)),
- name=resourceName, resourceID=self._resourceID,
- mode=bindMode, status=bindStatus,
- revision=bindRevision,
- message=bindMessage, ownerHome=self._home
- )
- yield new.initFromStore(additionalBind)
- result.append(new)
- returnValue(result)
-
@classmethod
@inlineCallbacks
def loadAllObjects(cls, home):
@@ -3258,45 +3286,43 @@
dataRows = (yield cls._childrenAndMetadataForHomeID.on(home._txn, homeID=home._resourceID))
if dataRows:
+ # Get property stores
+ childResourceIDs = [dataRow[2] for dataRow in dataRows]
- # Get property stores for all these child resources (if any found)
+ # FIXME: The following returns {} for twistedcaldav.test.test_sharing.SharingTests.test_noWikiAccess
+ # propertyStores = yield PropertyStore.forMultipleResourcesWithResourceIDs(
+ # home.uid(), home._txn, childResourceIDs
+ #)
propertyStores = (yield PropertyStore.forMultipleResources(
home.uid(), home._txn,
cls._bindSchema.RESOURCE_ID, cls._bindSchema.HOME_RESOURCE_ID,
home._resourceID
))
- bind = cls._bindSchema
- rev = cls._revisionsSchema
- revisions = (yield Select(
- [rev.RESOURCE_ID, Max(rev.REVISION)],
- From=rev.join(bind, rev.RESOURCE_ID == bind.RESOURCE_ID, 'left'),
- Where=(bind.HOME_RESOURCE_ID == home._resourceID).
- And((rev.RESOURCE_NAME != None).Or(rev.DELETED == False)),
- GroupBy=rev.RESOURCE_ID
- ).on(home._txn))
+ # Get revisions
+ revisions = (yield cls._revisionsForResourceIDs(childResourceIDs).on(home._txn, resourceIDs=childResourceIDs))
revisions = dict(revisions)
# Create the actual objects merging in properties
- for items in dataRows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindRevision, bindMessage = items[:cls.bindColumnCount] #@UnusedVariable
- additionalBind = items[cls.bindColumnCount:cls.bindColumnCount + len(cls.additionalBindColumns())]
- metadata = items[cls.bindColumnCount + len(cls.additionalBindColumns()):]
+ for dataRow in dataRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = dataRow[:cls.bindColumnCount] #@UnusedVariable
+ additionalBind = dataRow[cls.bindColumnCount:cls.bindColumnCount + len(cls.additionalBindColumns())]
+ metadata = dataRow[cls.bindColumnCount + len(cls.additionalBindColumns()):]
- if bindStatus == _BIND_MODE_OWN:
+ if bindMode == _BIND_MODE_OWN:
ownerHome = home
- ownerName = resourceName
+ ownerName = bindName
else:
#TODO: get all ownerHomeIDs at once
- ownerHomeID, ownerName = (yield cls._ownerHomeWithResourceID.on(home._txn, resourceID=resourceID))[0]
- ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
+ ownerHome, ownerName = yield home.ownerHomeAndChildNameForChildID(resourceID)
child = cls(
home=home,
- name=resourceName, resourceID=resourceID,
+ name=bindName, resourceID=resourceID,
mode=bindMode, status=bindStatus,
- revision=bindRevision, message=bindMessage,
- ownerHome=ownerHome, ownerName=ownerName
+ revision=bindRevision,
+ message=bindMessage, ownerHome=ownerHome,
+ ownerName=ownerName,
)
for attr, value in zip(cls.additionalBindAttributes(), additionalBind):
setattr(child, attr, value)
@@ -3307,74 +3333,17 @@
# We have to re-adjust the property store object to account for possible shared
# collections as previously we loaded them all as if they were owned
- if bindStatus != _BIND_MODE_OWN:
+
+ if bindMode != _BIND_MODE_OWN:
propstore._setDefaultUserUID(ownerHome.uid())
yield child._loadPropertyStore(propstore)
results.append(child)
returnValue(results)
- @classproperty
- def _invitedBindForNameAndHomeID(cls): #@NoSelf
- bind = cls._bindSchema
- return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
- .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
- .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
- )
-
-
@classmethod
@inlineCallbacks
- def invitedObjectWithName(cls, home, name):
- """
- Retrieve the child with the given C{name} contained in the given
- C{home}.
-
- @param home: a L{CommonHome}.
-
- @param name: a string; the name of the L{CommonHomeChild} to retrieve.
-
- @param owned: a boolean - whether or not to get a shared child
- @return: an L{CommonHomeChild} or C{None} if no such child
- exists.
- """
- rows = yield cls._invitedBindForNameAndHomeID.on(home._txn,
- name=name, homeID=home._resourceID)
-
- if not rows:
- returnValue(None)
-
- item = rows[0]
- bindMode, homeID, resourceID, resourceName, bindStatus, bindRevision, bindMessage = item[:cls.bindColumnCount] #@UnusedVariable
- additionalBind = item[cls.bindColumnCount:]
-
- #TODO: combine with _invitedBindForNameAndHomeID and sort results
- ownerHomeID, ownerName = (yield cls._ownerHomeWithResourceID.on(home._txn, resourceID=resourceID))[0]
- ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
-
- child = cls(
- home=home,
- name=resourceName, resourceID=resourceID,
- mode=bindMode, status=bindStatus,
- revision=bindRevision, message=bindMessage,
- ownerHome=ownerHome, ownerName=ownerName,
- )
- yield child.initFromStore(additionalBind)
- returnValue(child)
-
-
- @classproperty
- def _childForNameAndHomeID(cls): #@NoSelf
- bind = cls._bindSchema
- return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
- .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
- .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
- )
-
-
- @classmethod
- @inlineCallbacks
- def objectWithName(cls, home, name):
+ def objectWithName(cls, home, name, accepted=True):
# replaces objectWithName()
"""
Retrieve the child with the given C{name} contained in the given
@@ -3397,21 +3366,8 @@
if rows is None:
# No cached copy
- rows = yield cls._childForNameAndHomeID.on(home._txn, name=name, homeID=home._resourceID)
+ rows = yield cls._bindForNameAndHomeID.on(home._txn, name=name, homeID=home._resourceID)
- if rows:
- item = rows[0]
- bindMode, homeID, resourceID, resourceName, bindStatus, bindRevision, bindMessage = item[:cls.bindColumnCount] #@UnusedVariable
- # get ownerHomeID
- if bindMode == _BIND_MODE_OWN:
- ownerHomeID = homeID
- ownerName = resourceName
- else:
- ownerHomeID, ownerName = (yield cls._ownerHomeWithResourceID.on(
- home._txn, resourceID=resourceID))[0]
- rows[0].insert(cls.bindColumnCount, ownerHomeID)
- rows[0].insert(cls.bindColumnCount + 1, ownerName)
-
if rows and queryCacher:
# Cache the result
queryCacher.setAfterCommit(home._txn, cacheKey, rows)
@@ -3419,41 +3375,33 @@
if not rows:
returnValue(None)
- item = rows[0] #@UnusedVariable
- bindMode, homeID, resourceID, resourceName, bindStatus, bindRevision, bindMessage, ownerHomeID, ownerName = item[:cls.bindColumnCount + 2]
- additionalBind = item[cls.bindColumnCount + 2:]
+ row = rows[0]
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = row[:cls.bindColumnCount] #@UnusedVariable
+ if (bindStatus == _BIND_STATUS_ACCEPTED) != bool(accepted):
+ returnValue(None)
+ additionalBind = row[cls.bindColumnCount:cls.bindColumnCount + len(cls.additionalBindColumns())]
if bindMode == _BIND_MODE_OWN:
ownerHome = home
+ ownerName = bindName
else:
- ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
+ ownerHome, ownerName = yield home.ownerHomeAndChildNameForChildID(resourceID)
child = cls(
home=home,
name=name, resourceID=resourceID,
mode=bindMode, status=bindStatus,
- revision=bindRevision, message=bindMessage,
- ownerHome=ownerHome, ownerName=ownerName,
+ revision=bindRevision,
+ message=bindMessage, ownerHome=ownerHome,
+ ownerName=ownerName
)
yield child.initFromStore(additionalBind)
returnValue(child)
- @classproperty
- def _bindForResourceIDAndHomeID(cls): #@NoSelf
- """
- DAL query that looks up home child names / bind modes by home child
- resource ID and home resource ID.
- """
- bind = cls._bindSchema
- return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
- .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
- )
-
-
@classmethod
@inlineCallbacks
- def objectWithID(cls, home, resourceID):
+ def objectWithID(cls, home, resourceID, accepted=True):
"""
Retrieve the child with the given C{resourceID} contained in the given
C{home}.
@@ -3468,29 +3416,19 @@
if not rows:
returnValue(None)
- item = rows[0]
- bindMode, homeID, resourceID, resourceName, bindStatus, bindRevision, bindMessage = item[:cls.bindColumnCount] #@UnusedVariable
- additionalBind = item[cls.bindColumnCount:]
+ row = rows[0]
+ bindMode, homeID, resourceID, bindName, bindStatus, bindRevision, bindMessage = row[:cls.bindColumnCount] #@UnusedVariable]
+ if (bindStatus == _BIND_STATUS_ACCEPTED) != bool(accepted):
+ returnValue(None)
- if bindMode == _BIND_MODE_OWN:
- ownerHome = home
- ownerName = resourceName
+ if accepted:
+ returnValue((yield home.objectWithShareUID(bindName)))
else:
- ownerHomeID, ownerName = (yield cls._ownerHomeWithResourceID.on(home._txn, resourceID=resourceID))[0]
- ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
- child = cls(
- home=home,
- name=resourceName, resourceID=resourceID,
- mode=bindMode, status=bindStatus,
- revision=bindRevision, message=bindMessage,
- ownerHome=ownerHome, ownerName=ownerName,
- )
- yield child.initFromStore(additionalBind)
- returnValue(child)
+ returnValue((yield home.invitedObjectWithShareUID(bindName)))
@classproperty
- def _insertHomeChild(cls): #@NoSelf
+ def _insertHomeChild(cls): #@NoSelf
"""
DAL statement to create a home child with all default values.
"""
@@ -3500,7 +3438,7 @@
@classproperty
- def _insertHomeChildMetaData(cls): #@NoSelf
+ def _insertHomeChildMetaData(cls): #@NoSelf
"""
DAL statement to create a home child with all default values.
"""
@@ -3509,32 +3447,13 @@
Return=(child.CREATED, child.MODIFIED))
- @classproperty
- def _bindInsertQuery(cls, **kw): #@NoSelf
- """
- DAL statement to create a bind entry that connects a collection to its
- home.
- """
- bind = cls._bindSchema
- return Insert({
- bind.HOME_RESOURCE_ID: Parameter("homeID"),
- bind.RESOURCE_ID: Parameter("resourceID"),
- bind.RESOURCE_NAME: Parameter("name"),
- bind.BIND_MODE: Parameter("mode"),
- bind.BIND_STATUS: Parameter("bindStatus"),
- bind.MESSAGE: Parameter("message"),
- })
-
-
@classmethod
@inlineCallbacks
def create(cls, home, name):
- child = (yield cls.objectWithName(home, name))
- if child is not None:
+
+ if (yield cls._bindForNameAndHomeID.on(home._txn,
+ name=name, homeID=home._resourceID)):
raise HomeChildNameAlreadyExistsError(name)
- invite = (yield cls.invitedObjectWithName(home, name))
- if invite is not None:
- raise HomeChildNameAlreadyExistsError(name)
if name.startswith("."):
raise HomeChildNameNotAllowedError(name)
@@ -3547,7 +3466,6 @@
_created, _modified = (
yield cls._insertHomeChildMetaData.on(home._txn,
resourceID=resourceID))[0]
-
# Bind table needs entry
yield cls._bindInsertQuery.on(
home._txn, homeID=home._resourceID, resourceID=resourceID,
@@ -3570,7 +3488,7 @@
@classproperty
- def _metadataByIDQuery(cls): #@NoSelf
+ def _metadataByIDQuery(cls): #@NoSelf
"""
DAL query to retrieve created/modified dates based on a resource ID.
"""
@@ -3639,16 +3557,6 @@
return "<%s: %s>" % (self.__class__.__name__, self._resourceID)
- @inlineCallbacks
- def invalidateQueryCache(self):
- queryCacher = self._txn._queryCacher
- if queryCacher is not None:
- cacheKey = queryCacher.keyForHomeChildMetaData(self._resourceID)
- yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
- cacheKey = queryCacher.keyForObjectWithName(self._home._resourceID, self._name)
- yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
-
-
def exists(self):
"""
An empty resource-id means this object does not yet exist in the DB.
@@ -3661,7 +3569,7 @@
@classproperty
- def _renameQuery(cls): #@NoSelf
+ def _renameQuery(cls): #@NoSelf
"""
DAL statement to rename a L{CommonHomeChild}
"""
@@ -3700,7 +3608,7 @@
@classproperty
- def _deleteQuery(cls): #@NoSelf
+ def _deleteQuery(cls): #@NoSelf
"""
DAL statement to delete a L{CommonHomeChild} by its resource ID.
"""
@@ -3722,7 +3630,7 @@
yield self._deletedSyncToken()
yield self._deleteQuery.on(self._txn, NoSuchHomeChildError,
resourceID=self._resourceID)
- self.properties()._removeResource()
+ yield self.properties()._removeResource()
# Set to non-existent state
self._resourceID = None
@@ -3750,7 +3658,7 @@
@classproperty
- def _ownerHomeWithResourceID(cls): #@NoSelf
+ def _ownerHomeWithResourceID(cls): #@NoSelf
"""
DAL query to retrieve the home resource ID and resource name of the owner from the bound
home-child ID.
@@ -3765,23 +3673,6 @@
@inlineCallbacks
- def sharerHomeID(self):
- """
- Retrieve the resource ID of the owner of this home.
-
- @return: a L{Deferred} that fires with the resource ID.
- @rtype: L{Deferred} firing L{int}
- """
- if self.owned():
- # If this was loaded by its owner then we can skip the query, since
- # we already know who the owner is.
- returnValue(self._home._resourceID)
- else:
- rid, _ignore_rname = (yield self._ownerHomeWithResourceID.on(self._txn, resourceID=self._resourceID))[0]
- returnValue(rid)
-
-
- @inlineCallbacks
def objectResources(self):
"""
Load and cache all children - Depth:1 optimization
@@ -3808,7 +3699,7 @@
@classproperty
- def _objectResourceNamesQuery(cls): #@NoSelf
+ def _objectResourceNamesQuery(cls): #@NoSelf
"""
DAL query to load all object resource names for a home child.
"""
@@ -3827,7 +3718,7 @@
@classproperty
- def _objectCountQuery(cls): #@NoSelf
+ def _objectCountQuery(cls): #@NoSelf
"""
DAL query to count all object resources for a home child.
"""
@@ -3893,7 +3784,7 @@
@classproperty
- def _resourceNameForUIDQuery(cls): #@NoSelf
+ def _resourceNameForUIDQuery(cls): #@NoSelf
"""
DAL query to retrieve the resource name for an object resource based on
its UID column.
@@ -3922,7 +3813,7 @@
@classproperty
- def _resourceUIDForNameQuery(cls): #@NoSelf
+ def _resourceUIDForNameQuery(cls): #@NoSelf
"""
DAL query to retrieve the UID for an object resource based on its
resource name column.
@@ -3983,12 +3874,14 @@
def removedObjectResource(self, child):
self._objects.pop(child.name(), None)
self._objects.pop(child.uid(), None)
+ if self._objectNames and child.name() in self._objectNames:
+ self._objectNames.remove(child.name())
yield self._deleteRevision(child.name())
yield self.notifyChanged()
@classproperty
- def _moveParentUpdateQuery(cls, adjustName=False): #@NoSelf
+ def _moveParentUpdateQuery(cls, adjustName=False): #@NoSelf
"""
DAL query to update a child to be in a new parent.
"""
@@ -4004,7 +3897,7 @@
)
- def _movedObjectResource(self, child, newparent):
+ def _movedObjectResource(self, child, newparent): #@UnusedVariable
"""
Method that subclasses can override to do an extra DB adjustments when a resource
is moved.
@@ -4200,7 +4093,7 @@
@classproperty
- def _lockLastModifiedQuery(cls): #@NoSelf
+ def _lockLastModifiedQuery(cls): #@NoSelf
schema = cls._homeChildMetaDataSchema
return Select(
From=schema,
@@ -4211,7 +4104,7 @@
@classproperty
- def _changeLastModifiedQuery(cls): #@NoSelf
+ def _changeLastModifiedQuery(cls): #@NoSelf
schema = cls._homeChildMetaDataSchema
return Update({schema.MODIFIED: utcNowSQL},
Where=schema.RESOURCE_ID == Parameter("resourceID"),
@@ -4256,13 +4149,11 @@
"_parentCollection",
)
- _objectTable = None
-
_objectSchema = None
BATCH_LOAD_SIZE = 50
- def __init__(self, parent, name, uid, resourceID=None, options=None):
+ def __init__(self, parent, name, uid, resourceID=None, options=None): #@UnusedVariable
self._parentCollection = parent
self._resourceID = resourceID
self._name = name
@@ -4277,12 +4168,18 @@
@classproperty
- def _allColumnsWithParent(cls): #@NoSelf
+ def _allColumnsWithParentQuery(cls): #@NoSelf
obj = cls._objectSchema
return Select(cls._allColumns, From=obj,
Where=obj.PARENT_RESOURCE_ID == Parameter("parentID"))
+ @classmethod
+ @inlineCallbacks
+ def _allColumnsWithParent(cls, parent):
+ returnValue((yield cls._allColumnsWithParentQuery.on(
+ parent._txn, parentID=parent._resourceID)))
+
@classmethod
@inlineCallbacks
def loadAllObjects(cls, parent):
@@ -4296,8 +4193,7 @@
results = []
# Load from the main table first
- dataRows = yield cls._allColumnsWithParent.on(
- parent._txn, parentID=parent._resourceID)
+ dataRows = yield cls._allColumnsWithParent(parent)
if dataRows:
# Get property stores for all these child resources (if any found)
@@ -4325,14 +4221,6 @@
@classmethod
- def _allColumnsWithParentAndNames(cls, names): #@NoSelf
- obj = cls._objectSchema
- return Select(cls._allColumns, From=obj,
- Where=(obj.PARENT_RESOURCE_ID == Parameter("parentID")).And(
- obj.RESOURCE_NAME.In(Parameter("names", len(names)))))
-
-
- @classmethod
@inlineCallbacks
def loadAllObjectsWithNames(cls, parent, names):
"""
@@ -4349,7 +4237,21 @@
@classmethod
+ def _allColumnsWithParentAndNamesQuery(cls, names):
+ obj = cls._objectSchema
+ return Select(cls._allColumns, From=obj,
+ Where=(obj.PARENT_RESOURCE_ID == Parameter("parentID")).And(
+ obj.RESOURCE_NAME.In(Parameter("names", len(names)))))
+
+
+ @classmethod
@inlineCallbacks
+ def _allColumnsWithParentAndNames(cls, parent, names):
+ returnValue((yield cls._allColumnsWithParentAndNamesQuery(names).on(
+ parent._txn, parentID=parent._resourceID, names=names)))
+
+ @classmethod
+ @inlineCallbacks
def _loadAllObjectsWithNames(cls, parent, names):
"""
Load all child objects with the specified names. This must create the
@@ -4366,8 +4268,7 @@
results = []
# Load from the main table first
- dataRows = yield cls._allColumnsWithParentAndNames(names).on(
- parent._txn, parentID=parent._resourceID, names=names)
+ dataRows = yield cls._allColumnsWithParentAndNames(parent, names)
if dataRows:
# Get property stores for all these child resources
@@ -4426,7 +4327,7 @@
@classmethod
- def _allWithParentAnd(cls, column, paramName):
+ def _allColumnsWithParentAnd(cls, column, paramName):
"""
DAL query for all columns where PARENT_RESOURCE_ID matches a parentID
parameter and a given instance column matches a given parameter name.
@@ -4439,19 +4340,18 @@
@classproperty
- def _allWithParentAndName(cls): #@NoSelf
- return cls._allWithParentAnd(cls._objectSchema.RESOURCE_NAME, "name")
+ def _allColumnsWithParentAndName(cls): #@NoSelf
+ return cls._allColumnsWithParentAnd(cls._objectSchema.RESOURCE_NAME, "name")
@classproperty
- def _allWithParentAndUID(cls): #@NoSelf
- return cls._allWithParentAnd(cls._objectSchema.UID, "uid")
+ def _allColumnsWithParentAndUID(cls): #@NoSelf
+ return cls._allColumnsWithParentAnd(cls._objectSchema.UID, "uid")
@classproperty
- def _allWithParentAndID(cls): #@NoSelf
- return cls._allWithParentAnd(cls._objectSchema.RESOURCE_ID,
- "resourceID")
+ def _allColumnsWithParentAndID(cls): #@NoSelf
+ return cls._allColumnsWithParentAnd(cls._objectSchema.RESOURCE_ID, "resourceID")
@inlineCallbacks
@@ -4466,15 +4366,15 @@
"""
if self._name:
- rows = yield self._allWithParentAndName.on(
+ rows = yield self._allColumnsWithParentAndName.on(
self._txn, name=self._name,
parentID=self._parentCollection._resourceID)
elif self._uid:
- rows = yield self._allWithParentAndUID.on(
+ rows = yield self._allColumnsWithParentAndUID.on(
self._txn, uid=self._uid,
parentID=self._parentCollection._resourceID)
elif self._resourceID:
- rows = yield self._allWithParentAndID.on(
+ rows = yield self._allColumnsWithParentAndID.on(
self._txn, resourceID=self._resourceID,
parentID=self._parentCollection._resourceID)
if rows:
@@ -4486,7 +4386,7 @@
@classproperty
- def _allColumns(cls): #@NoSelf
+ def _allColumns(cls): #@NoSelf
"""
Full set of columns in the object table that need to be loaded to
initialize the object resource state.
@@ -4546,6 +4446,7 @@
@param props: the L{PropertyStore} from C{properties()}.
"""
+
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self._resourceID)
@@ -4565,6 +4466,11 @@
return self._parentCollection._txn
+ @property
+ def _home(self):
+ return self._parentCollection._home
+
+
def transaction(self):
return self._parentCollection._txn
@@ -4578,7 +4484,7 @@
@classmethod
- def _selectForUpdateQuery(cls, nowait): #@NoSelf
+ def _selectForUpdateQuery(cls, nowait): #@NoSelf
"""
DAL statement to lock a L{CommonObjectResource} by its resource ID.
"""
@@ -4622,7 +4528,7 @@
@classproperty
- def _deleteQuery(cls): #@NoSelf
+ def _deleteQuery(cls): #@NoSelf
"""
DAL statement to delete a L{CommonObjectResource} by its resource ID.
"""
@@ -4652,7 +4558,7 @@
def remove(self):
yield self._deleteQuery.on(self._txn, NoSuchObjectResourceError,
resourceID=self._resourceID)
- self.properties()._removeResource()
+ yield self.properties()._removeResource()
yield self._parentCollection.removedObjectResource(self)
@@ -4697,7 +4603,7 @@
@classproperty
- def _textByIDQuery(cls): #@NoSelf
+ def _textByIDQuery(cls): #@NoSelf
"""
DAL query to load iCalendar/vCard text via an object's resource ID.
"""
@@ -4733,7 +4639,6 @@
"_resourceID",
)
- _revisionsTable = NOTIFICATION_OBJECT_REVISIONS_TABLE
_revisionsSchema = schema.NOTIFICATION_OBJECT_REVISIONS
_homeSchema = schema.NOTIFICATION_HOME
@@ -4760,6 +4665,7 @@
Return=_homeSchema.RESOURCE_ID
)
+
@property
def _home(self):
"""
@@ -5008,7 +4914,7 @@
@classproperty
- def _completelyNewRevisionQuery(cls): #@NoSelf
+ def _completelyNewRevisionQuery(cls): #@NoSelf
rev = cls._revisionsSchema
return Insert({rev.HOME_RESOURCE_ID: Parameter("homeID"),
# rev.RESOURCE_ID: Parameter("resourceID"),
@@ -5079,7 +4985,7 @@
@classproperty
- def _allColumnsByHomeIDQuery(cls): #@NoSelf
+ def _allColumnsByHomeIDQuery(cls): #@NoSelf
"""
DAL query to load all columns by home ID.
"""
@@ -5138,7 +5044,7 @@
@classproperty
- def _oneNotificationQuery(cls): #@NoSelf
+ def _oneNotificationQuery(cls): #@NoSelf
no = cls._objectSchema
return Select(
[
@@ -5179,7 +5085,7 @@
returnValue(None)
- def _loadPropertyStore(self, props=None, created=False):
+ def _loadPropertyStore(self, props=None, created=False): #@UnusedVariable
if props is None:
props = NonePropertyStore(self._home.uid())
self._propertyStore = props
@@ -5217,7 +5123,7 @@
@classproperty
- def _newNotificationQuery(cls): #@NoSelf
+ def _newNotificationQuery(cls): #@NoSelf
no = cls._objectSchema
return Insert(
{
@@ -5232,7 +5138,7 @@
@classproperty
- def _updateNotificationQuery(cls): #@NoSelf
+ def _updateNotificationQuery(cls): #@NoSelf
no = cls._objectSchema
return Update(
{
@@ -5357,7 +5263,6 @@
)
-
@inlineCallbacks
def mergeHomes(sqlTxn, one, other, homeType):
"""
@@ -5416,7 +5321,6 @@
yield returnValue(newer)
-
def _renameHome(txn, table, oldUID, newUID):
"""
Rename a calendar, addressbook, or notification home. Note that this
@@ -5443,7 +5347,6 @@
Where=table.OWNER_UID == oldUID).on(txn)
-
def _dontBotherWithNotifications(older, newer, merge):
"""
Notifications are more transient and can be easily worked around; don't
@@ -5451,7 +5354,6 @@
"""
-
@inlineCallbacks
def _normalizeHomeUUIDsIn(t, homeType):
"""
@@ -5534,7 +5436,6 @@
returnValue(None)
-
def _getHome(txn, homeType, uid):
"""
Like L{CommonHome.homeWithUID} but also honoring ENOTIFICATIONTYPE which
@@ -5558,7 +5459,6 @@
return txn.homeWithUID(homeType, uid)
-
@inlineCallbacks
def _normalizeColumnUUIDs(txn, column):
"""
@@ -5606,7 +5506,6 @@
return self
-
@inlineCallbacks
def _needsNormalizationUpgrade(txn):
"""
@@ -5630,7 +5529,6 @@
returnValue(False)
-
@inlineCallbacks
def fixUUIDNormalization(store):
"""
Property changes on: CalendarServer/trunk/txdav/common/datastore/sql.py
___________________________________________________________________
Added: svn:mergeinfo
+ /CalDAVTester/trunk/txdav/common/datastore/sql.py:11193-11198
/CalendarServer/branches/config-separation/txdav/common/datastore/sql.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/common/datastore/sql.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/common/datastore/sql.py:6167
/CalendarServer/branches/new-store/txdav/common/datastore/sql.py:5594-5934
/CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/sql.py:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/common/datastore/sql.py:5936-5981
/CalendarServer/branches/release/CalendarServer-4.3-dev/txdav/common/datastore/sql.py:10180-10190,10192
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/common/datastore/sql.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/common/datastore/sql.py:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/sql.py:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/common/datastore/sql.py:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace/txdav/common/datastore/sql.py:8137-8141
/CalendarServer/branches/users/cdaboo/ischedule-dkim/txdav/common/datastore/sql.py:9747-9979
/CalendarServer/branches/users/cdaboo/managed-attachments/txdav/common/datastore/sql.py:9985-10145
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/common/datastore/sql.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/common/datastore/sql.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/common/datastore/sql.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/common/datastore/sql.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/common/datastore/sql.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/common/datastore/sql.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/common/datastore/sql.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/common/datastore/sql.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/common/datastore/sql.py:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging/txdav/common/datastore/sql.py:8730-8743
/CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql.py:11088-11204
/CalendarServer/branches/users/glyph/always-abort-txn-on-error/txdav/common/datastore/sql.py:9958-9969
/CalendarServer/branches/users/glyph/case-insensitive-uid/txdav/common/datastore/sql.py:8772-8805
/CalendarServer/branches/users/glyph/conn-limit/txdav/common/datastore/sql.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/common/datastore/sql.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/common/datastore/sql.py:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect/txdav/common/datastore/sql.py:6824-6876
/CalendarServer/branches/users/glyph/deploybuild/txdav/common/datastore/sql.py:7563-7572
/CalendarServer/branches/users/glyph/digest-auth-redux/txdav/common/datastore/sql.py:10624-10635
/CalendarServer/branches/users/glyph/disable-quota/txdav/common/datastore/sql.py:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/common/datastore/sql.py:6592-6614
/CalendarServer/branches/users/glyph/imip-and-admin-html/txdav/common/datastore/sql.py:7866-7984
/CalendarServer/branches/users/glyph/ipv6-client/txdav/common/datastore/sql.py:9054-9105
/CalendarServer/branches/users/glyph/linux-tests/txdav/common/datastore/sql.py:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge/txdav/common/datastore/sql.py:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/common/datastore/sql.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/common/datastore/sql.py:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/common/datastore/sql.py:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete/txdav/common/datastore/sql.py:8321-8330
/CalendarServer/branches/users/glyph/new-export/txdav/common/datastore/sql.py:7444-7485
/CalendarServer/branches/users/glyph/one-home-list-api/txdav/common/datastore/sql.py:10048-10073
/CalendarServer/branches/users/glyph/oracle/txdav/common/datastore/sql.py:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/common/datastore/sql.py:7340-7351
/CalendarServer/branches/users/glyph/other-html/txdav/common/datastore/sql.py:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim/txdav/common/datastore/sql.py:8240-8251
/CalendarServer/branches/users/glyph/parallel-upgrade/txdav/common/datastore/sql.py:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1/txdav/common/datastore/sql.py:8571-8583
/CalendarServer/branches/users/glyph/q/txdav/common/datastore/sql.py:9560-9688
/CalendarServer/branches/users/glyph/queue-locking-and-timing/txdav/common/datastore/sql.py:10204-10289
/CalendarServer/branches/users/glyph/quota/txdav/common/datastore/sql.py:7604-7637
/CalendarServer/branches/users/glyph/sendfdport/txdav/common/datastore/sql.py:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes/txdav/common/datastore/sql.py:8436-8443
/CalendarServer/branches/users/glyph/shared-pool-take2/txdav/common/datastore/sql.py:8155-8174
/CalendarServer/branches/users/glyph/sharedpool/txdav/common/datastore/sql.py:6490-6550
/CalendarServer/branches/users/glyph/sharing-api/txdav/common/datastore/sql.py:9192-9205
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones/txdav/common/datastore/sql.py:8524-8535
/CalendarServer/branches/users/glyph/sql-store/txdav/common/datastore/sql.py:5929-6073
/CalendarServer/branches/users/glyph/start-service-start-loop/txdav/common/datastore/sql.py:11060-11065
/CalendarServer/branches/users/glyph/subtransactions/txdav/common/datastore/sql.py:7248-7258
/CalendarServer/branches/users/glyph/table-alias/txdav/common/datastore/sql.py:8651-8664
/CalendarServer/branches/users/glyph/uidexport/txdav/common/datastore/sql.py:7673-7676
/CalendarServer/branches/users/glyph/unshare-when-access-revoked/txdav/common/datastore/sql.py:10562-10595
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/common/datastore/sql.py:5084-5149
/CalendarServer/branches/users/glyph/uuid-normalize/txdav/common/datastore/sql.py:9268-9296
/CalendarServer/branches/users/glyph/xattrs-from-files/txdav/common/datastore/sql.py:7757-7769
/CalendarServer/branches/users/sagen/applepush/txdav/common/datastore/sql.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/common/datastore/sql.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources/txdav/common/datastore/sql.py:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/common/datastore/sql.py:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events/txdav/common/datastore/sql.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/common/datastore/sql.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/common/datastore/sql.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/common/datastore/sql.py:5084-5093
/CalendarServer/branches/users/sagen/testing/txdav/common/datastore/sql.py:10827-10851,10853-10855
/CalendarServer/branches/users/wsanchez/transations/txdav/common/datastore/sql.py:5515-5593
Modified: CalendarServer/trunk/txdav/common/datastore/sql_legacy.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_legacy.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/sql_legacy.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -749,7 +749,7 @@
if self.calendarid:
# AND the whole thing
- test = expression.isExpression("ADDRESSBOOK_OBJECT.ADDRESSBOOK_RESOURCE_ID", str(self.calendarid), True)
+ test = expression.isExpression("ADDRESSBOOK_OBJECT.ADDRESSBOOK_HOME_RESOURCE_ID", str(self.calendarid), True)
self.expression = test.andWith(self.expression)
# Generate ' where ...' partial statement
@@ -861,7 +861,7 @@
[self._objectSchema.RESOURCE_NAME,
self._objectSchema.VCARD_UID],
From=self._objectSchema,
- Where=self._objectSchema.ADDRESSBOOK_RESOURCE_ID ==
+ Where=self._objectSchema.ADDRESSBOOK_HOME_RESOURCE_ID ==
self.addressbook._resourceID
).on(self.addressbook._txn)
@@ -879,4 +879,4 @@
@inlineCallbacks
def resourcesExist(self, names):
returnValue(list(set(names).intersection(
- set((yield self.addressbook.listAddressbookObjects())))))
+ set((yield self.addressbook.listAddressBookObjects())))))
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -202,6 +202,7 @@
create table ADDRESSBOOK_HOME (
"RESOURCE_ID" integer primary key,
+ "ADDRESSBOOK_PROPERTY_STORE_ID" integer not null,
"OWNER_UID" nvarchar2(255) unique,
"DATAVERSION" integer default 0 not null
);
@@ -213,41 +214,67 @@
"MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
);
-create table ADDRESSBOOK (
- "RESOURCE_ID" integer primary key
-);
-
-create table ADDRESSBOOK_METADATA (
- "RESOURCE_ID" integer primary key references ADDRESSBOOK on delete cascade,
- "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table ADDRESSBOOK_BIND (
+create table SHARED_ADDRESSBOOK_BIND (
"ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
- "ADDRESSBOOK_RESOURCE_ID" integer not null references ADDRESSBOOK on delete cascade,
+ "OWNER_ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
"ADDRESSBOOK_RESOURCE_NAME" nvarchar2(255),
"BIND_MODE" integer not null,
"BIND_STATUS" integer not null,
"BIND_REVISION" integer default 0 not null,
"MESSAGE" nclob,
- primary key("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_ID"),
+ primary key("ADDRESSBOOK_HOME_RESOURCE_ID", "OWNER_ADDRESSBOOK_HOME_RESOURCE_ID"),
unique("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_NAME")
);
create table ADDRESSBOOK_OBJECT (
"RESOURCE_ID" integer primary key,
- "ADDRESSBOOK_RESOURCE_ID" integer not null references ADDRESSBOOK on delete cascade,
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
"RESOURCE_NAME" nvarchar2(255),
"VCARD_TEXT" nclob,
"VCARD_UID" nvarchar2(255),
+ "KIND" integer not null,
"MD5" nchar(32),
"CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
"MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- unique("ADDRESSBOOK_RESOURCE_ID", "RESOURCE_NAME"),
- unique("ADDRESSBOOK_RESOURCE_ID", "VCARD_UID")
+ unique("ADDRESSBOOK_HOME_RESOURCE_ID", "RESOURCE_NAME"),
+ unique("ADDRESSBOOK_HOME_RESOURCE_ID", "VCARD_UID")
);
+create table ADDRESSBOOK_OBJECT_KIND (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('person', 0);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('group', 1);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('resource', 2);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('location', 3);
+create table ABO_MEMBERS (
+ "GROUP_ID" integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ "ADDRESSBOOK_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "MEMBER_ID" integer not null references ADDRESSBOOK_OBJECT,
+ primary key("GROUP_ID", "MEMBER_ID")
+);
+
+create table ABO_FOREIGN_MEMBERS (
+ "GROUP_ID" integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ "ADDRESSBOOK_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "MEMBER_ADDRESS" nvarchar2(255),
+ primary key("GROUP_ID", "MEMBER_ADDRESS")
+);
+
+create table SHARED_GROUP_BIND (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "GROUP_RESOURCE_ID" integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ "GROUP_ADDRESSBOOK_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "BIND_REVISION" integer default 0 not null,
+ "MESSAGE" nclob,
+ primary key("ADDRESSBOOK_HOME_RESOURCE_ID", "GROUP_RESOURCE_ID"),
+ unique("ADDRESSBOOK_HOME_RESOURCE_ID", "GROUP_ADDRESSBOOK_RESOURCE_NAME")
+);
+
create table CALENDAR_OBJECT_REVISIONS (
"CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
"CALENDAR_RESOURCE_ID" integer references CALENDAR,
@@ -259,7 +286,7 @@
create table ADDRESSBOOK_OBJECT_REVISIONS (
"ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
- "ADDRESSBOOK_RESOURCE_ID" integer references ADDRESSBOOK,
+ "OWNER_ADDRESSBOOK_HOME_RESOURCE_ID" integer references ADDRESSBOOK_HOME,
"ADDRESSBOOK_NAME" nvarchar2(255) default null,
"RESOURCE_NAME" nvarchar2(255),
"REVISION" integer not null,
@@ -330,9 +357,9 @@
"VALUE" nvarchar2(255)
);
-insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '19');
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '20');
insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '4');
-insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '1');
+insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
NOTIFICATION_HOME_RESOURCE_ID
);
@@ -375,10 +402,14 @@
CALENDAR_HOME_RESOURCE_ID
);
-create index ADDRESSBOOK_BIND_RESO_205aa75c on ADDRESSBOOK_BIND (
- ADDRESSBOOK_RESOURCE_ID
+create index SHARED_ADDRESSBOOK_BI_e9a2e6d4 on SHARED_ADDRESSBOOK_BIND (
+ OWNER_ADDRESSBOOK_HOME_RESOURCE_ID
);
+create index SHARED_GROUP_BIND_RES_cf52f95d on SHARED_GROUP_BIND (
+ GROUP_RESOURCE_ID
+);
+
create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
CALENDAR_HOME_RESOURCE_ID,
CALENDAR_RESOURCE_ID
@@ -394,18 +425,18 @@
REVISION
);
-create index ADDRESSBOOK_OBJECT_RE_f460d62d on ADDRESSBOOK_OBJECT_REVISIONS (
+create index ADDRESSBOOK_OBJECT_RE_40cc2d73 on ADDRESSBOOK_OBJECT_REVISIONS (
ADDRESSBOOK_HOME_RESOURCE_ID,
- ADDRESSBOOK_RESOURCE_ID
+ OWNER_ADDRESSBOOK_HOME_RESOURCE_ID
);
-create index ADDRESSBOOK_OBJECT_RE_9a848f39 on ADDRESSBOOK_OBJECT_REVISIONS (
- ADDRESSBOOK_RESOURCE_ID,
+create index ADDRESSBOOK_OBJECT_RE_980b9872 on ADDRESSBOOK_OBJECT_REVISIONS (
+ OWNER_ADDRESSBOOK_HOME_RESOURCE_ID,
RESOURCE_NAME
);
-create index ADDRESSBOOK_OBJECT_RE_cb101e6b on ADDRESSBOOK_OBJECT_REVISIONS (
- ADDRESSBOOK_RESOURCE_ID,
+create index ADDRESSBOOK_OBJECT_RE_45004780 on ADDRESSBOOK_OBJECT_REVISIONS (
+ OWNER_ADDRESSBOOK_HOME_RESOURCE_ID,
REVISION
);
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -16,12 +16,14 @@
-- limitations under the License.
----
+
-----------------
-- Resource ID --
-----------------
create sequence RESOURCE_ID_SEQ;
+
-------------------------
-- Cluster Bookkeeping --
-------------------------
@@ -118,6 +120,7 @@
create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
-------------------
-- Calendar Bind --
-------------------
@@ -251,6 +254,7 @@
insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
insert into CALENDAR_ACCESS_TYPE values (4, 'restricted' );
+
-----------------
-- Instance ID --
-----------------
@@ -358,11 +362,13 @@
----------------------
create table ADDRESSBOOK_HOME (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
- OWNER_UID varchar(255) not null unique, -- implicit index
- DATAVERSION integer default 0 not null
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ ADDRESSBOOK_PROPERTY_STORE_ID integer default nextval('RESOURCE_ID_SEQ') not null, -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ DATAVERSION integer default 0 not null
);
+
-------------------------------
-- AddressBook Home Metadata --
-------------------------------
@@ -374,73 +380,118 @@
MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
);
------------------
--- AddressBook --
------------------
-create table ADDRESSBOOK (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+-----------------------------
+-- Shared AddressBook Bind --
+-----------------------------
+
+-- Joins sharee ADDRESSBOOK_HOME and owner ADDRESSBOOK_HOME
+
+create table SHARED_ADDRESSBOOK_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ OWNER_ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ BIND_REVISION integer default 0 not null,
+ MESSAGE text, -- FIXME: xml?
+
+ primary key (ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_ADDRESSBOOK_HOME_RESOURCE_ID), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME) -- implicit index
);
+create index SHARED_ADDRESSBOOK_BIND_RESOURCE_ID on
+ SHARED_ADDRESSBOOK_BIND(OWNER_ADDRESSBOOK_HOME_RESOURCE_ID);
---------------------------
--- AddressBook Metadata --
---------------------------
-create table ADDRESSBOOK_METADATA (
- RESOURCE_ID integer primary key references ADDRESSBOOK on delete cascade, -- implicit index
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+------------------------
+-- AddressBook Object --
+------------------------
+
+create table ADDRESSBOOK_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ VCARD_TEXT text not null,
+ VCARD_UID varchar(255) not null,
+ KIND integer not null, -- enum ADDRESSBOOK_OBJECT_KIND
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, VCARD_UID) -- implicit index
);
-----------------------
--- AddressBook Bind --
-----------------------
+-----------------------------
+-- AddressBook Object kind --
+-----------------------------
--- Joins ADDRESSBOOK_HOME and ADDRESSBOOK
+create table ADDRESSBOOK_OBJECT_KIND (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
-create table ADDRESSBOOK_BIND (
- ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
- ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK on delete cascade,
- ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
- BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
- BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
- BIND_REVISION integer default 0 not null,
- MESSAGE text, -- FIXME: xml?
+insert into ADDRESSBOOK_OBJECT_KIND values (0, 'person');
+insert into ADDRESSBOOK_OBJECT_KIND values (1, 'group' );
+insert into ADDRESSBOOK_OBJECT_KIND values (2, 'resource');
+insert into ADDRESSBOOK_OBJECT_KIND values (3, 'location');
- primary key (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID), -- implicit index
- unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME) -- implicit index
+
+---------------------------------
+-- Address Book Object Members --
+---------------------------------
+
+create table ABO_MEMBERS (
+ GROUP_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade, -- AddressBook Object's (kind=='group') RESOURCE_ID
+ ADDRESSBOOK_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ MEMBER_ID integer not null references ADDRESSBOOK_OBJECT, -- member AddressBook Object's RESOURCE_ID
+ primary key (GROUP_ID, MEMBER_ID) -- implicit index
);
-create index ADDRESSBOOK_BIND_RESOURCE_ID on
- ADDRESSBOOK_BIND(ADDRESSBOOK_RESOURCE_ID);
-create table ADDRESSBOOK_OBJECT (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
- ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK on delete cascade,
- RESOURCE_NAME varchar(255) not null,
- VCARD_TEXT text not null,
- VCARD_UID varchar(255) not null,
- MD5 char(32) not null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+------------------------------------------
+-- Address Book Object Foreign Members --
+------------------------------------------
- unique (ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME), -- implicit index
- unique (ADDRESSBOOK_RESOURCE_ID, VCARD_UID) -- implicit index
+create table ABO_FOREIGN_MEMBERS (
+ GROUP_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade, -- AddressBook Object's (kind=='group') RESOURCE_ID
+ ADDRESSBOOK_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ MEMBER_ADDRESS varchar(255) not null, -- member AddressBook Object's 'calendar' address
+ primary key (GROUP_ID, MEMBER_ADDRESS) -- implicit index
);
----------------
--- Revisions --
----------------
-create sequence REVISION_SEQ;
+-----------------------
+-- Shared Group Bind --
+-----------------------
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (kind == group)
+create table SHARED_GROUP_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ GROUP_RESOURCE_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ GROUP_ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ BIND_REVISION integer default 0 not null,
+ MESSAGE text, -- FIXME: xml?
+
+ primary key (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_RESOURCE_ID), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_RESOURCE_NAME) -- implicit index
+);
+
+create index SHARED_GROUP_BIND_RESOURCE_ID on
+ SHARED_GROUP_BIND(GROUP_RESOURCE_ID);
+
+
---------------
-- Revisions --
---------------
+create sequence REVISION_SEQ;
+
create table CALENDAR_OBJECT_REVISIONS (
CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
CALENDAR_RESOURCE_ID integer references CALENDAR,
@@ -459,28 +510,30 @@
create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
--------------------------------
+
+----------------------------------
-- AddressBook Object Revisions --
--------------------------------
+----------------------------------
create table ADDRESSBOOK_OBJECT_REVISIONS (
- ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
- ADDRESSBOOK_RESOURCE_ID integer references ADDRESSBOOK,
- ADDRESSBOOK_NAME varchar(255) default null,
- RESOURCE_NAME varchar(255),
- REVISION integer default nextval('REVISION_SEQ') not null,
- DELETED boolean not null
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ OWNER_ADDRESSBOOK_HOME_RESOURCE_ID integer references ADDRESSBOOK_HOME,
+ ADDRESSBOOK_NAME varchar(255) default null,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null
);
-create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_ADDRESSBOOK_RESOURCE_ID
- on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID);
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_ADDRESSBOOK_HOME_RESOURCE_ID
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_ADDRESSBOOK_HOME_RESOURCE_ID);
-create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
- on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME);
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME
+ on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME);
-create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_REVISION
- on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, REVISION);
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_REVISION
+ on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_ADDRESSBOOK_HOME_RESOURCE_ID, REVISION);
+
-----------------------------------
-- Notification Object Revisions --
-----------------------------------
@@ -497,6 +550,7 @@
create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
+
-------------------------------------------
-- Apple Push Notification Subscriptions --
-------------------------------------------
@@ -515,6 +569,7 @@
create index APN_SUBSCRIPTIONS_RESOURCE_KEY
on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
-----------------
-- IMIP Tokens --
-----------------
@@ -532,12 +587,14 @@
create index IMIP_TOKENS_TOKEN
on IMIP_TOKENS(TOKEN);
+
----------------
-- Work Items --
----------------
create sequence WORKITEM_SEQ;
+
---------------------------
-- IMIP Inivitation Work --
---------------------------
@@ -550,6 +607,7 @@
ICALENDAR_TEXT text not null
);
+
-----------------------
-- IMIP Polling Work --
-----------------------
@@ -559,6 +617,7 @@
NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP)
);
+
---------------------
-- IMIP Reply Work --
---------------------
@@ -571,6 +630,7 @@
ICALENDAR_TEXT text not null
);
+
------------------------
-- Push Notifications --
------------------------
@@ -600,6 +660,6 @@
VALUE varchar(255)
);
-insert into CALENDARSERVER values ('VERSION', '19');
+insert into CALENDARSERVER values ('VERSION', '20');
insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '4');
-insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '1');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
Deleted: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v18.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v18.sql 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v18.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,404 +0,0 @@
-create sequence RESOURCE_ID_SEQ;
-create sequence INSTANCE_ID_SEQ;
-create sequence ATTACHMENT_ID_SEQ;
-create sequence REVISION_SEQ;
-create sequence WORKITEM_SEQ;
-create table NODE_INFO (
- "HOSTNAME" nvarchar2(255),
- "PID" integer not null,
- "PORT" integer not null,
- "TIME" timestamp default CURRENT_TIMESTAMP at time zone 'UTC' not null,
- primary key("HOSTNAME", "PORT")
-);
-
-create table NAMED_LOCK (
- "LOCK_NAME" nvarchar2(255) primary key
-);
-
-create table CALENDAR_HOME (
- "RESOURCE_ID" integer primary key,
- "OWNER_UID" nvarchar2(255) unique,
- "DATAVERSION" integer default 0 not null
-);
-
-create table CALENDAR_HOME_METADATA (
- "RESOURCE_ID" integer primary key references CALENDAR_HOME on delete cascade,
- "QUOTA_USED_BYTES" integer default 0 not null,
- "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table CALENDAR (
- "RESOURCE_ID" integer primary key
-);
-
-create table CALENDAR_METADATA (
- "RESOURCE_ID" integer primary key references CALENDAR on delete cascade,
- "SUPPORTED_COMPONENTS" nvarchar2(255) default null,
- "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table NOTIFICATION_HOME (
- "RESOURCE_ID" integer primary key,
- "OWNER_UID" nvarchar2(255) unique
-);
-
-create table NOTIFICATION (
- "RESOURCE_ID" integer primary key,
- "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME,
- "NOTIFICATION_UID" nvarchar2(255),
- "XML_TYPE" nvarchar2(255),
- "XML_DATA" nclob,
- "MD5" nchar(32),
- "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- unique("NOTIFICATION_UID", "NOTIFICATION_HOME_RESOURCE_ID")
-);
-
-create table CALENDAR_BIND (
- "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
- "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
- "CALENDAR_RESOURCE_NAME" nvarchar2(255),
- "BIND_MODE" integer not null,
- "BIND_STATUS" integer not null,
- "MESSAGE" nclob,
- primary key("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_ID"),
- unique("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_NAME")
-);
-
-create table CALENDAR_BIND_MODE (
- "ID" integer primary key,
- "DESCRIPTION" nvarchar2(16) unique
-);
-
-insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
-insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
-insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
-insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
-create table CALENDAR_BIND_STATUS (
- "ID" integer primary key,
- "DESCRIPTION" nvarchar2(16) unique
-);
-
-insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
-insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
-insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
-insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
-create table CALENDAR_OBJECT (
- "RESOURCE_ID" integer primary key,
- "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
- "RESOURCE_NAME" nvarchar2(255),
- "ICALENDAR_TEXT" nclob,
- "ICALENDAR_UID" nvarchar2(255),
- "ICALENDAR_TYPE" nvarchar2(255),
- "ATTACHMENTS_MODE" integer default 0 not null,
- "DROPBOX_ID" nvarchar2(255),
- "ORGANIZER" nvarchar2(255),
- "RECURRANCE_MIN" date,
- "RECURRANCE_MAX" date,
- "ACCESS" integer default 0 not null,
- "SCHEDULE_OBJECT" integer default 0,
- "SCHEDULE_TAG" nvarchar2(36) default null,
- "SCHEDULE_ETAGS" nclob default null,
- "PRIVATE_COMMENTS" integer default 0 not null,
- "MD5" nchar(32),
- "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- unique("CALENDAR_RESOURCE_ID", "RESOURCE_NAME")
-);
-
-create table CALENDAR_OBJECT_ATTACHMENTS_MO (
- "ID" integer primary key,
- "DESCRIPTION" nvarchar2(16) unique
-);
-
-insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('none', 0);
-insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('read', 1);
-insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('write', 2);
-create table CALENDAR_ACCESS_TYPE (
- "ID" integer primary key,
- "DESCRIPTION" nvarchar2(32) unique
-);
-
-insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
-insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
-insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
-insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
-insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
-create table TIME_RANGE (
- "INSTANCE_ID" integer primary key,
- "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
- "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
- "FLOATING" integer not null,
- "START_DATE" timestamp not null,
- "END_DATE" timestamp not null,
- "FBTYPE" integer not null,
- "TRANSPARENT" integer not null
-);
-
-create table FREE_BUSY_TYPE (
- "ID" integer primary key,
- "DESCRIPTION" nvarchar2(16) unique
-);
-
-insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
-insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
-insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
-insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
-insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
-create table TRANSPARENCY (
- "TIME_RANGE_INSTANCE_ID" integer not null references TIME_RANGE on delete cascade,
- "USER_ID" nvarchar2(255),
- "TRANSPARENT" integer not null
-);
-
-create table ATTACHMENT (
- "ATTACHMENT_ID" integer primary key,
- "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
- "DROPBOX_ID" nvarchar2(255),
- "CONTENT_TYPE" nvarchar2(255),
- "SIZE" integer not null,
- "MD5" nchar(32),
- "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "PATH" nvarchar2(1024)
-);
-
-create table ATTACHMENT_CALENDAR_OBJECT (
- "ATTACHMENT_ID" integer not null references ATTACHMENT on delete cascade,
- "MANAGED_ID" nvarchar2(255),
- "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
- primary key("ATTACHMENT_ID", "CALENDAR_OBJECT_RESOURCE_ID"),
- unique("MANAGED_ID", "CALENDAR_OBJECT_RESOURCE_ID")
-);
-
-create table RESOURCE_PROPERTY (
- "RESOURCE_ID" integer not null,
- "NAME" nvarchar2(255),
- "VALUE" nclob,
- "VIEWER_UID" nvarchar2(255),
- primary key("RESOURCE_ID", "NAME", "VIEWER_UID")
-);
-
-create table ADDRESSBOOK_HOME (
- "RESOURCE_ID" integer primary key,
- "OWNER_UID" nvarchar2(255) unique,
- "DATAVERSION" integer default 0 not null
-);
-
-create table ADDRESSBOOK_HOME_METADATA (
- "RESOURCE_ID" integer primary key references ADDRESSBOOK_HOME on delete cascade,
- "QUOTA_USED_BYTES" integer default 0 not null,
- "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table ADDRESSBOOK (
- "RESOURCE_ID" integer primary key
-);
-
-create table ADDRESSBOOK_METADATA (
- "RESOURCE_ID" integer primary key references ADDRESSBOOK on delete cascade,
- "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table ADDRESSBOOK_BIND (
- "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
- "ADDRESSBOOK_RESOURCE_ID" integer not null references ADDRESSBOOK on delete cascade,
- "ADDRESSBOOK_RESOURCE_NAME" nvarchar2(255),
- "BIND_MODE" integer not null,
- "BIND_STATUS" integer not null,
- "MESSAGE" nclob,
- primary key("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_ID"),
- unique("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_NAME")
-);
-
-create table ADDRESSBOOK_OBJECT (
- "RESOURCE_ID" integer primary key,
- "ADDRESSBOOK_RESOURCE_ID" integer not null references ADDRESSBOOK on delete cascade,
- "RESOURCE_NAME" nvarchar2(255),
- "VCARD_TEXT" nclob,
- "VCARD_UID" nvarchar2(255),
- "MD5" nchar(32),
- "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- unique("ADDRESSBOOK_RESOURCE_ID", "RESOURCE_NAME"),
- unique("ADDRESSBOOK_RESOURCE_ID", "VCARD_UID")
-);
-
-create table CALENDAR_OBJECT_REVISIONS (
- "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
- "CALENDAR_RESOURCE_ID" integer references CALENDAR,
- "CALENDAR_NAME" nvarchar2(255) default null,
- "RESOURCE_NAME" nvarchar2(255),
- "REVISION" integer not null,
- "DELETED" integer not null
-);
-
-create table ADDRESSBOOK_OBJECT_REVISIONS (
- "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
- "ADDRESSBOOK_RESOURCE_ID" integer references ADDRESSBOOK,
- "ADDRESSBOOK_NAME" nvarchar2(255) default null,
- "RESOURCE_NAME" nvarchar2(255),
- "REVISION" integer not null,
- "DELETED" integer not null
-);
-
-create table NOTIFICATION_OBJECT_REVISIONS (
- "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME on delete cascade,
- "RESOURCE_NAME" nvarchar2(255),
- "REVISION" integer not null,
- "DELETED" integer not null,
- unique("NOTIFICATION_HOME_RESOURCE_ID", "RESOURCE_NAME")
-);
-
-create table APN_SUBSCRIPTIONS (
- "TOKEN" nvarchar2(255),
- "RESOURCE_KEY" nvarchar2(255),
- "MODIFIED" integer not null,
- "SUBSCRIBER_GUID" nvarchar2(255),
- "USER_AGENT" nvarchar2(255) default null,
- "IP_ADDR" nvarchar2(255) default null,
- primary key("TOKEN", "RESOURCE_KEY")
-);
-
-create table IMIP_TOKENS (
- "TOKEN" nvarchar2(255),
- "ORGANIZER" nvarchar2(255),
- "ATTENDEE" nvarchar2(255),
- "ICALUID" nvarchar2(255),
- "ACCESSED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- primary key("ORGANIZER", "ATTENDEE", "ICALUID")
-);
-
-create table IMIP_INVITATION_WORK (
- "WORK_ID" integer primary key not null,
- "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "FROM_ADDR" nvarchar2(255),
- "TO_ADDR" nvarchar2(255),
- "ICALENDAR_TEXT" nclob
-);
-
-create table IMIP_POLLING_WORK (
- "WORK_ID" integer primary key not null,
- "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table IMIP_REPLY_WORK (
- "WORK_ID" integer primary key not null,
- "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "ORGANIZER" nvarchar2(255),
- "ATTENDEE" nvarchar2(255),
- "ICALENDAR_TEXT" nclob
-);
-
-create table PUSH_NOTIFICATION_WORK (
- "WORK_ID" integer primary key not null,
- "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "PUSH_ID" nvarchar2(255)
-);
-
-create table GROUP_CACHER_POLLING_WORK (
- "WORK_ID" integer primary key not null,
- "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
-);
-
-create table CALENDARSERVER (
- "NAME" nvarchar2(255) primary key,
- "VALUE" nvarchar2(255)
-);
-
-insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '18');
-insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '3');
-insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '1');
-create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
- NOTIFICATION_HOME_RESOURCE_ID
-);
-
-create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
- CALENDAR_RESOURCE_ID
-);
-
-create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
- CALENDAR_RESOURCE_ID,
- ICALENDAR_UID
-);
-
-create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
- CALENDAR_RESOURCE_ID,
- RECURRANCE_MAX
-);
-
-create index CALENDAR_OBJECT_ICALE_82e731d5 on CALENDAR_OBJECT (
- ICALENDAR_UID
-);
-
-create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
- DROPBOX_ID
-);
-
-create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
- CALENDAR_RESOURCE_ID
-);
-
-create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
- CALENDAR_OBJECT_RESOURCE_ID
-);
-
-create index TRANSPARENCY_TIME_RAN_5f34467f on TRANSPARENCY (
- TIME_RANGE_INSTANCE_ID
-);
-
-create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
- CALENDAR_HOME_RESOURCE_ID
-);
-
-create index ADDRESSBOOK_BIND_RESO_205aa75c on ADDRESSBOOK_BIND (
- ADDRESSBOOK_RESOURCE_ID
-);
-
-create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
- CALENDAR_HOME_RESOURCE_ID,
- CALENDAR_RESOURCE_ID
-);
-
-create index CALENDAR_OBJECT_REVIS_2643d556 on CALENDAR_OBJECT_REVISIONS (
- CALENDAR_RESOURCE_ID,
- RESOURCE_NAME
-);
-
-create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
- CALENDAR_RESOURCE_ID,
- REVISION
-);
-
-create index ADDRESSBOOK_OBJECT_RE_f460d62d on ADDRESSBOOK_OBJECT_REVISIONS (
- ADDRESSBOOK_HOME_RESOURCE_ID,
- ADDRESSBOOK_RESOURCE_ID
-);
-
-create index ADDRESSBOOK_OBJECT_RE_9a848f39 on ADDRESSBOOK_OBJECT_REVISIONS (
- ADDRESSBOOK_RESOURCE_ID,
- RESOURCE_NAME
-);
-
-create index ADDRESSBOOK_OBJECT_RE_cb101e6b on ADDRESSBOOK_OBJECT_REVISIONS (
- ADDRESSBOOK_RESOURCE_ID,
- REVISION
-);
-
-create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
- NOTIFICATION_HOME_RESOURCE_ID,
- REVISION
-);
-
-create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
- RESOURCE_KEY
-);
-
-create index IMIP_TOKENS_TOKEN_e94b918f on IMIP_TOKENS (
- TOKEN
-);
-
Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v18.sql (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/old/oracle-dialect/v18.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v18.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v18.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,404 @@
+create sequence RESOURCE_ID_SEQ;
+create sequence INSTANCE_ID_SEQ;
+create sequence ATTACHMENT_ID_SEQ;
+create sequence REVISION_SEQ;
+create sequence WORKITEM_SEQ;
+create table NODE_INFO (
+ "HOSTNAME" nvarchar2(255),
+ "PID" integer not null,
+ "PORT" integer not null,
+ "TIME" timestamp default CURRENT_TIMESTAMP at time zone 'UTC' not null,
+ primary key("HOSTNAME", "PORT")
+);
+
+create table NAMED_LOCK (
+ "LOCK_NAME" nvarchar2(255) primary key
+);
+
+create table CALENDAR_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table CALENDAR_HOME_METADATA (
+ "RESOURCE_ID" integer primary key references CALENDAR_HOME on delete cascade,
+ "QUOTA_USED_BYTES" integer default 0 not null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR (
+ "RESOURCE_ID" integer primary key
+);
+
+create table CALENDAR_METADATA (
+ "RESOURCE_ID" integer primary key references CALENDAR on delete cascade,
+ "SUPPORTED_COMPONENTS" nvarchar2(255) default null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table NOTIFICATION_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique
+);
+
+create table NOTIFICATION (
+ "RESOURCE_ID" integer primary key,
+ "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME,
+ "NOTIFICATION_UID" nvarchar2(255),
+ "XML_TYPE" nvarchar2(255),
+ "XML_DATA" nclob,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique("NOTIFICATION_UID", "NOTIFICATION_HOME_RESOURCE_ID")
+);
+
+create table CALENDAR_BIND (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "CALENDAR_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "MESSAGE" nclob,
+ primary key("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_ID"),
+ unique("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_NAME")
+);
+
+create table CALENDAR_BIND_MODE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
+create table CALENDAR_BIND_STATUS (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
+create table CALENDAR_OBJECT (
+ "RESOURCE_ID" integer primary key,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob,
+ "ICALENDAR_UID" nvarchar2(255),
+ "ICALENDAR_TYPE" nvarchar2(255),
+ "ATTACHMENTS_MODE" integer default 0 not null,
+ "DROPBOX_ID" nvarchar2(255),
+ "ORGANIZER" nvarchar2(255),
+ "RECURRANCE_MIN" date,
+ "RECURRANCE_MAX" date,
+ "ACCESS" integer default 0 not null,
+ "SCHEDULE_OBJECT" integer default 0,
+ "SCHEDULE_TAG" nvarchar2(36) default null,
+ "SCHEDULE_ETAGS" nclob default null,
+ "PRIVATE_COMMENTS" integer default 0 not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique("CALENDAR_RESOURCE_ID", "RESOURCE_NAME")
+);
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MO (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('none', 0);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('write', 2);
+create table CALENDAR_ACCESS_TYPE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(32) unique
+);
+
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
+create table TIME_RANGE (
+ "INSTANCE_ID" integer primary key,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "FLOATING" integer not null,
+ "START_DATE" timestamp not null,
+ "END_DATE" timestamp not null,
+ "FBTYPE" integer not null,
+ "TRANSPARENT" integer not null
+);
+
+create table FREE_BUSY_TYPE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
+create table TRANSPARENCY (
+ "TIME_RANGE_INSTANCE_ID" integer not null references TIME_RANGE on delete cascade,
+ "USER_ID" nvarchar2(255),
+ "TRANSPARENT" integer not null
+);
+
+create table ATTACHMENT (
+ "ATTACHMENT_ID" integer primary key,
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "DROPBOX_ID" nvarchar2(255),
+ "CONTENT_TYPE" nvarchar2(255),
+ "SIZE" integer not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "PATH" nvarchar2(1024)
+);
+
+create table ATTACHMENT_CALENDAR_OBJECT (
+ "ATTACHMENT_ID" integer not null references ATTACHMENT on delete cascade,
+ "MANAGED_ID" nvarchar2(255),
+ "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ primary key("ATTACHMENT_ID", "CALENDAR_OBJECT_RESOURCE_ID"),
+ unique("MANAGED_ID", "CALENDAR_OBJECT_RESOURCE_ID")
+);
+
+create table RESOURCE_PROPERTY (
+ "RESOURCE_ID" integer not null,
+ "NAME" nvarchar2(255),
+ "VALUE" nclob,
+ "VIEWER_UID" nvarchar2(255),
+ primary key("RESOURCE_ID", "NAME", "VIEWER_UID")
+);
+
+create table ADDRESSBOOK_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table ADDRESSBOOK_HOME_METADATA (
+ "RESOURCE_ID" integer primary key references ADDRESSBOOK_HOME on delete cascade,
+ "QUOTA_USED_BYTES" integer default 0 not null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table ADDRESSBOOK (
+ "RESOURCE_ID" integer primary key
+);
+
+create table ADDRESSBOOK_METADATA (
+ "RESOURCE_ID" integer primary key references ADDRESSBOOK on delete cascade,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table ADDRESSBOOK_BIND (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "ADDRESSBOOK_RESOURCE_ID" integer not null references ADDRESSBOOK on delete cascade,
+ "ADDRESSBOOK_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "MESSAGE" nclob,
+ primary key("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_ID"),
+ unique("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_NAME")
+);
+
+create table ADDRESSBOOK_OBJECT (
+ "RESOURCE_ID" integer primary key,
+ "ADDRESSBOOK_RESOURCE_ID" integer not null references ADDRESSBOOK on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "VCARD_TEXT" nclob,
+ "VCARD_UID" nvarchar2(255),
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique("ADDRESSBOOK_RESOURCE_ID", "RESOURCE_NAME"),
+ unique("ADDRESSBOOK_RESOURCE_ID", "VCARD_UID")
+);
+
+create table CALENDAR_OBJECT_REVISIONS (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "CALENDAR_RESOURCE_ID" integer references CALENDAR,
+ "CALENDAR_NAME" nvarchar2(255) default null,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null
+);
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "ADDRESSBOOK_RESOURCE_ID" integer references ADDRESSBOOK,
+ "ADDRESSBOOK_NAME" nvarchar2(255) default null,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null
+);
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+ "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null,
+ unique("NOTIFICATION_HOME_RESOURCE_ID", "RESOURCE_NAME")
+);
+
+create table APN_SUBSCRIPTIONS (
+ "TOKEN" nvarchar2(255),
+ "RESOURCE_KEY" nvarchar2(255),
+ "MODIFIED" integer not null,
+ "SUBSCRIBER_GUID" nvarchar2(255),
+ "USER_AGENT" nvarchar2(255) default null,
+ "IP_ADDR" nvarchar2(255) default null,
+ primary key("TOKEN", "RESOURCE_KEY")
+);
+
+create table IMIP_TOKENS (
+ "TOKEN" nvarchar2(255),
+ "ORGANIZER" nvarchar2(255),
+ "ATTENDEE" nvarchar2(255),
+ "ICALUID" nvarchar2(255),
+ "ACCESSED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ primary key("ORGANIZER", "ATTENDEE", "ICALUID")
+);
+
+create table IMIP_INVITATION_WORK (
+ "WORK_ID" integer primary key not null,
+ "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "FROM_ADDR" nvarchar2(255),
+ "TO_ADDR" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob
+);
+
+create table IMIP_POLLING_WORK (
+ "WORK_ID" integer primary key not null,
+ "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table IMIP_REPLY_WORK (
+ "WORK_ID" integer primary key not null,
+ "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "ORGANIZER" nvarchar2(255),
+ "ATTENDEE" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob
+);
+
+create table PUSH_NOTIFICATION_WORK (
+ "WORK_ID" integer primary key not null,
+ "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "PUSH_ID" nvarchar2(255)
+);
+
+create table GROUP_CACHER_POLLING_WORK (
+ "WORK_ID" integer primary key not null,
+ "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDARSERVER (
+ "NAME" nvarchar2(255) primary key,
+ "VALUE" nvarchar2(255)
+);
+
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '18');
+insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '3');
+insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '1');
+create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
+ NOTIFICATION_HOME_RESOURCE_ID
+);
+
+create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
+ CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
+ CALENDAR_RESOURCE_ID,
+ ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
+ CALENDAR_RESOURCE_ID,
+ RECURRANCE_MAX
+);
+
+create index CALENDAR_OBJECT_ICALE_82e731d5 on CALENDAR_OBJECT (
+ ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
+ DROPBOX_ID
+);
+
+create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
+ CALENDAR_RESOURCE_ID
+);
+
+create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
+ CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index TRANSPARENCY_TIME_RAN_5f34467f on TRANSPARENCY (
+ TIME_RANGE_INSTANCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
+ CALENDAR_HOME_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_BIND_RESO_205aa75c on ADDRESSBOOK_BIND (
+ ADDRESSBOOK_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_HOME_RESOURCE_ID,
+ CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_2643d556 on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_RESOURCE_ID,
+ RESOURCE_NAME
+);
+
+create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_RESOURCE_ID,
+ REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_f460d62d on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_HOME_RESOURCE_ID,
+ ADDRESSBOOK_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_OBJECT_RE_9a848f39 on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_RESOURCE_ID,
+ RESOURCE_NAME
+);
+
+create index ADDRESSBOOK_OBJECT_RE_cb101e6b on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_RESOURCE_ID,
+ REVISION
+);
+
+create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
+ NOTIFICATION_HOME_RESOURCE_ID,
+ REVISION
+);
+
+create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
+ RESOURCE_KEY
+);
+
+create index IMIP_TOKENS_TOKEN_e94b918f on IMIP_TOKENS (
+ TOKEN
+);
+
Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v19.sql (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/old/oracle-dialect/v19.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v19.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v19.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,424 @@
+create sequence RESOURCE_ID_SEQ;
+create sequence INSTANCE_ID_SEQ;
+create sequence ATTACHMENT_ID_SEQ;
+create sequence REVISION_SEQ;
+create sequence WORKITEM_SEQ;
+create table NODE_INFO (
+ "HOSTNAME" nvarchar2(255),
+ "PID" integer not null,
+ "PORT" integer not null,
+ "TIME" timestamp default CURRENT_TIMESTAMP at time zone 'UTC' not null,
+ primary key("HOSTNAME", "PORT")
+);
+
+create table NAMED_LOCK (
+ "LOCK_NAME" nvarchar2(255) primary key
+);
+
+create table CALENDAR_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table CALENDAR (
+ "RESOURCE_ID" integer primary key
+);
+
+create table CALENDAR_HOME_METADATA (
+ "RESOURCE_ID" integer primary key references CALENDAR_HOME on delete cascade,
+ "QUOTA_USED_BYTES" integer default 0 not null,
+ "DEFAULT_EVENTS" integer default null references CALENDAR on delete set null,
+ "DEFAULT_TASKS" integer default null references CALENDAR on delete set null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_METADATA (
+ "RESOURCE_ID" integer primary key references CALENDAR on delete cascade,
+ "SUPPORTED_COMPONENTS" nvarchar2(255) default null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table NOTIFICATION_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique
+);
+
+create table NOTIFICATION (
+ "RESOURCE_ID" integer primary key,
+ "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME,
+ "NOTIFICATION_UID" nvarchar2(255),
+ "XML_TYPE" nvarchar2(255),
+ "XML_DATA" nclob,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique("NOTIFICATION_UID", "NOTIFICATION_HOME_RESOURCE_ID")
+);
+
+create table CALENDAR_BIND (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "CALENDAR_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "BIND_REVISION" integer default 0 not null,
+ "MESSAGE" nclob,
+ "TRANSP" integer default 0 not null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null,
+ primary key("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_ID"),
+ unique("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_NAME")
+);
+
+create table CALENDAR_BIND_MODE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
+create table CALENDAR_BIND_STATUS (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
+create table CALENDAR_TRANSP (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('opaque', 0);
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('transparent', 1);
+create table CALENDAR_OBJECT (
+ "RESOURCE_ID" integer primary key,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob,
+ "ICALENDAR_UID" nvarchar2(255),
+ "ICALENDAR_TYPE" nvarchar2(255),
+ "ATTACHMENTS_MODE" integer default 0 not null,
+ "DROPBOX_ID" nvarchar2(255),
+ "ORGANIZER" nvarchar2(255),
+ "RECURRANCE_MIN" date,
+ "RECURRANCE_MAX" date,
+ "ACCESS" integer default 0 not null,
+ "SCHEDULE_OBJECT" integer default 0,
+ "SCHEDULE_TAG" nvarchar2(36) default null,
+ "SCHEDULE_ETAGS" nclob default null,
+ "PRIVATE_COMMENTS" integer default 0 not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique("CALENDAR_RESOURCE_ID", "RESOURCE_NAME")
+);
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MO (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('none', 0);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('write', 2);
+create table CALENDAR_ACCESS_TYPE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(32) unique
+);
+
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
+create table TIME_RANGE (
+ "INSTANCE_ID" integer primary key,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "FLOATING" integer not null,
+ "START_DATE" timestamp not null,
+ "END_DATE" timestamp not null,
+ "FBTYPE" integer not null,
+ "TRANSPARENT" integer not null
+);
+
+create table FREE_BUSY_TYPE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
+create table TRANSPARENCY (
+ "TIME_RANGE_INSTANCE_ID" integer not null references TIME_RANGE on delete cascade,
+ "USER_ID" nvarchar2(255),
+ "TRANSPARENT" integer not null
+);
+
+create table ATTACHMENT (
+ "ATTACHMENT_ID" integer primary key,
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "DROPBOX_ID" nvarchar2(255),
+ "CONTENT_TYPE" nvarchar2(255),
+ "SIZE" integer not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "PATH" nvarchar2(1024)
+);
+
+create table ATTACHMENT_CALENDAR_OBJECT (
+ "ATTACHMENT_ID" integer not null references ATTACHMENT on delete cascade,
+ "MANAGED_ID" nvarchar2(255),
+ "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ primary key("ATTACHMENT_ID", "CALENDAR_OBJECT_RESOURCE_ID"),
+ unique("MANAGED_ID", "CALENDAR_OBJECT_RESOURCE_ID")
+);
+
+create table RESOURCE_PROPERTY (
+ "RESOURCE_ID" integer not null,
+ "NAME" nvarchar2(255),
+ "VALUE" nclob,
+ "VIEWER_UID" nvarchar2(255),
+ primary key("RESOURCE_ID", "NAME", "VIEWER_UID")
+);
+
+create table ADDRESSBOOK_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table ADDRESSBOOK_HOME_METADATA (
+ "RESOURCE_ID" integer primary key references ADDRESSBOOK_HOME on delete cascade,
+ "QUOTA_USED_BYTES" integer default 0 not null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table ADDRESSBOOK (
+ "RESOURCE_ID" integer primary key
+);
+
+create table ADDRESSBOOK_METADATA (
+ "RESOURCE_ID" integer primary key references ADDRESSBOOK on delete cascade,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table ADDRESSBOOK_BIND (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "ADDRESSBOOK_RESOURCE_ID" integer not null references ADDRESSBOOK on delete cascade,
+ "ADDRESSBOOK_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "BIND_REVISION" integer default 0 not null,
+ "MESSAGE" nclob,
+ primary key("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_ID"),
+ unique("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_NAME")
+);
+
+create table ADDRESSBOOK_OBJECT (
+ "RESOURCE_ID" integer primary key,
+ "ADDRESSBOOK_RESOURCE_ID" integer not null references ADDRESSBOOK on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "VCARD_TEXT" nclob,
+ "VCARD_UID" nvarchar2(255),
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique("ADDRESSBOOK_RESOURCE_ID", "RESOURCE_NAME"),
+ unique("ADDRESSBOOK_RESOURCE_ID", "VCARD_UID")
+);
+
+create table CALENDAR_OBJECT_REVISIONS (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "CALENDAR_RESOURCE_ID" integer references CALENDAR,
+ "CALENDAR_NAME" nvarchar2(255) default null,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null
+);
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "ADDRESSBOOK_RESOURCE_ID" integer references ADDRESSBOOK,
+ "ADDRESSBOOK_NAME" nvarchar2(255) default null,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null
+);
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+ "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null,
+ unique("NOTIFICATION_HOME_RESOURCE_ID", "RESOURCE_NAME")
+);
+
+create table APN_SUBSCRIPTIONS (
+ "TOKEN" nvarchar2(255),
+ "RESOURCE_KEY" nvarchar2(255),
+ "MODIFIED" integer not null,
+ "SUBSCRIBER_GUID" nvarchar2(255),
+ "USER_AGENT" nvarchar2(255) default null,
+ "IP_ADDR" nvarchar2(255) default null,
+ primary key("TOKEN", "RESOURCE_KEY")
+);
+
+create table IMIP_TOKENS (
+ "TOKEN" nvarchar2(255),
+ "ORGANIZER" nvarchar2(255),
+ "ATTENDEE" nvarchar2(255),
+ "ICALUID" nvarchar2(255),
+ "ACCESSED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ primary key("ORGANIZER", "ATTENDEE", "ICALUID")
+);
+
+create table IMIP_INVITATION_WORK (
+ "WORK_ID" integer primary key not null,
+ "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "FROM_ADDR" nvarchar2(255),
+ "TO_ADDR" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob
+);
+
+create table IMIP_POLLING_WORK (
+ "WORK_ID" integer primary key not null,
+ "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table IMIP_REPLY_WORK (
+ "WORK_ID" integer primary key not null,
+ "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "ORGANIZER" nvarchar2(255),
+ "ATTENDEE" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob
+);
+
+create table PUSH_NOTIFICATION_WORK (
+ "WORK_ID" integer primary key not null,
+ "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "PUSH_ID" nvarchar2(255)
+);
+
+create table GROUP_CACHER_POLLING_WORK (
+ "WORK_ID" integer primary key not null,
+ "NOT_BEFORE" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDARSERVER (
+ "NAME" nvarchar2(255) primary key,
+ "VALUE" nvarchar2(255)
+);
+
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '19');
+insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '4');
+insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '1');
+create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
+ NOTIFICATION_HOME_RESOURCE_ID
+);
+
+create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
+ CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
+ CALENDAR_RESOURCE_ID,
+ ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
+ CALENDAR_RESOURCE_ID,
+ RECURRANCE_MAX
+);
+
+create index CALENDAR_OBJECT_ICALE_82e731d5 on CALENDAR_OBJECT (
+ ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
+ DROPBOX_ID
+);
+
+create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
+ CALENDAR_RESOURCE_ID
+);
+
+create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
+ CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index TRANSPARENCY_TIME_RAN_5f34467f on TRANSPARENCY (
+ TIME_RANGE_INSTANCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
+ CALENDAR_HOME_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_BIND_RESO_205aa75c on ADDRESSBOOK_BIND (
+ ADDRESSBOOK_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_HOME_RESOURCE_ID,
+ CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_2643d556 on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_RESOURCE_ID,
+ RESOURCE_NAME
+);
+
+create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_RESOURCE_ID,
+ REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_f460d62d on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_HOME_RESOURCE_ID,
+ ADDRESSBOOK_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_OBJECT_RE_9a848f39 on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_RESOURCE_ID,
+ RESOURCE_NAME
+);
+
+create index ADDRESSBOOK_OBJECT_RE_cb101e6b on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_RESOURCE_ID,
+ REVISION
+);
+
+create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
+ NOTIFICATION_HOME_RESOURCE_ID,
+ REVISION
+);
+
+create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
+ RESOURCE_KEY
+);
+
+create index IMIP_TOKENS_TOKEN_e94b918f on IMIP_TOKENS (
+ TOKEN
+);
+
Deleted: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v18.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v18.sql 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v18.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,581 +0,0 @@
--- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
-
-----
--- Copyright (c) 2010-2013 Apple Inc. All rights reserved.
---
--- Licensed under the Apache License, Version 2.0 (the "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.
-----
-
------------------
--- Resource ID --
------------------
-
-create sequence RESOURCE_ID_SEQ;
-
--------------------------
--- Cluster Bookkeeping --
--------------------------
-
--- Information about a process connected to this database.
-
--- Note that this must match the node info schema in twext.enterprise.queue.
-create table NODE_INFO (
- HOSTNAME varchar(255) not null,
- PID integer not null,
- PORT integer not null,
- TIME timestamp not null default timezone('UTC', CURRENT_TIMESTAMP),
-
- primary key (HOSTNAME, PORT)
-);
-
--- Unique named locks. This table should always be empty, but rows are
--- temporarily created in order to prevent undesirable concurrency.
-create table NAMED_LOCK (
- LOCK_NAME varchar(255) primary key
-);
-
-
--------------------
--- Calendar Home --
--------------------
-
-create table CALENDAR_HOME (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
- OWNER_UID varchar(255) not null unique, -- implicit index
- DATAVERSION integer default 0 not null
-);
-
-----------------------------
--- Calendar Home Metadata --
-----------------------------
-
-create table CALENDAR_HOME_METADATA (
- RESOURCE_ID integer primary key references CALENDAR_HOME on delete cascade, -- implicit index
- QUOTA_USED_BYTES integer default 0 not null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
---------------
--- Calendar --
---------------
-
-create table CALENDAR (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
-);
-
-
------------------------
--- Calendar Metadata --
------------------------
-
-create table CALENDAR_METADATA (
- RESOURCE_ID integer primary key references CALENDAR on delete cascade, -- implicit index
- SUPPORTED_COMPONENTS varchar(255) default null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
-
----------------------------
--- Sharing Notifications --
----------------------------
-
-create table NOTIFICATION_HOME (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
- OWNER_UID varchar(255) not null unique -- implicit index
-);
-
-create table NOTIFICATION (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
- NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME,
- NOTIFICATION_UID varchar(255) not null,
- XML_TYPE varchar(255) not null,
- XML_DATA text not null,
- MD5 char(32) not null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-
- unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
-);
-
-create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
- NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
-
--------------------
--- Calendar Bind --
--------------------
-
--- Joins CALENDAR_HOME and CALENDAR
-
-create table CALENDAR_BIND (
- CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
- CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
- CALENDAR_RESOURCE_NAME varchar(255) not null,
- BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
- BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
- MESSAGE text,
-
- primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
- unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME) -- implicit index
-);
-
-create index CALENDAR_BIND_RESOURCE_ID on CALENDAR_BIND(CALENDAR_RESOURCE_ID);
-
--- Enumeration of calendar bind modes
-
-create table CALENDAR_BIND_MODE (
- ID integer primary key,
- DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_BIND_MODE values (0, 'own' );
-insert into CALENDAR_BIND_MODE values (1, 'read' );
-insert into CALENDAR_BIND_MODE values (2, 'write');
-insert into CALENDAR_BIND_MODE values (3, 'direct');
-
--- Enumeration of statuses
-
-create table CALENDAR_BIND_STATUS (
- ID integer primary key,
- DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_BIND_STATUS values (0, 'invited' );
-insert into CALENDAR_BIND_STATUS values (1, 'accepted');
-insert into CALENDAR_BIND_STATUS values (2, 'declined');
-insert into CALENDAR_BIND_STATUS values (3, 'invalid');
-
-
----------------------
--- Calendar Object --
----------------------
-
-create table CALENDAR_OBJECT (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
- CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
- RESOURCE_NAME varchar(255) not null,
- ICALENDAR_TEXT text not null,
- ICALENDAR_UID varchar(255) not null,
- ICALENDAR_TYPE varchar(255) not null,
- ATTACHMENTS_MODE integer default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
- DROPBOX_ID varchar(255),
- ORGANIZER varchar(255),
- RECURRANCE_MIN date, -- minimum date that recurrences have been expanded to.
- RECURRANCE_MAX date, -- maximum date that recurrences have been expanded to.
- ACCESS integer default 0 not null,
- SCHEDULE_OBJECT boolean default false,
- SCHEDULE_TAG varchar(36) default null,
- SCHEDULE_ETAGS text default null,
- PRIVATE_COMMENTS boolean default false not null,
- MD5 char(32) not null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-
- unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
-
- -- since the 'inbox' is a 'calendar resource' for the purpose of storing
- -- calendar objects, this constraint has to be selectively enforced by the
- -- application layer.
-
- -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
-);
-
-create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
- CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
-
-create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
- CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
-
-create index CALENDAR_OBJECT_ICALENDAR_UID on
- CALENDAR_OBJECT(ICALENDAR_UID);
-
-create index CALENDAR_OBJECT_DROPBOX_ID on
- CALENDAR_OBJECT(DROPBOX_ID);
-
--- Enumeration of attachment modes
-
-create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
- ID integer primary key,
- DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
-
-
--- Enumeration of calendar access types
-
-create table CALENDAR_ACCESS_TYPE (
- ID integer primary key,
- DESCRIPTION varchar(32) not null unique
-);
-
-insert into CALENDAR_ACCESS_TYPE values (0, '' );
-insert into CALENDAR_ACCESS_TYPE values (1, 'public' );
-insert into CALENDAR_ACCESS_TYPE values (2, 'private' );
-insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
-insert into CALENDAR_ACCESS_TYPE values (4, 'restricted' );
-
------------------
--- Instance ID --
------------------
-
-create sequence INSTANCE_ID_SEQ;
-
-
-----------------
--- Time Range --
-----------------
-
-create table TIME_RANGE (
- INSTANCE_ID integer primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
- CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
- CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
- FLOATING boolean not null,
- START_DATE timestamp not null,
- END_DATE timestamp not null,
- FBTYPE integer not null,
- TRANSPARENT boolean not null
-);
-
-create index TIME_RANGE_CALENDAR_RESOURCE_ID on
- TIME_RANGE(CALENDAR_RESOURCE_ID);
-create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
- TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
-
-
--- Enumeration of free/busy types
-
-create table FREE_BUSY_TYPE (
- ID integer primary key,
- DESCRIPTION varchar(16) not null unique
-);
-
-insert into FREE_BUSY_TYPE values (0, 'unknown' );
-insert into FREE_BUSY_TYPE values (1, 'free' );
-insert into FREE_BUSY_TYPE values (2, 'busy' );
-insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
-insert into FREE_BUSY_TYPE values (4, 'busy-tentative' );
-
-
-------------------
--- Transparency --
-------------------
-
-create table TRANSPARENCY (
- TIME_RANGE_INSTANCE_ID integer not null references TIME_RANGE on delete cascade,
- USER_ID varchar(255) not null,
- TRANSPARENT boolean not null
-);
-
-create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
- TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
-
-
-----------------
--- Attachment --
-----------------
-
-create sequence ATTACHMENT_ID_SEQ;
-
-create table ATTACHMENT (
- ATTACHMENT_ID integer primary key default nextval('ATTACHMENT_ID_SEQ'), -- implicit index
- CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
- DROPBOX_ID varchar(255),
- CONTENT_TYPE varchar(255) not null,
- SIZE integer not null,
- MD5 char(32) not null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- PATH varchar(1024) not null
-);
-
-create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
- ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
-
--- Many-to-many relationship between attachments and calendar objects
-create table ATTACHMENT_CALENDAR_OBJECT (
- ATTACHMENT_ID integer not null references ATTACHMENT on delete cascade,
- MANAGED_ID varchar(255) not null,
- CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
-
- primary key (ATTACHMENT_ID, CALENDAR_OBJECT_RESOURCE_ID), -- implicit index
- unique (MANAGED_ID, CALENDAR_OBJECT_RESOURCE_ID) --implicit index
-);
-
-
------------------------
--- Resource Property --
------------------------
-
-create table RESOURCE_PROPERTY (
- RESOURCE_ID integer not null, -- foreign key: *.RESOURCE_ID
- NAME varchar(255) not null,
- VALUE text not null, -- FIXME: xml?
- VIEWER_UID varchar(255),
-
- primary key (RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
-);
-
-
-----------------------
--- AddressBook Home --
-----------------------
-
-create table ADDRESSBOOK_HOME (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
- OWNER_UID varchar(255) not null unique, -- implicit index
- DATAVERSION integer default 0 not null
-);
-
--------------------------------
--- AddressBook Home Metadata --
--------------------------------
-
-create table ADDRESSBOOK_HOME_METADATA (
- RESOURCE_ID integer primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
- QUOTA_USED_BYTES integer default 0 not null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
------------------
--- AddressBook --
------------------
-
-create table ADDRESSBOOK (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
-);
-
-
---------------------------
--- AddressBook Metadata --
---------------------------
-
-create table ADDRESSBOOK_METADATA (
- RESOURCE_ID integer primary key references ADDRESSBOOK on delete cascade, -- implicit index
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
-
-----------------------
--- AddressBook Bind --
-----------------------
-
--- Joins ADDRESSBOOK_HOME and ADDRESSBOOK
-
-create table ADDRESSBOOK_BIND (
- ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
- ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK on delete cascade,
- ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
- BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
- BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
- MESSAGE text, -- FIXME: xml?
-
- primary key (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID), -- implicit index
- unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME) -- implicit index
-);
-
-create index ADDRESSBOOK_BIND_RESOURCE_ID on
- ADDRESSBOOK_BIND(ADDRESSBOOK_RESOURCE_ID);
-
-create table ADDRESSBOOK_OBJECT (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
- ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK on delete cascade,
- RESOURCE_NAME varchar(255) not null,
- VCARD_TEXT text not null,
- VCARD_UID varchar(255) not null,
- MD5 char(32) not null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-
- unique (ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME), -- implicit index
- unique (ADDRESSBOOK_RESOURCE_ID, VCARD_UID) -- implicit index
-);
-
----------------
--- Revisions --
----------------
-
-create sequence REVISION_SEQ;
-
-
----------------
--- Revisions --
----------------
-
-create table CALENDAR_OBJECT_REVISIONS (
- CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
- CALENDAR_RESOURCE_ID integer references CALENDAR,
- CALENDAR_NAME varchar(255) default null,
- RESOURCE_NAME varchar(255),
- REVISION integer default nextval('REVISION_SEQ') not null,
- DELETED boolean not null
-);
-
-create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
- on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
-
-create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
- on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME);
-
-create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
- on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
-
--------------------------------
--- AddressBook Object Revisions --
--------------------------------
-
-create table ADDRESSBOOK_OBJECT_REVISIONS (
- ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
- ADDRESSBOOK_RESOURCE_ID integer references ADDRESSBOOK,
- ADDRESSBOOK_NAME varchar(255) default null,
- RESOURCE_NAME varchar(255),
- REVISION integer default nextval('REVISION_SEQ') not null,
- DELETED boolean not null
-);
-
-create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_ADDRESSBOOK_RESOURCE_ID
- on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID);
-
-create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
- on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME);
-
-create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_REVISION
- on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, REVISION);
-
------------------------------------
--- Notification Object Revisions --
------------------------------------
-
-create table NOTIFICATION_OBJECT_REVISIONS (
- NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME on delete cascade,
- RESOURCE_NAME varchar(255),
- REVISION integer default nextval('REVISION_SEQ') not null,
- DELETED boolean not null,
-
- unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
-);
-
-create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
- on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
-
--------------------------------------------
--- Apple Push Notification Subscriptions --
--------------------------------------------
-
-create table APN_SUBSCRIPTIONS (
- TOKEN varchar(255) not null,
- RESOURCE_KEY varchar(255) not null,
- MODIFIED integer not null,
- SUBSCRIBER_GUID varchar(255) not null,
- USER_AGENT varchar(255) default null,
- IP_ADDR varchar(255) default null,
-
- primary key (TOKEN, RESOURCE_KEY) -- implicit index
-);
-
-create index APN_SUBSCRIPTIONS_RESOURCE_KEY
- on APN_SUBSCRIPTIONS(RESOURCE_KEY);
-
------------------
--- IMIP Tokens --
------------------
-
-create table IMIP_TOKENS (
- TOKEN varchar(255) not null,
- ORGANIZER varchar(255) not null,
- ATTENDEE varchar(255) not null,
- ICALUID varchar(255) not null,
- ACCESSED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-
- primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
-);
-
-create index IMIP_TOKENS_TOKEN
- on IMIP_TOKENS(TOKEN);
-
-----------------
--- Work Items --
-----------------
-
-create sequence WORKITEM_SEQ;
-
----------------------------
--- IMIP Inivitation Work --
----------------------------
-
-create table IMIP_INVITATION_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
- NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- FROM_ADDR varchar(255) not null,
- TO_ADDR varchar(255) not null,
- ICALENDAR_TEXT text not null
-);
-
------------------------
--- IMIP Polling Work --
------------------------
-
-create table IMIP_POLLING_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
- NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
----------------------
--- IMIP Reply Work --
----------------------
-
-create table IMIP_REPLY_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
- NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- ORGANIZER varchar(255) not null,
- ATTENDEE varchar(255) not null,
- ICALENDAR_TEXT text not null
-);
-
-------------------------
--- Push Notifications --
-------------------------
-
-create table PUSH_NOTIFICATION_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
- NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- PUSH_ID varchar(255) not null
-);
-
------------------
--- GroupCacher --
------------------
-
-create table GROUP_CACHER_POLLING_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
- NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
-
---------------------
--- Schema Version --
---------------------
-
-create table CALENDARSERVER (
- NAME varchar(255) primary key, -- implicit index
- VALUE varchar(255)
-);
-
-insert into CALENDARSERVER values ('VERSION', '18');
-insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '3');
-insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '1');
Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v18.sql (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/old/postgres-dialect/v18.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v18.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v18.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,581 @@
+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2013 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "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.
+----
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+-------------------------
+-- Cluster Bookkeeping --
+-------------------------
+
+-- Information about a process connected to this database.
+
+-- Note that this must match the node info schema in twext.enterprise.queue.
+create table NODE_INFO (
+ HOSTNAME varchar(255) not null,
+ PID integer not null,
+ PORT integer not null,
+ TIME timestamp not null default timezone('UTC', CURRENT_TIMESTAMP),
+
+ primary key (HOSTNAME, PORT)
+);
+
+-- Unique named locks. This table should always be empty, but rows are
+-- temporarily created in order to prevent undesirable concurrency.
+create table NAMED_LOCK (
+ LOCK_NAME varchar(255) primary key
+);
+
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ DATAVERSION integer default 0 not null
+);
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+create table CALENDAR_HOME_METADATA (
+ RESOURCE_ID integer primary key references CALENDAR_HOME on delete cascade, -- implicit index
+ QUOTA_USED_BYTES integer default 0 not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+
+-----------------------
+-- Calendar Metadata --
+-----------------------
+
+create table CALENDAR_METADATA (
+ RESOURCE_ID integer primary key references CALENDAR on delete cascade, -- implicit index
+ SUPPORTED_COMPONENTS varchar(255) default null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique -- implicit index
+);
+
+create table NOTIFICATION (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME,
+ NOTIFICATION_UID varchar(255) not null,
+ XML_TYPE varchar(255) not null,
+ XML_DATA text not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+ NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ CALENDAR_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ MESSAGE text,
+
+ primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+ unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME) -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own' );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+
+
+---------------------
+-- Calendar Object --
+---------------------
+
+create table CALENDAR_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ ICALENDAR_TEXT text not null,
+ ICALENDAR_UID varchar(255) not null,
+ ICALENDAR_TYPE varchar(255) not null,
+ ATTACHMENTS_MODE integer default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+ DROPBOX_ID varchar(255),
+ ORGANIZER varchar(255),
+ RECURRANCE_MIN date, -- minimum date that recurrences have been expanded to.
+ RECURRANCE_MAX date, -- maximum date that recurrences have been expanded to.
+ ACCESS integer default 0 not null,
+ SCHEDULE_OBJECT boolean default false,
+ SCHEDULE_TAG varchar(36) default null,
+ SCHEDULE_ETAGS text default null,
+ PRIVATE_COMMENTS boolean default false not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+ -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+ -- calendar objects, this constraint has to be selectively enforced by the
+ -- application layer.
+
+ -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ICALENDAR_UID on
+ CALENDAR_OBJECT(ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+ CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+ ID integer primary key,
+ DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, '' );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public' );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private' );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted' );
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+ INSTANCE_ID integer primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ FLOATING boolean not null,
+ START_DATE timestamp not null,
+ END_DATE timestamp not null,
+ FBTYPE integer not null,
+ TRANSPARENT boolean not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+ TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+ TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown' );
+insert into FREE_BUSY_TYPE values (1, 'free' );
+insert into FREE_BUSY_TYPE values (2, 'busy' );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative' );
+
+
+------------------
+-- Transparency --
+------------------
+
+create table TRANSPARENCY (
+ TIME_RANGE_INSTANCE_ID integer not null references TIME_RANGE on delete cascade,
+ USER_ID varchar(255) not null,
+ TRANSPARENT boolean not null
+);
+
+create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
+ TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
+
+
+----------------
+-- Attachment --
+----------------
+
+create sequence ATTACHMENT_ID_SEQ;
+
+create table ATTACHMENT (
+ ATTACHMENT_ID integer primary key default nextval('ATTACHMENT_ID_SEQ'), -- implicit index
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ DROPBOX_ID varchar(255),
+ CONTENT_TYPE varchar(255) not null,
+ SIZE integer not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ PATH varchar(1024) not null
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+ ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+-- Many-to-many relationship between attachments and calendar objects
+create table ATTACHMENT_CALENDAR_OBJECT (
+ ATTACHMENT_ID integer not null references ATTACHMENT on delete cascade,
+ MANAGED_ID varchar(255) not null,
+ CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+
+ primary key (ATTACHMENT_ID, CALENDAR_OBJECT_RESOURCE_ID), -- implicit index
+ unique (MANAGED_ID, CALENDAR_OBJECT_RESOURCE_ID) --implicit index
+);
+
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+ RESOURCE_ID integer not null, -- foreign key: *.RESOURCE_ID
+ NAME varchar(255) not null,
+ VALUE text not null, -- FIXME: xml?
+ VIEWER_UID varchar(255),
+
+ primary key (RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ DATAVERSION integer default 0 not null
+);
+
+-------------------------------
+-- AddressBook Home Metadata --
+-------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+ RESOURCE_ID integer primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+ QUOTA_USED_BYTES integer default 0 not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+-----------------
+-- AddressBook --
+-----------------
+
+create table ADDRESSBOOK (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+
+--------------------------
+-- AddressBook Metadata --
+--------------------------
+
+create table ADDRESSBOOK_METADATA (
+ RESOURCE_ID integer primary key references ADDRESSBOOK on delete cascade, -- implicit index
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+----------------------
+-- AddressBook Bind --
+----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK
+
+create table ADDRESSBOOK_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK on delete cascade,
+ ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ MESSAGE text, -- FIXME: xml?
+
+ primary key (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME) -- implicit index
+);
+
+create index ADDRESSBOOK_BIND_RESOURCE_ID on
+ ADDRESSBOOK_BIND(ADDRESSBOOK_RESOURCE_ID);
+
+create table ADDRESSBOOK_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ VCARD_TEXT text not null,
+ VCARD_UID varchar(255) not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+ unique (ADDRESSBOOK_RESOURCE_ID, VCARD_UID) -- implicit index
+);
+
+---------------
+-- Revisions --
+---------------
+
+create sequence REVISION_SEQ;
+
+
+---------------
+-- Revisions --
+---------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ CALENDAR_RESOURCE_ID integer references CALENDAR,
+ CALENDAR_NAME varchar(255) default null,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
+
+-------------------------------
+-- AddressBook Object Revisions --
+-------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ ADDRESSBOOK_RESOURCE_ID integer references ADDRESSBOOK,
+ ADDRESSBOOK_NAME varchar(255) default null,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_ADDRESSBOOK_RESOURCE_ID
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, REVISION);
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+ NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME on delete cascade,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null,
+
+ unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
+
+-------------------------------------------
+-- Apple Push Notification Subscriptions --
+-------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+ TOKEN varchar(255) not null,
+ RESOURCE_KEY varchar(255) not null,
+ MODIFIED integer not null,
+ SUBSCRIBER_GUID varchar(255) not null,
+ USER_AGENT varchar(255) default null,
+ IP_ADDR varchar(255) default null,
+
+ primary key (TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+ on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+-----------------
+-- IMIP Tokens --
+-----------------
+
+create table IMIP_TOKENS (
+ TOKEN varchar(255) not null,
+ ORGANIZER varchar(255) not null,
+ ATTENDEE varchar(255) not null,
+ ICALUID varchar(255) not null,
+ ACCESSED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
+);
+
+create index IMIP_TOKENS_TOKEN
+ on IMIP_TOKENS(TOKEN);
+
+----------------
+-- Work Items --
+----------------
+
+create sequence WORKITEM_SEQ;
+
+---------------------------
+-- IMIP Inivitation Work --
+---------------------------
+
+create table IMIP_INVITATION_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ FROM_ADDR varchar(255) not null,
+ TO_ADDR varchar(255) not null,
+ ICALENDAR_TEXT text not null
+);
+
+-----------------------
+-- IMIP Polling Work --
+-----------------------
+
+create table IMIP_POLLING_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+---------------------
+-- IMIP Reply Work --
+---------------------
+
+create table IMIP_REPLY_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ ORGANIZER varchar(255) not null,
+ ATTENDEE varchar(255) not null,
+ ICALENDAR_TEXT text not null
+);
+
+------------------------
+-- Push Notifications --
+------------------------
+
+create table PUSH_NOTIFICATION_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ PUSH_ID varchar(255) not null
+);
+
+-----------------
+-- GroupCacher --
+-----------------
+
+create table GROUP_CACHER_POLLING_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+ NAME varchar(255) primary key, -- implicit index
+ VALUE varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '18');
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '3');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '1');
Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v19.sql (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/old/postgres-dialect/v19.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v19.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v19.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,605 @@
+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2013 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "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.
+----
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+-------------------------
+-- Cluster Bookkeeping --
+-------------------------
+
+-- Information about a process connected to this database.
+
+-- Note that this must match the node info schema in twext.enterprise.queue.
+create table NODE_INFO (
+ HOSTNAME varchar(255) not null,
+ PID integer not null,
+ PORT integer not null,
+ TIME timestamp not null default timezone('UTC', CURRENT_TIMESTAMP),
+
+ primary key (HOSTNAME, PORT)
+);
+
+-- Unique named locks. This table should always be empty, but rows are
+-- temporarily created in order to prevent undesirable concurrency.
+create table NAMED_LOCK (
+ LOCK_NAME varchar(255) primary key
+);
+
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ DATAVERSION integer default 0 not null
+);
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+create table CALENDAR_HOME_METADATA (
+ RESOURCE_ID integer primary key references CALENDAR_HOME on delete cascade, -- implicit index
+ QUOTA_USED_BYTES integer default 0 not null,
+ DEFAULT_EVENTS integer default null references CALENDAR on delete set null,
+ DEFAULT_TASKS integer default null references CALENDAR on delete set null,
+ ALARM_VEVENT_TIMED text default null,
+ ALARM_VEVENT_ALLDAY text default null,
+ ALARM_VTODO_TIMED text default null,
+ ALARM_VTODO_ALLDAY text default null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+-----------------------
+-- Calendar Metadata --
+-----------------------
+
+create table CALENDAR_METADATA (
+ RESOURCE_ID integer primary key references CALENDAR on delete cascade, -- implicit index
+ SUPPORTED_COMPONENTS varchar(255) default null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique -- implicit index
+);
+
+create table NOTIFICATION (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME,
+ NOTIFICATION_UID varchar(255) not null,
+ XML_TYPE varchar(255) not null,
+ XML_DATA text not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+ NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ CALENDAR_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ BIND_REVISION integer default 0 not null,
+ MESSAGE text,
+ TRANSP integer default 0 not null, -- enum CALENDAR_TRANSP
+ ALARM_VEVENT_TIMED text default null,
+ ALARM_VEVENT_ALLDAY text default null,
+ ALARM_VTODO_TIMED text default null,
+ ALARM_VTODO_ALLDAY text default null,
+
+ primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+ unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME) -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own' );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+
+
+-- Enumeration of transparency
+
+create table CALENDAR_TRANSP (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_TRANSP values (0, 'opaque' );
+insert into CALENDAR_TRANSP values (1, 'transparent');
+
+
+---------------------
+-- Calendar Object --
+---------------------
+
+create table CALENDAR_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ ICALENDAR_TEXT text not null,
+ ICALENDAR_UID varchar(255) not null,
+ ICALENDAR_TYPE varchar(255) not null,
+ ATTACHMENTS_MODE integer default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+ DROPBOX_ID varchar(255),
+ ORGANIZER varchar(255),
+ RECURRANCE_MIN date, -- minimum date that recurrences have been expanded to.
+ RECURRANCE_MAX date, -- maximum date that recurrences have been expanded to.
+ ACCESS integer default 0 not null,
+ SCHEDULE_OBJECT boolean default false,
+ SCHEDULE_TAG varchar(36) default null,
+ SCHEDULE_ETAGS text default null,
+ PRIVATE_COMMENTS boolean default false not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+ -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+ -- calendar objects, this constraint has to be selectively enforced by the
+ -- application layer.
+
+ -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ICALENDAR_UID on
+ CALENDAR_OBJECT(ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+ CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+ ID integer primary key,
+ DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, '' );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public' );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private' );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted' );
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+ INSTANCE_ID integer primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ FLOATING boolean not null,
+ START_DATE timestamp not null,
+ END_DATE timestamp not null,
+ FBTYPE integer not null,
+ TRANSPARENT boolean not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+ TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+ TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown' );
+insert into FREE_BUSY_TYPE values (1, 'free' );
+insert into FREE_BUSY_TYPE values (2, 'busy' );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative' );
+
+
+------------------
+-- Transparency --
+------------------
+
+create table TRANSPARENCY (
+ TIME_RANGE_INSTANCE_ID integer not null references TIME_RANGE on delete cascade,
+ USER_ID varchar(255) not null,
+ TRANSPARENT boolean not null
+);
+
+create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
+ TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
+
+
+----------------
+-- Attachment --
+----------------
+
+create sequence ATTACHMENT_ID_SEQ;
+
+create table ATTACHMENT (
+ ATTACHMENT_ID integer primary key default nextval('ATTACHMENT_ID_SEQ'), -- implicit index
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ DROPBOX_ID varchar(255),
+ CONTENT_TYPE varchar(255) not null,
+ SIZE integer not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ PATH varchar(1024) not null
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+ ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+-- Many-to-many relationship between attachments and calendar objects
+create table ATTACHMENT_CALENDAR_OBJECT (
+ ATTACHMENT_ID integer not null references ATTACHMENT on delete cascade,
+ MANAGED_ID varchar(255) not null,
+ CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+
+ primary key (ATTACHMENT_ID, CALENDAR_OBJECT_RESOURCE_ID), -- implicit index
+ unique (MANAGED_ID, CALENDAR_OBJECT_RESOURCE_ID) --implicit index
+);
+
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+ RESOURCE_ID integer not null, -- foreign key: *.RESOURCE_ID
+ NAME varchar(255) not null,
+ VALUE text not null, -- FIXME: xml?
+ VIEWER_UID varchar(255),
+
+ primary key (RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ DATAVERSION integer default 0 not null
+);
+
+-------------------------------
+-- AddressBook Home Metadata --
+-------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+ RESOURCE_ID integer primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+ QUOTA_USED_BYTES integer default 0 not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+-----------------
+-- AddressBook --
+-----------------
+
+create table ADDRESSBOOK (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+
+--------------------------
+-- AddressBook Metadata --
+--------------------------
+
+create table ADDRESSBOOK_METADATA (
+ RESOURCE_ID integer primary key references ADDRESSBOOK on delete cascade, -- implicit index
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+----------------------
+-- AddressBook Bind --
+----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK
+
+create table ADDRESSBOOK_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK on delete cascade,
+ ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ BIND_REVISION integer default 0 not null,
+ MESSAGE text, -- FIXME: xml?
+
+ primary key (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME) -- implicit index
+);
+
+create index ADDRESSBOOK_BIND_RESOURCE_ID on
+ ADDRESSBOOK_BIND(ADDRESSBOOK_RESOURCE_ID);
+
+create table ADDRESSBOOK_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ VCARD_TEXT text not null,
+ VCARD_UID varchar(255) not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+ unique (ADDRESSBOOK_RESOURCE_ID, VCARD_UID) -- implicit index
+);
+
+---------------
+-- Revisions --
+---------------
+
+create sequence REVISION_SEQ;
+
+
+---------------
+-- Revisions --
+---------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ CALENDAR_RESOURCE_ID integer references CALENDAR,
+ CALENDAR_NAME varchar(255) default null,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
+
+-------------------------------
+-- AddressBook Object Revisions --
+-------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ ADDRESSBOOK_RESOURCE_ID integer references ADDRESSBOOK,
+ ADDRESSBOOK_NAME varchar(255) default null,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_ADDRESSBOOK_RESOURCE_ID
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, REVISION);
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+ NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME on delete cascade,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null,
+
+ unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
+
+-------------------------------------------
+-- Apple Push Notification Subscriptions --
+-------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+ TOKEN varchar(255) not null,
+ RESOURCE_KEY varchar(255) not null,
+ MODIFIED integer not null,
+ SUBSCRIBER_GUID varchar(255) not null,
+ USER_AGENT varchar(255) default null,
+ IP_ADDR varchar(255) default null,
+
+ primary key (TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+ on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+-----------------
+-- IMIP Tokens --
+-----------------
+
+create table IMIP_TOKENS (
+ TOKEN varchar(255) not null,
+ ORGANIZER varchar(255) not null,
+ ATTENDEE varchar(255) not null,
+ ICALUID varchar(255) not null,
+ ACCESSED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
+);
+
+create index IMIP_TOKENS_TOKEN
+ on IMIP_TOKENS(TOKEN);
+
+----------------
+-- Work Items --
+----------------
+
+create sequence WORKITEM_SEQ;
+
+---------------------------
+-- IMIP Inivitation Work --
+---------------------------
+
+create table IMIP_INVITATION_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ FROM_ADDR varchar(255) not null,
+ TO_ADDR varchar(255) not null,
+ ICALENDAR_TEXT text not null
+);
+
+-----------------------
+-- IMIP Polling Work --
+-----------------------
+
+create table IMIP_POLLING_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+---------------------
+-- IMIP Reply Work --
+---------------------
+
+create table IMIP_REPLY_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ ORGANIZER varchar(255) not null,
+ ATTENDEE varchar(255) not null,
+ ICALENDAR_TEXT text not null
+);
+
+------------------------
+-- Push Notifications --
+------------------------
+
+create table PUSH_NOTIFICATION_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ PUSH_ID varchar(255) not null
+);
+
+-----------------
+-- GroupCacher --
+-----------------
+
+create table GROUP_CACHER_POLLING_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+ NAME varchar(255) primary key, -- implicit index
+ VALUE varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '19');
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '4');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '1');
Deleted: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,59 +0,0 @@
-----
--- Copyright (c) 2012-2013 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.
-----
-
----------------------------------------------------
--- Upgrade database schema from VERSION 18 to 19 --
----------------------------------------------------
-
--- Calendar home related updates
-
-alter table ATTACHMENT
- add ("DEFAULT_EVENTS" integer default null references CALENDAR on delete set null,
- "DEFAULT_TASKS" integer default null references CALENDAR on delete set null,
- "ALARM_VEVENT_TIMED" nclob default null,
- "ALARM_VEVENT_ALLDAY" nclob default null,
- "ALARM_VTODO_TIMED" nclob default null,
- "ALARM_VTODO_ALLDAY" nclob default null);
-
-
--- Calendar bind related updates
-
-alter table CALENDAR_BIND
- add ("BIND_REVISION" integer default 0 not null,
- "TRANSP" integer default 0 not null,
- "ALARM_VEVENT_TIMED" nclob default null,
- "ALARM_VEVENT_ALLDAY" nclob default null,
- "ALARM_VTODO_TIMED" nclob default null,
- "ALARM_VTODO_ALLDAY" nclob default null);
-
-create table CALENDAR_TRANSP (
- "ID" integer primary key,
- "DESCRIPTION" nvarchar2(16) unique
-);
-
-insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('opaque', 0);
-insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('transparent', 1);
-
-
--- Addressbook bind related updates
-
-alter table ADDRESSBOOK_BIND
- add ("BIND_REVISION" integer default 0 not null);
-
-
--- Now update the version
--- No data upgrades
-update CALENDARSERVER set VALUE = '19' where NAME = 'VERSION';
Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,59 @@
+----
+-- Copyright (c) 2012-2013 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.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 18 to 19 --
+---------------------------------------------------
+
+-- Calendar home related updates
+
+alter table ATTACHMENT
+ add ("DEFAULT_EVENTS" integer default null references CALENDAR on delete set null,
+ "DEFAULT_TASKS" integer default null references CALENDAR on delete set null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null);
+
+
+-- Calendar bind related updates
+
+alter table CALENDAR_BIND
+ add ("BIND_REVISION" integer default 0 not null,
+ "TRANSP" integer default 0 not null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null);
+
+create table CALENDAR_TRANSP (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('opaque', 0);
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('transparent', 1);
+
+
+-- Addressbook bind related updates
+
+alter table ADDRESSBOOK_BIND
+ add ("BIND_REVISION" integer default 0 not null);
+
+
+-- Now update the version
+-- No data upgrades
+update CALENDARSERVER set VALUE = '19' where NAME = 'VERSION';
Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_19_to_20.sql (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_19_to_20.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_19_to_20.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_19_to_20.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,251 @@
+----
+-- Copyright (c) 2011-2013 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.
+----
+
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 19 to 20 --
+---------------------------------------------------
+
+----------------
+-- New Tables --
+----------------
+
+-----------------------------
+-- Shared AddressBook Bind --
+-----------------------------
+
+-- Joins sharee ADDRESSBOOK_HOME and owner ADDRESSBOOK_HOME
+
+create table SHARED_ADDRESSBOOK_BIND (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "OWNER_ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "ADDRESSBOOK_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "MESSAGE" nclob,
+ primary key("ADDRESSBOOK_HOME_RESOURCE_ID", "OWNER_ADDRESSBOOK_HOME_RESOURCE_ID"),
+ unique("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_NAME")
+);
+
+create index SHARED_ADDRESSBOOK_BI_e9a2e6d4 on SHARED_ADDRESSBOOK_BIND (
+ OWNER_ADDRESSBOOK_HOME_RESOURCE_ID
+);
+
+
+-----------------------
+-- Shared Group Bind --
+-----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (kind == group)
+
+create table SHARED_GROUP_BIND (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "GROUP_RESOURCE_ID" integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ "GROUP_ADDRESSBOOK_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "MESSAGE" nclob,
+ primary key("ADDRESSBOOK_HOME_RESOURCE_ID", "GROUP_RESOURCE_ID"),
+ unique("ADDRESSBOOK_HOME_RESOURCE_ID", "GROUP_ADDRESSBOOK_RESOURCE_NAME")
+);
+
+create index SHARED_GROUP_BIND_RES_cf52f95d on SHARED_GROUP_BIND (
+ GROUP_RESOURCE_ID
+);
+
+
+-----------------------------
+-- AddressBook Object kind --
+-----------------------------
+
+create table ADDRESSBOOK_OBJECT_KIND (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('person', 0);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('group', 1);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('resource', 2);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('location', 3);
+
+
+---------------------------------
+-- Address Book Object Members --
+---------------------------------
+
+create table ABO_MEMBERS (
+ "GROUP_ID" integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ "ADDRESSBOOK_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "MEMBER_ID" integer not null references ADDRESSBOOK_OBJECT,
+ primary key("GROUP_ID", "MEMBER_ID")
+);
+
+
+------------------------------------------
+-- Address Book Object Foreign Members --
+------------------------------------------
+
+create table ABO_FOREIGN_MEMBERS (
+ "GROUP_ID" integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ "ADDRESSBOOK_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "MEMBER_ADDRESS" nvarchar2(255),
+ primary key("GROUP_ID", "MEMBER_ADDRESS")
+);
+
+
+
+-----------------------------
+-- Alter ADDRESSBOOK_HOME --
+-----------------------------
+
+alter table ADDRESSBOOK_HOME
+ add ("ADDRESSBOOK_PROPERTY_STORE_ID" integer not null);
+
+update ADDRESSBOOK_HOME
+ set ADDRESSBOOK_PROPERTY_STORE_ID = (
+ select ADDRESSBOOK_RESOURCE_ID
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_HOME_RESOURCE_ID = ADDRESSBOOK_HOME.RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ )
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_HOME_RESOURCE_ID = ADDRESSBOOK_HOME.RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ );
+
+
+--------------------------------
+-- change ADDRESSBOOK_OBJECT --
+--------------------------------
+
+alter table ADDRESSBOOK_OBJECT
+ add ("KIND" integer); -- enum ADDRESSBOOK_OBJECT_KIND
+ add ("ADDRESSBOOK_HOME_RESOURCE_ID" integer references ADDRESSBOOK_HOME on delete cascade);
+
+update ADDRESSBOOK_OBJECT
+ set ADDRESSBOOK_HOME_RESOURCE_ID = (
+ select ADDRESSBOOK_HOME_RESOURCE_ID
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT.ADDRESSBOOK_RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ ), KIND = 0 -- ADDRESSBOOK_OBJECT_KIND 'person'
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT.ADDRESSBOOK_RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ );
+
+-- delete rows for shared and non-default address books
+delete
+ from ADDRESSBOOK_OBJECT
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT.ADDRESSBOOK_RESOURCE_ID and (
+ ADDRESSBOOK_BIND.BIND_MODE != 0 or -- not CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME != 'addressbook'
+ )
+ );
+
+-- add non null constraints after update and delete are complete
+alter table ADDRESSBOOK_OBJECT
+ modify ("KIND" not null,
+ "ADDRESSBOOK_HOME_RESOURCE_ID" not null)
+ drop ("ADDRESSBOOK_RESOURCE_ID");
+
+
+------------------------------------------
+-- change ADDRESSBOOK_OBJECT_REVISIONS --
+------------------------------------------
+
+alter table ADDRESSBOOK_OBJECT_REVISIONS
+ add ("OWNER_ADDRESSBOOK_HOME_RESOURCE_ID" integer references ADDRESSBOOK_HOME);
+
+update ADDRESSBOOK_OBJECT_REVISIONS
+ set OWNER_ADDRESSBOOK_HOME_RESOURCE_ID = (
+ select ADDRESSBOOK_HOME_RESOURCE_ID
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT_REVISIONS.ADDRESSBOOK_RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ )
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT_REVISIONS.ADDRESSBOOK_RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ );
+
+-- delete rows for shared and non-default address books
+delete
+ from ADDRESSBOOK_OBJECT_REVISIONS
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT_REVISIONS.ADDRESSBOOK_RESOURCE_ID and (
+ ADDRESSBOOK_BIND.BIND_MODE != 0 or -- not CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME != 'addressbook'
+ )
+ );
+
+alter table ADDRESSBOOK_OBJECT_REVISIONS
+ drop ("ADDRESSBOOK_RESOURCE_ID");
+
+
+-------------------------------
+-- change RESOURCE_PROPERTY --
+-------------------------------
+
+-- delete rows for shared and non-default address books
+delete
+ from RESOURCE_PROPERTY
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = RESOURCE_PROPERTY.RESOURCE_ID and (
+ ADDRESSBOOK_BIND.BIND_MODE != 0 or -- not CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME != 'addressbook'
+ )
+ );
+
+
+-------------------------------------
+-- Drop ADDRESSBOOK related tables --
+-------------------------------------
+
+drop table ADDRESSBOOK_METADATA;
+drop table ADDRESSBOOK_BIND;
+drop table ADDRESSBOOK;
+
+-- update schema version
+update CALENDARSERVER set VALUE = '20' where NAME = 'VERSION';
Deleted: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,60 +0,0 @@
-----
--- Copyright (c) 2012-2013 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.
-----
-
----------------------------------------------------
--- Upgrade database schema from VERSION 18 to 19 --
----------------------------------------------------
-
-
--- Calendar home related updates
-
-alter table CALENDAR_HOME_METADATA
- add column DEFAULT_EVENTS integer default null references CALENDAR on delete set null,
- add column DEFAULT_TASKS integer default null references CALENDAR on delete set null,
- add column ALARM_VEVENT_TIMED text default null,
- add column ALARM_VEVENT_ALLDAY text default null,
- add column ALARM_VTODO_TIMED text default null,
- add column ALARM_VTODO_ALLDAY text default null;
-
-
--- Calendar bind related updates
-
-alter table CALENDAR_BIND
- add column BIND_REVISION integer default 0 not null,
- add column TRANSP integer default 0 not null,
- add column ALARM_VEVENT_TIMED text default null,
- add column ALARM_VEVENT_ALLDAY text default null,
- add column ALARM_VTODO_TIMED text default null,
- add column ALARM_VTODO_ALLDAY text default null;
-
-create table CALENDAR_TRANSP (
- ID integer primary key,
- DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_TRANSP values (0, 'opaque' );
-insert into CALENDAR_TRANSP values (1, 'transparent');
-
-
--- Addressbook bind related updates
-
-alter table ADDRESSBOOK_BIND
- add column BIND_REVISION integer default 0 not null;
-
-
--- Now update the version
--- No data upgrades
-update CALENDARSERVER set VALUE = '19' where NAME = 'VERSION';
Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,60 @@
+----
+-- Copyright (c) 2012-2013 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.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 18 to 19 --
+---------------------------------------------------
+
+
+-- Calendar home related updates
+
+alter table CALENDAR_HOME_METADATA
+ add column DEFAULT_EVENTS integer default null references CALENDAR on delete set null,
+ add column DEFAULT_TASKS integer default null references CALENDAR on delete set null,
+ add column ALARM_VEVENT_TIMED text default null,
+ add column ALARM_VEVENT_ALLDAY text default null,
+ add column ALARM_VTODO_TIMED text default null,
+ add column ALARM_VTODO_ALLDAY text default null;
+
+
+-- Calendar bind related updates
+
+alter table CALENDAR_BIND
+ add column BIND_REVISION integer default 0 not null,
+ add column TRANSP integer default 0 not null,
+ add column ALARM_VEVENT_TIMED text default null,
+ add column ALARM_VEVENT_ALLDAY text default null,
+ add column ALARM_VTODO_TIMED text default null,
+ add column ALARM_VTODO_ALLDAY text default null;
+
+create table CALENDAR_TRANSP (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_TRANSP values (0, 'opaque' );
+insert into CALENDAR_TRANSP values (1, 'transparent');
+
+
+-- Addressbook bind related updates
+
+alter table ADDRESSBOOK_BIND
+ add column BIND_REVISION integer default 0 not null;
+
+
+-- Now update the version
+-- No data upgrades
+update CALENDARSERVER set VALUE = '19' where NAME = 'VERSION';
Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_19_to_20.sql (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_19_to_20.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_19_to_20.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_19_to_20.sql 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,250 @@
+----
+-- Copyright (c) 2011-2013 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.
+----
+
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 19 to 20 --
+---------------------------------------------------
+
+----------------
+-- New Tables --
+----------------
+
+-----------------------------
+-- Shared AddressBook Bind --
+-----------------------------
+
+-- Joins sharee ADDRESSBOOK_HOME and owner ADDRESSBOOK_HOME
+
+create table SHARED_ADDRESSBOOK_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ OWNER_ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ MESSAGE text, -- FIXME: xml?
+
+ primary key (ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_ADDRESSBOOK_HOME_RESOURCE_ID), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME) -- implicit index
+);
+
+create index SHARED_ADDRESSBOOK_BIND_RESOURCE_ID on
+ SHARED_ADDRESSBOOK_BIND(OWNER_ADDRESSBOOK_HOME_RESOURCE_ID);
+
+
+-----------------------
+-- Shared Group Bind --
+-----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (kind == group)
+
+create table SHARED_GROUP_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ GROUP_RESOURCE_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ GROUP_ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ MESSAGE text, -- FIXME: xml?
+
+ primary key (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_RESOURCE_ID), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_RESOURCE_NAME) -- implicit index
+);
+
+create index SHARED_GROUP_BIND_RESOURCE_ID on
+ SHARED_GROUP_BIND(GROUP_RESOURCE_ID);
+
+-----------------------------
+-- AddressBook Object kind --
+-----------------------------
+
+create table ADDRESSBOOK_OBJECT_KIND (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND values (0, 'person');
+insert into ADDRESSBOOK_OBJECT_KIND values (1, 'group' );
+insert into ADDRESSBOOK_OBJECT_KIND values (2, 'resource');
+insert into ADDRESSBOOK_OBJECT_KIND values (3, 'location');
+
+
+---------------------------------
+-- Address Book Object Members --
+---------------------------------
+
+create table ABO_MEMBERS (
+ GROUP_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade, -- AddressBook Object's (kind=='group') RESOURCE_ID
+ ADDRESSBOOK_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ MEMBER_ID integer not null references ADDRESSBOOK_OBJECT, -- member AddressBook Object's RESOURCE_ID
+ primary key (GROUP_ID, MEMBER_ID) -- implicit index
+);
+
+
+------------------------------------------
+-- Address Book Object Foreign Members --
+------------------------------------------
+
+create table ABO_FOREIGN_MEMBERS (
+ GROUP_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade, -- AddressBook Object's (kind=='group') RESOURCE_ID
+ ADDRESSBOOK_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ MEMBER_ADDRESS varchar(255) not null, -- member AddressBook Object's 'calendar' address
+ primary key (GROUP_ID, MEMBER_ADDRESS) -- implicit index
+);
+
+
+
+-----------------------------
+-- Alter ADDRESSBOOK_HOME --
+-----------------------------
+
+alter table ADDRESSBOOK_HOME
+ add column ADDRESSBOOK_PROPERTY_STORE_ID integer default nextval('RESOURCE_ID_SEQ') not null;
+
+update ADDRESSBOOK_HOME
+ set ADDRESSBOOK_PROPERTY_STORE_ID = (
+ select ADDRESSBOOK_RESOURCE_ID
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_HOME_RESOURCE_ID = ADDRESSBOOK_HOME.RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ )
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_HOME_RESOURCE_ID = ADDRESSBOOK_HOME.RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ );
+
+
+--------------------------------
+-- change ADDRESSBOOK_OBJECT --
+--------------------------------
+
+alter table ADDRESSBOOK_OBJECT
+ add column KIND integer, -- enum ADDRESSBOOK_OBJECT_KIND
+ add column ADDRESSBOOK_HOME_RESOURCE_ID integer references ADDRESSBOOK_HOME on delete cascade;
+
+update ADDRESSBOOK_OBJECT
+ set ADDRESSBOOK_HOME_RESOURCE_ID = (
+ select ADDRESSBOOK_HOME_RESOURCE_ID
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT.ADDRESSBOOK_RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ ), KIND = 0 -- ADDRESSBOOK_OBJECT_KIND 'person'
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT.ADDRESSBOOK_RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ );
+
+-- delete rows for shared and non-default address books
+delete
+ from ADDRESSBOOK_OBJECT
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT.ADDRESSBOOK_RESOURCE_ID and (
+ ADDRESSBOOK_BIND.BIND_MODE != 0 or -- not CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME != 'addressbook'
+ )
+ );
+
+-- add non null constraints after update and delete are complete
+alter table ADDRESSBOOK_OBJECT
+ alter column KIND set not null,
+ alter column ADDRESSBOOK_HOME_RESOURCE_ID set not null,
+ drop column ADDRESSBOOK_RESOURCE_ID;
+
+
+------------------------------------------
+-- change ADDRESSBOOK_OBJECT_REVISIONS --
+------------------------------------------
+
+alter table ADDRESSBOOK_OBJECT_REVISIONS
+ add column OWNER_ADDRESSBOOK_HOME_RESOURCE_ID integer references ADDRESSBOOK_HOME;
+
+update ADDRESSBOOK_OBJECT_REVISIONS
+ set OWNER_ADDRESSBOOK_HOME_RESOURCE_ID = (
+ select ADDRESSBOOK_HOME_RESOURCE_ID
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT_REVISIONS.ADDRESSBOOK_RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ )
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT_REVISIONS.ADDRESSBOOK_RESOURCE_ID and
+ ADDRESSBOOK_BIND.BIND_MODE = 0 and -- CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME = 'addressbook'
+ );
+
+-- delete rows for shared and non-default address books
+delete
+ from ADDRESSBOOK_OBJECT_REVISIONS
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = ADDRESSBOOK_OBJECT_REVISIONS.ADDRESSBOOK_RESOURCE_ID and (
+ ADDRESSBOOK_BIND.BIND_MODE != 0 or -- not CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME != 'addressbook'
+ )
+ );
+
+alter table ADDRESSBOOK_OBJECT_REVISIONS
+ drop column ADDRESSBOOK_RESOURCE_ID;
+
+
+-------------------------------
+-- change RESOURCE_PROPERTY --
+-------------------------------
+
+-- delete rows for shared and non-default address books
+delete
+ from RESOURCE_PROPERTY
+ where exists (
+ select *
+ from ADDRESSBOOK_BIND
+ where
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID = RESOURCE_PROPERTY.RESOURCE_ID and (
+ ADDRESSBOOK_BIND.BIND_MODE != 0 or -- not CALENDAR_BIND_MODE 'own'
+ ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME != 'addressbook'
+ )
+ );
+
+
+-------------------------------------
+-- Drop ADDRESSBOOK related tables --
+-------------------------------------
+
+drop table ADDRESSBOOK_METADATA;
+drop table ADDRESSBOOK_BIND;
+drop table ADDRESSBOOK;
+
+-- update schema version
+update CALENDARSERVER set VALUE = '20' where NAME = 'VERSION';
Modified: CalendarServer/trunk/txdav/common/datastore/sql_tables.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_tables.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/sql_tables.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -58,12 +58,18 @@
schema.CALENDAR_BIND.CALENDAR_RESOURCE_ID
schema.CALENDAR_BIND.HOME_RESOURCE_ID = \
schema.CALENDAR_BIND.CALENDAR_HOME_RESOURCE_ID
-schema.ADDRESSBOOK_BIND.RESOURCE_NAME = \
- schema.ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME
-schema.ADDRESSBOOK_BIND.RESOURCE_ID = \
- schema.ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_ID
-schema.ADDRESSBOOK_BIND.HOME_RESOURCE_ID = \
- schema.ADDRESSBOOK_BIND.ADDRESSBOOK_HOME_RESOURCE_ID
+schema.SHARED_ADDRESSBOOK_BIND.RESOURCE_NAME = \
+ schema.SHARED_ADDRESSBOOK_BIND.ADDRESSBOOK_RESOURCE_NAME
+schema.SHARED_ADDRESSBOOK_BIND.RESOURCE_ID = \
+ schema.SHARED_ADDRESSBOOK_BIND.OWNER_ADDRESSBOOK_HOME_RESOURCE_ID
+schema.SHARED_ADDRESSBOOK_BIND.HOME_RESOURCE_ID = \
+ schema.SHARED_ADDRESSBOOK_BIND.ADDRESSBOOK_HOME_RESOURCE_ID
+schema.SHARED_GROUP_BIND.RESOURCE_NAME = \
+ schema.SHARED_GROUP_BIND.GROUP_ADDRESSBOOK_RESOURCE_NAME
+schema.SHARED_GROUP_BIND.RESOURCE_ID = \
+ schema.SHARED_GROUP_BIND.GROUP_RESOURCE_ID
+schema.SHARED_GROUP_BIND.HOME_RESOURCE_ID = \
+ schema.SHARED_GROUP_BIND.ADDRESSBOOK_HOME_RESOURCE_ID
schema.CALENDAR_OBJECT_REVISIONS.RESOURCE_ID = \
schema.CALENDAR_OBJECT_REVISIONS.CALENDAR_RESOURCE_ID
schema.CALENDAR_OBJECT_REVISIONS.HOME_RESOURCE_ID = \
@@ -71,7 +77,7 @@
schema.CALENDAR_OBJECT_REVISIONS.COLLECTION_NAME = \
schema.CALENDAR_OBJECT_REVISIONS.CALENDAR_NAME
schema.ADDRESSBOOK_OBJECT_REVISIONS.RESOURCE_ID = \
- schema.ADDRESSBOOK_OBJECT_REVISIONS.ADDRESSBOOK_RESOURCE_ID
+ schema.ADDRESSBOOK_OBJECT_REVISIONS.OWNER_ADDRESSBOOK_HOME_RESOURCE_ID
schema.ADDRESSBOOK_OBJECT_REVISIONS.HOME_RESOURCE_ID = \
schema.ADDRESSBOOK_OBJECT_REVISIONS.ADDRESSBOOK_HOME_RESOURCE_ID
schema.ADDRESSBOOK_OBJECT_REVISIONS.COLLECTION_NAME = \
@@ -91,7 +97,7 @@
schema.ADDRESSBOOK_OBJECT.UID = \
schema.ADDRESSBOOK_OBJECT.VCARD_UID
schema.ADDRESSBOOK_OBJECT.PARENT_RESOURCE_ID = \
- schema.ADDRESSBOOK_OBJECT.ADDRESSBOOK_RESOURCE_ID
+ schema.ADDRESSBOOK_OBJECT.ADDRESSBOOK_HOME_RESOURCE_ID
@@ -185,40 +191,16 @@
_BIND_MODE_DIRECT = _bindMode('direct')
-# Compatibility tables for string formatting:
-CALENDAR_HOME_TABLE = _S(schema.CALENDAR_HOME)
-CALENDAR_HOME_METADATA_TABLE = _S(schema.CALENDAR_HOME_METADATA)
-ADDRESSBOOK_HOME_TABLE = _S(schema.ADDRESSBOOK_HOME)
-ADDRESSBOOK_HOME_METADATA_TABLE = _S(schema.ADDRESSBOOK_HOME_METADATA)
-NOTIFICATION_HOME_TABLE = _S(schema.NOTIFICATION_HOME)
-CALENDAR_TABLE = _S(schema.CALENDAR)
-ADDRESSBOOK_TABLE = _S(schema.ADDRESSBOOK)
-CALENDAR_BIND_TABLE = _S(schema.CALENDAR_BIND)
-ADDRESSBOOK_BIND_TABLE = _S(schema.ADDRESSBOOK_BIND)
-CALENDAR_OBJECT_REVISIONS_TABLE = _S(schema.CALENDAR_OBJECT_REVISIONS)
-ADDRESSBOOK_OBJECT_REVISIONS_TABLE = _S(schema.ADDRESSBOOK_OBJECT_REVISIONS)
-NOTIFICATION_OBJECT_REVISIONS_TABLE = _S(schema.NOTIFICATION_OBJECT_REVISIONS)
-CALENDAR_OBJECT_TABLE = _S(schema.CALENDAR_OBJECT)
-ADDRESSBOOK_OBJECT_TABLE = _S(schema.ADDRESSBOOK_OBJECT)
+_addressBookObjectKind = _schemaConstants(
+ schema.ADDRESSBOOK_OBJECT_KIND.DESCRIPTION,
+ schema.ADDRESSBOOK_OBJECT_KIND.ID
+)
-# Some combined tables used in join-string-formatting.
-CALENDAR_AND_CALENDAR_BIND = _combine(CHILD=CALENDAR_TABLE,
- BIND=CALENDAR_BIND_TABLE)
-CALENDAR_OBJECT_AND_BIND_TABLE = _combine(OBJECT=CALENDAR_OBJECT_TABLE,
- BIND=CALENDAR_BIND_TABLE)
-CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE = _combine(
- REV=CALENDAR_OBJECT_REVISIONS_TABLE,
- BIND=CALENDAR_BIND_TABLE)
-ADDRESSBOOK_AND_ADDRESSBOOK_BIND = _combine(CHILD=ADDRESSBOOK_TABLE,
- BIND=ADDRESSBOOK_BIND_TABLE)
-ADDRESSBOOK_OBJECT_AND_BIND_TABLE = _combine(OBJECT=ADDRESSBOOK_OBJECT_TABLE,
- BIND=ADDRESSBOOK_BIND_TABLE)
-ADDRESSBOOK_OBJECT_REVISIONS_AND_BIND_TABLE = _combine(
- REV=ADDRESSBOOK_OBJECT_REVISIONS_TABLE,
- BIND=ADDRESSBOOK_BIND_TABLE)
+_ABO_KIND_PERSON = _addressBookObjectKind('person')
+_ABO_KIND_GROUP = _addressBookObjectKind('group')
+_ABO_KIND_RESOURCE = _addressBookObjectKind('resource')
+_ABO_KIND_LOCATION = _addressBookObjectKind('location')
-
-
class SchemaBroken(Exception):
"""
The schema is broken and cannot be translated.
@@ -395,7 +377,6 @@
out.write('\n);\n\n')
-
def splitSQLString(sqlString):
"""
Strings which mix zero or more sql statements with zero or more pl/sql
Modified: CalendarServer/trunk/txdav/common/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/test/test_sql.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/test/test_sql.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -28,8 +28,7 @@
from txdav.common.datastore.sql import log, CommonStoreTransactionMonitor, \
CommonHome, CommonHomeChild, ECALENDARTYPE
-from txdav.common.datastore.sql_tables import schema, CALENDAR_BIND_TABLE, \
- CALENDAR_OBJECT_REVISIONS_TABLE
+from txdav.common.datastore.sql_tables import schema
from txdav.common.datastore.test.util import CommonCommonTests, buildStore
from txdav.common.icommondatastore import AllRetriesFailed
from twext.enterprise.dal.syntax import Insert
@@ -290,16 +289,13 @@
"""
class TestCommonHome(CommonHome):
- _bindTable = CALENDAR_BIND_TABLE
- _revisionsTable = CALENDAR_OBJECT_REVISIONS_TABLE
+ pass
class TestCommonHomeChild(CommonHomeChild):
_homeChildSchema = schema.CALENDAR
_homeChildMetaDataSchema = schema.CALENDAR_METADATA
_bindSchema = schema.CALENDAR_BIND
_revisionsSchema = schema.CALENDAR_OBJECT_REVISIONS
- _bindTable = CALENDAR_BIND_TABLE
- _revisionsTable = CALENDAR_OBJECT_REVISIONS_TABLE
def resourceType(self):
return davxml.ResourceType.calendar
Modified: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -24,7 +24,7 @@
from twisted.trial.unittest import TestCase
from txdav.common.datastore.test.util import theStoreBuilder, StubNotifierFactory
from txdav.common.datastore.upgrade.sql.upgrade import UpgradeDatabaseSchemaStep, \
- UpgradeDatabaseDataStep
+ UpgradeDatabaseAddressBookDataStep, UpgradeDatabaseCalendarDataStep
import re
class SchemaUpgradeTests(TestCase):
@@ -212,13 +212,13 @@
@inlineCallbacks
- def _dbDataUpgrades(self, version):
+ def _dbDataUpgrades(self, version, versionKey, upgraderClass):
"""
This does a full DB test of all possible data upgrade paths. For each old schema, it loads it into the DB
then runs the data upgrade service. This ensures all the upgrade_XX.py files work correctly - at least for
postgres.
- TODO: this currently does not create any calendar data to test with. It simply runs the upgrade on an empty
+ TODO: this currently does not create any data to test with. It simply runs the upgrade on an empty
store.
"""
@@ -236,13 +236,13 @@
yield startTxn.execSQL("create schema test_dbUpgrades;")
yield startTxn.execSQL("set search_path to test_dbUpgrades;")
yield startTxn.execSQL(path.getContent())
- yield startTxn.execSQL("update CALENDARSERVER set VALUE = '%s' where NAME = 'CALENDAR-DATAVERSION';" % (oldVersion,))
+ yield startTxn.execSQL("update CALENDARSERVER set VALUE = '%s' where NAME = '%s';" % (oldVersion, versionKey,))
yield startTxn.commit()
@inlineCallbacks
def _loadVersion():
startTxn = store.newTransaction("test_dbUpgrades")
- new_version = yield startTxn.execSQL("select value from calendarserver where name = 'CALENDAR-DATAVERSION';")
+ new_version = yield startTxn.execSQL("select value from calendarserver where name = '%s';" % (versionKey,))
yield startTxn.commit()
returnValue(int(new_version[0][0]))
@@ -263,10 +263,10 @@
self.addCleanup(_cleanupOldData)
test_upgrader = UpgradeDatabaseSchemaStep(None)
- expected_version = self._getSchemaVersion(test_upgrader.schemaLocation.child("current.sql"), "CALENDAR-DATAVERSION")
+ expected_version = self._getSchemaVersion(test_upgrader.schemaLocation.child("current.sql"), versionKey)
oldVersion = version
- upgrader = UpgradeDatabaseDataStep(store)
+ upgrader = upgraderClass(store)
yield _loadOldData(test_upgrader.schemaLocation.child("current.sql"), oldVersion)
yield upgrader.databaseUpgrade()
new_version = yield _loadVersion()
@@ -274,6 +274,7 @@
self.assertEqual(new_version, expected_version)
+
test_upgrader = UpgradeDatabaseSchemaStep(None)
# Bind test methods for each schema version
@@ -282,6 +283,16 @@
return self._dbSchemaUpgrades(lchild)
setattr(SchemaUpgradeTests, "test_dbSchemaUpgrades_%s" % (child.basename().split(".", 1)[0],), f)
+# Bind test methods for each addressbook data version
+versions = set()
+for child in test_upgrader.schemaLocation.child("old").child(POSTGRES_DIALECT).globChildren("*.sql"):
+ version = SchemaUpgradeTests._getRawSchemaVersion(child, "ADDRESSBOOK-DATAVERSION")
+ versions.add(version if version else 1)
+for version in sorted(versions):
+ def f(self, lversion=version):
+ return self._dbDataUpgrades(lversion, "ADDRESSBOOK-DATAVERSION", UpgradeDatabaseAddressBookDataStep)
+ setattr(SchemaUpgradeTests, "test_dbAddressBookDataUpgrades_%s" % (version,), f)
+
# Bind test methods for each calendar data version
versions = set()
for child in test_upgrader.schemaLocation.child("old").child(POSTGRES_DIALECT).globChildren("*.sql"):
@@ -289,5 +300,5 @@
versions.add(version if version else 1)
for version in sorted(versions):
def f(self, lversion=version):
- return self._dbDataUpgrades(lversion)
- setattr(SchemaUpgradeTests, "test_dbDataUpgrades_%s" % (version,), f)
+ return self._dbDataUpgrades(lversion, "CALENDAR-DATAVERSION", UpgradeDatabaseCalendarDataStep)
+ setattr(SchemaUpgradeTests, "test_dbCalendarDataUpgrades_%s" % (version,), f)
Modified: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -56,6 +56,7 @@
self.versionKey = None
self.versionDescriptor = ""
+ self.upgradeFilePrefix = ""
self.upgradeFileSuffix = ""
self.defaultKeyValue = None
@@ -177,8 +178,8 @@
fp = self.getPathToUpgrades(dialect)
upgrades = []
- regex = re.compile("upgrade_from_(\d+)_to_(\d+)%s" % (self.upgradeFileSuffix,))
- for child in fp.globChildren("upgrade_*%s" % (self.upgradeFileSuffix,)):
+ regex = re.compile("%supgrade_from_(\d+)_to_(\d+)%s" % (self.upgradeFilePrefix, self.upgradeFileSuffix,))
+ for child in fp.globChildren("%supgrade_*%s" % (self.upgradeFilePrefix, self.upgradeFileSuffix,)):
matched = regex.match(child.basename())
if matched is not None:
fromV = int(matched.group(1))
@@ -272,7 +273,7 @@
-class UpgradeDatabaseDataStep(UpgradeDatabaseCoreStep):
+class _UpgradeDatabaseDataStep(UpgradeDatabaseCoreStep):
"""
Checks and upgrades the database data. This assumes there are a bunch of
upgrade python modules that we can execute against the database to
@@ -283,19 +284,6 @@
@type sqlStore: L{txdav.idav.IDataStore}
"""
- def __init__(self, sqlStore, **kwargs):
- """
- Initialize the Step.
-
- @param sqlStore: The store to operate on. Can be C{None} when doing unit tests.
- """
- super(UpgradeDatabaseDataStep, self).__init__(sqlStore, **kwargs)
-
- self.versionKey = "CALENDAR-DATAVERSION"
- self.versionDescriptor = "data"
- self.upgradeFileSuffix = ".py"
-
-
def getPathToUpgrades(self, dialect):
return self.pyLocation.child("upgrades")
@@ -321,6 +309,59 @@
+class UpgradeDatabaseAddressBookDataStep(_UpgradeDatabaseDataStep):
+ """
+ Checks and upgrades the database data. This assumes there are a bunch of
+ upgrade python modules that we can execute against the database to
+ accomplish the upgrade.
+
+ @ivar sqlStore: The store to operate on.
+
+ @type sqlStore: L{txdav.idav.IDataStore}
+ """
+
+ def __init__(self, sqlStore, **kwargs):
+ """
+ Initialize the Step.
+
+ @param sqlStore: The store to operate on. Can be C{None} when doing unit tests.
+ """
+ super(UpgradeDatabaseAddressBookDataStep, self).__init__(sqlStore, **kwargs)
+
+ self.versionKey = "ADDRESSBOOK-DATAVERSION"
+ self.versionDescriptor = "addressbook data"
+ self.upgradeFilePrefix = "addressbook_"
+ self.upgradeFileSuffix = ".py"
+
+
+
+class UpgradeDatabaseCalendarDataStep(_UpgradeDatabaseDataStep):
+ """
+ Checks and upgrades the database data. This assumes there are a bunch of
+ upgrade python modules that we can execute against the database to
+ accomplish the upgrade.
+
+ @ivar sqlStore: The store to operate on.
+
+ @type sqlStore: L{txdav.idav.IDataStore}
+ """
+
+ def __init__(self, sqlStore, **kwargs):
+ """
+ Initialize the service.
+
+ @param sqlStore: The store to operate on. Can be C{None} when doing unit tests.
+ @param service: Wrapped service. Can be C{None} when doing unit tests.
+ """
+ super(UpgradeDatabaseCalendarDataStep, self).__init__(sqlStore, **kwargs)
+
+ self.versionKey = "CALENDAR-DATAVERSION"
+ self.versionDescriptor = "calendar data"
+ self.upgradeFilePrefix = "calendar_"
+ self.upgradeFileSuffix = ".py"
+
+
+
class UpgradeDatabaseOtherStep(UpgradeDatabaseCoreStep):
"""
Do any other upgrade behaviors once all the schema, data, file migration upgraders
Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/addressbook_upgrade_from_1_to_2.py (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/upgrade/sql/upgrades/addressbook_upgrade_from_1_to_2.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/addressbook_upgrade_from_1_to_2.py (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/addressbook_upgrade_from_1_to_2.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,84 @@
+# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
+# #
+# Copyright (c) 2011-2013 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.
+# #
+
+from twext.enterprise.dal.syntax import Update
+
+from twisted.internet.defer import inlineCallbacks
+
+from txdav.base.propertystore.base import PropertyName
+from txdav.common.datastore.sql_tables import _ABO_KIND_GROUP, schema
+from txdav.common.datastore.upgrade.sql.upgrades.util import updateAddressBookDataVersion, \
+ doToEachHomeNotAtVersion, removeProperty, cleanPropertyStore
+from txdav.xml import element
+
+"""
+AddressBook Data upgrade from database version 1 to 2
+"""
+
+UPGRADE_TO_VERSION = 2
+
+ at inlineCallbacks
+def doUpgrade(sqlStore):
+ """
+ fill in members tables and increment data version
+ """
+ yield populateMemberTables(sqlStore)
+ yield removeResourceType(sqlStore)
+
+ # bump data version
+ yield updateAddressBookDataVersion(sqlStore, UPGRADE_TO_VERSION)
+
+
+ at inlineCallbacks
+def populateMemberTables(sqlStore):
+ """
+ Set the group kind and and members tables
+ """
+ @inlineCallbacks
+ def doIt(txn, homeResourceID):
+ """
+ KIND is set to person by schema upgrade.
+ To upgrade MEMBERS and FOREIGN_MEMBERS:
+ 1. Set group KIND (avoids assert)
+ 2. Write groups. Write logic will fill in MEMBERS and FOREIGN_MEMBERS
+ (Remember that all members resource IDs must already be in the address book).
+ """
+ home = yield txn.addressbookHomeWithResourceID(homeResourceID)
+ abObjectResources = yield home.addressbook().objectResources()
+ for abObject in abObjectResources:
+ component = yield abObject.component()
+ lcResourceKind = component.resourceKind().lower() if component.resourceKind() else component.resourceKind();
+ if lcResourceKind == "group":
+ # update kind
+ abo = schema.ADDRESSBOOK_OBJECT
+ yield Update({abo.KIND: _ABO_KIND_GROUP},
+ Where=abo.RESOURCE_ID == abObject._resourceID,
+ ).on(txn)
+ abObject._kind = _ABO_KIND_GROUP
+ #update rest
+ yield abObject.setComponent(component)
+
+
+ # Do this to each calendar home not already at version 2
+ yield doToEachHomeNotAtVersion(sqlStore, schema.ADDRESSBOOK_HOME, UPGRADE_TO_VERSION, doIt)
+
+ at inlineCallbacks
+def removeResourceType(sqlStore):
+ sqlTxn = sqlStore.newTransaction()
+ yield removeProperty(sqlTxn, PropertyName.fromElement(element.ResourceType))
+ yield sqlTxn.commit()
+ yield cleanPropertyStore()
Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_1_to_2.py (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_1_to_2.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_1_to_2.py (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_1_to_2.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,90 @@
+# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
+##
+# Copyright (c) 2011-2013 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.
+##
+
+from twext.enterprise.dal.syntax import Update
+from txdav.xml.parser import WebDAVDocument
+from twisted.internet.defer import inlineCallbacks
+from twistedcaldav import caldavxml
+from txdav.common.datastore.sql_tables import schema
+from txdav.common.datastore.upgrade.sql.upgrades.util import rowsForProperty,\
+ removeProperty, updateCalendarDataVersion, doToEachHomeNotAtVersion
+
+"""
+Calendar data upgrade from database version 1 to 2
+"""
+
+UPGRADE_TO_VERSION = 2
+
+ at inlineCallbacks
+def doUpgrade(sqlStore):
+ """
+ Do the required upgrade steps.
+ """
+ yield moveSupportedComponentSetProperties(sqlStore)
+ yield splitCalendars(sqlStore)
+
+ # Always bump the DB value
+ yield updateCalendarDataVersion(sqlStore, UPGRADE_TO_VERSION)
+
+
+
+ at inlineCallbacks
+def moveSupportedComponentSetProperties(sqlStore):
+ """
+ Need to move all the CalDAV:supported-component-set properties in the
+ RESOURCE_PROPERTY table to the new CALENDAR_METADATA table column,
+ extracting the new format value from the XML property.
+ """
+
+ sqlTxn = sqlStore.newTransaction()
+ try:
+ rows = (yield rowsForProperty(sqlTxn, caldavxml.SupportedCalendarComponentSet))
+ for calendar_rid, value in rows:
+ prop = WebDAVDocument.fromString(value).root_element
+ supported_components = ",".join(sorted([comp.attributes["name"].upper() for comp in prop.children]))
+ meta = schema.CALENDAR_METADATA
+ yield Update(
+ {
+ meta.SUPPORTED_COMPONENTS : supported_components
+ },
+ Where=(meta.RESOURCE_ID == calendar_rid)
+ ).on(sqlTxn)
+
+ yield removeProperty(sqlTxn, caldavxml.SupportedCalendarComponentSet)
+ yield sqlTxn.commit()
+ except RuntimeError:
+ yield sqlTxn.abort()
+ raise
+
+
+
+ at inlineCallbacks
+def splitCalendars(sqlStore):
+ """
+ Split all calendars by component type.
+ """
+
+ @inlineCallbacks
+ def doIt(txn, homeResourceID):
+ """
+ Split each regular calendar in the home.
+ """
+ home = yield txn.calendarHomeWithResourceID(homeResourceID)
+ yield home.splitCalendars()
+
+ # Do this to each calendar home not already at version 2
+ yield doToEachHomeNotAtVersion(sqlStore, schema.CALENDAR_HOME, UPGRADE_TO_VERSION, doIt)
Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_2_to_3.py (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_2_to_3.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_2_to_3.py (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_2_to_3.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,42 @@
+# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
+##
+# Copyright (c) 2011-2013 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.
+##
+
+"""
+Upgrade to deal with normalization of UUIDs in
+CALENDAR_HOME/ADDRESSBOOK_HOME/NOTIFICATION/APN_SUBSCRIPTIONS tables, as well
+as in calendar data and properties.
+"""
+
+from txdav.common.datastore.sql import fixUUIDNormalization
+from twisted.internet.defer import inlineCallbacks
+from txdav.common.datastore.upgrade.sql.upgrades.util import updateCalendarDataVersion
+
+UPGRADE_TO_VERSION = 3
+
+ at inlineCallbacks
+def doUpgrade(sqlStore):
+ """
+ Do the UUID-normalization upgrade if necessary and then bump the data
+ version to indicate that it's been done.
+ """
+ yield fixUUIDNormalization(sqlStore)
+
+ # Always bump the DB value
+ yield updateCalendarDataVersion(
+ sqlStore, UPGRADE_TO_VERSION
+ )
+
Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_3_to_4.py (from rev 11204, CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_3_to_4.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_3_to_4.py (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/calendar_upgrade_from_3_to_4.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -0,0 +1,322 @@
+# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
+##
+# Copyright (c) 2011-2013 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.
+##
+
+from twext.enterprise.dal.syntax import Select, Delete, Parameter
+
+from twisted.internet.defer import inlineCallbacks
+
+from twistedcaldav import caldavxml, customxml
+
+from txdav.base.propertystore.base import PropertyName
+from txdav.common.datastore.sql_tables import schema, _BIND_MODE_OWN
+from txdav.common.datastore.upgrade.sql.upgrades.util import rowsForProperty, updateCalendarDataVersion, \
+ updateAllCalendarHomeDataVersions, removeProperty, cleanPropertyStore
+from txdav.xml.parser import WebDAVDocument
+from txdav.xml import element
+from twisted.python.failure import Failure
+
+"""
+Data upgrade from database version 3 to 4
+"""
+
+UPGRADE_TO_VERSION = 4
+BATCH_SIZE = 100
+
+ at inlineCallbacks
+def doUpgrade(sqlStore):
+ """
+ Do the required upgrade steps.
+ """
+ yield moveDefaultCalendarProperties(sqlStore)
+ yield moveCalendarTranspProperties(sqlStore)
+ yield moveDefaultAlarmProperties(sqlStore)
+ yield removeResourceType(sqlStore)
+
+ # Always bump the DB value
+ yield updateCalendarDataVersion(sqlStore, UPGRADE_TO_VERSION)
+ yield updateAllCalendarHomeDataVersions(sqlStore, UPGRADE_TO_VERSION)
+
+
+
+ at inlineCallbacks
+def moveDefaultCalendarProperties(sqlStore):
+ """
+ Need to move all the CalDAV:default-calendar and CS:default-tasks properties in the
+ RESOURCE_PROPERTY table to the new CALENDAR_HOME_METADATA table columns, extracting
+ the new value from the XML property.
+ """
+
+ meta = schema.CALENDAR_HOME_METADATA
+ yield _processDefaultCalendarProperty(sqlStore, caldavxml.ScheduleDefaultCalendarURL, meta.DEFAULT_EVENTS)
+ yield _processDefaultCalendarProperty(sqlStore, customxml.ScheduleDefaultTasksURL, meta.DEFAULT_TASKS)
+
+
+
+ at inlineCallbacks
+def _processDefaultCalendarProperty(sqlStore, propname, colname):
+ """
+ Move the specified property value to the matching CALENDAR_HOME_METADATA table column.
+
+ Since the number of calendar homes may well be large, we need to do this in batches.
+ """
+
+ cb = schema.CALENDAR_BIND
+ rp = schema.RESOURCE_PROPERTY
+
+ try:
+ while True:
+ sqlTxn = sqlStore.newTransaction()
+ rows = (yield rowsForProperty(sqlTxn, propname, batch=BATCH_SIZE))
+ if len(rows) == 0:
+ yield sqlTxn.commit()
+ break
+ delete_ids = []
+ for inbox_rid, value in rows:
+ delete_ids.append(inbox_rid)
+ ids = yield Select(
+ [cb.CALENDAR_HOME_RESOURCE_ID, ],
+ From=cb,
+ Where=cb.CALENDAR_RESOURCE_ID == inbox_rid,
+ ).on(sqlTxn)
+ if len(ids) > 0:
+
+ calendarHome = (yield sqlTxn.calendarHomeWithResourceID(ids[0][0]))
+ if calendarHome is not None:
+
+ prop = WebDAVDocument.fromString(value).root_element
+ defaultCalendar = str(prop.children[0])
+ parts = defaultCalendar.split("/")
+ if len(parts) == 5:
+
+ calendarName = parts[-1]
+ calendarHomeUID = parts[-2]
+ expectedHome = (yield sqlTxn.calendarHomeWithUID(calendarHomeUID))
+ if expectedHome is not None and expectedHome.id() == calendarHome.id():
+
+ calendar = (yield calendarHome.calendarWithName(calendarName))
+ if calendar is not None:
+ yield calendarHome.setDefaultCalendar(
+ calendar, tasks=(propname ==
+ customxml.ScheduleDefaultTasksURL))
+
+ # Always delete the row so that batch processing works correctly
+ yield Delete(
+ From=rp,
+ Where=(rp.RESOURCE_ID.In(Parameter("ids", len(delete_ids)))).And
+ (rp.NAME == PropertyName.fromElement(propname).toString()),
+ ).on(sqlTxn, ids=delete_ids)
+
+ yield sqlTxn.commit()
+
+ yield cleanPropertyStore()
+
+ except RuntimeError:
+ f = Failure()
+ yield sqlTxn.abort()
+ f.raiseException()
+
+
+
+ at inlineCallbacks
+def moveCalendarTranspProperties(sqlStore):
+ """
+ Need to move all the CalDAV:schedule-calendar-transp properties in the
+ RESOURCE_PROPERTY table to the new CALENDAR_BIND table columns, extracting
+ the new value from the XML property.
+ """
+
+ cb = schema.CALENDAR_BIND
+ rp = schema.RESOURCE_PROPERTY
+
+ try:
+ calendars_for_id = {}
+ while True:
+ sqlTxn = sqlStore.newTransaction()
+ rows = (yield rowsForProperty(sqlTxn, caldavxml.ScheduleCalendarTransp, with_uid=True, batch=BATCH_SIZE))
+ if len(rows) == 0:
+ yield sqlTxn.commit()
+ break
+ delete_ids = []
+ for calendar_rid, value, viewer in rows:
+ delete_ids.append(calendar_rid)
+ if calendar_rid not in calendars_for_id:
+ ids = yield Select(
+ [cb.CALENDAR_HOME_RESOURCE_ID, cb.BIND_MODE, ],
+ From=cb,
+ Where=cb.CALENDAR_RESOURCE_ID == calendar_rid,
+ ).on(sqlTxn)
+ calendars_for_id[calendar_rid] = ids
+
+ if viewer:
+ calendarHome = (yield sqlTxn.calendarHomeWithUID(viewer))
+ else:
+ calendarHome = None
+ for row in calendars_for_id[calendar_rid]:
+ home_id, bind_mode = row
+ if bind_mode == _BIND_MODE_OWN:
+ calendarHome = (yield sqlTxn.calendarHomeWithResourceID(home_id))
+ break
+
+ if calendarHome is not None:
+ prop = WebDAVDocument.fromString(value).root_element
+ calendar = (yield calendarHome.childWithID(calendar_rid))
+ yield calendar.setUsedForFreeBusy(prop == caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()))
+
+ # Always delete the row so that batch processing works correctly
+ yield Delete(
+ From=rp,
+ Where=(rp.RESOURCE_ID.In(Parameter("ids", len(delete_ids)))).And
+ (rp.NAME == PropertyName.fromElement(caldavxml.ScheduleCalendarTransp).toString()),
+ ).on(sqlTxn, ids=delete_ids)
+
+ yield sqlTxn.commit()
+
+ sqlTxn = sqlStore.newTransaction()
+ yield removeProperty(sqlTxn, PropertyName.fromElement(caldavxml.CalendarFreeBusySet))
+ yield sqlTxn.commit()
+ yield cleanPropertyStore()
+
+ except RuntimeError:
+ f = Failure()
+ yield sqlTxn.abort()
+ f.raiseException()
+
+
+
+ at inlineCallbacks
+def moveDefaultAlarmProperties(sqlStore):
+ """
+ Need to move all the CalDAV:default-calendar and CS:default-tasks properties in the
+ RESOURCE_PROPERTY table to the new CALENDAR_HOME_METADATA table columns, extracting
+ the new value from the XML property.
+ """
+
+ yield _processDefaultAlarmProperty(
+ sqlStore,
+ caldavxml.DefaultAlarmVEventDateTime,
+ True,
+ True,
+ )
+ yield _processDefaultAlarmProperty(
+ sqlStore,
+ caldavxml.DefaultAlarmVEventDate,
+ True,
+ False,
+ )
+ yield _processDefaultAlarmProperty(
+ sqlStore,
+ caldavxml.DefaultAlarmVToDoDateTime,
+ False,
+ True,
+ )
+ yield _processDefaultAlarmProperty(
+ sqlStore,
+ caldavxml.DefaultAlarmVToDoDate,
+ False,
+ False,
+ )
+
+
+
+ at inlineCallbacks
+def _processDefaultAlarmProperty(sqlStore, propname, vevent, timed):
+ """
+ Move the specified property value to the matching CALENDAR_HOME_METADATA or CALENDAR_BIND table column.
+
+ Since the number of properties may well be large, we need to do this in batches.
+ """
+
+ hm = schema.CALENDAR_HOME_METADATA
+ cb = schema.CALENDAR_BIND
+ rp = schema.RESOURCE_PROPERTY
+
+ try:
+ calendars_for_id = {}
+ while True:
+ sqlTxn = sqlStore.newTransaction()
+ rows = (yield rowsForProperty(sqlTxn, propname, with_uid=True, batch=BATCH_SIZE))
+ if len(rows) == 0:
+ yield sqlTxn.commit()
+ break
+ delete_ids = []
+ for rid, value, viewer in rows:
+ delete_ids.append(rid)
+
+ prop = WebDAVDocument.fromString(value).root_element
+ alarm = str(prop.children[0]) if prop.children else None
+
+ # First check if the rid is a home - this is the most common case
+ ids = yield Select(
+ [hm.RESOURCE_ID, ],
+ From=hm,
+ Where=hm.RESOURCE_ID == rid,
+ ).on(sqlTxn)
+
+ if len(ids) > 0:
+ # Home object
+ calendarHome = (yield sqlTxn.calendarHomeWithResourceID(ids[0][0]))
+ if calendarHome is not None:
+ yield calendarHome.setDefaultAlarm(alarm, vevent, timed)
+ else:
+ # rid is a calendar - we need to find the per-user calendar for the resource viewer
+ if rid not in calendars_for_id:
+ ids = yield Select(
+ [cb.CALENDAR_HOME_RESOURCE_ID, cb.BIND_MODE, ],
+ From=cb,
+ Where=cb.CALENDAR_RESOURCE_ID == rid,
+ ).on(sqlTxn)
+ calendars_for_id[rid] = ids
+
+ if viewer:
+ calendarHome = (yield sqlTxn.calendarHomeWithUID(viewer))
+ else:
+ calendarHome = None
+ for row in calendars_for_id[rid]:
+ home_id, bind_mode = row
+ if bind_mode == _BIND_MODE_OWN:
+ calendarHome = (yield sqlTxn.calendarHomeWithResourceID(home_id))
+ break
+
+ if calendarHome is not None:
+ calendar = yield calendarHome.childWithID(rid)
+ if calendar is not None:
+ yield calendar.setDefaultAlarm(alarm, vevent, timed)
+
+ # Always delete the row so that batch processing works correctly
+ yield Delete(
+ From=rp,
+ Where=(rp.RESOURCE_ID.In(Parameter("ids", len(delete_ids)))).And
+ (rp.NAME == PropertyName.fromElement(propname).toString()),
+ ).on(sqlTxn, ids=delete_ids)
+
+ yield sqlTxn.commit()
+
+ yield cleanPropertyStore()
+
+ except RuntimeError:
+ f = Failure()
+ yield sqlTxn.abort()
+ f.raiseException()
+
+
+
+ at inlineCallbacks
+def removeResourceType(sqlStore):
+ sqlTxn = sqlStore.newTransaction()
+ yield removeProperty(sqlTxn, PropertyName.fromElement(element.ResourceType))
+ yield sqlTxn.commit()
+ yield cleanPropertyStore()
Modified: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -19,7 +19,7 @@
from txdav.caldav.datastore.test.util import CommonStoreTests
from txdav.xml.element import HRef
from twext.enterprise.dal.syntax import Update
-from txdav.common.datastore.upgrade.sql.upgrades.upgrade_from_3_to_4 import moveDefaultCalendarProperties, \
+from txdav.common.datastore.upgrade.sql.upgrades.calendar_upgrade_from_3_to_4 import moveDefaultCalendarProperties, \
moveCalendarTranspProperties, removeResourceType, moveDefaultAlarmProperties
from txdav.xml import element
from twistedcaldav import caldavxml
Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,89 +0,0 @@
-# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
-##
-# Copyright (c) 2011-2013 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.
-##
-
-from twext.enterprise.dal.syntax import Update
-from txdav.xml.parser import WebDAVDocument
-from twisted.internet.defer import inlineCallbacks
-from twistedcaldav import caldavxml
-from txdav.common.datastore.sql_tables import schema
-from txdav.common.datastore.upgrade.sql.upgrades.util import rowsForProperty,\
- removeProperty, updateDataVersion, doToEachCalendarHomeNotAtVersion
-
-"""
-Data upgrade from database version 1 to 2
-"""
-
-UPGRADE_TO_VERSION = 2
-
- at inlineCallbacks
-def doUpgrade(sqlStore):
- """
- Do the required upgrade steps.
- """
- yield moveSupportedComponentSetProperties(sqlStore)
- yield splitCalendars(sqlStore)
-
- # Always bump the DB value
- yield updateDataVersion(sqlStore, "CALENDAR-DATAVERSION", UPGRADE_TO_VERSION)
-
-
-
- at inlineCallbacks
-def moveSupportedComponentSetProperties(sqlStore):
- """
- Need to move all the CalDAV:supported-component-set properties in the
- RESOURCE_PROPERTY table to the new CALENDAR_METADATA table column,
- extracting the new format value from the XML property.
- """
-
- sqlTxn = sqlStore.newTransaction()
- try:
- rows = (yield rowsForProperty(sqlTxn, caldavxml.SupportedCalendarComponentSet))
- for calendar_rid, value in rows:
- prop = WebDAVDocument.fromString(value).root_element
- supported_components = ",".join(sorted([comp.attributes["name"].upper() for comp in prop.children]))
- meta = schema.CALENDAR_METADATA
- yield Update(
- {
- meta.SUPPORTED_COMPONENTS : supported_components
- },
- Where=(meta.RESOURCE_ID == calendar_rid)
- ).on(sqlTxn)
-
- yield removeProperty(sqlTxn, caldavxml.SupportedCalendarComponentSet)
- yield sqlTxn.commit()
- except RuntimeError:
- yield sqlTxn.abort()
- raise
-
-
-
- at inlineCallbacks
-def splitCalendars(sqlStore):
- """
- Split all calendars by component type.
- """
-
- @inlineCallbacks
- def doIt(home):
- """
- Split each regular calendar in the home.
- """
- yield home.splitCalendars()
-
- # Do this to each calendar home not already at version 2
- yield doToEachCalendarHomeNotAtVersion(sqlStore, UPGRADE_TO_VERSION, doIt)
Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_2_to_3.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_2_to_3.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_2_to_3.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,41 +0,0 @@
-# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
-##
-# Copyright (c) 2011-2013 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.
-##
-
-"""
-Upgrade to deal with normalization of UUIDs in
-CALENDAR_HOME/ADDRESSBOOK_HOME/NOTIFICATION/APN_SUBSCRIPTIONS tables, as well
-as in calendar data and properties.
-"""
-
-from txdav.common.datastore.sql import fixUUIDNormalization
-from twisted.internet.defer import inlineCallbacks
-from txdav.common.datastore.upgrade.sql.upgrades.util import updateDataVersion
-
-UPGRADE_TO_VERSION = 3
-
- at inlineCallbacks
-def doUpgrade(sqlStore):
- """
- Do the UUID-normalization upgrade if necessary and then bump the data
- version to indicate that it's been done.
- """
- yield fixUUIDNormalization(sqlStore)
-
- # Always bump the DB value
- yield updateDataVersion(
- sqlStore, "CALENDAR-DATAVERSION", UPGRADE_TO_VERSION
- )
Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -1,322 +0,0 @@
-# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
-##
-# Copyright (c) 2011-2013 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.
-##
-
-from twext.enterprise.dal.syntax import Select, Delete, Parameter
-
-from twisted.internet.defer import inlineCallbacks
-
-from twistedcaldav import caldavxml, customxml
-
-from txdav.base.propertystore.base import PropertyName
-from txdav.common.datastore.sql_tables import schema, _BIND_MODE_OWN
-from txdav.common.datastore.upgrade.sql.upgrades.util import rowsForProperty, updateDataVersion, \
- updateAllCalendarHomeDataVersions, removeProperty, cleanPropertyStore
-from txdav.xml.parser import WebDAVDocument
-from txdav.xml import element
-from twisted.python.failure import Failure
-
-"""
-Data upgrade from database version 3 to 4
-"""
-
-UPGRADE_TO_VERSION = 4
-BATCH_SIZE = 100
-
- at inlineCallbacks
-def doUpgrade(sqlStore):
- """
- Do the required upgrade steps.
- """
- yield moveDefaultCalendarProperties(sqlStore)
- yield moveCalendarTranspProperties(sqlStore)
- yield moveDefaultAlarmProperties(sqlStore)
- yield removeResourceType(sqlStore)
-
- # Always bump the DB value
- yield updateDataVersion(sqlStore, "CALENDAR-DATAVERSION", UPGRADE_TO_VERSION)
- yield updateAllCalendarHomeDataVersions(sqlStore, UPGRADE_TO_VERSION)
-
-
-
- at inlineCallbacks
-def moveDefaultCalendarProperties(sqlStore):
- """
- Need to move all the CalDAV:default-calendar and CS:default-tasks properties in the
- RESOURCE_PROPERTY table to the new CALENDAR_HOME_METADATA table columns, extracting
- the new value from the XML property.
- """
-
- meta = schema.CALENDAR_HOME_METADATA
- yield _processDefaultCalendarProperty(sqlStore, caldavxml.ScheduleDefaultCalendarURL, meta.DEFAULT_EVENTS)
- yield _processDefaultCalendarProperty(sqlStore, customxml.ScheduleDefaultTasksURL, meta.DEFAULT_TASKS)
-
-
-
- at inlineCallbacks
-def _processDefaultCalendarProperty(sqlStore, propname, colname):
- """
- Move the specified property value to the matching CALENDAR_HOME_METADATA table column.
-
- Since the number of calendar homes may well be large, we need to do this in batches.
- """
-
- cb = schema.CALENDAR_BIND
- rp = schema.RESOURCE_PROPERTY
-
- try:
- while True:
- sqlTxn = sqlStore.newTransaction()
- rows = (yield rowsForProperty(sqlTxn, propname, batch=BATCH_SIZE))
- if len(rows) == 0:
- yield sqlTxn.commit()
- break
- delete_ids = []
- for inbox_rid, value in rows:
- delete_ids.append(inbox_rid)
- ids = yield Select(
- [cb.CALENDAR_HOME_RESOURCE_ID, ],
- From=cb,
- Where=cb.CALENDAR_RESOURCE_ID == inbox_rid,
- ).on(sqlTxn)
- if len(ids) > 0:
-
- calendarHome = (yield sqlTxn.calendarHomeWithResourceID(ids[0][0]))
- if calendarHome is not None:
-
- prop = WebDAVDocument.fromString(value).root_element
- defaultCalendar = str(prop.children[0])
- parts = defaultCalendar.split("/")
- if len(parts) == 5:
-
- calendarName = parts[-1]
- calendarHomeUID = parts[-2]
- expectedHome = (yield sqlTxn.calendarHomeWithUID(calendarHomeUID))
- if expectedHome is not None and expectedHome.id() == calendarHome.id():
-
- calendar = (yield calendarHome.calendarWithName(calendarName))
- if calendar is not None:
- yield calendarHome.setDefaultCalendar(
- calendar, tasks=(propname ==
- customxml.ScheduleDefaultTasksURL))
-
- # Always delete the row so that batch processing works correctly
- yield Delete(
- From=rp,
- Where=(rp.RESOURCE_ID.In(Parameter("ids", len(delete_ids)))).And
- (rp.NAME == PropertyName.fromElement(propname).toString()),
- ).on(sqlTxn, ids=delete_ids)
-
- yield sqlTxn.commit()
-
- yield cleanPropertyStore()
-
- except RuntimeError:
- f = Failure()
- yield sqlTxn.abort()
- f.raiseException()
-
-
-
- at inlineCallbacks
-def moveCalendarTranspProperties(sqlStore):
- """
- Need to move all the CalDAV:schedule-calendar-transp properties in the
- RESOURCE_PROPERTY table to the new CALENDAR_BIND table columns, extracting
- the new value from the XML property.
- """
-
- cb = schema.CALENDAR_BIND
- rp = schema.RESOURCE_PROPERTY
-
- try:
- calendars_for_id = {}
- while True:
- sqlTxn = sqlStore.newTransaction()
- rows = (yield rowsForProperty(sqlTxn, caldavxml.ScheduleCalendarTransp, with_uid=True, batch=BATCH_SIZE))
- if len(rows) == 0:
- yield sqlTxn.commit()
- break
- delete_ids = []
- for calendar_rid, value, viewer in rows:
- delete_ids.append(calendar_rid)
- if calendar_rid not in calendars_for_id:
- ids = yield Select(
- [cb.CALENDAR_HOME_RESOURCE_ID, cb.BIND_MODE, ],
- From=cb,
- Where=cb.CALENDAR_RESOURCE_ID == calendar_rid,
- ).on(sqlTxn)
- calendars_for_id[calendar_rid] = ids
-
- if viewer:
- calendarHome = (yield sqlTxn.calendarHomeWithUID(viewer))
- else:
- calendarHome = None
- for row in calendars_for_id[calendar_rid]:
- home_id, bind_mode = row
- if bind_mode == _BIND_MODE_OWN:
- calendarHome = (yield sqlTxn.calendarHomeWithResourceID(home_id))
- break
-
- if calendarHome is not None:
- prop = WebDAVDocument.fromString(value).root_element
- calendar = (yield calendarHome.childWithID(calendar_rid))
- yield calendar.setUsedForFreeBusy(prop == caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()))
-
- # Always delete the row so that batch processing works correctly
- yield Delete(
- From=rp,
- Where=(rp.RESOURCE_ID.In(Parameter("ids", len(delete_ids)))).And
- (rp.NAME == PropertyName.fromElement(caldavxml.ScheduleCalendarTransp).toString()),
- ).on(sqlTxn, ids=delete_ids)
-
- yield sqlTxn.commit()
-
- sqlTxn = sqlStore.newTransaction()
- yield removeProperty(sqlTxn, PropertyName.fromElement(caldavxml.CalendarFreeBusySet))
- yield sqlTxn.commit()
- yield cleanPropertyStore()
-
- except RuntimeError:
- f = Failure()
- yield sqlTxn.abort()
- f.raiseException()
-
-
-
- at inlineCallbacks
-def moveDefaultAlarmProperties(sqlStore):
- """
- Need to move all the CalDAV:default-calendar and CS:default-tasks properties in the
- RESOURCE_PROPERTY table to the new CALENDAR_HOME_METADATA table columns, extracting
- the new value from the XML property.
- """
-
- yield _processDefaultAlarmProperty(
- sqlStore,
- caldavxml.DefaultAlarmVEventDateTime,
- True,
- True,
- )
- yield _processDefaultAlarmProperty(
- sqlStore,
- caldavxml.DefaultAlarmVEventDate,
- True,
- False,
- )
- yield _processDefaultAlarmProperty(
- sqlStore,
- caldavxml.DefaultAlarmVToDoDateTime,
- False,
- True,
- )
- yield _processDefaultAlarmProperty(
- sqlStore,
- caldavxml.DefaultAlarmVToDoDate,
- False,
- False,
- )
-
-
-
- at inlineCallbacks
-def _processDefaultAlarmProperty(sqlStore, propname, vevent, timed):
- """
- Move the specified property value to the matching CALENDAR_HOME_METADATA or CALENDAR_BIND table column.
-
- Since the number of properties may well be large, we need to do this in batches.
- """
-
- hm = schema.CALENDAR_HOME_METADATA
- cb = schema.CALENDAR_BIND
- rp = schema.RESOURCE_PROPERTY
-
- try:
- calendars_for_id = {}
- while True:
- sqlTxn = sqlStore.newTransaction()
- rows = (yield rowsForProperty(sqlTxn, propname, with_uid=True, batch=BATCH_SIZE))
- if len(rows) == 0:
- yield sqlTxn.commit()
- break
- delete_ids = []
- for rid, value, viewer in rows:
- delete_ids.append(rid)
-
- prop = WebDAVDocument.fromString(value).root_element
- alarm = str(prop.children[0]) if prop.children else None
-
- # First check if the rid is a home - this is the most common case
- ids = yield Select(
- [hm.RESOURCE_ID, ],
- From=hm,
- Where=hm.RESOURCE_ID == rid,
- ).on(sqlTxn)
-
- if len(ids) > 0:
- # Home object
- calendarHome = (yield sqlTxn.calendarHomeWithResourceID(ids[0][0]))
- if calendarHome is not None:
- yield calendarHome.setDefaultAlarm(alarm, vevent, timed)
- else:
- # rid is a calendar - we need to find the per-user calendar for the resource viewer
- if rid not in calendars_for_id:
- ids = yield Select(
- [cb.CALENDAR_HOME_RESOURCE_ID, cb.BIND_MODE, ],
- From=cb,
- Where=cb.CALENDAR_RESOURCE_ID == rid,
- ).on(sqlTxn)
- calendars_for_id[rid] = ids
-
- if viewer:
- calendarHome = (yield sqlTxn.calendarHomeWithUID(viewer))
- else:
- calendarHome = None
- for row in calendars_for_id[rid]:
- home_id, bind_mode = row
- if bind_mode == _BIND_MODE_OWN:
- calendarHome = (yield sqlTxn.calendarHomeWithResourceID(home_id))
- break
-
- if calendarHome is not None:
- calendar = yield calendarHome.childWithID(rid)
- if calendar is not None:
- yield calendar.setDefaultAlarm(alarm, vevent, timed)
-
- # Always delete the row so that batch processing works correctly
- yield Delete(
- From=rp,
- Where=(rp.RESOURCE_ID.In(Parameter("ids", len(delete_ids)))).And
- (rp.NAME == PropertyName.fromElement(propname).toString()),
- ).on(sqlTxn, ids=delete_ids)
-
- yield sqlTxn.commit()
-
- yield cleanPropertyStore()
-
- except RuntimeError:
- f = Failure()
- yield sqlTxn.abort()
- f.raiseException()
-
-
-
- at inlineCallbacks
-def removeResourceType(sqlStore):
- sqlTxn = sqlStore.newTransaction()
- yield removeProperty(sqlTxn, PropertyName.fromElement(element.ResourceType))
- yield sqlTxn.commit()
- yield cleanPropertyStore()
Modified: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -87,7 +87,7 @@
@inlineCallbacks
-def updateDataVersion(store, key, version):
+def _updateDataVersion(store, key, version):
txn = store.newTransaction("updateDataVersion")
cs = schema.CALENDARSERVER
@@ -100,19 +100,19 @@
def updateCalendarDataVersion(store, version):
- return updateDataVersion(store, "CALENDAR-DATAVERSION", version)
+ return _updateDataVersion(store, "CALENDAR-DATAVERSION", version)
def updateAddressBookDataVersion(store, version):
- return updateDataVersion(store, "ADDRESSBOOK-DATAVERSION", version)
+ return _updateDataVersion(store, "ADDRESSBOOK-DATAVERSION", version)
@inlineCallbacks
-def doToEachCalendarHomeNotAtVersion(store, version, doIt):
+def doToEachHomeNotAtVersion(store, homeSchema, version, doIt):
"""
- Do something to each calendar home whose version column indicates it is older
+ Do something to each home whose version column indicates it is older
than the specified version. Do this in batches as there may be a lot of work to do.
"""
@@ -121,12 +121,11 @@
# Get the next home with an old version
txn = store.newTransaction("updateDataVersion")
try:
- ch = schema.CALENDAR_HOME
rows = yield Select(
- [ch.RESOURCE_ID, ch.OWNER_UID, ],
- From=ch,
- Where=ch.DATAVERSION < version,
- OrderBy=ch.OWNER_UID,
+ [homeSchema.RESOURCE_ID, homeSchema.OWNER_UID, ],
+ From=homeSchema,
+ Where=homeSchema.DATAVERSION < version,
+ OrderBy=homeSchema.OWNER_UID,
Limit=1,
).on(txn)
@@ -135,14 +134,13 @@
returnValue(None)
# Apply to the home
- resource_id, _ignore_owner_uid = rows[0]
- home = yield txn.calendarHomeWithResourceID(resource_id)
- yield doIt(home)
+ homeResourceID, _ignore_owner_uid = rows[0]
+ yield doIt(txn, homeResourceID)
# Update the home to the current version
yield Update(
- {ch.DATAVERSION: version},
- Where=ch.RESOURCE_ID == resource_id,
+ {homeSchema.DATAVERSION: version},
+ Where=homeSchema.RESOURCE_ID == homeResourceID,
).on(txn)
yield txn.commit()
except RuntimeError:
Modified: CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py 2013-05-16 19:52:20 UTC (rev 11204)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py 2013-05-16 20:35:53 UTC (rev 11205)
@@ -360,7 +360,7 @@
# Want metadata preserved
home = (yield txn.addressbookHomeWithUID("home1"))
- adbk = (yield home.addressbookWithName("addressbook_1"))
+ adbk = (yield home.addressbookWithName("addressbook"))
for name, md5 in (
("1.vcf", ABCommonTests.md5Values[0]),
("2.vcf", ABCommonTests.md5Values[1]),
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130516/53ddf3ae/attachment-0001.html>
More information about the calendarserver-changes
mailing list