[CalendarServer-changes] [11089] CalendarServer/branches/users/gaya/sharedgroups-3

source_changes at macosforge.org source_changes at macosforge.org
Mon Apr 22 18:04:00 PDT 2013


Revision: 11089
          http://trac.calendarserver.org//changeset/11089
Author:   gaya at apple.com
Date:     2013-04-22 18:04:00 -0700 (Mon, 22 Apr 2013)
Log Message:
-----------
add changes from sharedgroups-2 branch

Modified Paths:
--------------
    CalendarServer/branches/users/gaya/sharedgroups-3/calendarserver/tools/dbinspect.py
    CalendarServer/branches/users/gaya/sharedgroups-3/calendarserver/tools/obliterate.py
    CalendarServer/branches/users/gaya/sharedgroups-3/contrib/tools/sqldata_from_path.py
    CalendarServer/branches/users/gaya/sharedgroups-3/testserver
    CalendarServer/branches/users/gaya/sharedgroups-3/twext/web2/resource.py
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/method/put_common.py
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/resource.py
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/scheduling/caldav/resource.py
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/scheduling/caldav/test/test_resource.py
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/sharing.py
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/storebridge.py
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_resource.py
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_sharing.py
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_wrapping.py
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/vcard.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/base/propertystore/sql.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/caldav/datastore/sql.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/sql.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/common.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/test_file.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/test_sql.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/iaddressbookstore.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_legacy.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/current.sql
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_tables.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/test/test_sql.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/upgrade/test/test_migrate.py

Added Paths:
-----------
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/
    CalendarServer/branches/users/gaya/sharedgroups-3/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/2.vcf
    CalendarServer/branches/users/gaya/sharedgroups-3/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/home2/
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/
    CalendarServer/branches/users/gaya/sharedgroups-3/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/44745975-AE6D-4FB0-80A6-A298427E047A.vcf
    CalendarServer/branches/users/gaya/sharedgroups-3/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/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf
    CalendarServer/branches/users/gaya/sharedgroups-3/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/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf
    CalendarServer/branches/users/gaya/sharedgroups-3/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-2923A3E5C4E2.vcf
    CalendarServer/branches/users/gaya/sharedgroups-3/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/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/
    CalendarServer/branches/users/gaya/sharedgroups-3/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/2.vcf
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home_empty/
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home_empty/addressbook/

Removed Paths:
-------------
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook_1/
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook_2/
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook_empty/
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook_bad/

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/calendarserver/tools/dbinspect.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/calendarserver/tools/dbinspect.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/calendarserver/tools/dbinspect.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -816,12 +816,10 @@
 
             schema.ADDRESSBOOK_OBJECT_REVISIONS,
 
-            schema.ADDRESSBOOK,
-            #schema.ADDRESSBOOK_BIND, - cascades
-            #schema.ADDRESSBOOK_OBJECT, - cascades
-
             schema.ADDRESSBOOK_HOME,
             #schema.ADDRESSBOOK_HOME_METADATA, - cascades
+            #schema.ADDRESSBOOK_HOME_BIND, - cascades
+            #schema.ADDRESSBOOK_OBJECT, - cascades
 
             schema.NOTIFICATION_HOME,
             schema.NOTIFICATION,

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/calendarserver/tools/obliterate.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/calendarserver/tools/obliterate.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/calendarserver/tools/obliterate.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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/branches/users/gaya/sharedgroups-3/contrib/tools/sqldata_from_path.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/contrib/tools/sqldata_from_path.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/contrib/tools/sqldata_from_path.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -45,20 +45,20 @@
         sys.exit(0)
 
 if __name__ == '__main__':
-    
+
     options, args = getopt.getopt(sys.argv[1:], "", [])
     if options:
         usage("No options allowed")
-    
+
     if len(args) != 1:
         usage("One argument only must be provided.")
-        
+
     # Determine the type of path
     segments = args[0].split("/")
 
     if len(segments) not in (6, 8,):
         usage("Must provide a path to a calendar or addressbook object resource.")
-        
+
     if segments[0] != "":
         usage("Must provide a /calendars/... or /addressbooks/... path.")
     if segments[1] not in ("calendars", "addressbooks",):
@@ -66,12 +66,12 @@
     if segments[2] != "__uids__":
         usage("Must provide a /.../__uids__/... path.")
 
-        
+
     datatype = segments[1]
     uid = segments[5 if len(segments[3]) == 2 else 3]
     collection = segments[6 if len(segments[3]) == 2 else 4]
     resource = segments[7 if len(segments[3]) == 2 else 5]
-    
+
     sqlstrings = {
         "calendars": {
             "home_table"        : "CALENDAR_HOME",
@@ -81,7 +81,7 @@
             "bind_home_id"      : "CALENDAR_HOME_RESOURCE_ID",
             "bind_name"         : "CALENDAR_RESOURCE_NAME",
             "bind_id"           : "CALENDAR_RESOURCE_ID",
-            
+
             "object_bind_id"    : "CALENDAR_RESOURCE_ID",
             "object_name"       : "RESOURCE_NAME",
             "object_data"       : "ICALENDAR_TEXT",
@@ -89,19 +89,19 @@
 
         "addressbooks": {
             "home_table"        : "ADDRESSBOOK_HOME",
-            "bind_table"        : "ADDRESSBOOK_BIND",
+            "bind_table"        : "ADDRESSBOOK_HOME_BIND",
             "object_table"      : "ADDRESSBOOK_OBJECT",
 
             "bind_home_id"      : "ADDRESSBOOK_HOME_RESOURCE_ID",
             "bind_name"         : "ADDRESSBOOK_RESOURCE_NAME",
             "bind_id"           : "ADDRESSBOOK_RESOURCE_ID",
-            
+
             "object_bind_id"    : "ADDRESSBOOK_RESOURCE_ID",
             "object_name"       : "RESOURCE_NAME",
             "object_data"       : "VCARD_TEXT",
         },
     }
-    
+
     sqlstrings[datatype]["uid"] = uid
     sqlstrings[datatype]["collection"] = collection
     sqlstrings[datatype]["resource"] = resource
@@ -113,4 +113,4 @@
                 select RESOURCE_ID from %(home_table)s where OWNER_UID = '%(uid)s'
             )
     );""" % sqlstrings[datatype])
-    
+

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/testserver
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/testserver	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/testserver	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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/branches/users/gaya/sharedgroups-3/twext/web2/resource.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twext/web2/resource.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twext/web2/resource.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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/branches/users/gaya/sharedgroups-3/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/method/put_common.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/method/put_common.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -819,7 +819,7 @@
         """
 
         # Only relevant if calendar is sharee collection
-        if self.destinationparent.isShareeCollection():
+        if self.destinationparent.isShareeResource():
 
             # Get all X-APPLE-DROPBOX's and ATTACH's that are http URIs
             xdropboxes = self.calendar.getAllPropertiesInAnyComponent(
@@ -888,7 +888,7 @@
             return
 
         # Never add default alarms to calendar data in shared calendars
-        if self.destinationparent.isShareeCollection():
+        if self.destinationparent.isShareeResource():
             return
 
         # Add default alarm for VEVENT and VTODO only
@@ -907,7 +907,7 @@
         # See if default exists and add using appropriate logic
         alarm = self.destinationparent.getDefaultAlarm(vevent, timed)
         if alarm and self.calendar.addAlarms(alarm):
-            self.dataChanged = True
+                self.dataChanged = True
 
 
     @inlineCallbacks
@@ -1036,8 +1036,8 @@
             if do_implicit_action and self.allowImplicitSchedule:
 
                 # Cannot do implicit in sharee's shared calendar
-                isShareeCollection = self.destinationparent.isShareeCollection()
-                if isShareeCollection:
+                isShareeResource = self.destinationparent.isShareeResource()
+                if isShareeResource:
                     scheduler.setSchedulingNotAllowed(
                         HTTPError,
                         ErrorResponse(

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/resource.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/resource.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -57,8 +57,7 @@
 from twext.web2.http_headers import MimeType, ETag
 from twext.web2.stream import MemoryStream
 
-from twistedcaldav import caldavxml, customxml
-from twistedcaldav import carddavxml
+from twistedcaldav import caldavxml, customxml, carddavxml
 from twistedcaldav.cache import PropfindCacheMixin, DisabledCacheNotifier, \
     CacheStoreNotifier
 from twistedcaldav.caldavxml import caldav_namespace
@@ -76,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
 
@@ -221,7 +220,7 @@
 
 
 class CalDAVResource (
-        CalDAVComplianceMixIn, SharedCollectionMixin,
+        CalDAVComplianceMixIn, SharedResourceMixin,
         DAVResourceWithChildrenMixin, DAVResource, LoggingMixIn
     ):
     """
@@ -583,7 +582,7 @@
                 if hasattr(self, "_newStoreObject"):
                     dataObject = getattr(self, "_newStoreObject")
                 if dataObject:
-                    label = "collection" if self.isShareeCollection() else "default"
+                    label = "collection" if self.isShareeResource() else "default"
                     nodeName = (yield dataObject.nodeName(label=label))
                     if nodeName:
                         propVal = customxml.PubSubXMPPPushKeyProperty(nodeName)
@@ -713,9 +712,9 @@
                 returnValue(customxml.AllowedSharingModes(customxml.CanBeShared()))
 
         elif qname == customxml.SharedURL.qname():
-            isShareeCollection = self.isShareeCollection()
+            isShareeResource = self.isShareeResource()
 
-            if isShareeCollection:
+            if isShareeResource:
                 returnValue(customxml.SharedURL(element.HRef.fromString(self._share.url())))
             else:
                 returnValue(None)
@@ -834,8 +833,8 @@
     def accessControlList(self, request, *args, **kwargs):
 
         acls = None
-        isShareeCollection = self.isShareeCollection()
-        if isShareeCollection:
+        isShareeResource = self.isShareeResource()
+        if isShareeResource:
             acls = (yield self.shareeAccessControlList(request, *args, **kwargs))
 
         if acls is None:
@@ -891,8 +890,8 @@
         Return the DAV:owner property value (MUST be a DAV:href or None).
         """
 
-        isShareeCollection = self.isShareeCollection()
-        if isShareeCollection:
+        isShareeResource = self.isShareeResource()
+        if isShareeResource:
             parent = (yield self.locateParent(request, self._share.url()))
         else:
             parent = (yield self.locateParent(request, request.urlForResource(self)))
@@ -908,8 +907,8 @@
         """
         Return the DAV:owner property value (MUST be a DAV:href or None).
         """
-        isShareeCollection = self.isShareeCollection()
-        if isShareeCollection:
+        isShareeResource = self.isShareeResource()
+        if isShareeResource:
             parent = (yield self.locateParent(request, self._share.url()))
         else:
             parent = (yield self.locateParent(request, request.urlForResource(self)))
@@ -1343,15 +1342,15 @@
         """
 
         sharedParent = None
-        isShareeCollection = self.isShareeCollection()
-        if isShareeCollection:
+        isShareeResource = self.isShareeResource()
+        if 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:
+                isShareeResource = parent.isShareeResource()
+                if isShareeResource:
                     # A sharee collection's quota root is the resource owner's root
                     sharedParent = (yield request.locateResource(parentForURL(parent._share.url())))
 
@@ -2737,6 +2736,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):
@@ -2772,7 +2779,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
@@ -2795,7 +2802,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/branches/users/gaya/sharedgroups-3/twistedcaldav/scheduling/caldav/resource.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/scheduling/caldav/resource.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/scheduling/caldav/resource.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -257,7 +257,7 @@
         if defaultCalendarProperty and len(defaultCalendarProperty.children) == 1:
             defaultCalendar = str(defaultCalendarProperty.children[0])
             cal = (yield request.locateResource(str(defaultCalendar)))
-            if cal is not None and isCalendarCollectionResource(cal) and cal.exists() and not cal.isShareeCollection():
+            if cal is not None and isCalendarCollectionResource(cal) and cal.exists() and not cal.isShareeResource():
                 returnValue(defaultCalendarProperty)
 
         # Default is not valid - we have to try to pick one
@@ -285,7 +285,7 @@
 
         # TODO: check that owner of the new calendar is the same as owner of this inbox
         if cal is None or not cal.exists() or not isCalendarCollectionResource(cal) or \
-            cal.isShareeCollection() or not cal.isSupportedComponent(componentType):
+            cal.isShareeResource() or not cal.isSupportedComponent(componentType):
             # Validate that href's point to a valid calendar.
             raise HTTPError(ErrorResponse(
                 responsecode.CONFLICT,

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/scheduling/caldav/test/test_resource.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/scheduling/caldav/test/test_resource.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/scheduling/caldav/test/test_resource.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -375,7 +375,7 @@
             self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newcalendar")
 
         # Force the new calendar to think it is a virtual share
-        newcalendar._isShareeCollection = True
+        newcalendar._isShareeResource = True
 
         try:
             default = yield inbox.readProperty(caldavxml.ScheduleDefaultCalendarURL, request)

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/sharing.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/sharing.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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}
     """
@@ -88,7 +88,7 @@
                 )
 
             # See if this property is on the shared calendar
-            isShared = yield self.isShared(request)
+            isShared = self.isShared(request)
             if isShared:
                 yield self.validateInvites(request)
                 invitations = yield self._allInvitations()
@@ -97,7 +97,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()
@@ -122,6 +122,7 @@
         Set the resource-type property on this resource to indicate that this
         is the owner's version of a resource which has been shared.
         """
+        #FIXME: generate resource type dynamically
         # Change resourcetype
         rtype = self.resourceType()
         rtype = element.ResourceType(*(rtype.children + (customxml.SharedOwner(),)))
@@ -131,8 +132,10 @@
     @inlineCallbacks
     def downgradeFromShare(self, request):
 
-        # Change resource type (note this might be called after deleting a resource
+        # Restore resource type (note this might be called after deleting a resource
         # so we have to cope with that)
+        #FIXME: generate resource type dynamically
+        #self.removeDeadProperty((dav_namespace, "resourcetype"))
         rtype = self.resourceType()
         rtype = element.ResourceType(*([child for child in rtype.children if child != customxml.SharedOwner()]))
         self.writeDeadProperty(rtype)
@@ -146,7 +149,7 @@
 
     @inlineCallbacks
     def changeUserInviteState(self, request, inviteUID, shareeUID, state, summary=None):
-        shared = (yield self.isShared(request))
+        shared = self.isShared(request)
         if not shared:
             raise HTTPError(ErrorResponse(
                 responsecode.FORBIDDEN,
@@ -162,7 +165,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)
 
@@ -214,7 +217,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(
@@ -241,28 +244,42 @@
         returnValue(response)
 
 
-    @inlineCallbacks
-    def isShared(self, request):
+    def isShared(self, request): #@UnusedVariable
         """
-        Return True if this is an owner shared calendar collection.
+        Return True if this is an owner shared resource
+        Similar to self.isSpecialCollection() but also allows groups
         """
-        returnValue((yield self.isSpecialCollection(customxml.SharedOwner)))
+        if not self.isCollection() and not self.isGroup():
+            return False
 
+        #FIXME: don't use dead properties, try:
+        # returnValue(bool(yield self._allInvitations()))
 
+        try:
+            resourcetype = self.resourceType()
+        except HTTPError, e:
+            assert e.response.code == responsecode.NOT_FOUND, (
+                "Unexpected response code: %s" % (e.response.code,)
+            )
+            return False
+
+        return bool(resourcetype.childrenOfType(customxml.SharedOwner))
+
+
     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 #  _isShareeResource attr is used by self tests
         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
@@ -273,13 +290,13 @@
         # 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)))
 
 
     def resourceType(self):
-        superObject = super(SharedCollectionMixin, self)
+        superObject = super(SharedResourceMixin, self)
         try:
             superMethod = superObject.resourceType
         except AttributeError:
@@ -287,8 +304,8 @@
         else:
             rtype = superMethod()
 
-        isShareeCollection = self.isShareeCollection()
-        if isShareeCollection:
+        isShareeResource = self.isShareeResource()
+        if isShareeResource:
             rtype = element.ResourceType(
                 *(
                     tuple([child for child in rtype.children if child.qname() != customxml.SharedOwner.qname()]) +
@@ -307,6 +324,9 @@
             return "calendar"
         elif self.isAddressBookCollection():
             return "addressbook"
+        elif self.isGroup():
+            #TODO: Add group xml resource type ?
+            return "group"
         else:
             return ""
 
@@ -376,7 +396,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()
@@ -431,7 +452,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(
@@ -521,8 +542,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.
@@ -559,21 +581,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)
 
 
@@ -581,41 +602,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)
@@ -623,11 +644,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)
@@ -635,7 +656,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)
@@ -660,7 +681,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)
@@ -684,25 +705,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)
@@ -822,6 +846,7 @@
                     "%s: %s" % (", ".join(error_text), inviteset,),
                 ))
 
+
         def _handleInviteRemove(inviteremove):
             userid = None
             access = []
@@ -896,7 +921,7 @@
         numRecords = (yield self.validateInvites(request))
 
         # Set the sharing state on the collection
-        shared = (yield self.isShared(request))
+        shared = self.isShared(request)
         if shared and numRecords == 0:
             yield self.downgradeFromShare(request)
         elif not shared and numRecords != 0:
@@ -965,15 +990,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 = {
@@ -981,6 +1014,7 @@
         ("text", "xml") : xmlRequestHandler,
     }
 
+
 invitationAccessMapToXML = {
     "read-only"           : customxml.ReadAccess,
     "read-write"          : customxml.ReadWriteAccess,
@@ -1010,32 +1044,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()
 
 
 
@@ -1048,11 +1083,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()
@@ -1062,7 +1097,7 @@
 
 
     @inlineCallbacks
-    def _shareForHomeChild(self, child, request=None):
+    def _shareForStoreObject(self, storeObject, request=None):
         """
         Determine the L{Share} associated with the given child.
 
@@ -1076,32 +1111,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)
 
@@ -1109,17 +1150,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)
 
@@ -1138,10 +1178,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,
@@ -1159,16 +1200,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,
@@ -1199,41 +1240,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.writeProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Transparent()), request)
+                yield shareeCalender.writeProperty(caldavxml.DefaultAlarmVEventDateTime.fromString(""), request)
+                yield shareeCalender.writeProperty(caldavxml.DefaultAlarmVEventDate.fromString(""), request)
+                yield shareeCalender.writeProperty(caldavxml.DefaultAlarmVToDoDateTime.fromString(""), request)
+                yield shareeCalender.writeProperty(caldavxml.DefaultAlarmVToDoDate.fromString(""), request)
+
+        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.writeProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Transparent()), request)
-            yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVEventDateTime.fromString(""), request)
-            yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVEventDate.fromString(""), request)
-            yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVToDoDateTime.fromString(""), request)
-            yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVToDoDate.fromString(""), request)
-
         # Notify client of changes
         yield self.notifyChanged()
 
@@ -1241,7 +1290,7 @@
         returnValue(XMLResponse(
             code=responsecode.OK,
             element=customxml.SharedAs(
-                element.HRef.fromString(joinURL(self.url(), share.name()))
+                element.HRef.fromString(sharedAsURL)
             )
         ))
 
@@ -1282,11 +1331,12 @@
         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()
 
+        #FIXME: Remove! Probably obsolete
         if self.isCalendarCollection():
             # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
             principal = (yield self.resourceOwnerPrincipal(request))
@@ -1296,9 +1346,9 @@
                 inbox.processFreeBusyCalendar(shareURL, False)
 
         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)
 
@@ -1308,9 +1358,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))
 
 
@@ -1319,12 +1367,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,
@@ -1333,17 +1380,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
@@ -1384,7 +1431,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
@@ -1415,14 +1464,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
@@ -1437,24 +1485,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):
@@ -1463,27 +1511,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/branches/users/gaya/sharedgroups-3/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/storebridge.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/storebridge.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -42,7 +42,6 @@
 from twistedcaldav.cache import CacheStoreNotifier, ResponseCacheMixin, \
     DisabledCacheNotifier
 from twistedcaldav.caldavxml import caldav_namespace
-from twistedcaldav.carddavxml import carddav_namespace
 from twistedcaldav.config import config
 from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
 from twistedcaldav.ical import Component as VCalendar, Property as VProperty, \
@@ -61,6 +60,8 @@
 from txdav.caldav.icalendarstore import QuotaExceeded, AttachmentStoreFailed, \
     AttachmentStoreValidManagedID, AttachmentRemoveFailed, \
     AttachmentDropboxNotAllowed
+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
@@ -141,7 +142,6 @@
                 self._newPropertyStore.keys()]
 
 
-
 def requiresPermissions(*permissions, **kw):
     """
     A decorator to wrap http_ methods in, to indicate that they should not be
@@ -266,7 +266,7 @@
 
 
     def owner_url(self):
-        if self.isShareeCollection():
+        if self.isShareeResource():
             return joinURL(self._share.url(), "/")
         else:
             return self.url()
@@ -451,8 +451,8 @@
         """
 
         # Check sharee collection first
-        isShareeCollection = self.isShareeCollection()
-        if isShareeCollection:
+        isShareeResource = self.isShareeResource()
+        if isShareeResource:
             log.debug("Removing shared collection %s" % (self,))
             yield self.removeShareeCollection(request)
             returnValue(NO_CONTENT)
@@ -1262,7 +1262,14 @@
         returnValue(result)
 
 
+    def resourceType(self,):
+        if self.hasDeadProperty((dav_namespace, "resourcetype")):
+            return super(CalendarCollectionResource, self).resourceType()
+        else:
+            return caldavxml.ResourceType.calendar
 
+
+
 class StoreScheduleInboxResource(_CalendarCollectionBehaviorMixin, _CommonHomeChildCollectionMixin, ScheduleInboxResource):
 
     def __init__(self, *a, **kw):
@@ -1739,7 +1746,7 @@
         return davxml.ACL(*aces)
 
 
-    def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
+    def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None): #@UnusedVariable
         # Permissions here are fixed, and are not subject to inheritance rules, etc.
         return succeed(self.defaultAccessControlList())
 
@@ -2778,11 +2785,9 @@
 
 
     def isAddressBookCollection(self):
-        """
-        Yes, it is a calendar collection.
-        """
         return True
 
+
     createAddressBookCollection = _CommonHomeChildCollectionMixin.createCollection
 
 
@@ -2821,73 +2826,21 @@
         returnValue(storer.returndata if hasattr(storer, "returndata") else None)
 
 
-    @inlineCallbacks
-    def storeRemove(self, request, viaRequest, where):
+    def http_MOVE(self, request):
         """
-        Delete this collection resource, first deleting each contained
-        object resource.
-
-        This has to emulate the behavior in fileop.delete in that any errors
-        need to be reported back in a multistatus response.
-
-        @param request: The request used to locate child resources.  Note that
-            this is the request which I{triggered} the C{DELETE}, but which may
-            not actually be a C{DELETE} request itself.
-
-        @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).
-
-        @rtype: something adaptable to L{twext.web2.iweb.IResponse}
+        Addressbooks may not be renamed.
         """
+        return FORBIDDEN
 
-        # Not allowed to delete the default address book
-        default = (yield self.isDefaultAddressBook(request))
-        if default:
-            log.err("Cannot DELETE default address book: %s" % (self,))
-            raise HTTPError(ErrorResponse(
-                FORBIDDEN,
-                (carddav_namespace, "default-addressbook-delete-allowed",),
-                "Cannot delete default address book",
-            ))
 
-        response = (
-            yield super(AddressBookCollectionResource, self).storeRemove(
-                request, viaRequest, where
-            )
-        )
+    def resourceType(self,):
+        if self.hasDeadProperty((dav_namespace, "resourcetype")):
+            return super(AddressBookCollectionResource, self).resourceType()
+        else:
+            return carddavxml.ResourceType.addressbook
 
-        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.
-        """
-        defaultAddressBook = (yield self.isDefaultAddressBook(request))
-
-        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}.
@@ -2931,7 +2884,118 @@
         )
 
 
+    @inlineCallbacks
+    def storeRemove(self, request, viaRequest, where):
+        """
+        Remove this address book object
+        """
+        # Handle sharing
+        wasShared = (yield self.isShared(request))
+        if wasShared:
+            yield self.downgradeFromShare(request)
 
+        response = (
+            yield super(AddressBookObjectResource, self).storeRemove(
+                request, viaRequest, where
+            )
+        )
+
+        returnValue(response)
+
+
+    @inlineCallbacks
+    def http_PUT(self, request):
+
+        try:
+            returnValue((yield super(AddressBookObjectResource, self).http_PUT(request)))
+
+        except GroupWithUnsharedAddressNotAllowedError:
+            raise HTTPError(StatusResponse(
+                FORBIDDEN,
+                "Sharee cannot add unshared group members",)
+            )
+
+    @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/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_resource.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_resource.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_resource.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -36,7 +36,7 @@
 class StubHome(object):
     def properties(self):
         return []
-    
+
     def addNotifier(self, notifier):
         pass
 
@@ -182,8 +182,8 @@
         """
         Make calendar
         """
-        
 
+
         request = SimpleRequest(self.site, "GET", "/addressbooks/users/wsanchez/")
         home = yield request.locateResource("/addressbooks/users/wsanchez")
 
@@ -211,8 +211,8 @@
         """
         Make adbk
         """
-        
 
+
         request = SimpleRequest(self.site, "GET", "/addressbooks/users/wsanchez/")
         home = yield request.locateResource("/addressbooks/users/wsanchez")
 
@@ -231,7 +231,7 @@
             HRef("/addressbooks/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newadbk/")
         ))
         request._newStoreTransaction.commit()
-        
+
         # Delete the normal adbk
         request = SimpleRequest(self.site, "GET", "/addressbooks/users/wsanchez/")
         home = yield request.locateResource("/addressbooks/users/wsanchez")
@@ -239,7 +239,7 @@
         yield adbk.storeRemove(request, False, "/addressbooks/users/wsanchez/addressbook")
 
         home.removeDeadProperty(carddavxml.DefaultAddressBookURL)
-        
+
         # default property not present
         try:
             home.readDeadProperty(carddavxml.DefaultAddressBookURL)
@@ -267,8 +267,8 @@
         """
         Make calendar
         """
-        
 
+
         request = SimpleRequest(self.site, "GET", "/addressbooks/users/wsanchez/")
         home = yield request.locateResource("/addressbooks/users/wsanchez")
 
@@ -284,10 +284,10 @@
             self.fail("carddavxml.DefaultAddressBookURL is not present")
         else:
             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)
         except HTTPError:

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_sharing.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_sharing.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -216,8 +216,8 @@
         self.assertEquals(rtype, regularCalendarType)
         isShared = (yield self.resource.isShared(None))
         self.assertFalse(isShared)
-        isShareeCollection = self.resource.isShareeCollection()
-        self.assertFalse(isShareeCollection)
+        isShareeResource = self.resource.isShareeResource()
+        self.assertFalse(isShareeResource)
 
         self.resource.upgradeToShare()
 
@@ -225,8 +225,8 @@
         self.assertEquals(rtype, sharedOwnerType)
         isShared = (yield self.resource.isShared(None))
         self.assertTrue(isShared)
-        isShareeCollection = self.resource.isShareeCollection()
-        self.assertFalse(isShareeCollection)
+        isShareeResource = self.resource.isShareeResource()
+        self.assertFalse(isShareeResource)
 
 
     @inlineCallbacks
@@ -238,8 +238,8 @@
         self.assertEquals(rtype, sharedOwnerType)
         isShared = (yield self.resource.isShared(None))
         self.assertTrue(isShared)
-        isShareeCollection = self.resource.isShareeCollection()
-        self.assertFalse(isShareeCollection)
+        isShareeResource = self.resource.isShareeResource()
+        self.assertFalse(isShareeResource)
 
         yield self.resource.downgradeFromShare(None)
 
@@ -247,8 +247,8 @@
         self.assertEquals(rtype, regularCalendarType)
         isShared = (yield self.resource.isShared(None))
         self.assertFalse(isShared)
-        isShareeCollection = self.resource.isShareeCollection()
-        self.assertFalse(isShareeCollection)
+        isShareeResource = self.resource.isShareeResource()
+        self.assertFalse(isShareeResource)
 
 
     @inlineCallbacks
@@ -279,8 +279,8 @@
 
         isShared = (yield self.resource.isShared(None))
         self.assertTrue(isShared)
-        isShareeCollection = self.resource.isShareeCollection()
-        self.assertFalse(isShareeCollection)
+        isShareeResource = self.resource.isShareeResource()
+        self.assertFalse(isShareeResource)
 
 
     @inlineCallbacks
@@ -309,8 +309,8 @@
 
         isShared = (yield self.resource.isShared(None))
         self.assertTrue(isShared)
-        isShareeCollection = (yield self.resource.isShareeCollection())
-        self.assertFalse(isShareeCollection)
+        isShareeResource = (yield self.resource.isShareeResource())
+        self.assertFalse(isShareeResource)
 
 
     @inlineCallbacks
@@ -734,7 +734,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/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_wrapping.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_wrapping.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/test/test_wrapping.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -33,7 +33,7 @@
 from twistedcaldav.vcard import Component as VCComponent
 
 from twistedcaldav.storebridge import DropboxCollection, \
-    CalendarCollectionResource, AddressBookCollectionResource
+    CalendarCollectionResource
 
 from twistedcaldav.test.util import TestCase
 
@@ -57,8 +57,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'
 
@@ -494,24 +497,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/branches/users/gaya/sharedgroups-3/twistedcaldav/vcard.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/vcard.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/vcard.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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/branches/users/gaya/sharedgroups-3/txdav/base/propertystore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/base/propertystore/sql.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/base/propertystore/sql.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -292,10 +292,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))
 
     @inlineCallbacks
@@ -316,8 +317,8 @@
                 yield self._insertQuery.on(
                     self._txn, resourceID=self._resourceID, value=value_str,
                     name=key_str, uid=uid)
-                
 
+
         # Reload from the DB
         self._cached = {}
         self._cacher.delete(str(self._resourceID))

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/caldav/datastore/sql.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/caldav/datastore/sql.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -68,13 +68,9 @@
     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, \
-    _ATTACHMENTS_MODE_READ
+from txdav.common.datastore.sql_tables import _ATTACHMENTS_MODE_NONE, \
+    _ATTACHMENTS_MODE_READ, _ATTACHMENTS_MODE_WRITE, \
+    _BIND_MODE_OWN, schema
 from txdav.common.icommondatastore import IndexedSearchException, \
     InternalDataStoreError, HomeChildNameAlreadyExistsError, \
     HomeChildNameNotAllowedError
@@ -313,15 +309,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)
@@ -587,14 +575,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):
@@ -910,13 +890,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.
@@ -960,7 +933,6 @@
 class CalendarObject(CommonObjectResource, CalendarObjectBase):
     implements(ICalendarObject)
 
-    _objectTable = CALENDAR_OBJECT_TABLE
     _objectSchema = schema.CALENDAR_OBJECT
 
     def __init__(self, calendar, name, uid, resourceID=None, metadata=None):
@@ -1845,11 +1817,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 = self._parentCollection.ownerHome()._resourceID
         managedID = str(uuid.uuid4())
         returnValue((
             yield ManagedAttachment.create(
-                self._txn, managedID, sharerHomeID, self._resourceID,
+                self._txn, managedID, ownerHomeID, self._resourceID,
             )
         ))
 
@@ -1859,10 +1831,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 = self._parentCollection.ownerHome()._resourceID
         returnValue((
             yield ManagedAttachment.update(
-                self._txn, managedID, sharerHomeID, self._resourceID, oldattachment._attachmentID,
+                self._txn, managedID, ownerHomeID, self._resourceID, oldattachment._attachmentID,
             )
         ))
 
@@ -1921,11 +1893,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 = self._parentCollection.ownerHome()._resourceID
         dropboxID = (yield self.dropboxID())
         returnValue((
             yield DropBoxAttachment.create(
-                self._txn, dropboxID, name, sharerHomeID,
+                self._txn, dropboxID, name, ownerHomeID,
             )
         ))
 

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/sql.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/sql.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -14,7 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
-from txdav.common.icommondatastore import InternalDataStoreError
 
 """
 SQL backend for CardDAV storage.
@@ -26,71 +25,71 @@
     "AddressBookObject",
 ]
 
-from zope.interface.declarations import implements
+from uuid import uuid4
 
+from twext.enterprise.dal.syntax import Delete, Insert, Len, Parameter, \
+    Update, Union, Max, Select, utcNowSQL
+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 txdav.xml.rfc2518 import ResourceType
-from twext.web2.http_headers import MimeType
-
 from twistedcaldav import carddavxml, customxml
 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.datastore.util import validateAddressBookComponent
+from txdav.carddav.iaddressbookstore import IAddressBookHome, IAddressBook, \
+    IAddressBookObject, GroupForSharedAddressBookDeleteNotAllowedError, \
+    GroupWithUnsharedAddressNotAllowedError, SharedGroupDeleteNotAllowedError
+from txdav.common.datastore.sql import CommonHome, CommonHomeChild, \
+    CommonObjectResource, EADDRESSBOOKTYPE, SharingMixIn
 from txdav.common.datastore.sql_legacy import PostgresLegacyABIndexEmulator
+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, \
+    AllRetriesFailed
+from txdav.xml.rfc2518 import ResourceType
 
-from txdav.carddav.datastore.util import validateAddressBookComponent
-from txdav.carddav.iaddressbookstore import IAddressBookHome, IAddressBook,\
-    IAddressBookObject
+from zope.interface.declarations import implements
 
-from txdav.common.datastore.sql import CommonHome, CommonHomeChild,\
-    CommonObjectResource, EADDRESSBOOKTYPE
-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 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.base.propertystore.base import PropertyName
 
-
-
 class AddressBookHome(CommonHome):
 
     implements(IAddressBookHome)
 
     # structured tables.  (new, preferred)
     _homeSchema = schema.ADDRESSBOOK_HOME
-    _bindSchema = schema.ADDRESSBOOK_BIND
+    _bindSchema = schema.ADDRESSBOOK_HOME_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, notifiers):
 
         self._childClass = AddressBook
         super(AddressBookHome, self).__init__(transaction, ownerUID, notifiers)
+        self._homeResourceID = 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
@@ -99,46 +98,264 @@
     removeAddressBookWithName = CommonHome.removeChildWithName
 
 
+    @classproperty
+    def _resourceIDAndHomeResourceIDFromOwnerQuery(cls): #@NoSelf
+        home = cls._homeSchema
+        return Select([home.RESOURCE_ID, home.HOME_RESOURCE_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._homeResourceID = 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 _loadPropertyStore(self):
+        props = yield PropertyStore.load(
+            self.uid(),
+            self.uid(),
+            self._txn,
+            self._homeResourceID, # not ._resourceID as in CommonHome._loadPropertyStore()
+            notifyCallback=self.notifyChanged
+        )
+        self._propertyStore = props
+
+
+    @inlineCallbacks
     def remove(self):
         ah = schema.ADDRESSBOOK_HOME
-        ab = schema.ADDRESSBOOK_BIND
+        ahb = schema.ADDRESSBOOK_HOME_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._homeResourceID
+            )
         ).on(self._txn)
 
         yield self._cacher.delete(str(self._ownerUID))
 
 
+    @inlineCallbacks
     def createdHome(self):
-        return self.createAddressBookWithName("addressbook")
+        # initialize synctoken
+        yield self.addressbook()._initSyncToken()
 
 
+    @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.RESOURCE_NAME, rev.DELETED],
+            From=rev,
+            Where=(rev.REVISION > Parameter("token")).And(
+                rev.HOME_RESOURCE_ID == Parameter("resourceID")).And(
+                rev.RESOURCE_ID == rev.HOME_RESOURCE_ID)
+        )
+
+    @inlineCallbacks
+    def changesSinceToken(self, token):
+        """
+        return list of (path, name, wasdeleted) of changes since token
+        Subclasses may override
+        """
+        results = [
+            (
+                self.addressbook().name(),
+                name if name else "",
+                wasdeleted
+            )
+            for name, wasdeleted in (
+                yield self._changesQuery.on(
+                    self._txn,
+                    resourceID=self._resourceID,
+                    token=token
+                )
+            )
+        ]
+        returnValue(results)
+
+
 AddressBookHome._register(EADDRESSBOOKTYPE)
 
 
 
-class AddressBook(CommonHomeChild):
+class AddressBook(CommonHomeChild, SharingMixIn):
     """
     SQL-based implementation of L{IAddressBook}.
     """
@@ -146,25 +363,44 @@
 
     # structured tables.  (new, preferred)
     _homeSchema = schema.ADDRESSBOOK_HOME
-    _bindSchema = schema.ADDRESSBOOK_BIND
-    _homeChildSchema = schema.ADDRESSBOOK
-    _homeChildMetaDataSchema = schema.ADDRESSBOOK_METADATA
+    _bindSchema = schema.ADDRESSBOOK_HOME_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, message=None, ownerHome=None, bindName=None):
+        ownerName = ownerHome.addressbook().name() if ownerHome else None
+        super(AddressBook, self).__init__(home, name, resourceID, mode, status, 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())
+
+
+    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
@@ -174,9 +410,15 @@
         return ResourceType.addressbook #@UndefinedVariable
 
 
+    #FIXME: Only used for shared group resouretype in SharedResourceMixin.upgradeToShare() and SharedResourceMixin.downgradeFromShare()
+    def objectResourcesHaveProperties(self):
+        return True
+
+
     ownerAddressBookHome = CommonHomeChild.ownerHome
+    viewerAddressBookHome = CommonHomeChild.viewerHome
     addressbookObjects = CommonHomeChild.objectResources
-    listAddressbookObjects = CommonHomeChild.listObjectResources
+    listAddressBookObjects = CommonHomeChild.listObjectResources
     addressbookObjectWithName = CommonHomeChild.objectResourceWithName
     addressbookObjectWithUID = CommonHomeChild.objectResourceWithUID
     createAddressBookObjectWithName = CommonHomeChild.createObjectResourceWithName
@@ -185,6 +427,10 @@
     addressbookObjectsSinceToken = CommonHomeChild.objectResourcesSinceToken
 
 
+    def shareeAddressBookName(self):
+        return self._home.shareeAddressBookName()
+
+
     def initPropertyStore(self, props):
         # Setup peruser special properties
         props.setSpecialProperties(
@@ -199,30 +445,842 @@
 
     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 self.removeObjectResource(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))),)
 
 
-class AddressBookObject(CommonObjectResource):
+    @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]
 
+            # 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_RESOURCE_ID == Parameter("addressbookResourceID"),)
+
+
+    def _fullySharedAddressBookGroupRow(self): #@NoSelf
+        return [
+            self._resourceID, # obj.ADDRESSBOOK_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.
+        """
+        results = [home.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, bindMessage = dataRow[:6] #@UnusedVariable
+            assert bindStatus != _BIND_MODE_OWN
+            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, bindMessage = groupBindRow[:6] #@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)
+            childResourceIDs = [ownerHome._resourceID for ownerHome in ownerHomeToDataRowMap]
+            propertyStores = yield PropertyStore.forMultipleResourcesWithResourceIDs(
+                home.uid(), home._txn, childResourceIDs
+            )
+            revisions = yield cls._revisionsForResourceIDs(childResourceIDs).on(home._txn, resourceIDs=childResourceIDs)
+            revisions = dict(revisions)
+
+            # Create the actual objects merging in properties
+            for ownerHome, dataRow in ownerHomeToDataRowMap.iteritems():
+                bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = dataRow[:6] #@UnusedVariable
+                metadata = dataRow[6:]
+
+                child = cls(
+                    home=home,
+                    name=ownerHome.shareeAddressBookName(),
+                    resourceID=ownerHome._resourceID,
+                    mode=bindMode, status=bindStatus,
+                    message=bindMessage, ownerHome=ownerHome,
+                    bindName=bindName
+                )
+
+                for attr, value in zip(cls.metadataAttributes(), metadata):
+                    setattr(child, attr, value)
+                child._syncTokenRevision = revisions[child._resourceID]
+                propstore = propertyStores.get(child._resourceID, 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():
+            returnValue(home.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._bindWithHomeIDAndAddressBookID.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, 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,
+                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, 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, 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:
+            returnValue(home.addressbook())
+
+        bindRows = yield cls._bindForResourceIDAndHomeID.on(
+            home._txn, resourceID=resourceID, homeID=home._resourceID
+        )
+        if bindRows:
+            bindMode, homeID, resourceID, bindName, bindStatus, 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._bindWithHomeIDAndAddressBookID.on(
+                    home._txn, homeID=home._resourceID, addressbookID=resourceID
+        )
+        if groupBindRows:
+            bindMode, homeID, resourceID, bindName, bindStatus, 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
+
+
+    @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 bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in rows: #@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._unacceptedBindWithHomeIDAndAddressBookID.on(
+                    self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+            )
+            #for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
+            returnValue([groupBindRow[2] for groupBindRow in groupBindRows])
+
+
+    @inlineCallbacks
+    def acceptedGroupIDs(self):
+        if self.owned():
+            returnValue([])
+        else:
+            groupBindRows = yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.on(
+                    self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+            )
+            #for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
+            returnValue([groupBindRow[2] for groupBindRow in groupBindRows])
+
+
+    @inlineCallbacks
+    def accessControlGroupIDs(self):
+        if self.owned():
+            returnValue(([], []))
+        else:
+            groupBindRows = yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.on(
+                    self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+            )
+            readWriteGroupIDs = []
+            readOnlyGroupIDs = []
+            for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@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._acceptedBindWithHomeIDAndAddressBookID.on(
+                self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+        )
+        readWriteGroupIDs = []
+        readOnlyGroupIDs = []
+        for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@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._acceptedBindWithHomeIDAndAddressBookID.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()
+                        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 bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in bindRows: #@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 bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in bindRows: #@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._acceptedBindWithHomeIDAndAddressBookID.on(
+                    self._txn, homeID=shareeHome._resourceID, addressbookID=sharedAddressBook._resourceID
+            )))
+            if acceptedBindCount == 1:
+                sharedAddressBook._deletedSyncToken(sharedRemoval=True)
+                shareeHome._children.pop(self.sharedAddressBook.name(), None)
+                shareeHome._children.pop(self.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._deleteBindWithResourceIDAndHomeID.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.GROUP_ADDRESSBOOK_HOME_BIND
 
-    def __init__(self, addressbook, name, uid, resourceID=None, metadata=None):
+    # used by CommonHomeChild._childrenAndMetadataForHomeID() only
+    #_homeChildSchema = schema.ADDRESSBOOK_OBJECT
+    #_homeChildMetaDataSchema = schema.ADDRESSBOOK_OBJECT
 
+
+    def __init__(self, addressbook, name, uid, resourceID=None, metadata=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)
 
 
+    def __repr__(self):
+        return '<%s: %s("%s")>' % (self.__class__.__name__, self._resourceID, self.name())
+
+
     @property
     def _addressbook(self):
         return self._parentCollection
@@ -232,22 +1290,380 @@
         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 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:
+                    bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = groupBindRows[0] #@UnusedVariable
+                    self._bindMode = bindMode
+                    self._bindStatus = bindStatus
+                    self._bindMessage = bindMessage
+                    self._bindName = bindName
+
+            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_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()
+
+
+    @inlineCallbacks
     def setComponent(self, component, inserting=False):
 
         validateAddressBookComponent(self, self._addressbook, component, inserting)
+        yield self.updateDatabase(component, inserting=inserting)
+        yield self._changeAddressBookRevision(self._addressbook, inserting)
 
-        yield self.updateDatabase(component, inserting=inserting)
-        if inserting:
-            yield self._addressbook._insertRevision(self._name)
+        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
 
 
+    @classmethod
+    def _resourceIDAndUIDForUIDsAndAddressBookResourceIDQuery(cls, uids):
+        abo = schema.ADDRESSBOOK_OBJECT
+        return Select([abo.RESOURCE_ID, abo.VCARD_UID],
+                      From=abo,
+                      Where=((abo.ADDRESSBOOK_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_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,
+    def updateDatabase(self, component, expand_until=None, reCreate=False, #@UnusedVariable
                        inserting=False):
         """
         Update the database tables for the new data being written.
@@ -256,41 +1672,184 @@
         @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
+        # 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:
 
-        # Special - if migrating we need to preserve the original md5    
+            # 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
+
+            # sort addreses 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)
+
+            # 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):
         """
@@ -299,29 +1858,76 @@
         the caller - that is not ideal but in theory we should have checked everything on the way in and
         only allowed in good data.
         """
-        text = yield self._text()
 
-        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 self._component is None:
 
-        # Fix any bogus data we can
-        fixed, unfixed = component.validVCardData(doFix=True, doRaise=False)
+            if not self.owned() and  self._resourceID == self._addressbook._resourceID:
+                component = yield self._addressbook._fullySharedAddressBookGroupComponent()
+            else:
+                text = yield self._text()
 
-        if unfixed:
-            self.log_error("Address data id=%s had unfixable problems:\n  %s" % (self._resourceID, "\n  ".join(unfixed),))
-        
-        if fixed:
-            self.log_error("Address data id=%s had fixable problems:\n  %s" % (self._resourceID, "\n  ".join(fixed),))
+                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)
+                    )
 
-        returnValue(component)
+                # Fix any bogus data we can
+                fixed, unfixed = component.validVCardData(doFix=True, doRaise=False)
 
+                if unfixed:
+                    self.log_error("Address data id=%s had unfixable problems:\n  %s" % (self._resourceID, "\n  ".join(unfixed),))
 
+                if fixed:
+                    self.log_error("Address data id=%s had fixable problems:\n  %s" % (self._resourceID, "\n  ".join(fixed),))
+
+                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)
+
+
     # IDataStoreObject
     def contentType(self):
         """
@@ -330,5 +1936,385 @@
         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
+
+    @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.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 bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@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 bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@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._acceptedBindWithHomeIDAndAddressBookID.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._deleteBindWithResourceIDAndHomeID.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
+            )
+            bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = groupBindRows[0] #@UnusedVariable
+            if bindStatus == _BIND_STATUS_ACCEPTED:
+                group = yield shareeHome.objectForShareUID(bindName)
+            else:
+                group = yield shareeHome.invitedObjectForShareUID(bindName)
+            bindName = yield self.updateShare(
+                group, mode=mode, status=status,
+                message=message
+            )
+
+        # 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._acceptedBindWithHomeIDAndAddressBookID.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()
+                        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 _acceptedBindWithHomeIDAndAddressBookID(cls): #@NoSelf
+        bind = cls._bindSchema
+        abo = cls._objectSchema
+        return Select(
+                  cls._bindColumns(),
+                  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_RESOURCE_ID == Parameter("addressbookID"))
+        )
+
+
+    @classproperty
+    def _unacceptedBindWithHomeIDAndAddressBookID(cls): #@NoSelf
+        bind = cls._bindSchema
+        abo = cls._objectSchema
+        return Select(
+                  cls._bindColumns(),
+                  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_RESOURCE_ID == Parameter("addressbookID"))
+        )
+
+
+    @classproperty
+    def _bindWithHomeIDAndAddressBookID(cls): #@NoSelf
+        bind = cls._bindSchema
+        abo = cls._objectSchema
+        return Select(
+                  cls._bindColumns(),
+                  From=bind.join(abo),
+                  Where=(bind.RESOURCE_ID == abo.RESOURCE_ID)
+                        .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                        .And(abo.ADDRESSBOOK_RESOURCE_ID == Parameter("addressbookID"))
+        )
+
+
 AddressBook._objectResourceClass = AddressBookObject

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/1.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/2.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home1/addressbook/3.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/3765A955-1B96-41EA-994D-335192BEDCCD.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44745975-AE6D-4FB0-80A6-A298427E047A.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/44EE78BF-8814-4471-899C-92280CEFB098.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/8424B7F0-C878-4722-B522-EBB07CF48AD7.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/934731C6-1C95-4C40-BE1F-FA4215B2307B.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/AFBB77B8-0438-4825-A1DB-A75D76B6C3A8.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E1.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/ED7A5AEC-AB19-4CE0-AD6A-2923A3E5C4E2.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/F0A6918D-8E09-43FA-9684-226810B8A96F.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home2/addressbook/FCBA0FA3-00B2-4C95-B4EC-4CCC4843F8B1.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/1.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -0,0 +1,2 @@
+BEGIN:VCARD
+END:VCARD

Added: CalendarServer/branches/users/gaya/sharedgroups-3/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	                        (rev 0)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/addressbook_store/ho/me/home_bad/addressbook/2.vcf	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/common.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/common.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/common.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -17,38 +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 twistedcaldav.vcard import Component as VComponent
+
 from txdav.idav import IPropertyStore, IDataStore
 from txdav.base.propertystore.base import PropertyName
-
-from txdav.common.icommondatastore import (
-    HomeChildNameAlreadyExistsError, ICommonTransaction
-)
+from txdav.common.icommondatastore import ICommonTransaction
 from txdav.common.icommondatastore import InvalidObjectResourceError
 from txdav.common.icommondatastore import NoSuchHomeChildError
 from txdav.common.icommondatastore import NoSuchObjectResourceError
 from txdav.common.icommondatastore import ObjectResourceNameAlreadyExistsError
-
 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, ResourceType
 
-
 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",
@@ -58,9 +54,7 @@
 
 
 home1_addressbookNames = [
-    "addressbook_1",
-    "addressbook_2",
-    "addressbook_empty",
+    "addressbook",
 ]
 
 
@@ -114,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
@@ -161,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")))
@@ -228,9 +218,9 @@
     def test_notifierID(self):
         home = yield self.homeUnderTest()
         self.assertEquals(home.notifierID(), "CardDAV|home1")
-        addressbook = yield home.addressbookWithName("addressbook_1")
+        addressbook = yield home.addressbookWithName("addressbook")
         self.assertEquals(addressbook.notifierID(), "CardDAV|home1")
-        self.assertEquals(addressbook.notifierID(label="collection"), "CardDAV|home1/addressbook_1")
+        self.assertEquals(addressbook.notifierID(label="collection"), "CardDAV|home1/addressbook")
 
 
     @inlineCallbacks
@@ -277,21 +267,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
@@ -312,14 +292,14 @@
         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)
         @inlineCallbacks
         def checkProperties():
             addressbookProperties = (yield home.addressbookWithName(name)).properties()
-            addressbookType = ResourceType.addressbook #@UndefinedVariable
+            addressbookType = ResourceType.addressbook
             self.assertEquals(
                 addressbookProperties[
                     PropertyName.fromString(ResourceType.sname())
@@ -346,21 +326,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
@@ -371,7 +336,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()
 
@@ -380,11 +347,7 @@
             self.notifierFactory.history,
             [
                 "CardDAV|home1",
-                "CardDAV|home1/addressbook_1",
-                "CardDAV|home1",
-                "CardDAV|home1/addressbook_2",
-                "CardDAV|home1",
-                "CardDAV|home1/addressbook_empty"
+                "CardDAV|home1/addressbook",
             ]
         )
 
@@ -516,7 +479,7 @@
             self.notifierFactory.history,
             [
                 "CardDAV|home1",
-                "CardDAV|home1/addressbook_1",
+                "CardDAV|home1/addressbook",
             ]
         )
 
@@ -538,7 +501,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
@@ -670,21 +633,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
@@ -706,7 +654,7 @@
             self.notifierFactory.history,
             [
                 "CardDAV|home1",
-                "CardDAV|home1/addressbook_1",
+                "CardDAV|home1/addressbook",
             ]
         )
 
@@ -822,7 +770,7 @@
             self.notifierFactory.history,
             [
                 "CardDAV|home1",
-                "CardDAV|home1/addressbook_1",
+                "CardDAV|home1/addressbook",
             ]
         )
 
@@ -926,10 +874,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
@@ -939,13 +888,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/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/test_file.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/test_file.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/test_file.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -50,6 +50,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):
@@ -79,7 +80,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?"
 
 
@@ -305,7 +306,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
@@ -490,3 +491,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/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/test_sql.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/test/test_sql.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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.
@@ -60,18 +66,18 @@
                 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()
 
@@ -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):
@@ -215,7 +219,7 @@
         version = yield txn.calendarserverValue("ADDRESSBOOK-DATAVERSION")[0][0]
         ch = schema.ADDRESSBOOK_HOME
         homeVersion = yield Select(
-            [ch.DATAVERSION,],
+            [ch.DATAVERSION, ],
             From=ch,
             Where=ch.OWNER_UID == "home_version",
         ).on(txn)[0][0]
@@ -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;;;
@@ -289,28 +293,261 @@
         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 adbk.removeAddressBookObjectWithName("sg.vcf")
+        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
+
+        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)
@@ -321,12 +558,12 @@
         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

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/iaddressbookstore.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/iaddressbookstore.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/iaddressbookstore.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -59,8 +59,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, \
@@ -200,7 +199,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}.
@@ -541,7 +540,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.
         """
@@ -1359,15 +1358,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)
 
 
@@ -1379,11 +1378,7 @@
     _homeMetaDataTable = None
     _childClass = None
     _childTable = None
-    _bindTable = None
-    _objectBindTable = None
     _notifierPrefix = None
-    _revisionsTable = None
-    _notificationRevisionsTable = NOTIFICATION_OBJECT_REVISIONS_TABLE
 
     _dataVersionKey = None
     _dataVersionValue = None
@@ -1404,14 +1399,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):
         """
@@ -1632,48 +1620,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
@@ -1692,8 +1682,10 @@
         if child is None:
             raise NoSuchHomeChildError()
 
+        resourceID = child._resourceID
         yield child.remove()
         self._children.pop(name, None)
+        self._children.pop(resourceID, None)
 
 
     @classproperty
@@ -1746,35 +1738,52 @@
     def _changesQuery(cls): #@NoSelf
         bind = cls._bindSchema
         rev = cls._revisionsSchema
-        return Select([bind.RESOURCE_NAME, rev.COLLECTION_NAME,
-                       rev.RESOURCE_NAME, rev.DELETED],
-                      From=rev.join(
-                          bind,
-                          (bind.HOME_RESOURCE_ID ==
-                           Parameter("resourceID")).And(
-                               rev.RESOURCE_ID ==
-                               bind.RESOURCE_ID),
-                          'left outer'),
-                      Where=(rev.REVISION > Parameter("token")).And(
-                          rev.HOME_RESOURCE_ID ==
-                          Parameter("resourceID")))
+        return Select(
+            [bind.RESOURCE_NAME,
+             rev.COLLECTION_NAME,
+             rev.RESOURCE_NAME,
+             rev.DELETED],
+            From=rev.join(
+                bind,
+                (
+                    bind.HOME_RESOURCE_ID == Parameter("resourceID")).And(
+                    rev.RESOURCE_ID == bind.RESOURCE_ID
+                ), 'left outer'
+            ),
+            Where=(rev.REVISION > Parameter("token")).And(
+                rev.HOME_RESOURCE_ID ==
+                Parameter("resourceID")
+            )
+        )
 
 
     @inlineCallbacks
-    def resourceNamesSinceToken(self, token, depth):
-
+    def changesSinceToken(self, token):
+        """
+        return list of (path, name, wasdeleted) of changes since token
+        Subclasses may override
+        """
         results = [
             (
                 path if path else (collection if collection else ""),
                 name if name else "",
                 wasdeleted
             )
-            for path, collection, name, wasdeleted in
-            (yield self._changesQuery.on(self._txn,
-                                         resourceID=self._resourceID,
-                                         token=token))
+            for path, collection, name, wasdeleted in (
+                yield self._changesQuery.on(
+                    self._txn,
+                    resourceID=self._resourceID,
+                    token=token
+                )
+            )
         ]
+        returnValue(results)
 
+
+    @inlineCallbacks
+    def resourceNamesSinceToken(self, token, depth): #@UnusedVariable
+
+        results = yield self.changesSinceToken(token)
         deleted = []
         deleted_collections = set()
         changed_collections = set()
@@ -1793,30 +1802,24 @@
                     changed_collections.add(path)
 
         # Now deal with shared collections
-        bind = self._bindSchema
         rev = self._revisionsSchema
-        shares = yield self.children()
-        for share in shares:
+        for share in (yield self.children()):
             if not share.owned():
                 sharetoken = 0 if share.name() in changed_collections else token
-                shareID = (yield Select(
-                    [bind.RESOURCE_ID], From=bind,
-                    Where=(bind.RESOURCE_NAME == share.name()).And(
-                        bind.HOME_RESOURCE_ID == self._resourceID).And(
-                            bind.BIND_MODE != _BIND_MODE_OWN)
-                ).on(self._txn))[0][0]
                 results = [
                     (
                         share.name(),
                         name if name else "",
                         wasdeleted
                     )
-                    for name, wasdeleted in
-                    (yield Select([rev.RESOURCE_NAME, rev.DELETED],
-                                     From=rev,
-                                    Where=(rev.REVISION > sharetoken).And(
-                                    rev.RESOURCE_ID == shareID)).on(self._txn))
-                    if name
+                    for name, wasdeleted in (
+                        yield Select(
+                            [rev.RESOURCE_NAME, rev.DELETED],
+                            From=rev,
+                            Where=(rev.REVISION > sharetoken).And(
+                                    rev.RESOURCE_ID == share._resourceID)
+                        ).on(self._txn)
+                    ) if name
                 ]
 
                 for path, name, wasdeleted in results:
@@ -2126,7 +2129,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
@@ -2429,194 +2443,123 @@
 
 
 
-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, 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._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:
-            childID = "%s/%s" % (self._ownerHome.uid(), self._ownerName)
-            self._notifiers = [notifier.clone(label="collection", id=childID)
-                         for notifier in self._ownerHome._notifiers]
-        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
+        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"),
+        })
 
 
-    @classproperty
-    def _childNamesForHomeID(cls): #@NoSelf
+    @classmethod
+    def _updateBindColumnsQuery(cls, columnMap):
         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 Update(columnMap,
+                      Where=(bind.RESOURCE_ID == Parameter("resourceID"))
+                      .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
+                      Return=bind.RESOURCE_NAME)
 
 
-    @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.
-        """
+    @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")})
 
-        # Common behavior is to have created and modified
 
-        return (
-            cls._homeChildMetaDataSchema.CREATED,
-            cls._homeChildMetaDataSchema.MODIFIED,
+    @classproperty
+    def _deleteBindWithResourceIDAndHomeID(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 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.
-        """
+    def _bindColumns(cls):
+        bind = cls._bindSchema
+        return (bind.BIND_MODE,
+                bind.HOME_RESOURCE_ID,
+                bind.RESOURCE_ID,
+                bind.RESOURCE_NAME,
+                bind.BIND_STATUS,
+                bind.MESSAGE,)
 
-        # Common behavior is to have created and modified
 
-        return (
-            "_created",
-            "_modified",
+    @classmethod
+    def _bindFor(cls, condition):
+        bind = cls._bindSchema
+        return Select(
+                  cls._bindColumns(),
+                  From=bind,
+                  Where=condition
         )
 
 
-    @classmethod
-    @inlineCallbacks
-    def listObjects(cls, home):
-        """
-        Retrieve the names of the children that exist in the given home.
+    @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: 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 = [bind.BIND_MODE,
-                   bind.HOME_RESOURCE_ID,
-                   bind.RESOURCE_ID,
-                   bind.RESOURCE_NAME,
-                   bind.BIND_STATUS,
-                   bind.MESSAGE]
-        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
@@ -2631,9 +2574,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
@@ -2652,25 +2594,26 @@
             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
+            )
 
         # Must send notification to ensure cache invalidation occurs
         yield self.notifyChanged()
 
-        returnValue(sharedName)
+        returnValue(bindName)
 
 
     @inlineCallbacks
@@ -2686,7 +2629,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}
@@ -2721,17 +2664,21 @@
                         )
 
             #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()
+                    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
@@ -2758,42 +2705,109 @@
         @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()
                 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._deleteBindWithResourceIDAndHomeID.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()
+        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 bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in acceptedRows: #@UnusedVariable
+            home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+            new = yield home.objectWithShareUID(bindName)
+
+            yield new.initFromStore()
+            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 bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in rows: #@UnusedVariable
+            home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+            new = yield home.invitedObjectWithShareUID(bindName)
+            result.append(new)
+
+        returnValue(result)
+
+
     def shareMode(self):
         """
         @see: L{ICalendar.shareMode}
@@ -2829,130 +2843,151 @@
         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
 
+        return (
+            cls._homeChildMetaDataSchema.CREATED,
+            cls._homeChildMetaDataSchema.MODIFIED,
+        )
+
+
     @classmethod
-    def _bindFor(cls, condition): #@NoSelf
-        bind = cls._bindSchema
-        return Select(
-            [bind.BIND_MODE,
-             bind.HOME_RESOURCE_ID,
-             bind.RESOURCE_ID,
-             bind.RESOURCE_NAME,
-             bind.BIND_STATUS,
-             bind.MESSAGE],
-                  From=bind,
-                  Where=condition
+    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 _sharedBindForResourceID(cls): #@NoSelf
+    def _childrenAndMetadataForHomeID(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)
-                            )
+        child = cls._homeChildSchema
+        childMetaData = cls._homeChildMetaDataSchema
+        columns = cls._bindColumns() + 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))
 
 
-    @inlineCallbacks
-    def asShared(self):
-        """
-        Retrieve all the versions of this L{CommonHomeChild} as it is shared to
-        everyone.
+    @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
+        )
 
-        @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, homeID=self._home._resourceID
-        )
+class CommonHomeChild(LoggingMixIn, FancyEqMixin, Memoizable, _SharedSyncLogic, HomeChildBase, SharingMixIn):
+    """
+    Common ancestor class of AddressBooks and Calendars.
+    """
 
-        cls = self.__class__ # for ease of grepping...
-        result = []
-        for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in acceptedRows: #@UnusedVariable
-            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,
-                message=bindMessage, ownerHome=self._home
-            )
-            yield new.initFromStore()
-            result.append(new)
-        returnValue(result)
+    compareAttributes = (
+        "_name",
+        "_home",
+        "_resourceID",
+    )
 
+    _objectResourceClass = None
 
-    @classproperty
-    def _invitedBindForResourceID(cls): #@NoSelf
-        bind = cls._bindSchema
-        return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
-                            .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
-                            )
+    _bindSchema = None
+    _homeSchema = None
+    _homeChildSchema = None
+    _homeChildMetaDataSchema = None
+    _revisionsSchema = None
+    _objectSchema = None
 
 
-    @inlineCallbacks
-    def asInvited(self):
+    def __init__(self, home, name, resourceID, mode, status, message=None, ownerHome=None, ownerName=None):
+
+        self._home = home
+        self._name = name
+        self._resourceID = resourceID
+        self._bindMode = mode
+        self._bindStatus = status
+        self._bindMessage = message
+        if status != _BIND_STATUS_ACCEPTED:
+            assert ownerHome
+            assert ownerName
+        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:
+            childID = "%s/%s" % (self._ownerHome.uid(), self._ownerName)
+            self._notifiers = [notifier.clone(label="collection", id=childID)
+                         for notifier in self._ownerHome._notifiers]
+        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 bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in rows: #@UnusedVariable
-            # 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,
-                message=bindMessage, ownerHome=self._home
-            )
-            yield new.initFromStore()
-            result.append(new)
-        returnValue(result)
 
-
     @classmethod
     @inlineCallbacks
     def loadAllObjects(cls, home):
@@ -2969,44 +3004,32 @@
         dataRows = (yield cls._childrenAndMetadataForHomeID.on(home._txn, homeID=home._resourceID))
 
         if dataRows:
-
-            # Get property stores for all these child resources (if any found)
-            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 property stores for all these child resources
+            childResourceIDs = [dataRow[2] for dataRow in dataRows]
+            propertyStores = yield PropertyStore.forMultipleResourcesWithResourceIDs(
+                home.uid(), home._txn, childResourceIDs
+            )
+            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, bindMessage = items[:6] #@UnusedVariable
+            bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = items[:6] #@UnusedVariable
             metadata = items[6:]
 
             if bindStatus == _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,
-                message=bindMessage,
-                ownerHome=ownerHome, ownerName=ownerName
+                message=bindMessage, ownerHome=ownerHome,
+                ownerName=ownerName,
             )
             for attr, value in zip(cls.metadataAttributes(), metadata):
                 setattr(child, attr, value)
@@ -3022,65 +3045,9 @@
         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)
-
-        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
-
-        #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,
-            message=bindMessage,
-            ownerHome=ownerHome, ownerName=ownerName,
-        )
-        yield child.initFromStore()
-        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
@@ -3103,20 +3070,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:
-                bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@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].append(ownerHomeID)
-                rows[0].append(ownerName)
-
             if rows and queryCacher:
                 # Cache the result
                 queryCacher.setAfterCommit(home._txn, cacheKey, rows)
@@ -3124,39 +3079,30 @@
         if not rows:
             returnValue(None)
 
-        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage, ownerHomeID, ownerName = rows[0] #@UnusedVariable
+        bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+        if (bindStatus == _BIND_STATUS_ACCEPTED) != bool(accepted):
+            returnValue(None)
 
         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,
-            message=bindMessage,
-            ownerHome=ownerHome, ownerName=ownerName,
+            message=bindMessage, ownerHome=ownerHome,
+            ownerName=ownerName
         )
         yield child.initFromStore()
         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}.
@@ -3171,23 +3117,14 @@
         if not rows:
             returnValue(None)
 
-        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+        bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = rows[0] #@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,
-            message=bindMessage,
-            ownerHome=ownerHome, ownerName=ownerName,
-        )
-        yield child.initFromStore()
-        returnValue(child)
+            returnValue((yield home.invitedObjectWithShareUID(bindName)))
 
 
     @classproperty
@@ -3210,32 +3147,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)
@@ -3248,7 +3166,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,
@@ -3401,7 +3318,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
@@ -3448,23 +3365,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
@@ -3681,29 +3581,14 @@
         yield child.remove()
         self._objects.pop(name, None)
         self._objects.pop(uid, None)
+        if self._objectNames and name in self._objectNames:
+            self._objectNames.remove(name)
         yield self._deleteRevision(name)
         yield self.notifyChanged()
 
 
-    @classproperty
-    def _moveParentUpdateQuery(cls, adjustName=False): #@NoSelf
+    def _movedObjectResource(self, child, newparent): #@UnusedVariable
         """
-        DAL query to update a child to be in a new parent.
-        """
-        obj = cls._objectSchema
-        cols = {
-            obj.PARENT_RESOURCE_ID: Parameter("newParentID")
-        }
-        if adjustName:
-            cols[obj.RESOURCE_NAME] = Parameter("newName")
-        return Update(
-            cols,
-            Where=obj.RESOURCE_ID == Parameter("resourceID")
-        )
-
-
-    def _movedObjectResource(self, child, newparent):
-        """
         Method that subclasses can override to do an extra DB adjustments when a resource
         is moved.
         """
@@ -3927,13 +3812,11 @@
         "_parentCollection",
     )
 
-    _objectTable = None
-
     _objectSchema = None
 
     BATCH_LOAD_SIZE = 50
 
-    def __init__(self, parent, name, uid, resourceID=None, metadata=None):
+    def __init__(self, parent, name, uid, resourceID=None, metadata=None): #@UnusedVariable
         self._parentCollection = parent
         self._resourceID = resourceID
         self._name = name
@@ -3948,12 +3831,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):
@@ -3967,8 +3856,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)
@@ -3996,14 +3884,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):
         """
@@ -4020,7 +3900,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
@@ -4037,8 +3931,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
@@ -4097,7 +3990,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.
@@ -4110,19 +4003,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
@@ -4137,15 +4029,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:
@@ -4217,6 +4109,7 @@
         @param props: the L{PropertyStore} from C{properties()}.
         """
 
+
     def __repr__(self):
         return "<%s: %s>" % (self.__class__.__name__, self._resourceID)
 
@@ -4226,12 +4119,17 @@
         return self._parentCollection._txn
 
 
+    @property
+    def _home(self):
+        return self._parentCollection._home
+
+
     def transaction(self):
         return self._parentCollection._txn
 
 
     @classmethod
-    def _selectForUpdateQuery(cls, nowait): #@NoSelf
+    def _selectForUpdateQuery(cls, nowait):
         """
         DAL statement to lock a L{CommonObjectResource} by its resource ID.
         """
@@ -4301,7 +4199,7 @@
     def remove(self):
         yield self._deleteQuery.on(self._txn, NoSuchObjectResourceError,
                                    resourceID=self._resourceID)
-        self.properties()._removeResource()
+        yield self.properties()._removeResource()
 
         # Set to non-existent state
         self._resourceID = None
@@ -4380,7 +4278,6 @@
         "_resourceID",
     )
 
-    _revisionsTable = NOTIFICATION_OBJECT_REVISIONS_TABLE
     _revisionsSchema = schema.NOTIFICATION_OBJECT_REVISIONS
     _homeSchema = schema.NOTIFICATION_HOME
 
@@ -4418,6 +4315,7 @@
         Return=_homeSchema.RESOURCE_ID
     )
 
+
     @property
     def _home(self):
         """
@@ -4830,7 +4728,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
@@ -4998,7 +4896,6 @@
     )
 
 
-
 @inlineCallbacks
 def mergeHomes(sqlTxn, one, other, homeType):
     """
@@ -5057,7 +4954,6 @@
     yield returnValue(newer)
 
 
-
 def _renameHome(txn, table, oldUID, newUID):
     """
     Rename a calendar, addressbook, or notification home.  Note that this
@@ -5084,7 +4980,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
@@ -5092,7 +4987,6 @@
     """
 
 
-
 @inlineCallbacks
 def _normalizeHomeUUIDsIn(t, homeType):
     """
@@ -5175,7 +5069,6 @@
     returnValue(None)
 
 
-
 def _getHome(txn, homeType, uid):
     """
     Like L{CommonHome.homeWithUID} but also honoring ENOTIFICATIONTYPE which
@@ -5199,7 +5092,6 @@
         return txn.homeWithUID(homeType, uid)
 
 
-
 @inlineCallbacks
 def _normalizeColumnUUIDs(txn, column):
     """
@@ -5247,7 +5139,6 @@
         return self
 
 
-
 @inlineCallbacks
 def _needsNormalizationUpgrade(txn):
     """
@@ -5271,7 +5162,6 @@
     returnValue(False)
 
 
-
 @inlineCallbacks
 def fixUUIDNormalization(store):
     """

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_legacy.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_legacy.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_legacy.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/current.sql	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_schema/current.sql	2013-04-23 01:04:00 UTC (rev 11089)
@@ -16,12 +16,14 @@
 -- limitations under the License.
 ----
 
+
 -----------------
 -- Resource ID --
 -----------------
 
 create sequence RESOURCE_ID_SEQ;
 
+
 -------------------------
 -- Cluster Bookkeeping --
 -------------------------
@@ -55,6 +57,7 @@
   DATAVERSION      integer      default 0 not null
 );
 
+
 ----------------------------
 -- Calendar Home Metadata --
 ----------------------------
@@ -66,6 +69,7 @@
   MODIFIED         timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
 );
 
+
 --------------
 -- Calendar --
 --------------
@@ -112,6 +116,7 @@
 create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
   NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
 
+
 -------------------
 -- Calendar Bind --
 -------------------
@@ -228,6 +233,7 @@
 insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
 insert into CALENDAR_ACCESS_TYPE values (4, 'restricted'   );
 
+
 -----------------
 -- Instance ID --
 -----------------
@@ -336,10 +342,12 @@
 
 create table ADDRESSBOOK_HOME (
   RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  HOME_RESOURCE_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 --
 -------------------------------
@@ -351,35 +359,16 @@
   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
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_HOME
 
-create table ADDRESSBOOK_BIND (
+create table ADDRESSBOOK_HOME_BIND (
   ADDRESSBOOK_HOME_RESOURCE_ID integer      not null references ADDRESSBOOK_HOME,
-  ADDRESSBOOK_RESOURCE_ID      integer      not null references ADDRESSBOOK on delete cascade,
+  ADDRESSBOOK_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
@@ -389,15 +378,21 @@
   unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
 );
 
-create index ADDRESSBOOK_BIND_RESOURCE_ID on
-  ADDRESSBOOK_BIND(ADDRESSBOOK_RESOURCE_ID);
+create index ADDRESSBOOK_HOME_BIND_RESOURCE_ID on
+  ADDRESSBOOK_HOME_BIND(ADDRESSBOOK_RESOURCE_ID);
 
+
+------------------------
+-- AddressBook Object --
+------------------------
+
 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,
+  ADDRESSBOOK_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 OBJECT_KIND
   MD5                     char(32)     not null,
   CREATED                 timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
   MODIFIED                timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
@@ -406,17 +401,74 @@
   unique (ADDRESSBOOK_RESOURCE_ID, VCARD_UID)      -- implicit index
 );
 
----------------
--- Revisions --
----------------
 
-create sequence REVISION_SEQ;
+-----------------------------
+-- 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
+);
+
+
+-----------------------------
+-- Group Address Book Bind --
+-----------------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (acting as Address Book)
+
+create table GROUP_ADDRESSBOOK_HOME_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 GROUP_ADDRESSBOOK_HOME_BIND_RESOURCE_ID on
+  GROUP_ADDRESSBOOK_HOME_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,
@@ -435,13 +487,14 @@
 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_RESOURCE_ID      integer      references ADDRESSBOOK_HOME,
   ADDRESSBOOK_NAME             varchar(255) default null,
   RESOURCE_NAME                varchar(255),
   REVISION                     integer      default nextval('REVISION_SEQ') not null,
@@ -457,6 +510,7 @@
 create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_REVISION
   on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, REVISION);
 
+
 -----------------------------------
 -- Notification Object Revisions --
 -----------------------------------
@@ -473,6 +527,7 @@
 create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
   on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
 
+
 -------------------------------------------
 -- Apple Push Notification Subscriptions --
 -------------------------------------------
@@ -491,6 +546,7 @@
 create index APN_SUBSCRIPTIONS_RESOURCE_KEY
    on APN_SUBSCRIPTIONS(RESOURCE_KEY);
 
+   
 -----------------
 -- IMIP Tokens --
 -----------------
@@ -508,12 +564,14 @@
 create index IMIP_TOKENS_TOKEN
    on IMIP_TOKENS(TOKEN);
 
+   
 ----------------
 -- Work Items --
 ----------------
 
 create sequence WORKITEM_SEQ;
 
+
 ---------------------------
 -- IMIP Inivitation Work --
 ---------------------------
@@ -526,6 +584,7 @@
   ICALENDAR_TEXT                text         not null
 );
 
+
 -----------------------
 -- IMIP Polling Work --
 -----------------------
@@ -535,6 +594,7 @@
   NOT_BEFORE                    timestamp    default timezone('UTC', CURRENT_TIMESTAMP)
 );
 
+
 ---------------------
 -- IMIP Reply Work --
 ---------------------
@@ -547,6 +607,7 @@
   ICALENDAR_TEXT                text         not null
 );
 
+
 ------------------------
 -- Push Notifications --
 ------------------------

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_tables.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_tables.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql_tables.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -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.ADDRESSBOOK_HOME_BIND.RESOURCE_NAME = \
+    schema.ADDRESSBOOK_HOME_BIND.ADDRESSBOOK_RESOURCE_NAME
+schema.ADDRESSBOOK_HOME_BIND.RESOURCE_ID = \
+    schema.ADDRESSBOOK_HOME_BIND.ADDRESSBOOK_RESOURCE_ID
+schema.ADDRESSBOOK_HOME_BIND.HOME_RESOURCE_ID = \
+    schema.ADDRESSBOOK_HOME_BIND.ADDRESSBOOK_HOME_RESOURCE_ID
+schema.GROUP_ADDRESSBOOK_HOME_BIND.RESOURCE_NAME = \
+    schema.GROUP_ADDRESSBOOK_HOME_BIND.GROUP_ADDRESSBOOK_RESOURCE_NAME
+schema.GROUP_ADDRESSBOOK_HOME_BIND.RESOURCE_ID = \
+    schema.GROUP_ADDRESSBOOK_HOME_BIND.GROUP_RESOURCE_ID
+schema.GROUP_ADDRESSBOOK_HOME_BIND.HOME_RESOURCE_ID = \
+    schema.GROUP_ADDRESSBOOK_HOME_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 = \
@@ -175,40 +181,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.

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/test/test_sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/test/test_sql.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/test/test_sql.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -26,10 +26,9 @@
 from twisted.trial.unittest import TestCase
 from twisted.internet.defer import Deferred
 
-from txdav.common.datastore.sql import log, CommonStoreTransactionMonitor,\
+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
@@ -61,7 +60,7 @@
         """
         txn.execSQL works with all logging options on.
         """
-        
+
         # Patch config to turn on logging then rebuild the store
         self.patch(self._sqlStore, "logLabels", True)
         self.patch(self._sqlStore, "logStats", True)
@@ -70,7 +69,7 @@
         txn = self.transactionUnderTest()
         cs = schema.CALENDARSERVER
         version = (yield Select(
-                [cs.VALUE,],
+                [cs.VALUE, ],
                 From=cs,
                 Where=cs.NAME == 'VERSION',
             ).on(txn))
@@ -82,20 +81,20 @@
         """
         CommonStoreTransactionMonitor logs waiting transactions.
         """
-        
+
         c = Clock()
         self.patch(CommonStoreTransactionMonitor, "callLater", c.callLater)
 
         # Patch config to turn on log waits then rebuild the store
         self.patch(self._sqlStore, "logTransactionWaits", 1)
-        
+
         ctr = [0]
         def counter(_ignore):
             ctr[0] += 1
         self.patch(log, "error", counter)
 
-        txn = self.transactionUnderTest()        
- 
+        txn = self.transactionUnderTest()
+
         c.advance(2)
         self.assertNotEqual(ctr[0], 0)
         txn.abort()
@@ -105,13 +104,13 @@
         """
         CommonStoreTransactionMonitor terminates long transactions.
         """
-        
+
         c = Clock()
         self.patch(CommonStoreTransactionMonitor, "callLater", c.callLater)
 
         # Patch config to turn on transaction timeouts then rebuild the store
         self.patch(self._sqlStore, "timeoutTransactions", 1)
-        
+
         ctr = [0]
         def counter(_ignore):
             ctr[0] += 1
@@ -128,14 +127,14 @@
         """
         CommonStoreTransactionMonitor logs waiting transactions and terminates long transactions.
         """
-        
+
         c = Clock()
         self.patch(CommonStoreTransactionMonitor, "callLater", c.callLater)
 
         # Patch config to turn on log waits then rebuild the store
         self.patch(self._sqlStore, "logTransactionWaits", 1)
         self.patch(self._sqlStore, "timeoutTransactions", 2)
-        
+
         ctr = [0, 0]
         def counter(logStr):
             if "wait" in logStr:
@@ -145,7 +144,7 @@
         self.patch(log, "error", counter)
 
         txn = self.transactionUnderTest()
-        
+
         c.advance(2)
         self.assertNotEqual(ctr[0], 0)
         self.assertNotEqual(ctr[1], 0)
@@ -156,7 +155,7 @@
         """
         txn.subtransaction runs loop once.
         """
-        
+
         txn = self.transactionUnderTest()
         ctr = [0]
 
@@ -164,11 +163,11 @@
             ctr[0] += 1
             cs = schema.CALENDARSERVER
             return Select(
-                [cs.VALUE,],
+                [cs.VALUE, ],
                 From=cs,
                 Where=cs.NAME == 'VERSION',
             ).on(subtxn)
-            
+
         (yield txn.subtransaction(_test, retries=0))[0][0]
         self.assertEqual(ctr[0], 1)
 
@@ -178,7 +177,7 @@
         """
         txn.subtransaction runs loop twice when one failure.
         """
-        
+
         txn = self.transactionUnderTest()
         ctr = [0]
 
@@ -188,11 +187,11 @@
                 raise ValueError
             cs = schema.CALENDARSERVER
             return Select(
-                [cs.VALUE,],
+                [cs.VALUE, ],
                 From=cs,
                 Where=cs.NAME == 'VERSION',
             ).on(subtxn)
-            
+
         (yield txn.subtransaction(_test, retries=1))[0][0]
         self.assertEqual(ctr[0], 2)
 
@@ -202,7 +201,7 @@
         """
         txn.subtransaction runs loop once when one failure and no retries.
         """
-        
+
         txn = self.transactionUnderTest()
         ctr = [0]
 
@@ -211,11 +210,11 @@
             raise ValueError
             cs = schema.CALENDARSERVER
             return Select(
-                [cs.VALUE,],
+                [cs.VALUE, ],
                 From=cs,
                 Where=cs.NAME == 'VERSION',
             ).on(subtxn)
-        
+
         try:
             (yield txn.subtransaction(_test, retries=0))[0][0]
         except AllRetriesFailed:
@@ -231,7 +230,7 @@
         txn.subtransaction runs loop three times when all fail and two retries
         requested.
         """
-        
+
         txn = self.transactionUnderTest()
         ctr = [0]
 
@@ -240,11 +239,11 @@
             raise ValueError
             cs = schema.CALENDARSERVER
             return Select(
-                [cs.VALUE,],
+                [cs.VALUE, ],
                 From=cs,
                 Where=cs.NAME == 'VERSION',
             ).on(subtxn)
-        
+
         try:
             (yield txn.subtransaction(_test, retries=2))[0][0]
         except AllRetriesFailed:
@@ -286,26 +285,23 @@
         """
         CommonHomeChild._changeRevision actions.
         """
-        
+
         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
-    
+
         txn = self.transactionUnderTest()
         home = yield txn.homeWithUID(ECALENDARTYPE, "uid", create=True)
         homeChild = yield TestCommonHomeChild.create(home, "B")
-        
+
         # insert test
         token = yield homeChild.syncToken()
         yield homeChild._changeRevision("insert", "C")

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/upgrade/test/test_migrate.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/upgrade/test/test_migrate.py	2013-04-22 22:18:11 UTC (rev 11088)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/upgrade/test/test_migrate.py	2013-04-23 01:04:00 UTC (rev 11089)
@@ -399,7 +399,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/20130422/b698f5a7/attachment-0001.html>


More information about the calendarserver-changes mailing list