text: #!/usr/bin/python
  # -*- coding:utf-8 -*-
  
  import xml.etree.ElementTree as ET
  from obs.model import *
  from obs import util
  from obs import const
  
  class Adapter(object):
      
      OBS_ALLOWED_ACL_CONTROL = ['private', 'public-read', 'public-read-write', 'public-read-delivered', 'public-read-write-delivered']
      V2_ALLOWED_ACL_CONTROL = ['private', 'public-read', 'public-read-write', 'authenticated-read', 'bucket-owner-read', 'bucket-owner-full-control', 'log-delivery-write']
      
      OBS_ALLOWED_STORAGE_CLASS = ['STANDARD', 'WARM', 'COLD']
      V2_ALLOWED_STORAGE_CLASS = ['STANDARD', 'STANDARD_IA', 'GLACIER']
      
      OBS_ALLOWED_GROUP = ['Everyone']
      V2_ALLOWED_GROUP = ['http://acs.amazonaws.com/groups/global/AllUsers', 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers', 'http://acs.amazonaws.com/groups/s3/LogDelivery']
      
      OBS_ALLOWED_RESTORE_TIER = ['Expedited', 'Standard']
      V2_ALLOWED_RESTORE_TIER = ['Expedited', 'Standard', 'Bulk']
      
      OBS_ALLOWED_EVENT_TYPE = ['ObjectCreated:*', 'ObjectCreated:Put', 'ObjectCreated:Post', 'ObjectCreated:Copy', 
                                'ObjectCreated:CompleteMultipartUpload', 'ObjectRemoved:*', 'ObjectRemoved:Delete', 'ObjectRemoved:DeleteMarkerCreated']
      V2_ALLOWED_EVENT_TYPE = ['s3:ObjectCreated:*', 's3:ObjectCreated:Put', 's3:ObjectCreated:Post', 's3:ObjectCreated:Copy', 
                                's3:ObjectCreated:CompleteMultipartUpload', 's3:ObjectRemoved:*', 's3:ObjectRemoved:Delete', 's3:ObjectRemoved:DeleteMarkerCreated']
      
      def __init__(self, signature):
          self.is_obs = signature.lower() == 'obs'
      
      def _get_header_prefix(self):
          return const.OBS_HEADER_PREFIX if self.is_obs else const.V2_HEADER_PREFIX
      
      def _get_meta_header_prefix(self):
          return const.OBS_META_HEADER_PREFIX if self.is_obs else const.V2_META_HEADER_PREFIX
      
      def auth_prefix(self):
          return 'OBS' if self.is_obs else 'AWS'
      
      def acl_header(self):
          return self._get_header_prefix() + 'acl'
      
      def date_header(self):
          return self._get_header_prefix() + 'date'
      
      def security_token_header(self):
          return self._get_header_prefix() + 'security-token'
      
      def content_sha256_header(self):
          return self._get_header_prefix() + 'content-sha256'
      
      def default_storage_class_header(self):
          return self._get_header_prefix() + 'storage-class' if self.is_obs else 'x-default-storage-class'
      
      def storage_class_header(self):
          return self._get_header_prefix() + 'storage-class'
      
      def request_id_header(self):
          return self._get_header_prefix() + 'request-id'
      
      def location_header(self):
          return self._get_header_prefix() + 'location'
      
      def bucket_region_header(self):
          return self._get_header_prefix() + 'bucket-location' if self.is_obs else self._get_header_prefix() + 'bucket-region'
      
      def server_version_header(self):
          return 'x-obs-version'
      
      def version_id_header(self):
          return self._get_header_prefix() + 'version-id'
      
      def copy_source_version_id(self):
          return self._get_header_prefix() + 'copy-source-version-id'
      
      def delete_marker_header(self):
          return self._get_header_prefix() + 'delete-marker'
      
      def sse_kms_header(self):
          return self._get_header_prefix() + 'server-side-encryption'
      
      def sse_kms_key_header(self):
          return self._get_header_prefix() +  'server-side-encryption-kms-key-id' if self.is_obs else self._get_header_prefix() + 'server-side-encryption-aws-kms-key-id'
      
      def copy_source_sse_c_header(self):
          return self._get_header_prefix() + 'copy-source-server-side-encryption-customer-algorithm'
      
      def copy_source_sse_c_key_header(self):
          return self._get_header_prefix() + 'copy-source-server-side-encryption-customer-key'
      
      def copy_source_sse_c_key_md5_header(self):
          return self._get_header_prefix() + 'copy-source-server-side-encryption-customer-key-MD5'
      
      def sse_c_header(self):
          return self._get_header_prefix() + 'server-side-encryption-customer-algorithm'
      
      def sse_c_key_header(self):
          return self._get_header_prefix() + 'server-side-encryption-customer-key'
      
      def sse_c_key_md5_header(self):
          return self._get_header_prefix() + 'server-side-encryption-customer-key-MD5'
      
      def website_redirect_location_header(self):
          return self._get_header_prefix() + 'website-redirect-location'
      
      def success_action_redirect_header(self):
          return 'success-action-redirect'
      
      def restore_header(self):
          return self._get_header_prefix() + 'restore'
      
      def expires_header(self):
          return 'x-obs-expires'
      
      def expiration_header(self):
          return self._get_header_prefix() + 'expiration'
      
      def copy_source_header(self):
          return self._get_header_prefix() + 'copy-source'
      
      def copy_source_range_header(self):
          return self._get_header_prefix() + 'copy-source-range'
      
      def metadata_directive_header(self):
          return self._get_header_prefix() + 'metadata-directive'
      
      def copy_source_if_match_header(self):
          return self._get_header_prefix() + 'copy-source-if-match'
      
      def copy_source_if_none_match_header(self):
          return self._get_header_prefix() + 'copy-source-if-none-match'
      
      def copy_source_if_modified_since_header(self):
          return self._get_header_prefix() + 'copy-source-if-modified-since'
      
      def copy_source_if_unmodified_since_header(self):
          return self._get_header_prefix() + 'copy-source-if-unmodified-since'
      
      def next_position_header(self):
          return 'x-obs-next-append-position'
      
      def object_type_header(self):
          return 'x-obs-object-type'
      
      def adapt_group(self, group):
          if self.is_obs:
              return group if group in self.OBS_ALLOWED_GROUP else 'Everyone' if group == 'http://acs.amazonaws.com/groups/global/AllUsers' or group == 'AllUsers' else None
          return group if group in self.V2_ALLOWED_GROUP else 'http://acs.amazonaws.com/groups/global/AllUsers' if group == 'Everyone' else 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers' if \
              group == 'AuthenticatedUsers' else 'http://acs.amazonaws.com/groups/s3/LogDelivery' if group == 'LogDelivery' else None
      
      def adapt_retore_tier(self, tier):
          if self.is_obs:
              return tier if tier in self.OBS_ALLOWED_RESTORE_TIER else None
          
          return tier if tier in self.V2_ALLOWED_RESTORE_TIER else None
      
      def adapt_acl_control(self, aclControl):
          if self.is_obs:
              return aclControl if aclControl in self.OBS_ALLOWED_ACL_CONTROL else None
          
          return aclControl if aclControl in self.V2_ALLOWED_ACL_CONTROL else None
              
      def adapt_event_type(self, eventType):
          if self.is_obs:
              return eventType if eventType in self.OBS_ALLOWED_EVENT_TYPE else eventType[3:] if eventType in self.V2_ALLOWED_EVENT_TYPE else None
          
          return eventType if eventType in self.V2_ALLOWED_EVENT_TYPE else 's3:' + eventType if eventType in self.OBS_ALLOWED_EVENT_TYPE else None
  
      
      def adapt_storage_class(self, storageClass):
          if self.is_obs:
              return storageClass if storageClass in self.OBS_ALLOWED_STORAGE_CLASS else 'WARM' if storageClass == 'STANDARD_IA' else 'COLD' if storageClass == 'GLACIER' else None
          return storageClass if storageClass in self.V2_ALLOWED_STORAGE_CLASS else 'STANDARD_IA' if storageClass == 'WARM' else 'GLACIER' if storageClass == 'COLD' else None
      
      def adapt_extension_permission(self, permission, is_bucket=True):
          header = None
          if permission is not None and permission.startswith(self._get_header_prefix()):
              permission = permission[len(self._get_header_prefix()):]
          if permission == 'READ':
              header = 'grant-read'
          elif permission == 'WRITE':
              if is_bucket:
                  header = 'grant-write'
          elif permission == 'READ_ACP':
              header = 'grant-read-acp'
          elif permission == 'WRITE_ACP':
              header = 'grant-write-acp'
          elif permission == 'FULL_CONTROL':
              header = 'grant-full-control'
          elif permission == 'READ_DELIVERED':
              if is_bucket:
                  header = 'grant-read-delivered'
          elif permission == 'FULL_CONTROL_DELIVERED':
              if is_bucket:
                  header = 'grant-full-control-delivered'
          return self._get_header_prefix() + header if header is not None else None
  
  class Convertor(object):
      def __init__(self, signature, ha=None):
          self.is_obs = signature.lower() == 'obs'
          self.ha = ha
      
      def _put_key_value(self, headers, key, value):
          if value is not None:
              if const.IS_PYTHON2:
                  value = util.safe_encode(value)
              value = util.to_string(value)
              if util.is_valid(value):
                  headers[key] = value
      
      def trans_create_bucket(self, **kwargs):
          headers = {}
          header = kwargs.get('header')
          if header is not None:
              self._put_key_value(headers, self.ha.acl_header(), self.ha.adapt_acl_control(header.get('aclControl')))
              self._put_key_value(headers, self.ha.default_storage_class_header(), self.ha.adapt_storage_class(header.get('storageClass')))
              
              extensionGrants = header.get('extensionGrants')
              if extensionGrants is not None and len(extensionGrants) > 0:
                  grantDict = {}
                  for extensionGrant in extensionGrants:
                      permission = self.ha.adapt_extension_permission(extensionGrant.get('permission'))
                      if permission is not None and extensionGrant.get('granteeId') is not None:
                          granteeIds = grantDict.get(permission)
                          if granteeIds is None:
                              granteeIds = set()
                              grantDict[permission] = granteeIds
                          granteeIds.add('id=%s' % util.to_string(extensionGrant['granteeId']))
                  
                  for key, value in grantDict:
                      self._put_key_value(headers, key, ','.join(value))
          return {'headers' : headers, 'entity' : None if kwargs.get('location') is None else self.trans_bucket_location(kwargs.get('location'))}
  
      def trans_bucket_location(self, location):
          root = ET.Element('CreateBucketConfiguration')
          ET.SubElement(root, 'Location' if self.is_obs else 'LocationConstraint').text = util.to_string(location)
          return ET.tostring(root, 'UTF-8')
      
      def trans_list_buckets(self, **kwargs):
          headers = {}
          if kwargs.get('isQueryLocation'):
              self._put_key_value(headers, self.ha.location_header(), 'true')
          return {'headers' : headers}
      
      def trans_list_objects(self, **kwargs):
          pathArgs = {}
          self._put_key_value(pathArgs, 'prefix', kwargs.get('prefix'))
          self._put_key_value(pathArgs, 'marker', kwargs.get('marker'))
          self._put_key_value(pathArgs, 'delimiter', kwargs.get('delimiter'))
          self._put_key_value(pathArgs, 'max-keys', kwargs.get('max_keys'))
          return {'pathArgs' : pathArgs}
      
      def trans_list_versions(self, **kwargs):
          pathArgs = {'versions' : None}
          version = kwargs.get('version')
          if version is not None:
              self._put_key_value(pathArgs, 'prefix', version.get('prefix'))
              self._put_key_value(pathArgs, 'key-marker', version.get('key_marker'))
              self._put_key_value(pathArgs, 'max-keys', version.get('max_keys'))
              self._put_key_value(pathArgs, 'delimiter', version.get('delimiter'))
              self._put_key_value(pathArgs, 'version-id-marker', version.get('version_id_marker'))
          return {'pathArgs' : pathArgs}
      
      def trans_get_bucket_metadata(self, **kwargs):
          headers = {}
          self._put_key_value(headers, const.ORIGIN_HEADER, kwargs.get('origin'))
          requestHeaders = kwargs.get('requestHeaders')
          _requestHeaders = requestHeaders[0] if isinstance(requestHeaders, list) and len(requestHeaders) == 1 else requestHeaders
          self._put_key_value(headers, const.ACCESS_CONTROL_REQUEST_HEADERS_HEADER, _requestHeaders)
          return {'headers' : headers}
      
      def trans_get_bucket_storage_policy(self):
          return {
              'pathArgs' : {'storageClass' if self.is_obs else 'storagePolicy': None},
          } 
      
      def trans_set_bucket_storage_policy(self, **kwargs):
          return {
              'pathArgs' : {'storageClass' if self.is_obs else 'storagePolicy': None},
              'entity' : self.trans_storage_policy(kwargs.get('storageClass'))
          }
          
      def trans_storage_policy(self, storageClass):
          if self.is_obs:
              root = ET.Element('StorageClass')
              root.text = util.to_string(self.ha.adapt_storage_class(util.to_string(storageClass)))
              return ET.tostring(root, 'UTF-8')
          
          root = ET.Element('StoragePolicy')
          ET.SubElement(root, 'DefaultStorageClass').text = util.to_string(self.ha.adapt_storage_class(util.to_string(storageClass)))
          return ET.tostring(root, 'UTF-8')
      
      def trans_quota(self, quota):
          root = ET.Element('Quota')
          ET.SubElement(root, 'StorageQuota').text = util.to_string(quota)
          return ET.tostring(root, 'UTF-8')
      
      def trans_set_bucket_tagging(self, **kwargs):
          entity = self.trans_tag_info(kwargs.get('tagInfo'))
          return {
              'pathArgs' : {'tagging' : None},
              'headers' : {const.CONTENT_MD5_HEADER: util.base64_encode(util.md5_encode(entity))},
              'entity' : entity
          }
      
      def trans_tag_info(self, tagInfo):
          root = ET.Element('Tagging')
          tagSetEle = ET.SubElement(root, 'TagSet')
          if tagInfo.get('tagSet') is not None and len(tagInfo['tagSet']) > 0:
              for tag in tagInfo['tagSet']:
                  if tag.get('key') is not None and tag.get('value') is not None:
                      tagEle = ET.SubElement(tagSetEle, 'Tag')
                      ET.SubElement(tagEle, 'Key').text = util.safe_decode(tag['key'])
                      ET.SubElement(tagEle, 'Value').text = util.safe_decode(tag['value'])
          return ET.tostring(root, 'UTF-8')
      
      def trans_set_bucket_cors(self, **kwargs):
          entity = self.trans_cors_rules(kwargs.get('corsRuleList'))
          headers = {const.CONTENT_MD5_HEADER: util.base64_encode(util.md5_encode(entity))}
          return {'pathArgs': {'cors' : None}, 'headers': headers, 'entity': entity}
      
      def trans_cors_rules(self, corsRuleList):
          root = ET.Element('CORSConfiguration')
          for cors in corsRuleList:
              corsRuleEle = ET.SubElement(root, 'CORSRule')
              if cors.get('id') is not None:
                  ET.SubElement(corsRuleEle, 'ID').text = util.to_string(cors['id'])
              if cors.get('allowedMethod') is not None:
                  for v in cors['allowedMethod']:
                      ET.SubElement(corsRuleEle, 'AllowedMethod').text = util.to_string(v)
              if cors.get('allowedOrigin') is not None:
                  for v in cors['allowedOrigin']:
                      ET.SubElement(corsRuleEle, 'AllowedOrigin').text = util.to_string(v)
              if cors.get('allowedHeader') is not None:
                  for v in cors['allowedHeader']:
                      ET.SubElement(corsRuleEle, 'AllowedHeader').text = util.to_string(v)
              if cors.get('maxAgeSecond') is not None:
                  ET.SubElement(corsRuleEle, 'MaxAgeSeconds').text = util.to_string(cors['maxAgeSecond'])
              if cors.get('exposeHeader') is not None:
                  for v in cors['exposeHeader']:
                      ET.SubElement(corsRuleEle, 'ExposeHeader').text = util.to_string(v)
          return ET.tostring(root, 'UTF-8')
      
      def trans_delete_objects(self, **kwargs):
          entity = self.trans_delete_objects_request(kwargs.get('deleteObjectsRequest'))
          headers = {const.CONTENT_MD5_HEADER: util.base64_encode(util.md5_encode(entity))}
          return {'pathArgs' : {'delete': None}, 'headers' : headers, 'entity' : entity}
      
      def trans_delete_objects_request(self, deleteObjectsRequest):
          root = ET.Element('Delete')
          if deleteObjectsRequest is not None:
              if deleteObjectsRequest.get('quiet') is not None:
                  ET.SubElement(root, 'Quiet').text = util.to_string(deleteObjectsRequest['quiet']).lower()
              if isinstance(deleteObjectsRequest.get('objects'), list) and len(deleteObjectsRequest['objects']) > 0:
                  for obj in deleteObjectsRequest['objects']:
                      if obj.get('key') is not None:
                          objectEle = ET.SubElement(root, 'Object')
                          ET.SubElement(objectEle, 'Key').text = util.safe_decode(obj['key'])
                          if obj.get('versionId') is not None:
                              ET.SubElement(objectEle, 'VersionId').text = util.safe_decode(obj['versionId'])
          return ET.tostring(root, 'UTF-8')
      
      def trans_version_status(self, status):
          root = ET.Element('VersioningConfiguration')
          ET.SubElement(root, 'Status').text = util.to_string(status)
          return ET.tostring(root, 'UTF-8')
      
      def trans_set_bucket_lifecycle(self, **kwargs):
          entity = self.trans_lifecycle(kwargs.get('lifecycle'))
          headers = {const.CONTENT_MD5_HEADER: util.base64_encode(util.md5_encode(entity))}
          return {'pathArgs' : {'lifecycle':None}, 'headers': headers, 'entity':entity}
      
      def _transTransition(self, ruleEle, transition):
          transitionEle = ET.SubElement(ruleEle, 'Transition')
          if transition.get('days') is not None:
              ET.SubElement(transitionEle, 'Days').text = util.to_string(transition['days'])
          elif transition.get('date') is not None:
              date = transition['date'].ToUTMidTime() if isinstance(transition['date'], DateTime) else transition['date']
              ET.SubElement(transitionEle, 'Date').text = util.to_string(date)
          ET.SubElement(transitionEle, 'StorageClass').text = util.to_string(self.ha.adapt_storage_class(transition.get('storageClass'))) 
  
      def _transNoncurrentVersionTransition(self, ruleEle, noncurrentVersionTransition):
          noncurrentVersionTransitionEle = ET.SubElement(ruleEle, 'NoncurrentVersionTransition')
          if noncurrentVersionTransition.get('noncurrentDays') is not None:
              ET.SubElement(noncurrentVersionTransitionEle, 'NoncurrentDays').text = util.to_string(noncurrentVersionTransition['noncurrentDays'])
          ET.SubElement(noncurrentVersionTransitionEle, 'StorageClass').text = util.to_string(self.ha.adapt_storage_class(noncurrentVersionTransition['storageClass']))
      
      def trans_lifecycle(self, lifecycle):
          root = ET.Element('LifecycleConfiguration')
          rules = lifecycle.get('rule')
          if rules is not None and len(rules) > 0:
              for item in rules:
                  ruleEle = ET.SubElement(root, 'Rule')
                  if item.get('id') is not None:
                      ET.SubElement(ruleEle, 'ID').text = util.safe_decode(item['id'])
                  if item.get('prefix') is not None:
                      ET.SubElement(ruleEle, 'Prefix').text = util.safe_decode(item['prefix'])
                  ET.SubElement(ruleEle, 'Status').text = util.to_string(item.get('status'))
                  
                  if item.get('transition') is not None:
                      _transition = item['transition']
                      if isinstance(_transition, list):
                          for transition in _transition:
                              self._transTransition(ruleEle, transition)
                      else:
                          self._transTransition(ruleEle, _transition)
          
                  if item.get('expiration') is not None and (item['expiration'].get('date') is not None or item['expiration'].get('days') is not None):
                      expirationEle = ET.SubElement(ruleEle, 'Expiration')
                      if item['expiration'].get('days') is not None:
                          ET.SubElement(expirationEle, 'Days').text = util.to_string(item['expiration']['days'])
                      elif item['expiration'].get('date') is not None:
                          date = item['expiration']['date'].ToUTMidTime() if isinstance(item['expiration']['date'], DateTime) else item['expiration']['date']
                          ET.SubElement(expirationEle, 'Date').text = util.to_string(date)
              
                  if item.get('noncurrentVersionTransition') is not None:
                      if isinstance(item['noncurrentVersionTransition'], list):
                          for noncurrentVersionTransition in item['noncurrentVersionTransition']:
                              self._transNoncurrentVersionTransition(ruleEle, noncurrentVersionTransition)
                      else:
                          self._transNoncurrentVersionTransition(ruleEle, item['noncurrentVersionTransition'])
              
                  if item.get('noncurrentVersionExpiration') is not None and item['noncurrentVersionExpiration'].get('noncurrentDays') is not None:
                      noncurrentVersionExpirationEle = ET.SubElement(ruleEle, 'NoncurrentVersionExpiration')
                      ET.SubElement(noncurrentVersionExpirationEle, 'NoncurrentDays').text = util.to_string(item['noncurrentVersionExpiration']['noncurrentDays'])
                  
          return ET.tostring(root, 'UTF-8')    
      
      def trans_website(self, website):
          root = ET.Element('WebsiteConfiguration')
          if website.get('redirectAllRequestTo') is not None:
              redirectAllEle = ET.SubElement(root, 'RedirectAllRequestsTo')
              if website['redirectAllRequestTo'].get('hostName') is not None:
                  ET.SubElement(redirectAllEle, 'HostName').text = util.to_string(website['redirectAllRequestTo']['hostName'])
              if website['redirectAllRequestTo'].get('protocol') is not None:
                  ET.SubElement(redirectAllEle, 'Protocol').text = util.to_string(website['redirectAllRequestTo']['protocol'])
          else:
              if website.get('indexDocument') is not None and website['indexDocument'].get('suffix') is not None:
                  indexDocEle = ET.SubElement(root, 'IndexDocument')
                  ET.SubElement(indexDocEle, 'Suffix').text = util.to_string(website['indexDocument']['suffix'])
              if website.get('errorDocument') is not None and website['errorDocument'].get('key') is not None:
                  errorDocEle = ET.SubElement(root, 'ErrorDocument')
                  ET.SubElement(errorDocEle, 'Key').text = util.to_string(website['errorDocument']['key'])
              if isinstance(website.get('routingRules'), list) and len(website['routingRules']) > 0:
                  routingRulesEle = ET.SubElement(root, 'RoutingRules')
                  for routingRule in website['routingRules']:
                      routingRuleEle = ET.SubElement(routingRulesEle, 'RoutingRule')
                      if routingRule.get('condition') is not None:
                          conditionEle = ET.SubElement(routingRuleEle, 'Condition')
                          if routingRule['condition'].get('keyPrefixEquals') is not None:
                              ET.SubElement(conditionEle, 'KeyPrefixEquals').text = util.to_string(routingRule['condition']['keyPrefixEquals'])
                          if routingRule['condition'].get('httpErrorCodeReturnedEquals') is not None:
                              ET.SubElement(conditionEle, 'HttpErrorCodeReturnedEquals').text = util.to_string(routingRule['condition']['httpErrorCodeReturnedEquals'])
                      
                      if routingRule.get('redirect') is not None:
                          redirectEle = ET.SubElement(routingRuleEle, 'Redirect')
                          redirect = routingRule['redirect']
                          if redirect.get('protocol') is not None:
                              ET.SubElement(redirectEle, 'Protocol').text = util.to_string(redirect['protocol'])
                          
                          if redirect.get('hostName') is not None:
                              ET.SubElement(redirectEle, 'HostName').text = util.to_string(redirect['hostName'])
      
                          if redirect.get('replaceKeyPrefixWith') is not None:
                              ET.SubElement(redirectEle, 'ReplaceKeyPrefixWith').text = util.safe_decode(redirect['replaceKeyPrefixWith'])
      
                          if redirect.get('replaceKeyWith') is not None:
                              ET.SubElement(redirectEle, 'ReplaceKeyWith').text = util.safe_decode(redirect['replaceKeyWith'])                        
                          
                          if redirect.get('httpRedirectCode') is not None:
                              ET.SubElement(redirectEle, 'HttpRedirectCode').text = util.to_string(redirect['httpRedirectCode'])
          return ET.tostring(root, 'UTF-8')
      
      def trans_notification(self, notification):
          root = ET.Element('NotificationConfiguration')
          if notification is not None and len(notification) > 0 and notification.get('topicConfigurations') is not None and len(notification['topicConfigurations']) > 0:
              for topicConfiguration in notification['topicConfigurations']:
                  topicConfigurationEle = ET.SubElement(root, 'TopicConfiguration')
                  if topicConfiguration.get('id') is not None:
                      ET.SubElement(topicConfigurationEle, 'Id').text = util.safe_decode(topicConfiguration['id'])
                      
                  if isinstance(topicConfiguration.get('filterRules'), list) and len(topicConfiguration['filterRules']) > 0:
                      filterEle = ET.SubElement(topicConfigurationEle, 'Filter')
                      filterRulesEle = ET.SubElement(filterEle, 'Object' if self.is_obs else 'S3Key')
                      for filterRule in topicConfiguration['filterRules']:
                          filterRuleEle = ET.SubElement(filterRulesEle, 'FilterRule')
                          if filterRule.get('name') is not None:
                              ET.SubElement(filterRuleEle, 'Name').text = util.to_string(filterRule['name'])
                          if filterRule.get('value') is not None:
                              ET.SubElement(filterRuleEle, 'Value').text = util.safe_decode(filterRule['value'])
                  
                  if topicConfiguration.get('topic') is not None:
                      ET.SubElement(topicConfigurationEle, 'Topic').text = util.to_string(topicConfiguration['topic'])
                  
                  if isinstance(topicConfiguration.get('events'), list) and len(topicConfiguration['events']) > 0:
                      for event in topicConfiguration['events']:
                          ET.SubElement(topicConfigurationEle, 'Event').text = util.to_string(self.ha.adapt_event_type(event))
                      
          return ET.tostring(root, 'UTF-8')
      
      def trans_complete_multipart_upload_request(self, completeMultipartUploadRequest):
          root = ET.Element('CompleteMultipartUpload')
          parts = [] if completeMultipartUploadRequest.get('parts') is None else (sorted(completeMultipartUploadRequest['parts'], key=lambda d: d.partNum))
          for obj in parts:
              partEle = ET.SubElement(root, 'Part')
              ET.SubElement(partEle, 'PartNumber').text = util.to_string(obj.get('partNum'))
              ET.SubElement(partEle, 'ETag').text = util.to_string(obj.get('etag'))
          return ET.tostring(root, 'UTF-8')
      
      def trans_restore_object(self, **kwargs):
          pathArgs = {'restore': None}
          self._put_key_value(pathArgs, const.VERSION_ID_PARAM, kwargs.get('versionId'))
          entity = self.trans_restore(days=kwargs.get('days'), tier=kwargs.get('tier'))
          headers = {const.CONTENT_MD5_HEADER: util.base64_encode(util.md5_encode(entity))}
          return {'pathArgs': pathArgs, 'headers':headers, 'entity':entity}
      
      def trans_set_bucket_acl(self, **kwargs):
          headers = {}
          aclControl = kwargs.get('aclControl')
          if aclControl is not None:
              self._put_key_value(headers, self.ha.acl_header(), self.ha.adapt_acl_control(aclControl))
              entity = None
          else:
              acl = kwargs.get('acl')
              entity = None if acl is None or len(acl) == 0 else self.trans_acl(acl)
          return {'pathArgs' : {'acl': None}, 'headers': headers, 'entity': entity}
      
      def trans_set_object_acl(self, **kwargs):
          pathArgs = {'acl': None}
          versionId = kwargs.get('versionId')
          if versionId:
              pathArgs[const.VERSION_ID_PARAM] = util.to_string(versionId)
          
          headers = {}
          aclControl = kwargs.get('aclControl')
          if aclControl is not None:
              self._put_key_value(headers, self.ha.acl_header(), self.ha.adapt_acl_control(aclControl))
              entity = None
          else:
              acl = kwargs.get('acl')
              entity = None if acl is None or len(acl) == 0 else self.trans_acl(acl, False)     
          return {'pathArgs' : pathArgs, 'headers': headers, 'entity': entity}
      
      def trans_acl(self, acl, is_bucket=True):
          root = ET.Element('AccessControlPolicy')
          if acl.get('owner') is not None:
              ownerEle = ET.SubElement(root, 'Owner')
              owner = acl['owner']
              ET.SubElement(ownerEle, 'ID').text = util.to_string(owner.get('owner_id'))
              if owner.get('owner_name') is not None and not self.is_obs:
                  ET.SubElement(ownerEle, 'DisplayName').text = util.safe_decode(owner['owner_name'])
          
          if not is_bucket and self.is_obs and acl.get('delivered') is not None:
              ET.SubElement(root, 'Delivered').text = util.to_string(acl['delivered']).lower()
          
          grants = acl.get('grants')
          if grants is not None and len(grants) > 0:
              aclEle = ET.SubElement(root, 'AccessControlList')
              self.trans_grantee(aclEle, grants)
          return ET.tostring(root, 'UTF-8')
  
      def trans_grantee(self, aclEle, grants):
          for grant in grants:
              grantEle = ET.SubElement(aclEle, 'Grant')
              if grant.get('grantee') is not None:
                  attrib = {'xmlns:xsi' : 'http://www.w3.org/2001/XMLSchema-instance'}
                  grantee = grant['grantee']
                  if grantee.get('group') is not None:
                      attrib['xsi:type'] = 'Group'
                      group_val = self.ha.adapt_group(util.to_string(grantee['group']))
                      if group_val:
                          granteeEle = ET.SubElement(grantEle, 'Grantee', None if self.is_obs else attrib)
                          ET.SubElement(granteeEle, 'Canned' if self.is_obs else 'URI').text = group_val
                  elif grantee.get('grantee_id') is not None:
                      attrib['xsi:type'] = 'CanonicalUser'
                      granteeEle = ET.SubElement(grantEle, 'Grantee', None if self.is_obs else attrib)
                      ET.SubElement(granteeEle, 'ID').text = util.to_string(grantee['grantee_id'])
                      if grantee.get('grantee_name') is not None and not self.is_obs:
                          ET.SubElement(granteeEle, 'DisplayName').text = util.safe_decode(grantee['grantee_name'])
              if grant.get('permission') is not None:
                  ET.SubElement(grantEle, 'Permission').text = util.to_string(grant['permission'])
              
              if grant.get('delivered') is not None and self.is_obs:
                  ET.SubElement(grantEle, 'Delivered').text = util.to_string(grant['delivered']).lower()
      
      def trans_logging(self, logging):
          root = ET.Element('BucketLoggingStatus')
          if self.is_obs and logging.get('agency') is not None:
              ET.SubElement(root, 'Agency').text = util.to_string(logging['agency'])
          if logging.get('targetBucket') is not None or logging.get('targetPrefix') is not None or (logging.get('targetGrants') is not None and len(logging['targetGrants']) > 0):
              loggingEnableEle = ET.SubElement(root, 'LoggingEnabled')
              if logging.get('targetBucket') is not None:
                  ET.SubElement(loggingEnableEle, 'TargetBucket').text = util.to_string(logging['targetBucket'])
              if logging.get('targetPrefix') is not None:
                  ET.SubElement(loggingEnableEle, 'TargetPrefix').text = util.safe_decode(logging['targetPrefix'])
              if logging.get('targetGrants') is not None and len(logging['targetGrants']) > 0:
                  grantsEle = ET.SubElement(loggingEnableEle, 'TargetGrants')
                  self.trans_grantee(grantsEle, logging['targetGrants'])
          return ET.tostring(root, 'UTF-8')
      
      def trans_restore(self, days, tier):
          root = ET.Element('RestoreRequest')
          ET.SubElement(root, 'Days').text = util.to_string(days)
          tier = self.ha.adapt_retore_tier(tier)
          if tier is not None:
              glacierJobEle = ET.SubElement(root, 'GlacierJobParameters')
              ET.SubElement(glacierJobEle, 'Tier').text = util.to_string(tier)
          return ET.tostring(root, 'UTF-8')
      
      def trans_put_object(self, **kwargs):
          _headers = {}
          metadata = kwargs.get('metadata')
          headers = kwargs.get('headers')
          if metadata is not None:
              for k, v in metadata.items():
                  if not util.to_string(k).lower().startswith(self.ha._get_header_prefix()):
                      k = self.ha._get_meta_header_prefix() + k
                  self._put_key_value(_headers, k, v)
          if headers is not None and len(headers) > 0:
              self._put_key_value(_headers, const.CONTENT_MD5_HEADER, headers.get('md5'))
              self._put_key_value(_headers, self.ha.acl_header(), self.ha.adapt_acl_control(headers.get('acl')))
              self._put_key_value(_headers, self.ha.website_redirect_location_header(), headers.get('location'))
              self._put_key_value(_headers, const.CONTENT_TYPE_HEADER, headers.get('contentType'))
              self._set_sse_header(headers.get('sseHeader'), _headers)
              self._put_key_value(_headers, self.ha.storage_class_header(), self.ha.adapt_storage_class(headers.get('storageClass')))
              self._put_key_value(_headers, const.CONTENT_LENGTH_HEADER, headers.get('contentLength'))
              self._put_key_value(_headers, self.ha.expires_header(), headers.get('expires'))
              
              if self.is_obs:
                  self._put_key_value(_headers, self.ha.success_action_redirect_header(), headers.get('successActionRedirect'))
                  
              if headers.get('extensionGrants') is not None and len(headers['extensionGrants']) > 0:
                  grantDict = {}
                  for extensionGrant in headers['extensionGrants']:
                      permission = self.ha.adapt_extension_permission(extensionGrant.get('permission'), False)
                      if permission is not None and extensionGrant.get('granteeId') is not None:
                          granteeIds = grantDict.get(permission)
                          if granteeIds is None:
                              granteeIds = set()
                              grantDict[permission] = granteeIds
                          granteeIds.add('id=%s' % util.to_string(extensionGrant['granteeId']))
                  
                  for key, value in grantDict:
                      self._put_key_value(_headers, key, ','.join(value))
          return _headers
      
      def trans_initiate_multipart_upload(self, **kwargs):
          headers = {}
          self._put_key_value(headers, self.ha.acl_header(), self.ha.adapt_acl_control(kwargs.get('acl')))
          self._put_key_value(headers, self.ha.storage_class_header(), self.ha.adapt_storage_class(kwargs.get('storageClass')))
          metadata = kwargs.get('metadata')
          if metadata is not None:
              for k, v in metadata.items():
                  if not util.to_string(k).lower().startswith(self.ha._get_header_prefix()):
                      k = self.ha._get_meta_header_prefix() + k
                  self._put_key_value(headers, k, v)
          self._put_key_value(headers, self.ha.website_redirect_location_header(), kwargs.get('websiteRedirectLocation'))
          self._put_key_value(headers, const.CONTENT_TYPE_HEADER, kwargs.get('contentType'))
          self._put_key_value(headers, self.ha.expires_header(), kwargs.get('expires'))
          self._set_sse_header(kwargs.get('sseHeader'), headers)
          
          extensionGrants = kwargs.get('extensionGrants')
          if extensionGrants is not None and len(extensionGrants) > 0:
              grantDict = {}
              for extensionGrant in extensionGrants:
                  permission = self.ha.adapt_extension_permission(extensionGrant.get('permission'), False)
                  if permission is not None and extensionGrant.get('granteeId') is not None:
                      granteeIds = grantDict.get(permission)
                      if granteeIds is None:
                          granteeIds = set()
                          grantDict[permission] = granteeIds
                      granteeIds.add('id=%s' % util.to_string(extensionGrant['granteeId']))
              
              for key, value in grantDict:
                  self._put_key_value(headers, key, ','.join(value))
          return {'pathArgs': {'uploads': None}, 'headers': headers}
      
      def trans_copy_object(self, **kwargs):
          _headers = {}
          metadata = kwargs.get('metadata')
          if metadata is not None:
              for k, v in metadata.items():
                  if not util.to_string(k).lower().startswith(self.ha._get_header_prefix()):
                      k = self.ha._get_meta_header_prefix() + k
                  self._put_key_value(_headers, k, v)
          
          copy_source = '/%s/%s' % (util.to_string(kwargs.get('sourceBucketName')), util.to_string(kwargs.get('sourceObjectKey')))
          versionId = kwargs.get('versionId')
          if versionId is not None:
              copy_source = '%s?versionId=%s' % (copy_source, versionId)
          _headers[self.ha.copy_source_header()] = copy_source
          
          headers = kwargs.get('headers')
          if headers is not None and len(headers) > 0:
              self._put_key_value(_headers, self.ha.acl_header(), self.ha.adapt_acl_control(headers.get('acl')))
              self._put_key_value(_headers, self.ha.storage_class_header(), self.ha.adapt_storage_class(headers.get('storageClass')))
              
              self._put_key_value(_headers, self.ha.metadata_directive_header(), headers.get('directive'))
              self._put_key_value(_headers, self.ha.copy_source_if_match_header(), headers.get('if_match'))
              self._put_key_value(_headers, self.ha.copy_source_if_none_match_header(), headers.get('if_none_match'))
              self._put_key_value(_headers, self.ha.copy_source_if_modified_since_header(), headers['if_modified_since'].ToGMTTime() if isinstance(headers.get('if_modified_since'), DateTime) else headers.get('if_modified_since'))
              self._put_key_value(_headers, self.ha.copy_source_if_unmodified_since_header(), headers['if_unmodified_since'].ToGMTTime() if isinstance(headers.get('if_unmodified_since'), DateTime) else headers.get('if_unmodified_since'))
                  
              self._put_key_value(_headers, self.ha.website_redirect_location_header(), headers.get('location'))
              self._put_key_value(_headers, const.CACHE_CONTROL_HEADER, headers.get('cacheControl'))
              self._put_key_value(_headers, const.CONTENT_DISPOSITION_HEADER, headers.get('contentDisposition'))
              
              self._put_key_value(_headers, const.CONTENT_ENCODING_HEADER, headers.get('contentEncoding'))
              self._put_key_value(_headers, const.CONTENT_LANGUAGE_HEADER, headers.get('contentLanguage'))
              self._put_key_value(_headers, const.CONTENT_TYPE_HEADER, headers.get('contentType'))
              self._put_key_value(_headers, const.EXPIRES_HEADER, headers.get('expires'))
  
              self._set_sse_header(headers.get('destSseHeader'), _headers)
              self._set_source_sse_header(headers.get('sourceSseHeader'), _headers)
                  
              if self.is_obs:
                  self._put_key_value(_headers, self.ha.success_action_redirect_header(), headers.get('successActionRedirect'))
                  
              if headers.get('extensionGrants') is not None:
                  grantDict = {}
                  for extensionGrant in headers['extensionGrants']:
                      permission = self.ha.adapt_extension_permission(extensionGrant.get('permission'), False)
                      if permission is not None and extensionGrant.get('granteeId') is not None:
                          granteeIds = grantDict.get(permission)
                          if granteeIds is None:
                              granteeIds = set()
                              grantDict[permission] = granteeIds
                          granteeIds.add('id=%s' % util.to_string(extensionGrant['granteeId']))
                  
                  for key, value in grantDict:
                      self._put_key_value(_headers, key, ','.join(value))
                  
          return {'headers' : _headers}
      
      def trans_copy_part(self, **kwargs):
          headers = {}
          self._put_key_value(headers, self.ha.copy_source_header(), kwargs.get('copySource'))
          copySourceRange = kwargs.get('copySourceRange')
          if copySourceRange is not None:
              copySourceRange = util.to_string(copySourceRange)
              self._put_key_value(headers, self.ha.copy_source_range_header(), copySourceRange if copySourceRange.startswith('bytes=') else 'bytes=' + copySourceRange)
          self._set_sse_header(kwargs.get('destSseHeader'), headers)
          self._set_source_sse_header(kwargs.get('sourceSseHeader'), headers)
              
          return {'headers' : headers, 'pathArgs' : {'partNumber': kwargs.get('partNumber'), 'uploadId': kwargs.get('uploadId')}}
      
      def trans_get_object(self, **kwargs):
          pathArgs = {}
          getObjectRequest = kwargs.get('getObjectRequest')
          if getObjectRequest is not None and len(getObjectRequest) > 0:
              self._put_key_value(pathArgs, const.RESPONSE_CACHE_CONTROL_PARAM, getObjectRequest.get('cache_control'))
              self._put_key_value(pathArgs, const.RESPONSE_CONTENT_DISPOSITION_PARAM, getObjectRequest.get('content_disposition'))
              self._put_key_value(pathArgs, const.RESPONSE_CONTENT_ENCODING_PARAM, getObjectRequest.get('content_encoding'))
              self._put_key_value(pathArgs, const.RESPONSE_CONTENT_LANGUAGE_PARAM, getObjectRequest.get('content_language'))
              self._put_key_value(pathArgs, const.RESPONSE_CONTENT_TYPE_PARAM, getObjectRequest.get('content_type'))
              self._put_key_value(pathArgs, const.RESPONSE_EXPIRES_PARAM, getObjectRequest.get('expires'))
              self._put_key_value(pathArgs, const.VERSION_ID_PARAM, getObjectRequest.get('versionId'))
              self._put_key_value(pathArgs, const.X_IMAGE_PROCESS_PARAM, getObjectRequest.get('imageProcess'))
  
          _headers = {}
          headers = kwargs.get('headers')
          if headers is not None and len(headers) > 0:
              if headers.get('range') is not None:
                  _range = util.to_string(headers['range'])
                  self._put_key_value(_headers, const.RANGE_HEADER, _range if _range.startswith('bytes=') else 'bytes=' + _range)
              self._put_key_value(_headers, const.IF_MODIFIED_SINCE, headers['if_modified_since'].ToGMTTime() if isinstance(headers.get('if_modified_since'), DateTime) else headers.get('if_modified_since'))
              self._put_key_value(_headers, const.IF_UNMODIFIED_SINCE, headers['if_unmodified_since'].ToGMTTime() if isinstance(headers.get('if_unmodified_since'), DateTime) else headers.get('if_unmodified_since'))
              self._put_key_value(_headers, const.IF_MATCH, headers.get('if_match'))
              self._put_key_value(_headers, const.IF_NONE_MATCH, headers.get('if_none_match'))
              self._put_key_value(_headers, const.ORIGIN_HEADER, headers.get('origin'))
              self._put_key_value(_headers, const.ACCESS_CONTROL_REQUEST_HEADERS_HEADER, headers.get('requestHeaders'))
              self._set_sse_header(headers.get('sseHeader'), _headers, True)
          return {'pathArgs': pathArgs, 'headers': _headers}
      
      def trans_list_multipart_uploads(self, **kwargs):
          pathArgs = {'uploads' : None}
          multipart = kwargs.get('multipart')
          if multipart is not None:
              self._put_key_value(pathArgs, 'delimiter', multipart.get('delimiter'))
              self._put_key_value(pathArgs, 'prefix', multipart.get('prefix'))
              self._put_key_value(pathArgs, 'max-uploads', multipart.get('max_uploads'))
              self._put_key_value(pathArgs, 'key-marker', multipart.get('key_marker'))
              self._put_key_value(pathArgs, 'upload-id-marker', multipart.get('upload_id_marker'))
          return {'pathArgs': pathArgs}
      
      def _set_source_sse_header(self, sseHeader, headers=None):
          if headers is None:
              headers = {}
          if isinstance(sseHeader, SseCHeader):
              self._put_key_value(headers, self.ha.copy_source_sse_c_header(), sseHeader.get('encryption'))
              key = util.to_string(sseHeader.get('key'))
              self._put_key_value(headers, self.ha.copy_source_sse_c_key_header(), util.base64_encode(key))
              self._put_key_value(headers, self.ha.copy_source_sse_c_key_md5_header(), util.base64_encode(util.md5_encode(key)))
          return headers
      
      def _set_sse_header(self, sseHeader, headers=None, onlySseCHeader=False):
          if headers is None:
              headers = {}
          if isinstance(sseHeader, SseCHeader):
              self._put_key_value(headers, self.ha.sse_c_header(), sseHeader.get('encryption'))
              key = util.to_string(sseHeader.get('key'))
              self._put_key_value(headers, self.ha.sse_c_key_header(), util.base64_encode(key))
              self._put_key_value(headers, self.ha.sse_c_key_md5_header(), util.base64_encode(util.md5_encode(key)))
          elif isinstance(sseHeader, SseKmsHeader) and not onlySseCHeader:
              self._put_key_value(headers, self.ha.sse_kms_header(), sseHeader.get('encryption') if self.is_obs else 'aws:' + util.to_string(sseHeader.get('encryption')))
              if sseHeader.get('key') is not None:
                  self._put_key_value(headers, self.ha.sse_kms_key_header(), sseHeader['key'])
          return headers
      
      def trans_set_bucket_replication(self, **kwargs):
          entity = self.trans_replication(kwargs.get('replication'))
          headers = {const.CONTENT_MD5_HEADER: util.base64_encode(util.md5_encode(entity))}
          return {'pathArgs': {'replication': None}, 'headers': headers, 'entity': entity}
      
      def trans_replication(self, replication):
          root = ET.Element('ReplicationConfiguration')
          if self.is_obs and replication.get('agency') is not None:
              ET.SubElement(root, 'Agency').text = util.to_string(replication['agency'])
          
          if replication.get('replicationRules') is not None:
              for replicationRule in replication['replicationRules']:
                  ruleEle = ET.SubElement(root, 'Rule')
                  if replicationRule.get('id') is not None:
                      ET.SubElement(ruleEle, 'ID').text = util.safe_decode(replicationRule['id'])
                  if replicationRule.get('prefix') is not None:
                      ET.SubElement(ruleEle, 'Prefix').text = util.safe_decode(replicationRule['prefix'])
                  if replicationRule.get('status') is not None:
                      ET.SubElement(ruleEle, 'Status').text = util.to_string(replicationRule['status'])
                  
                  if replication.get('bucket') is not None:
                      destinationEle = ET.SubElement(ruleEle, 'Destination')
                      bucket_name = util.to_string(replicationRule['bucket'])
                      bucket_name = bucket_name if self.is_obs else bucket_name if bucket_name.startswith('arn:aws:s3:::') else 'arn:aws:s3:::' + bucket_name
                      ET.SubElement(destinationEle, 'Bucket').text = bucket_name
                      if replicationRule.get('storageClass') is not None:
                          ET.SubElement(destinationEle, 'Bucket').text = self.ha.adapt_storage_class(replicationRule['storageClass'])
          return ET.tostring(root, 'UTF-8')
      
      def _find_item(self, root, itemname):
          result = root.find(itemname)
          if result is None:
              return None
          result = result.text
          if const.IS_PYTHON2:
              result = util.safe_encode(result)
          return util.to_string(result)
      
      
      def parseListBuckets(self, xml, headers=None):
          root = ET.fromstring(xml)
          owner_id = self._find_item(root, './Owner/ID')
          owner_name = None if self.is_obs else self._find_item(root, './Owner/DisplayName')
          owner = Owner(owner_id=owner_id, owner_name=owner_name)
      
          buckets = root.find('Buckets').findall('Bucket')
          entries = []
      
          for bucket in buckets:
              name = self._find_item(bucket, 'Name')
              d = self._find_item(bucket, 'CreationDate')
              location = self._find_item(bucket, 'Location')
              create_date = DateTime.UTCToLocal(d)
              curr_bucket = Bucket(name=name, create_date=create_date, location=location)
              entries.append(curr_bucket)
          return ListBucketsResponse(buckets=entries, owner=owner)
      
      def parseErrorResult(self, xml, headers=None):
          root = ET.fromstring(xml)
          code = self._find_item(root, './Code')
          message = self._find_item(root, './Message')
          requestId = self._find_item(root, './RequestId')
          hostId = self._find_item(root, './HostId')
          resource = self._find_item(root, './Resource')
          return code, message, requestId, hostId, resource
      
      def parseListObjects(self, xml, headers=None):
          root = ET.fromstring(xml)
      
          name = self._find_item(root, 'Name')
          prefix = self._find_item(root, 'Prefix')
          marker = self._find_item(root, 'Marker')
          delimiter = self._find_item(root, 'Delimiter')
          max_keys = self._find_item(root, 'MaxKeys')
          is_truncated = self._find_item(root, 'IsTruncated')
          next_marker = self._find_item(root, 'NextMarker')
      
          key_entries = []
          contents = root.findall('Contents')
          if contents is not None:
              for node in contents:
                  key = self._find_item(node, 'Key')
                  lastmodified = self._find_item(node, 'LastModified')
                  etag = self._find_item(node, 'ETag')
                  size = self._find_item(node, 'Size')
                  storage = self._find_item(node, 'StorageClass')
      
                  owner_id = self._find_item(node, './Owner/ID')
                  owner_name = None if self.is_obs else self._find_item(node, './Owner/DisplayName')
                  owner = Owner(owner_id=owner_id, owner_name=owner_name)
                  isAppendable = self._find_item(node, 'Type')
                  key_entry = Content(key=key, lastModified=DateTime.UTCToLocal(lastmodified), etag=etag, size=util.to_long(size), owner=owner, storageClass=storage, 
                                      isAppendable=isAppendable == 'Appendable')
                  key_entries.append(key_entry)
          
          commonprefixs = []
          prefixes = root.findall('CommonPrefixes')
          if prefixes is not None:
              for p in prefixes:
                  pre = self._find_item(p, 'Prefix')
                  commonprefix = CommonPrefix(prefix=pre)
                  commonprefixs.append(commonprefix)
                  
          location = headers.get(self.ha.bucket_region_header())
          return ListObjectsResponse(name=name, location=location, prefix=prefix, marker=marker, delimiter=delimiter, max_keys=util.to_int(max_keys),
                                     is_truncated=util.to_bool(is_truncated), next_marker=next_marker, contents=key_entries, commonPrefixs=commonprefixs)
      
      def parseGetBucketMetadata(self, headers):
          option = GetBucketMetadataResponse()
          option.accessContorlAllowOrigin = headers.get('access-control-allow-origin')
          option.accessContorlAllowHeaders = headers.get('access-control-allow-headers')
          option.accessContorlAllowMethods = headers.get('access-control-allow-methods')
          option.accessContorlExposeHeaders = headers.get('access-control-expose-headers')
          option.accessContorlMaxAge = util.to_int(headers.get('access-control-max-age'))
          option.storageClass = headers.get(self.ha.default_storage_class_header())
          option.location = headers.get(self.ha.bucket_region_header())
          option.obsVersion = headers.get(self.ha.server_version_header())
          return option
      
      def parseGetBucketLocation(self, xml, headers=None):
          root = ET.fromstring(xml)
          location = self._find_item(root, './Location' if self.is_obs else './LocationConstraint')
          return LocationResponse(location=location)
      
      def parseGetBucketStorageInfo(self, xml, headers=None):
          root = ET.fromstring(xml)
          size = self._find_item(root, './Size')
          objectNumber = self._find_item(root, './ObjectNumber')
          return GetBucketStorageInfoResponse(size=util.to_long(size), objectNumber=util.to_int(objectNumber))
      
      def parseGetBucketPolicy(self, json_str, headers=None):
          return Policy(policyJSON=json_str)
      
      def parseGetBucketStoragePolicy(self, xml, headers=None):
          root = ET.fromstring(xml)
          storageClass = root.text if self.is_obs else self._find_item(root, './DefaultStorageClass') 
          return GetBucketStoragePolicyResponse(storageClass=storageClass)
      
      def parseGetBucketQuota(self, xml, headers=None):
          root = ET.fromstring(xml)
          quota = self._find_item(root, './StorageQuota')
          return GetBucketQuotaResponse(quota=util.to_long(quota))
      
      def parseGetBucketTagging(self, xml, headers=None):
          result = TagInfo()
          root = ET.fromstring(xml)
          tags = root.findall('./TagSet/Tag')
          if tags:
              for tag in tags:
                  key = tag.find('./Key')
                  key = util.safe_encode(key.text) if key is not None else None
                  value = tag.find('./Value')
                  value = util.safe_encode(value.text) if value is not None else None
                  result.addTag(key, value)
          return result
      
      def parseGetBucketCors(self, xml, headers=None):
          root = ET.fromstring(xml)
          corsList = []
          rules = root.findall('./CORSRule')
          if rules is not None:
              for rule in rules:
                  _id = self._find_item(rule, './ID')
                  maxAgeSecond = rule.find('./MaxAgeSeconds')
                  maxAgeSecond = util.to_int(maxAgeSecond.text) if maxAgeSecond is not None else None
      
                  method = rule.findall('./AllowedMethod')
                  allowMethod = []
                  if method is not None:
                      for v in method:
                          allowMethod.append(util.to_string(v.text))
                  allowedOrigin = []
                  method = rule.findall('./AllowedOrigin')
                  if method is not None:
                      for v in method:
                          allowedOrigin.append(util.to_string(v.text))
                  allowedHeader = []
                  method = rule.findall('./AllowedHeader')
                  if method is not None:
                      for v in method:
                          allowedHeader.append(util.to_string(v.text))
                  exposeHeader = []
                  method = rule.findall('./ExposeHeader')
                  if method is not None:
                      for v in method:
                          exposeHeader.append(util.to_string(v.text))
      
                  corsList.append(CorsRule(id=_id, allowedMethod=allowMethod, allowedOrigin=allowedOrigin, 
                                           allowedHeader=allowedHeader, maxAgeSecond=maxAgeSecond, exposeHeader=exposeHeader))
          return corsList
      
      def parseListVersions(self, xml, headers=None):
          root = ET.fromstring(xml)
          Name = self._find_item(root, './Name')
          Prefix = self._find_item(root, './Prefix')
          Delimiter = self._find_item(root, './Delimiter')
          KeyMarker = self._find_item(root, './KeyMarker')
          VersionIdMarker = self._find_item(root, './VersionIdMarker')
          NextKeyMarker = self._find_item(root, './NextKeyMarker')
          NextVersionIdMarker = self._find_item(root, './NextVersionIdMarker')
          MaxKeys = self._find_item(root, './MaxKeys')
          IsTruncated = self._find_item(root, './IsTruncated')
          location = headers.get(self.ha.bucket_region_header())
          head = ObjectVersionHead(name=Name, location=location, prefix=Prefix, delimiter=Delimiter, keyMarker=KeyMarker, versionIdMarker=VersionIdMarker,
                                   nextKeyMarker=NextKeyMarker, nextVersionIdMarker=NextVersionIdMarker, maxKeys=util.to_int(MaxKeys),
                                   isTruncated=util.to_bool(IsTruncated))
      
          versions = root.findall('./Version')
          version_list = []
          for version in versions:
              Key = self._find_item(version, './Key')
              VersionId = self._find_item(version, './VersionId')
              IsLatest = self._find_item(version, './IsLatest')
              LastModified = self._find_item(version, './LastModified')
              ETag = self._find_item(version, './ETag')
              Size = self._find_item(version, './Size')
              owner = version.find('./Owner')
              Owners = None
              if owner is not None:
                  ID = self._find_item(owner, './ID')
                  DisplayName = None if self.is_obs else self._find_item(owner, './DisplayName')
                  Owners = Owner(owner_id=ID, owner_name=DisplayName)
      
              StorageClass = self._find_item(version, './StorageClass')
              isAppendable = self._find_item(version, './Type')
              Version = ObjectVersion(key=Key, versionId=VersionId, isLatest=util.to_bool(IsLatest), lastModified=DateTime.UTCToLocal(LastModified), etag=ETag, size=util.to_long(Size), owner=Owners,
                                      storageClass=StorageClass, isAppendable=(isAppendable=='Appendable'))
              version_list.append(Version)
      
          markers = root.findall('./DeleteMarker')
          marker_list = []
          for marker in markers:
              Key = self._find_item(marker, './Key')
              VersionId = self._find_item(marker, './VersionId')
              IsLatest = self._find_item(marker, './IsLatest')
              LastModified = self._find_item(marker, './LastModified')
              owner = marker.find('./Owner')
              Owners = None
              if owner is not None:
                  ID = self._find_item(owner, './ID')
                  DisplayName = None if self.is_obs else self._find_item(owner, './DisplayName')
                  Owners = Owner(owner_id=ID, owner_name=DisplayName)
              Marker = ObjectDeleteMarker(key=Key, versionId=VersionId, isLatest=util.to_bool(IsLatest), lastModified=DateTime.UTCToLocal(LastModified), owner=Owners)
              marker_list.append(Marker)
      
          prefixs = root.findall('./CommonPrefixes')
          prefix_list = []
          for prefix in prefixs:
              Prefix = self._find_item(prefix, './Prefix')
              Pre = CommonPrefix(prefix=Prefix)
              prefix_list.append(Pre)
          return ObjectVersions(head=head, markers=marker_list, commonPrefixs=prefix_list, versions=version_list)
      
      def parseOptionsBucket(self, headers):
          option = OptionsResponse()
          option.accessContorlAllowOrigin = headers.get('access-control-allow-origin')
          option.accessContorlAllowHeaders = headers.get('access-control-allow-headers')
          option.accessContorlAllowMethods = headers.get('access-control-allow-methods')
          option.accessContorlExposeHeaders = headers.get('access-control-expose-headers')
          option.accessContorlMaxAge = util.to_int(headers.get('access-control-max-age'))
          return option
      
      def parseDeleteObjects(self, xml, headers=None):
          root = ET.fromstring(xml)
          deleted_list = []
          error_list = []
          deleteds = root.findall('./Deleted')
          if deleteds:
              for d in deleteds:
                  key = self._find_item(d, './Key')
                  versionId = self._find_item(d, './VersionId')
                  deleteMarker = d.find('./DeleteMarker')
                  deleteMarker = util.to_bool(deleteMarker.text) if deleteMarker is not None else None
                  deleteMarkerVersionId = self._find_item(d, './DeleteMarkerVersionId')
                  deleted_list.append(DeleteObjectResult(key=key, deleteMarker=deleteMarker, versionId=versionId, deleteMarkerVersionId=deleteMarkerVersionId))
          errors = root.findall('./Error')
          if errors:
              for e in errors:
                  _key = self._find_item(e, './Key')
                  _versionId = self._find_item(e, './VersionId')
                  _code = self._find_item(e, './Code')
                  _message = self._find_item(e, './Message')
                  error_list.append(ErrorResult(key=_key, versionId=_versionId, code=_code, message=_message))
          return DeleteObjectsResponse(deleted=deleted_list, error=error_list)
      
      def parseDeleteObject(self, headers):
          deleteObjectResponse = DeleteObjectResponse()
          delete_marker = headers.get(self.ha.delete_marker_header())
          deleteObjectResponse.deleteMarker = util.to_bool(delete_marker) if delete_marker is not None else None
          deleteObjectResponse.versionId = headers.get(self.ha.version_id_header())
          return deleteObjectResponse
      
      def parseGetBucketVersioning(self, xml, headers=None):
          root = ET.fromstring(xml)
          return self._find_item(root, 'Status')
      
      def parseGetBucketLifecycle(self, xml, headers=None):
          root = ET.fromstring(xml)
          rules = root.findall('./Rule')
          entries = []
          for rule in rules:
              _id = self._find_item(rule, './ID')
              prefix = self._find_item(rule, './Prefix')
              status = self._find_item(rule, './Status')
              expira = rule.find('./Expiration')
              expiration = None
              if expira is not None:
                  d = expira.find('./Date')
                  date = DateTime.UTCToLocalMid(d.text) if d is not None else None
                  day = expira.find('./Days')
                  days = util.to_int(day.text) if day is not None else None
                  expiration = Expiration(date=date, days=days)
      
              nocurrentExpira = rule.find('./NoncurrentVersionExpiration')
              noncurrentVersionExpiration = NoncurrentVersionExpiration(noncurrentDays=util.to_int(nocurrentExpira.find('./NoncurrentDays').text)) if nocurrentExpira is not None else None
      
              transis = rule.findall('./Transition')
              transitions = []
              if transis is not None:
                  for transi in transis:
                      d = transi.find('./Date')
                      date = DateTime.UTCToLocalMid(d.text) if d is not None else None
                      days = transi.find('./Days')
                      days = util.to_int(days.text) if days is not None else None
                      storageClass = self._find_item(transi, './StorageClass')
                      transition = Transition(storageClass, date=date, days=days)
                      transitions.append(transition)
              
              noncurrentVersionTransis = rule.findall('./NoncurrentVersionTransition')
              noncurrentVersionTransitions = []
              if noncurrentVersionTransis is not None:
                  for noncurrentVersionTransis in noncurrentVersionTransis:
                      storageClass = self._find_item(noncurrentVersionTransis, './StorageClass')
                      noncurrentDays = noncurrentVersionTransis.find('./NoncurrentDays')
                      noncurrentDays = util.to_int(noncurrentDays.text) if noncurrentDays is not None else None
                      noncurrentVersionTransition = NoncurrentVersionTransition(storageClass=storageClass, noncurrentDays=noncurrentDays)
                      noncurrentVersionTransitions.append(noncurrentVersionTransition)
                      
              rule = Rule(id=_id, prefix=prefix, status=status, expiration=expiration, noncurrentVersionExpiration=noncurrentVersionExpiration)
              rule.transition = transitions 
              rule.noncurrentVersionTransition = noncurrentVersionTransitions
              entries.append(rule)
          return LifecycleResponse(lifecycleConfig=Lifecycle(rule=entries))
      
      def parseGetBucketWebsite(self, xml, headers=None):
          root = ET.fromstring(xml)
          redirectAll = None
          redirectAllRequestTo = root.find('./RedirectAllRequestsTo')
          if redirectAllRequestTo is not None:
              hostname = self._find_item(redirectAllRequestTo, './HostName')
              protocol = self._find_item(redirectAllRequestTo, './Protocol')
              redirectAll = RedirectAllRequestTo(hostName=hostname, protocol=protocol)
              return WebsiteConfiguration(redirectAllRequestTo=redirectAll)
              
          index = None
          indexDocument = root.find('./IndexDocument')
          if indexDocument is not None:
              Suffix = self._find_item(indexDocument, './Suffix')
              index = IndexDocument(suffix=Suffix)
      
          error = None
          errorDocument = root.find('./ErrorDocument')
          if errorDocument is not None:
              Key = self._find_item(errorDocument, './Key')
              error = ErrorDocument(key=Key)
      
          routs = None
          routingRules = root.findall('./RoutingRules/RoutingRule')
          if routingRules is not None and len(routingRules) > 0:
              routs = []
              for rout in routingRules:
                  KeyPrefixEquals = rout.find('./Condition/KeyPrefixEquals')
                  KeyPrefixEquals = util.to_string(KeyPrefixEquals.text) if KeyPrefixEquals is not None else None
                  HttpErrorCodeReturnedEquals = rout.find('./Condition/HttpErrorCodeReturnedEquals')
                  HttpErrorCodeReturnedEquals = util.to_int(HttpErrorCodeReturnedEquals.text) if HttpErrorCodeReturnedEquals is not None else None
      
                  condition = Condition(keyPrefixEquals=KeyPrefixEquals, httpErrorCodeReturnedEquals=HttpErrorCodeReturnedEquals)
      
                  Protocol = self._find_item(rout, './Redirect/Protocol')
                  HostName = self._find_item(rout, './Redirect/HostName')
                  ReplaceKeyPrefixWith = self._find_item(rout, './Redirect/ReplaceKeyPrefixWith')
                  ReplaceKeyWith = self._find_item(rout, './Redirect/ReplaceKeyWith')
                  HttpRedirectCode = rout.find('./Redirect/HttpRedirectCode')
                  HttpRedirectCode = util.to_int(HttpRedirectCode.text) if HttpRedirectCode is not None else None
                  redirect = Redirect(protocol=Protocol, hostName=HostName, replaceKeyPrefixWith=ReplaceKeyPrefixWith, replaceKeyWith=ReplaceKeyWith,
                                      httpRedirectCode=HttpRedirectCode)
                  routingRule = RoutingRule(condition=condition, redirect=redirect)
                  routs.append(routingRule)
      
          return WebsiteConfiguration(indexDocument=index, errorDocument=error, routingRules=routs)
      
      def parseGetBucketNotification(self, xml, headers=None):
          notification = Notification()
          root = ET.fromstring(xml)
          topicConfigurations = root.findall('./TopicConfiguration')
          if topicConfigurations is not None:
              tc_list = []
              for topicConfiguration in topicConfigurations:
                  tc = TopicConfiguration()
                  tc.id = self._find_item(topicConfiguration, './Id')
                  tc.topic = self._find_item(topicConfiguration, './Topic')
                  event_list = []
                  events = topicConfiguration.findall('./Event')
                  if events is not None:
                      for event in events:
                          event_list.append(util.to_string(event.text))
      
                  tc.events = event_list
                  filterRule_list = []
                  filterRules = topicConfiguration.findall('./Filter/Object/FilterRule' if self.is_obs else './Filter/S3Key/FilterRule')
                  if filterRules is not None:
                      for filterRule in filterRules:
                          name = filterRule.find('./Name')
                          value = filterRule.find('./Value')
                          fr = FilterRule(name=util.to_string(name.text) if name is not None else None, value=util.to_string(value.text)
                                          if value is not None else None)
                          filterRule_list.append(fr)
                  tc.filterRules = filterRule_list
                  tc_list.append(tc)
      
              notification.topicConfigurations = tc_list
          return notification
      
      def parseListMultipartUploads(self, xml, headers=None):
          root = ET.fromstring(xml)
          bucket = self._find_item(root, './Bucket')
          KeyMarker = self._find_item(root, './KeyMarker')
          UploadIdMarker = self._find_item(root, './UploadIdMarker')
          NextKeyMarker = self._find_item(root, './NextKeyMarker')
          NextUploadIdMarker = self._find_item(root, './NextUploadIdMarker')
      
          MaxUploads = root.find('./MaxUploads')
          MaxUploads = util.to_int(MaxUploads.text) if MaxUploads is not None else None
      
          IsTruncated = root.find('./IsTruncated')
          IsTruncated = util.to_bool(IsTruncated.text) if IsTruncated is not None else None
      
          prefix = self._find_item(root, './Prefix')
          delimiter = self._find_item(root, './Delimiter')
      
          rules = root.findall('./Upload')
          uploadlist = []
          if rules:
              for rule in rules:
                  Key = self._find_item(rule, './Key')
                  UploadId = self._find_item(rule, './UploadId')
      
                  ID = self._find_item(rule, './Initiator/ID')
      
                  DisplayName = None if self.is_obs else self._find_item(rule, './Initiator/DisplayName')
                  initiator = Initiator(id=ID, name=DisplayName)
      
                  owner_id = self._find_item(rule, './Owner/ID')
                  owner_name = None if self.is_obs else self._find_item(rule, './Owner/DisplayName')
                  ower = Owner(owner_id=owner_id, owner_name=owner_name)
      
                  StorageClass = self._find_item(rule, './StorageClass')
      
                  Initiated = rule.find('./Initiated')
                  Initiated = DateTime.UTCToLocal(Initiated.text) if Initiated is not None else None
                  upload = Upload(key=Key, uploadId=UploadId, initiator=initiator, owner=ower, storageClass=StorageClass, initiated=Initiated)
                  uploadlist.append(upload)
          common = root.findall('./CommonPrefixes')
          commonlist = []
          if common:
              for comm in common:
                  comm_prefix = self._find_item(comm, './Prefix')
                  Comm_Prefix = CommonPrefix(prefix=comm_prefix)
                  commonlist.append(Comm_Prefix)
          return ListMultipartUploadsResponse(bucket=bucket, keyMarker=KeyMarker, uploadIdMarker=UploadIdMarker,
                                              nextKeyMarker=NextKeyMarker, nextUploadIdMarker=NextUploadIdMarker, maxUploads=MaxUploads,
                                              isTruncated=IsTruncated, prefix=prefix, delimiter=delimiter, upload=uploadlist, commonPrefixs=commonlist)
      
      def parseCompleteMultipartUpload(self, xml, headers=None):
          root = ET.fromstring(xml)
          location = self._find_item(root, './Location')
          bucket = self._find_item(root, './Bucket')
          key = self._find_item(root, './Key')
          eTag = self._find_item(root, './ETag')
          completeMultipartUploadResponse = CompleteMultipartUploadResponse(location=location, bucket=bucket, key=key, etag=eTag)
          completeMultipartUploadResponse.versionId = headers.get(self.ha.version_id_header())
          completeMultipartUploadResponse.sseKms = headers.get(self.ha.sse_kms_header())
          completeMultipartUploadResponse.sseKmsKey = headers.get(self.ha.sse_kms_key_header())
          completeMultipartUploadResponse.sseC = headers.get(self.ha.sse_c_header())
          completeMultipartUploadResponse.sseCKeyMd5 = headers.get(self.ha.sse_c_key_md5_header().lower())
      
          return completeMultipartUploadResponse
      
      def parseListParts(self, xml, headers=None):
          root = ET.fromstring(xml)
          bucketName = self._find_item(root, './Bucket')
          objectKey = self._find_item(root, './Key')
          uploadId = self._find_item(root, './UploadId')
      
          storageClass = self._find_item(root, './StorageClass')
          partNumbermarker = root.find('./PartNumberMarker')
          partNumbermarker = util.to_int(partNumbermarker.text) if partNumbermarker is not None else None
          nextPartNumberMarker = root.find('./NextPartNumberMarker')
          nextPartNumberMarker = util.to_int(nextPartNumberMarker.text) if nextPartNumberMarker is not None else None
          maxParts = root.find('./MaxParts')
          maxParts = util.to_int(maxParts) if maxParts is not None else None
          isTruncated = root.find('./IsTruncated')
          isTruncated = util.to_bool(isTruncated.text) if isTruncated is not None else None
      
          initiatorid = self._find_item(root, './Initiator/ID')
          displayname = None if self.is_obs else self._find_item(root, './Initiator/DisplayName')
      
          initiator = Initiator(id=initiatorid, name=displayname)
      
          ownerid = self._find_item(root, './Owner/ID')
          ownername = self._find_item(root, './Owner/DisplayName')
      
          owner = Owner(owner_id=ownerid, owner_name=ownername)
      
          part_list = root.findall('./Part')
          parts = []
          if part_list:
              for part in part_list:
                  partnumber = part.find('./PartNumber')
                  partnumber = util.to_int(partnumber.text) if partnumber is not None else None
                  modifieddate = part.find('./LastModified')
                  modifieddate = DateTime.UTCToLocal(modifieddate.text) if modifieddate is not None else None
                  etag = self._find_item(part, './ETag')
                  size = part.find('./Size')
                  size = util.to_long(size.text) if size is not None else None
                  parts.append(Part(partNumber=partnumber, lastModified=modifieddate, etag=etag, size=size))
      
          return ListPartsResponse(bucketName=bucketName, objectKey=objectKey, uploadId=uploadId, initiator=initiator, owner=owner, storageClass=storageClass,
                                   partNumberMarker=partNumbermarker, nextPartNumberMarker=nextPartNumberMarker, maxParts=maxParts, isTruncated=isTruncated, parts=parts)
      
      
      def parseGetBucketAcl(self, xml, headers=None):
          root = ET.fromstring(xml)
          owner_id = self._find_item(root, './Owner/ID')
          owner_name = None if self.is_obs else self._find_item(root, './Owner/DisplayName')
          owner = Owner(owner_id=owner_id, owner_name=owner_name)
          grants = root.findall('./AccessControlList/Grant')
          return ACL(owner=owner, grants=self.parseGrants(grants))
  
      def parseGrants(self, grants, headers=None):
          grant_list = []
          if grants is not None:
              if self.is_obs:
                  for grant in grants:
                      group1 = grant.find('./Grantee/Canned')
                      if group1 is not None:
                          grantee = Grantee(group=util.to_string(group1.text))
                      else:
                          _id = grant.find('./Grantee/ID')
                          grantee = Grantee(grantee_id=_id.text if _id is not None else None)
                      permission = self._find_item(grant, './Permission')
                      delivered = grant.find('./Delivered')
                      delivered = util.to_string(delivered.text) if delivered is not None else None
                      cur_grant = Grant(grantee=grantee, permission=permission, delivered=True if delivered == 'true' else False)
                      grant_list.append(cur_grant)
              else:
                  ns = '{http://www.w3.org/2001/XMLSchema-instance}'
                  for grant in grants:
                      if grant.find('./Grantee').attrib.get('{0}type'.format(ns)) == 'Group':
                          group1 = self._find_item(grant, './Grantee/URI')
                          grantee = Grantee(group=group1)
                      elif grant.find('./Grantee').attrib.get('{0}type'.format(ns)) == 'CanonicalUser':
                          owner_id = self._find_item(grant, './Grantee/ID')
                          owner_name = None if self.is_obs else self._find_item(grant, './Grantee/DisplayName')
                          grantee = Grantee(grantee_id=owner_id, grantee_name=owner_name)
          
                      permission = self._find_item(grant, './Permission')
                      cur_grant = Grant(grantee=grantee, permission=permission)
                      grant_list.append(cur_grant)
          return grant_list
      
      def parseGetBucketLogging(self, xml, headers=None):
          root = ET.fromstring(xml)
          bucket = self._find_item(root, './LoggingEnabled/TargetBucket')
          prefix = self._find_item(root, './LoggingEnabled/TargetPrefix')
          agency = self._find_item(root, './Agency')
          grants = root.findall('./LoggingEnabled/TargetGrants/Grant')
          return Logging(targetBucket=bucket, targetPrefix=prefix, targetGrants=self.parseGrants(grants), agency=agency)
  
      def parseGetObjectAcl(self, xml, headers=None):
          root = ET.fromstring(xml)
          owner_id = self._find_item(root, './Owner/ID')
          owner_name = None
          if not self.is_obs:
              owner_name = self._find_item(root, './Owner/DisplayName')
              delivered = None
          else:
              delivered = self._find_item(root, './Delivered')
              delivered = util.to_string(delivered.text) if delivered is not None else None
              
          owner = Owner(owner_id=owner_id, owner_name=owner_name)
          grants = root.findall('./AccessControlList/Grant')
          return ACL(owner=owner, grants=self.parseGrants(grants), delivered=True if delivered == 'true' else False)
      
      def parsePutContent(self, headers):
          option = PutContentResponse()
          option.storageClass = headers.get(self.ha.storage_class_header())
          option.versionId = headers.get(self.ha.version_id_header())
          option.sseKms = headers.get(self.ha.sse_kms_header())
          option.sseKmsKey = headers.get(self.ha.sse_kms_key_header())
          option.sseC = headers.get(self.ha.sse_c_header())
          option.sseCKeyMd5 = headers.get(self.ha.sse_c_key_md5_header().lower())
          option.etag = headers.get(const.ETAG_HEADER.lower())
          return option
      
      def parseAppendObject(self, headers):
          option = AppendObjectResponse()
          option.storageClass = headers.get(self.ha.storage_class_header())
          option.sseKms = headers.get(self.ha.sse_kms_header())
          option.sseKmsKey = headers.get(self.ha.sse_kms_key_header())
          option.sseC = headers.get(self.ha.sse_c_header())
          option.sseCKeyMd5 = headers.get(self.ha.sse_c_key_md5_header().lower())
          option.etag = headers.get(const.ETAG_HEADER.lower())
          option.nextPosition = util.to_long(headers.get(self.ha.next_position_header()))
          return option
      
      def parseInitiateMultipartUpload(self, xml, headers=None):
          root = ET.fromstring(xml)
          bucketName = self._find_item(root, './Bucket')
          objectKey = self._find_item(root, './Key')
          uploadId = self._find_item(root, './UploadId')
          response = InitiateMultipartUploadResponse(bucketName=bucketName, objectKey=objectKey, uploadId=uploadId)
          response.sseKms = headers.get(self.ha.sse_kms_header())
          response.sseKmsKey = headers.get(self.ha.sse_kms_key_header())
          response.sseC = headers.get(self.ha.sse_c_header())
          response.sseCKeyMd5 = headers.get(self.ha.sse_c_key_md5_header().lower())
          return response
      
      def parseCopyObject(self, xml, headers=None):
          root = ET.fromstring(xml)
          lastModified = root.find('./LastModified')
          lastModified = DateTime.UTCToLocal(lastModified.text) if lastModified is not None else None
          eTag = self._find_item(root, './ETag')
          copyObjectResponse = CopyObjectResponse(lastModified=lastModified, etag=eTag)
          copyObjectResponse.versionId = headers.get(self.ha.version_id_header())
          copyObjectResponse.copySourceVersionId = headers.get(self.ha.copy_source_version_id())
          copyObjectResponse.sseKms = headers.get(self.ha.sse_kms_header())
          copyObjectResponse.sseKmsKey = headers.get(self.ha.sse_kms_key_header())
          copyObjectResponse.sseC = headers.get(self.ha.sse_c_header())
          copyObjectResponse.sseCKeyMd5 = headers.get(self.ha.sse_c_key_md5_header().lower())
          return copyObjectResponse
      
      def _parseGetObjectCommonHeader(self, headers, option):
          option.accessContorlAllowOrigin = headers.get('access-control-allow-origin')
          option.accessContorlAllowHeaders = headers.get('access-control-allow-headers')
          option.accessContorlAllowMethods = headers.get('access-control-allow-methods')
          option.accessContorlExposeHeaders = headers.get('access-control-expose-headers')
          option.accessContorlMaxAge = util.to_int(headers.get('access-control-max-age'))
          option.storageClass = headers.get(self.ha.storage_class_header())
          option.expiration = headers.get(self.ha.expiration_header())
          option.versionId = headers.get(self.ha.version_id_header())
          option.websiteRedirectLocation = headers.get(self.ha.website_redirect_location_header())
          option.sseKms = headers.get(self.ha.sse_kms_header())
          option.sseKmsKey = headers.get(self.ha.sse_kms_key_header())
          option.sseC = headers.get(self.ha.sse_c_header())
          option.sseCKeyMd5 = headers.get(self.ha.sse_c_key_md5_header().lower())
          option.restore = headers.get(self.ha.restore_header())
          option.etag = headers.get(const.ETAG_HEADER.lower())
          option.contentLength = util.to_long(headers.get(const.CONTENT_LENGTH_HEADER.lower()))
          option.contentType = headers.get(const.CONTENT_TYPE_HEADER.lower())
          option.lastModified = headers.get(const.LAST_MODIFIED_HEADER.lower())
      
      def parseGetObjectMetadata(self, headers):
          option = GetObjectMetadataResponse()
          self._parseGetObjectCommonHeader(headers, option)
          option.isAppendable = headers.get(self.ha.object_type_header()) == 'Appendable'
          if option.isAppendable:
              option.nextPosition = util.to_long(headers.get(self.ha.next_position_header()))
          return option
      
      def parseGetObject(self, headers, option):
          self._parseGetObjectCommonHeader(headers, option)
          option.deleteMarker = headers.get(self.ha.delete_marker_header())
          option.cacheControl = headers.get(const.CACHE_CONTROL_HEADER.lower())
          option.contentDisposition = headers.get(const.CONTENT_DISPOSITION_HEADER.lower())
          option.contentEncoding = headers.get(const.CONTENT_ENCODING_HEADER.lower())
          option.contentLanguage = headers.get(const.CONTENT_LANGUAGE_HEADER.lower())
          option.expires = headers.get(const.EXPIRES_HEADER.lower())
          return option
  
      def parseUploadPart(self, headers):
          uploadPartResponse = UploadPartResponse()
          uploadPartResponse.etag = headers.get(const.ETAG_HEADER.lower())
          uploadPartResponse.sseKms = headers.get(self.ha.sse_kms_header())
          uploadPartResponse.sseKmsKey = headers.get(self.ha.sse_kms_key_header())
          uploadPartResponse.sseC = headers.get(self.ha.sse_c_header())
          uploadPartResponse.sseCKeyMd5 = headers.get(self.ha.sse_c_key_md5_header().lower())
          return uploadPartResponse
      
      def parseCopyPart(self, xml, headers=None):
          root = ET.fromstring(xml)
          lastModified = root.find('./LastModified')
          lastModified = DateTime.UTCToLocal(lastModified.text) if lastModified is not None else None
          etag = self._find_item(root, './ETag')
          copyPartResponse = CopyPartResponse(modifiedDate=lastModified, lastModified=lastModified, etag=etag)
          copyPartResponse.sseKms = headers.get(self.ha.sse_kms_header())
          copyPartResponse.sseKmsKey = headers.get(self.ha.sse_kms_key_header())
          copyPartResponse.sseC = headers.get(self.ha.sse_c_header())
          copyPartResponse.sseCKeyMd5 = headers.get(self.ha.sse_c_key_md5_header().lower())
          return copyPartResponse
      
      def parseGetBucketReplication(self, xml, headers=None):
          root = ET.fromstring(xml)
          agency = None
          if self.is_obs:
              agency = self._find_item(root, './Agency')
          _rules = []
          rules = root.findall('./Rule')
          if rules is not None:
              for rule in rules:
                  _id = self._find_item(rule, './ID')
                  prefix = self._find_item(rule, './Prefix')
                  status = self._find_item(rule, './Status')
                  bucket = self._find_item(rule, './Destination/Bucket')
                  storageClass = self._find_item(rule, './Destination/StorageClass')
                  _rules.append(ReplicationRule(id=_id, prefix=prefix, status=status, bucket=bucket, storageClass=storageClass))
          replication = Replication(agency=agency, replicationRules=_rules)
          return replication
  
  