azure/multiapi/storage/v2017_04_17/blob/baseblobservice.py [259:1261]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        return url

    def generate_account_shared_access_signature(self, resource_types, permission,
                                                 expiry, start=None, ip=None, protocol=None):
        '''
        Generates a shared access signature for the blob service.
        Use the returned signature with the sas_token parameter of any BlobService.

        :param ResourceTypes resource_types:
            Specifies the resource types that are accessible with the account SAS.
        :param AccountPermissions permission:
            The permissions associated with the shared access signature. The 
            user is restricted to operations allowed by the permissions. 
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has been 
            specified in an associated stored access policy.
        :param expiry:
            The time at which the shared access signature becomes invalid. 
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has 
            been specified in an associated stored access policy. Azure will always 
            convert values to UTC. If a date is passed in without timezone info, it 
            is assumed to be UTC.
        :type expiry: datetime or str
        :param start:
            The time at which the shared access signature becomes valid. If 
            omitted, start time for this call is assumed to be the time when the 
            storage service receives the request. Azure will always convert values 
            to UTC. If a date is passed in without timezone info, it is assumed to 
            be UTC.
        :type start: datetime or str
        :param str ip:
            Specifies an IP address or a range of IP addresses from which to accept requests.
            If the IP address from which the request originates does not match the IP address
            or address range specified on the SAS token, the request is not authenticated.
            For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
            restricts the request to those IP addresses.
        :param str protocol:
            Specifies the protocol permitted for a request made. The default value
            is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values.
        :return: A Shared Access Signature (sas) token.
        :rtype: str
        '''
        _validate_not_none('self.account_name', self.account_name)
        _validate_not_none('self.account_key', self.account_key)

        sas = BlobSharedAccessSignature(self.account_name, self.account_key)
        return sas.generate_account(Services.BLOB, resource_types, permission,
                                    expiry, start=start, ip=ip, protocol=protocol)

    def generate_container_shared_access_signature(self, container_name,
                                                   permission=None, expiry=None,
                                                   start=None, id=None, ip=None, protocol=None,
                                                   cache_control=None, content_disposition=None,
                                                   content_encoding=None, content_language=None,
                                                   content_type=None):
        '''
        Generates a shared access signature for the container.
        Use the returned signature with the sas_token parameter of any BlobService.

        :param str container_name:
            Name of container.
        :param ContainerPermissions permission:
            The permissions associated with the shared access signature. The 
            user is restricted to operations allowed by the permissions.
            Permissions must be ordered read, write, delete, list.
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has been 
            specified in an associated stored access policy.
        :param expiry:
            The time at which the shared access signature becomes invalid. 
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has 
            been specified in an associated stored access policy. Azure will always 
            convert values to UTC. If a date is passed in without timezone info, it 
            is assumed to be UTC.
        :type expiry: datetime or str
        :param start:
            The time at which the shared access signature becomes valid. If 
            omitted, start time for this call is assumed to be the time when the 
            storage service receives the request. Azure will always convert values 
            to UTC. If a date is passed in without timezone info, it is assumed to 
            be UTC.
        :type start: datetime or str
        :param str id:
            A unique value up to 64 characters in length that correlates to a 
            stored access policy. To create a stored access policy, use 
            set_blob_service_properties.
        :param str ip:
            Specifies an IP address or a range of IP addresses from which to accept requests.
            If the IP address from which the request originates does not match the IP address
            or address range specified on the SAS token, the request is not authenticated.
            For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
            restricts the request to those IP addresses.
        :param str protocol:
            Specifies the protocol permitted for a request made. The default value
            is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values.
        :param str cache_control:
            Response header value for Cache-Control when resource is accessed
            using this shared access signature.
        :param str content_disposition:
            Response header value for Content-Disposition when resource is accessed
            using this shared access signature.
        :param str content_encoding:
            Response header value for Content-Encoding when resource is accessed
            using this shared access signature.
        :param str content_language:
            Response header value for Content-Language when resource is accessed
            using this shared access signature.
        :param str content_type:
            Response header value for Content-Type when resource is accessed
            using this shared access signature.
        :return: A Shared Access Signature (sas) token.
        :rtype: str
        '''
        _validate_not_none('container_name', container_name)
        _validate_not_none('self.account_name', self.account_name)
        _validate_not_none('self.account_key', self.account_key)

        sas = BlobSharedAccessSignature(self.account_name, self.account_key)
        return sas.generate_container(
            container_name,
            permission,
            expiry,
            start=start,
            id=id,
            ip=ip,
            protocol=protocol,
            cache_control=cache_control,
            content_disposition=content_disposition,
            content_encoding=content_encoding,
            content_language=content_language,
            content_type=content_type,
        )

    def generate_blob_shared_access_signature(
            self, container_name, blob_name, permission=None,
            expiry=None, start=None, id=None, ip=None, protocol=None,
            cache_control=None, content_disposition=None,
            content_encoding=None, content_language=None,
            content_type=None):
        '''
        Generates a shared access signature for the blob.
        Use the returned signature with the sas_token parameter of any BlobService.

        :param str container_name:
            Name of container.
        :param str blob_name:
            Name of blob.
        :param BlobPermissions permission:
            The permissions associated with the shared access signature. The 
            user is restricted to operations allowed by the permissions.
            Permissions must be ordered read, write, delete, list.
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has been 
            specified in an associated stored access policy.
        :param expiry:
            The time at which the shared access signature becomes invalid. 
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has 
            been specified in an associated stored access policy. Azure will always 
            convert values to UTC. If a date is passed in without timezone info, it 
            is assumed to be UTC.
        :type expiry: datetime or str
        :param start:
            The time at which the shared access signature becomes valid. If 
            omitted, start time for this call is assumed to be the time when the 
            storage service receives the request. Azure will always convert values 
            to UTC. If a date is passed in without timezone info, it is assumed to 
            be UTC.
        :type start: datetime or str
        :param str id:
            A unique value up to 64 characters in length that correlates to a 
            stored access policy. To create a stored access policy, use :func:`~set_container_acl`.
        :param str ip:
            Specifies an IP address or a range of IP addresses from which to accept requests.
            If the IP address from which the request originates does not match the IP address
            or address range specified on the SAS token, the request is not authenticated.
            For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
            restricts the request to those IP addresses.
        :param str protocol:
            Specifies the protocol permitted for a request made. The default value
            is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values.
        :param str cache_control:
            Response header value for Cache-Control when resource is accessed
            using this shared access signature.
        :param str content_disposition:
            Response header value for Content-Disposition when resource is accessed
            using this shared access signature.
        :param str content_encoding:
            Response header value for Content-Encoding when resource is accessed
            using this shared access signature.
        :param str content_language:
            Response header value for Content-Language when resource is accessed
            using this shared access signature.
        :param str content_type:
            Response header value for Content-Type when resource is accessed
            using this shared access signature.
        :return: A Shared Access Signature (sas) token.
        :rtype: str
        '''
        _validate_not_none('container_name', container_name)
        _validate_not_none('blob_name', blob_name)
        _validate_not_none('self.account_name', self.account_name)
        _validate_not_none('self.account_key', self.account_key)

        sas = BlobSharedAccessSignature(self.account_name, self.account_key)
        return sas.generate_blob(
            container_name,
            blob_name,
            permission,
            expiry,
            start=start,
            id=id,
            ip=ip,
            protocol=protocol,
            cache_control=cache_control,
            content_disposition=content_disposition,
            content_encoding=content_encoding,
            content_language=content_language,
            content_type=content_type,
        )

    def list_containers(self, prefix=None, num_results=None, include_metadata=False,
                        marker=None, timeout=None):
        '''
        Returns a generator to list the containers under the specified account.
        The generator will lazily follow the continuation tokens returned by
        the service and stop when all containers have been returned or num_results is reached.

        If num_results is specified and the account has more than that number of 
        containers, the generator will have a populated next_marker field once it 
        finishes. This marker can be used to create a new generator if more 
        results are desired.

        :param str prefix:
            Filters the results to return only containers whose names
            begin with the specified prefix.
        :param int num_results:
            Specifies the maximum number of containers to return. A single list
            request may return up to 1000 contianers and potentially a continuation
            token which should be followed to get additional resutls.
        :param bool include_metadata:
            Specifies that container metadata be returned in the response.
        :param str marker:
            An opaque continuation token. This value can be retrieved from the 
            next_marker field of a previous generator object if num_results was 
            specified and that generator has finished enumerating results. If 
            specified, this generator will begin returning results from the point 
            where the previous generator stopped.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        '''
        include = 'metadata' if include_metadata else None
        operation_context = _OperationContext(location_lock=True)
        kwargs = {'prefix': prefix, 'marker': marker, 'max_results': num_results,
                  'include': include, 'timeout': timeout, '_context': operation_context}
        resp = self._list_containers(**kwargs)

        return ListGenerator(resp, self._list_containers, (), kwargs)

    def _list_containers(self, prefix=None, marker=None, max_results=None,
                         include=None, timeout=None, _context=None):
        '''
        Returns a list of the containers under the specified account.

        :param str prefix:
            Filters the results to return only containers whose names
            begin with the specified prefix.
        :param str marker:
            A string value that identifies the portion of the list
            to be returned with the next list operation. The operation returns
            a next_marker value within the response body if the list returned was
            not complete. The marker value may then be used in a subsequent
            call to request the next set of list items. The marker value is
            opaque to the client.
        :param int max_results:
            Specifies the maximum number of containers to return. A single list
            request may return up to 1000 contianers and potentially a continuation
            token which should be followed to get additional resutls.
        :param str include:
            Include this parameter to specify that the container's
            metadata be returned as part of the response body. set this
            parameter to string 'metadata' to get container's metadata.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        '''
        request = HTTPRequest()
        request.method = 'GET'
        request.host_locations = self._get_host_locations(secondary=True)
        request.path = _get_path()
        request.query = {
            'comp': 'list',
            'prefix': _to_str(prefix),
            'marker': _to_str(marker),
            'maxresults': _int_to_str(max_results),
            'include': _to_str(include),
            'timeout': _int_to_str(timeout)
        }

        return self._perform_request(request, _convert_xml_to_containers, operation_context=_context)

    def create_container(self, container_name, metadata=None,
                         public_access=None, fail_on_exist=False, timeout=None):
        '''
        Creates a new container under the specified account. If the container
        with the same name already exists, the operation fails if
        fail_on_exist is True.

        :param str container_name:
            Name of container to create.
        :param metadata:
            A dict with name_value pairs to associate with the
            container as metadata. Example:{'Category':'test'}
        :type metadata: dict(str, str)
        :param ~azure.storage.blob.models.PublicAccess public_access:
            Possible values include: container, blob.
        :param bool fail_on_exist:
            Specify whether to throw an exception when the container exists.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: True if container is created, False if container already exists.
        :rtype: bool
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'PUT'
        request.host_locations = self._get_host_locations()
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {
            'x-ms-blob-public-access': _to_str(public_access)
        }
        _add_metadata_headers(metadata, request)

        if not fail_on_exist:
            try:
                self._perform_request(request)
                return True
            except AzureHttpError as ex:
                _dont_fail_on_exist(ex)
                return False
        else:
            self._perform_request(request)
            return True

    def get_container_properties(self, container_name, lease_id=None, timeout=None):
        '''
        Returns all user-defined metadata and system properties for the specified
        container. The data returned does not include the container's list of blobs.

        :param str container_name:
            Name of existing container.
        :param str lease_id:
            If specified, get_container_properties only succeeds if the
            container's lease is active and matches this ID.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: properties for the specified container within a container object.
        :rtype: :class:`~azure.storage.blob.models.Container`
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'GET'
        request.host_locations = self._get_host_locations(secondary=True)
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {'x-ms-lease-id': _to_str(lease_id)}

        return self._perform_request(request, _parse_container, [container_name])

    def get_container_metadata(self, container_name, lease_id=None, timeout=None):
        '''
        Returns all user-defined metadata for the specified container.

        :param str container_name:
            Name of existing container.
        :param str lease_id:
            If specified, get_container_metadata only succeeds if the
            container's lease is active and matches this ID.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return:
            A dictionary representing the container metadata name, value pairs.
        :rtype: dict(str, str)
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'GET'
        request.host_locations = self._get_host_locations(secondary=True)
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'comp': 'metadata',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {'x-ms-lease-id': _to_str(lease_id)}

        return self._perform_request(request, _parse_metadata)

    def set_container_metadata(self, container_name, metadata=None,
                               lease_id=None, if_modified_since=None, timeout=None):
        '''
        Sets one or more user-defined name-value pairs for the specified
        container. Each call to this operation replaces all existing metadata
        attached to the container. To remove all metadata from the container,
        call this operation with no metadata dict.

        :param str container_name:
            Name of existing container.
        :param metadata:
            A dict containing name-value pairs to associate with the container as 
            metadata. Example: {'category':'test'}
        :type metadata: dict(str, str)
        :param str lease_id:
            If specified, set_container_metadata only succeeds if the
            container's lease is active and matches this ID.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: ETag and last modified properties for the updated Container
        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'PUT'
        request.host_locations = self._get_host_locations()
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'comp': 'metadata',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {
            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
            'x-ms-lease-id': _to_str(lease_id),
        }
        _add_metadata_headers(metadata, request)

        return self._perform_request(request, _parse_base_properties)

    def get_container_acl(self, container_name, lease_id=None, timeout=None):
        '''
        Gets the permissions for the specified container.
        The permissions indicate whether container data may be accessed publicly.

        :param str container_name:
            Name of existing container.
        :param lease_id:
            If specified, get_container_acl only succeeds if the
            container's lease is active and matches this ID.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: A dictionary of access policies associated with the container. dict of str to
            :class:`azure.storage.common.models.AccessPolicy` and a public_access property
            if public access is turned on
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'GET'
        request.host_locations = self._get_host_locations(secondary=True)
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'comp': 'acl',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {'x-ms-lease-id': _to_str(lease_id)}

        return self._perform_request(request, _convert_xml_to_signed_identifiers_and_access)

    def set_container_acl(self, container_name, signed_identifiers=None,
                          public_access=None, lease_id=None,
                          if_modified_since=None, if_unmodified_since=None, timeout=None):
        '''
        Sets the permissions for the specified container or stored access 
        policies that may be used with Shared Access Signatures. The permissions
        indicate whether blobs in a container may be accessed publicly.

        :param str container_name:
            Name of existing container.
        :param signed_identifiers:
            A dictionary of access policies to associate with the container. The 
            dictionary may contain up to 5 elements. An empty dictionary 
            will clear the access policies set on the service. 
        :type signed_identifiers: dict(str, :class:`~azure.storage.common.models.AccessPolicy`)
        :param ~azure.storage.blob.models.PublicAccess public_access:
            Possible values include: container, blob.
        :param str lease_id:
            If specified, set_container_acl only succeeds if the
            container's lease is active and matches this ID.
        :param datetime if_modified_since:
            A datetime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified date/time.
        :param datetime if_unmodified_since:
            A datetime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: ETag and last modified properties for the updated Container
        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
        '''
        _validate_not_none('container_name', container_name)
        _validate_access_policies(signed_identifiers)
        request = HTTPRequest()
        request.method = 'PUT'
        request.host_locations = self._get_host_locations()
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'comp': 'acl',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {
            'x-ms-blob-public-access': _to_str(public_access),
            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
            'x-ms-lease-id': _to_str(lease_id),
        }
        request.body = _get_request_body(
            _convert_signed_identifiers_to_xml(signed_identifiers))

        return self._perform_request(request, _parse_base_properties)

    def delete_container(self, container_name, fail_not_exist=False,
                         lease_id=None, if_modified_since=None,
                         if_unmodified_since=None, timeout=None):
        '''
        Marks the specified container for deletion. The container and any blobs
        contained within it are later deleted during garbage collection.

        :param str container_name:
            Name of container to delete.
        :param bool fail_not_exist:
            Specify whether to throw an exception when the container doesn't
            exist.
        :param str lease_id:
            If specified, delete_container only succeeds if the
            container's lease is active and matches this ID.
            Required if the container has an active lease.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: True if container is deleted, False container doesn't exist.
        :rtype: bool
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'DELETE'
        request.host_locations = self._get_host_locations()
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {
            'x-ms-lease-id': _to_str(lease_id),
            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
        }

        if not fail_not_exist:
            try:
                self._perform_request(request)
                return True
            except AzureHttpError as ex:
                _dont_fail_not_exist(ex)
                return False
        else:
            self._perform_request(request)
            return True

    def _lease_container_impl(
            self, container_name, lease_action, lease_id, lease_duration,
            lease_break_period, proposed_lease_id, if_modified_since,
            if_unmodified_since, timeout):
        '''
        Establishes and manages a lease on a container.
        The Lease Container operation can be called in one of five modes
            Acquire, to request a new lease
            Renew, to renew an existing lease
            Change, to change the ID of an existing lease
            Release, to free the lease if it is no longer needed so that another
                client may immediately acquire a lease against the container
            Break, to end the lease but ensure that another client cannot acquire
                a new lease until the current lease period has expired

        :param str container_name:
            Name of existing container.
        :param str lease_action:
            Possible _LeaseActions values: acquire|renew|release|break|change
        :param str lease_id:
            Required if the container has an active lease.
        :param int lease_duration:
            Specifies the duration of the lease, in seconds, or negative one
            (-1) for a lease that never expires. A non-infinite lease can be
            between 15 and 60 seconds. A lease duration cannot be changed
            using renew or change. For backwards compatibility, the default is
            60, and the value is only used on an acquire operation.
        :param int lease_break_period:
            For a break operation, this is the proposed duration of
            seconds that the lease should continue before it is broken, between
            0 and 60 seconds. This break period is only used if it is shorter
            than the time remaining on the lease. If longer, the time remaining
            on the lease is used. A new lease will not be available before the
            break period has expired, but the lease may be held for longer than
            the break period. If this header does not appear with a break
            operation, a fixed-duration lease breaks after the remaining lease
            period elapses, and an infinite lease breaks immediately.
        :param str proposed_lease_id:
            Optional for Acquire, required for Change. Proposed lease ID, in a
            GUID string format. The Blob service returns 400 (Invalid request)
            if the proposed lease ID is not in the correct format.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return:
            Response headers returned from the service call.
        :rtype: dict(str, str)
        '''
        _validate_not_none('container_name', container_name)
        _validate_not_none('lease_action', lease_action)
        request = HTTPRequest()
        request.method = 'PUT'
        request.host_locations = self._get_host_locations()
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'comp': 'lease',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {
            'x-ms-lease-id': _to_str(lease_id),
            'x-ms-lease-action': _to_str(lease_action),
            'x-ms-lease-duration': _to_str(lease_duration),
            'x-ms-lease-break-period': _to_str(lease_break_period),
            'x-ms-proposed-lease-id': _to_str(proposed_lease_id),
            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
        }

        return self._perform_request(request, _parse_lease)

    def acquire_container_lease(
            self, container_name, lease_duration=-1, proposed_lease_id=None,
            if_modified_since=None, if_unmodified_since=None, timeout=None):
        '''
        Requests a new lease. If the container does not have an active lease,
        the Blob service creates a lease on the container and returns a new
        lease ID.

        :param str container_name:
            Name of existing container.
        :param int lease_duration:
            Specifies the duration of the lease, in seconds, or negative one
            (-1) for a lease that never expires. A non-infinite lease can be
            between 15 and 60 seconds. A lease duration cannot be changed
            using renew or change. Default is -1 (infinite lease).
        :param str proposed_lease_id:
            Proposed lease ID, in a GUID string format. The Blob service returns
            400 (Invalid request) if the proposed lease ID is not in the correct format.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: the lease ID of the newly created lease.
        :return: str
        '''
        _validate_not_none('lease_duration', lease_duration)
        if lease_duration != -1 and \
                (lease_duration < 15 or lease_duration > 60):
            raise ValueError(_ERROR_INVALID_LEASE_DURATION)

        lease = self._lease_container_impl(container_name,
                                           _LeaseActions.Acquire,
                                           None,  # lease_id
                                           lease_duration,
                                           None,  # lease_break_period
                                           proposed_lease_id,
                                           if_modified_since,
                                           if_unmodified_since,
                                           timeout)
        return lease['id']

    def renew_container_lease(
            self, container_name, lease_id, if_modified_since=None,
            if_unmodified_since=None, timeout=None):
        '''
        Renews the lease. The lease can be renewed if the lease ID specified
        matches that associated with the container. Note that
        the lease may be renewed even if it has expired as long as the container
        has not been leased again since the expiration of that lease. When you
        renew a lease, the lease duration clock resets.
        
        :param str container_name:
            Name of existing container.
        :param str lease_id:
            Lease ID for active lease.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: the lease ID of the renewed lease.
        :return: str
        '''
        _validate_not_none('lease_id', lease_id)

        lease = self._lease_container_impl(container_name,
                                           _LeaseActions.Renew,
                                           lease_id,
                                           None,  # lease_duration
                                           None,  # lease_break_period
                                           None,  # proposed_lease_id
                                           if_modified_since,
                                           if_unmodified_since,
                                           timeout)
        return lease['id']

    def release_container_lease(
            self, container_name, lease_id, if_modified_since=None,
            if_unmodified_since=None, timeout=None):
        '''
        Release the lease. The lease may be released if the lease_id specified matches
        that associated with the container. Releasing the lease allows another client
        to immediately acquire the lease for the container as soon as the release is complete. 

        :param str container_name:
            Name of existing container.
        :param str lease_id:
            Lease ID for active lease.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        '''
        _validate_not_none('lease_id', lease_id)

        self._lease_container_impl(container_name,
                                   _LeaseActions.Release,
                                   lease_id,
                                   None,  # lease_duration
                                   None,  # lease_break_period
                                   None,  # proposed_lease_id
                                   if_modified_since,
                                   if_unmodified_since,
                                   timeout)

    def break_container_lease(
            self, container_name, lease_break_period=None,
            if_modified_since=None, if_unmodified_since=None, timeout=None):
        '''
        Break the lease, if the container has an active lease. Once a lease is
        broken, it cannot be renewed. Any authorized request can break the lease;
        the request is not required to specify a matching lease ID. When a lease
        is broken, the lease break period is allowed to elapse, during which time
        no lease operation except break and release can be performed on the container.
        When a lease is successfully broken, the response indicates the interval
        in seconds until a new lease can be acquired. 

        :param str container_name:
            Name of existing container.
        :param int lease_break_period:
            This is the proposed duration of seconds that the lease
            should continue before it is broken, between 0 and 60 seconds. This
            break period is only used if it is shorter than the time remaining
            on the lease. If longer, the time remaining on the lease is used.
            A new lease will not be available before the break period has
            expired, but the lease may be held for longer than the break
            period. If this header does not appear with a break
            operation, a fixed-duration lease breaks after the remaining lease
            period elapses, and an infinite lease breaks immediately.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: Approximate time remaining in the lease period, in seconds.
        :return: int
        '''
        if (lease_break_period is not None) and (lease_break_period < 0 or lease_break_period > 60):
            raise ValueError(_ERROR_INVALID_LEASE_BREAK_PERIOD)

        lease = self._lease_container_impl(container_name,
                                           _LeaseActions.Break,
                                           None,  # lease_id
                                           None,  # lease_duration
                                           lease_break_period,
                                           None,  # proposed_lease_id
                                           if_modified_since,
                                           if_unmodified_since,
                                           timeout)
        return lease['time']

    def change_container_lease(
            self, container_name, lease_id, proposed_lease_id,
            if_modified_since=None, if_unmodified_since=None, timeout=None):
        '''
        Change the lease ID of an active lease. A change must include the current
        lease ID and a new lease ID.

        :param str container_name:
            Name of existing container.
        :param str lease_id:
            Lease ID for active lease.
        :param str proposed_lease_id:
            Proposed lease ID, in a GUID string format. The Blob service returns 400
            (Invalid request) if the proposed lease ID is not in the correct format.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        '''
        _validate_not_none('lease_id', lease_id)

        self._lease_container_impl(container_name,
                                   _LeaseActions.Change,
                                   lease_id,
                                   None,  # lease_duration
                                   None,  # lease_break_period
                                   proposed_lease_id,
                                   if_modified_since,
                                   if_unmodified_since,
                                   timeout)

    def list_blobs(self, container_name, prefix=None, num_results=None, include=None,
                   delimiter=None, marker=None, timeout=None):
        '''
        Returns a generator to list the blobs under the specified container.
        The generator will lazily follow the continuation tokens returned by
        the service and stop when all blobs have been returned or num_results is reached.

        If num_results is specified and the account has more than that number of 
        blobs, the generator will have a populated next_marker field once it 
        finishes. This marker can be used to create a new generator if more 
        results are desired.

        :param str container_name:
            Name of existing container.
        :param str prefix:
            Filters the results to return only blobs whose names
            begin with the specified prefix.
        :param int num_results:
            Specifies the maximum number of blobs to return,
            including all :class:`BlobPrefix` elements. If the request does not specify
            num_results or specifies a value greater than 5,000, the server will
            return up to 5,000 items. Setting num_results to a value less than
            or equal to zero results in error response code 400 (Bad Request).
        :param ~azure.storage.blob.models.Include include:
            Specifies one or more additional datasets to include in the response.
        :param str delimiter:
            When the request includes this parameter, the operation
            returns a :class:`~azure.storage.blob.models.BlobPrefix` element in the
            result list that acts as a placeholder for all blobs whose names begin
            with the same substring up to the appearance of the delimiter character.
            The delimiter may be a single character or a string.
        :param str marker:
            An opaque continuation token. This value can be retrieved from the 
            next_marker field of a previous generator object if num_results was 
            specified and that generator has finished enumerating results. If 
            specified, this generator will begin returning results from the point 
            where the previous generator stopped.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        '''
        operation_context = _OperationContext(location_lock=True)
        args = (container_name,)
        kwargs = {'prefix': prefix, 'marker': marker, 'max_results': num_results,
                  'include': include, 'delimiter': delimiter, 'timeout': timeout,
                  '_context': operation_context}
        resp = self._list_blobs(*args, **kwargs)

        return ListGenerator(resp, self._list_blobs, args, kwargs)

    def _list_blobs(self, container_name, prefix=None, marker=None,
                    max_results=None, include=None, delimiter=None, timeout=None,
                    _context=None):
        '''
        Returns the list of blobs under the specified container.

        :param str container_name:
            Name of existing container.
        :parm str prefix:
            Filters the results to return only blobs whose names
            begin with the specified prefix.
        :param str marker:
            A string value that identifies the portion of the list
            to be returned with the next list operation. The operation returns
            a next_marker value within the response body if the list returned was
            not complete. The marker value may then be used in a subsequent
            call to request the next set of list items. The marker value is
            opaque to the client.
        :param int max_results:
            Specifies the maximum number of blobs to return,
            including all :class:`~azure.storage.blob.models.BlobPrefix` elements. If the request does not specify
            max_results or specifies a value greater than 5,000, the server will
            return up to 5,000 items. Setting max_results to a value less than
            or equal to zero results in error response code 400 (Bad Request).
        :param str include:
            Specifies one or more datasets to include in the
            response. To specify more than one of these options on the URI,
            you must separate each option with a comma. Valid values are:
                snapshots:
                    Specifies that snapshots should be included in the
                    enumeration. Snapshots are listed from oldest to newest in
                    the response.
                metadata:
                    Specifies that blob metadata be returned in the response.
                uncommittedblobs:
                    Specifies that blobs for which blocks have been uploaded,
                    but which have not been committed using Put Block List
                    (REST API), be included in the response.
                copy:
                    Version 2012-02-12 and newer. Specifies that metadata
                    related to any current or previous Copy Blob operation
                    should be included in the response.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



azure/multiapi/storage/v2017_11_09/blob/baseblobservice.py [285:1287]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        return url

    def generate_account_shared_access_signature(self, resource_types, permission,
                                                 expiry, start=None, ip=None, protocol=None):
        '''
        Generates a shared access signature for the blob service.
        Use the returned signature with the sas_token parameter of any BlobService.

        :param ResourceTypes resource_types:
            Specifies the resource types that are accessible with the account SAS.
        :param AccountPermissions permission:
            The permissions associated with the shared access signature. The 
            user is restricted to operations allowed by the permissions. 
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has been 
            specified in an associated stored access policy.
        :param expiry:
            The time at which the shared access signature becomes invalid. 
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has 
            been specified in an associated stored access policy. Azure will always 
            convert values to UTC. If a date is passed in without timezone info, it 
            is assumed to be UTC.
        :type expiry: datetime or str
        :param start:
            The time at which the shared access signature becomes valid. If 
            omitted, start time for this call is assumed to be the time when the 
            storage service receives the request. Azure will always convert values 
            to UTC. If a date is passed in without timezone info, it is assumed to 
            be UTC.
        :type start: datetime or str
        :param str ip:
            Specifies an IP address or a range of IP addresses from which to accept requests.
            If the IP address from which the request originates does not match the IP address
            or address range specified on the SAS token, the request is not authenticated.
            For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
            restricts the request to those IP addresses.
        :param str protocol:
            Specifies the protocol permitted for a request made. The default value
            is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values.
        :return: A Shared Access Signature (sas) token.
        :rtype: str
        '''
        _validate_not_none('self.account_name', self.account_name)
        _validate_not_none('self.account_key', self.account_key)

        sas = BlobSharedAccessSignature(self.account_name, self.account_key)
        return sas.generate_account(Services.BLOB, resource_types, permission,
                                    expiry, start=start, ip=ip, protocol=protocol)

    def generate_container_shared_access_signature(self, container_name,
                                                   permission=None, expiry=None,
                                                   start=None, id=None, ip=None, protocol=None,
                                                   cache_control=None, content_disposition=None,
                                                   content_encoding=None, content_language=None,
                                                   content_type=None):
        '''
        Generates a shared access signature for the container.
        Use the returned signature with the sas_token parameter of any BlobService.

        :param str container_name:
            Name of container.
        :param ContainerPermissions permission:
            The permissions associated with the shared access signature. The 
            user is restricted to operations allowed by the permissions.
            Permissions must be ordered read, write, delete, list.
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has been 
            specified in an associated stored access policy.
        :param expiry:
            The time at which the shared access signature becomes invalid. 
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has 
            been specified in an associated stored access policy. Azure will always 
            convert values to UTC. If a date is passed in without timezone info, it 
            is assumed to be UTC.
        :type expiry: datetime or str
        :param start:
            The time at which the shared access signature becomes valid. If 
            omitted, start time for this call is assumed to be the time when the 
            storage service receives the request. Azure will always convert values 
            to UTC. If a date is passed in without timezone info, it is assumed to 
            be UTC.
        :type start: datetime or str
        :param str id:
            A unique value up to 64 characters in length that correlates to a 
            stored access policy. To create a stored access policy, use 
            set_blob_service_properties.
        :param str ip:
            Specifies an IP address or a range of IP addresses from which to accept requests.
            If the IP address from which the request originates does not match the IP address
            or address range specified on the SAS token, the request is not authenticated.
            For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
            restricts the request to those IP addresses.
        :param str protocol:
            Specifies the protocol permitted for a request made. The default value
            is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values.
        :param str cache_control:
            Response header value for Cache-Control when resource is accessed
            using this shared access signature.
        :param str content_disposition:
            Response header value for Content-Disposition when resource is accessed
            using this shared access signature.
        :param str content_encoding:
            Response header value for Content-Encoding when resource is accessed
            using this shared access signature.
        :param str content_language:
            Response header value for Content-Language when resource is accessed
            using this shared access signature.
        :param str content_type:
            Response header value for Content-Type when resource is accessed
            using this shared access signature.
        :return: A Shared Access Signature (sas) token.
        :rtype: str
        '''
        _validate_not_none('container_name', container_name)
        _validate_not_none('self.account_name', self.account_name)
        _validate_not_none('self.account_key', self.account_key)

        sas = BlobSharedAccessSignature(self.account_name, self.account_key)
        return sas.generate_container(
            container_name,
            permission,
            expiry,
            start=start,
            id=id,
            ip=ip,
            protocol=protocol,
            cache_control=cache_control,
            content_disposition=content_disposition,
            content_encoding=content_encoding,
            content_language=content_language,
            content_type=content_type,
        )

    def generate_blob_shared_access_signature(
            self, container_name, blob_name, permission=None,
            expiry=None, start=None, id=None, ip=None, protocol=None,
            cache_control=None, content_disposition=None,
            content_encoding=None, content_language=None,
            content_type=None):
        '''
        Generates a shared access signature for the blob.
        Use the returned signature with the sas_token parameter of any BlobService.

        :param str container_name:
            Name of container.
        :param str blob_name:
            Name of blob.
        :param BlobPermissions permission:
            The permissions associated with the shared access signature. The 
            user is restricted to operations allowed by the permissions.
            Permissions must be ordered read, write, delete, list.
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has been 
            specified in an associated stored access policy.
        :param expiry:
            The time at which the shared access signature becomes invalid. 
            Required unless an id is given referencing a stored access policy 
            which contains this field. This field must be omitted if it has 
            been specified in an associated stored access policy. Azure will always 
            convert values to UTC. If a date is passed in without timezone info, it 
            is assumed to be UTC.
        :type expiry: datetime or str
        :param start:
            The time at which the shared access signature becomes valid. If 
            omitted, start time for this call is assumed to be the time when the 
            storage service receives the request. Azure will always convert values 
            to UTC. If a date is passed in without timezone info, it is assumed to 
            be UTC.
        :type start: datetime or str
        :param str id:
            A unique value up to 64 characters in length that correlates to a 
            stored access policy. To create a stored access policy, use :func:`~set_container_acl`.
        :param str ip:
            Specifies an IP address or a range of IP addresses from which to accept requests.
            If the IP address from which the request originates does not match the IP address
            or address range specified on the SAS token, the request is not authenticated.
            For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
            restricts the request to those IP addresses.
        :param str protocol:
            Specifies the protocol permitted for a request made. The default value
            is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values.
        :param str cache_control:
            Response header value for Cache-Control when resource is accessed
            using this shared access signature.
        :param str content_disposition:
            Response header value for Content-Disposition when resource is accessed
            using this shared access signature.
        :param str content_encoding:
            Response header value for Content-Encoding when resource is accessed
            using this shared access signature.
        :param str content_language:
            Response header value for Content-Language when resource is accessed
            using this shared access signature.
        :param str content_type:
            Response header value for Content-Type when resource is accessed
            using this shared access signature.
        :return: A Shared Access Signature (sas) token.
        :rtype: str
        '''
        _validate_not_none('container_name', container_name)
        _validate_not_none('blob_name', blob_name)
        _validate_not_none('self.account_name', self.account_name)
        _validate_not_none('self.account_key', self.account_key)

        sas = BlobSharedAccessSignature(self.account_name, self.account_key)
        return sas.generate_blob(
            container_name,
            blob_name,
            permission,
            expiry,
            start=start,
            id=id,
            ip=ip,
            protocol=protocol,
            cache_control=cache_control,
            content_disposition=content_disposition,
            content_encoding=content_encoding,
            content_language=content_language,
            content_type=content_type,
        )

    def list_containers(self, prefix=None, num_results=None, include_metadata=False,
                        marker=None, timeout=None):
        '''
        Returns a generator to list the containers under the specified account.
        The generator will lazily follow the continuation tokens returned by
        the service and stop when all containers have been returned or num_results is reached.

        If num_results is specified and the account has more than that number of 
        containers, the generator will have a populated next_marker field once it 
        finishes. This marker can be used to create a new generator if more 
        results are desired.

        :param str prefix:
            Filters the results to return only containers whose names
            begin with the specified prefix.
        :param int num_results:
            Specifies the maximum number of containers to return. A single list
            request may return up to 1000 contianers and potentially a continuation
            token which should be followed to get additional resutls.
        :param bool include_metadata:
            Specifies that container metadata be returned in the response.
        :param str marker:
            An opaque continuation token. This value can be retrieved from the 
            next_marker field of a previous generator object if num_results was 
            specified and that generator has finished enumerating results. If 
            specified, this generator will begin returning results from the point 
            where the previous generator stopped.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        '''
        include = 'metadata' if include_metadata else None
        operation_context = _OperationContext(location_lock=True)
        kwargs = {'prefix': prefix, 'marker': marker, 'max_results': num_results,
                  'include': include, 'timeout': timeout, '_context': operation_context}
        resp = self._list_containers(**kwargs)

        return ListGenerator(resp, self._list_containers, (), kwargs)

    def _list_containers(self, prefix=None, marker=None, max_results=None,
                         include=None, timeout=None, _context=None):
        '''
        Returns a list of the containers under the specified account.

        :param str prefix:
            Filters the results to return only containers whose names
            begin with the specified prefix.
        :param str marker:
            A string value that identifies the portion of the list
            to be returned with the next list operation. The operation returns
            a next_marker value within the response body if the list returned was
            not complete. The marker value may then be used in a subsequent
            call to request the next set of list items. The marker value is
            opaque to the client.
        :param int max_results:
            Specifies the maximum number of containers to return. A single list
            request may return up to 1000 contianers and potentially a continuation
            token which should be followed to get additional resutls.
        :param str include:
            Include this parameter to specify that the container's
            metadata be returned as part of the response body. set this
            parameter to string 'metadata' to get container's metadata.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        '''
        request = HTTPRequest()
        request.method = 'GET'
        request.host_locations = self._get_host_locations(secondary=True)
        request.path = _get_path()
        request.query = {
            'comp': 'list',
            'prefix': _to_str(prefix),
            'marker': _to_str(marker),
            'maxresults': _int_to_str(max_results),
            'include': _to_str(include),
            'timeout': _int_to_str(timeout)
        }

        return self._perform_request(request, _convert_xml_to_containers, operation_context=_context)

    def create_container(self, container_name, metadata=None,
                         public_access=None, fail_on_exist=False, timeout=None):
        '''
        Creates a new container under the specified account. If the container
        with the same name already exists, the operation fails if
        fail_on_exist is True.

        :param str container_name:
            Name of container to create.
        :param metadata:
            A dict with name_value pairs to associate with the
            container as metadata. Example:{'Category':'test'}
        :type metadata: dict(str, str)
        :param ~azure.storage.blob.models.PublicAccess public_access:
            Possible values include: container, blob.
        :param bool fail_on_exist:
            Specify whether to throw an exception when the container exists.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: True if container is created, False if container already exists.
        :rtype: bool
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'PUT'
        request.host_locations = self._get_host_locations()
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {
            'x-ms-blob-public-access': _to_str(public_access)
        }
        _add_metadata_headers(metadata, request)

        if not fail_on_exist:
            try:
                self._perform_request(request)
                return True
            except AzureHttpError as ex:
                _dont_fail_on_exist(ex)
                return False
        else:
            self._perform_request(request)
            return True

    def get_container_properties(self, container_name, lease_id=None, timeout=None):
        '''
        Returns all user-defined metadata and system properties for the specified
        container. The data returned does not include the container's list of blobs.

        :param str container_name:
            Name of existing container.
        :param str lease_id:
            If specified, get_container_properties only succeeds if the
            container's lease is active and matches this ID.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: properties for the specified container within a container object.
        :rtype: :class:`~azure.storage.blob.models.Container`
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'GET'
        request.host_locations = self._get_host_locations(secondary=True)
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {'x-ms-lease-id': _to_str(lease_id)}

        return self._perform_request(request, _parse_container, [container_name])

    def get_container_metadata(self, container_name, lease_id=None, timeout=None):
        '''
        Returns all user-defined metadata for the specified container.

        :param str container_name:
            Name of existing container.
        :param str lease_id:
            If specified, get_container_metadata only succeeds if the
            container's lease is active and matches this ID.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return:
            A dictionary representing the container metadata name, value pairs.
        :rtype: dict(str, str)
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'GET'
        request.host_locations = self._get_host_locations(secondary=True)
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'comp': 'metadata',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {'x-ms-lease-id': _to_str(lease_id)}

        return self._perform_request(request, _parse_metadata)

    def set_container_metadata(self, container_name, metadata=None,
                               lease_id=None, if_modified_since=None, timeout=None):
        '''
        Sets one or more user-defined name-value pairs for the specified
        container. Each call to this operation replaces all existing metadata
        attached to the container. To remove all metadata from the container,
        call this operation with no metadata dict.

        :param str container_name:
            Name of existing container.
        :param metadata:
            A dict containing name-value pairs to associate with the container as 
            metadata. Example: {'category':'test'}
        :type metadata: dict(str, str)
        :param str lease_id:
            If specified, set_container_metadata only succeeds if the
            container's lease is active and matches this ID.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: ETag and last modified properties for the updated Container
        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'PUT'
        request.host_locations = self._get_host_locations()
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'comp': 'metadata',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {
            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
            'x-ms-lease-id': _to_str(lease_id),
        }
        _add_metadata_headers(metadata, request)

        return self._perform_request(request, _parse_base_properties)

    def get_container_acl(self, container_name, lease_id=None, timeout=None):
        '''
        Gets the permissions for the specified container.
        The permissions indicate whether container data may be accessed publicly.

        :param str container_name:
            Name of existing container.
        :param lease_id:
            If specified, get_container_acl only succeeds if the
            container's lease is active and matches this ID.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: A dictionary of access policies associated with the container. dict of str to
            :class:`azure.storage.common.models.AccessPolicy` and a public_access property
            if public access is turned on
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'GET'
        request.host_locations = self._get_host_locations(secondary=True)
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'comp': 'acl',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {'x-ms-lease-id': _to_str(lease_id)}

        return self._perform_request(request, _convert_xml_to_signed_identifiers_and_access)

    def set_container_acl(self, container_name, signed_identifiers=None,
                          public_access=None, lease_id=None,
                          if_modified_since=None, if_unmodified_since=None, timeout=None):
        '''
        Sets the permissions for the specified container or stored access 
        policies that may be used with Shared Access Signatures. The permissions
        indicate whether blobs in a container may be accessed publicly.

        :param str container_name:
            Name of existing container.
        :param signed_identifiers:
            A dictionary of access policies to associate with the container. The 
            dictionary may contain up to 5 elements. An empty dictionary 
            will clear the access policies set on the service. 
        :type signed_identifiers: dict(str, :class:`~azure.storage.common.models.AccessPolicy`)
        :param ~azure.storage.blob.models.PublicAccess public_access:
            Possible values include: container, blob.
        :param str lease_id:
            If specified, set_container_acl only succeeds if the
            container's lease is active and matches this ID.
        :param datetime if_modified_since:
            A datetime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified date/time.
        :param datetime if_unmodified_since:
            A datetime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: ETag and last modified properties for the updated Container
        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
        '''
        _validate_not_none('container_name', container_name)
        _validate_access_policies(signed_identifiers)
        request = HTTPRequest()
        request.method = 'PUT'
        request.host_locations = self._get_host_locations()
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'comp': 'acl',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {
            'x-ms-blob-public-access': _to_str(public_access),
            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
            'x-ms-lease-id': _to_str(lease_id),
        }
        request.body = _get_request_body(
            _convert_signed_identifiers_to_xml(signed_identifiers))

        return self._perform_request(request, _parse_base_properties)

    def delete_container(self, container_name, fail_not_exist=False,
                         lease_id=None, if_modified_since=None,
                         if_unmodified_since=None, timeout=None):
        '''
        Marks the specified container for deletion. The container and any blobs
        contained within it are later deleted during garbage collection.

        :param str container_name:
            Name of container to delete.
        :param bool fail_not_exist:
            Specify whether to throw an exception when the container doesn't
            exist.
        :param str lease_id:
            If specified, delete_container only succeeds if the
            container's lease is active and matches this ID.
            Required if the container has an active lease.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: True if container is deleted, False container doesn't exist.
        :rtype: bool
        '''
        _validate_not_none('container_name', container_name)
        request = HTTPRequest()
        request.method = 'DELETE'
        request.host_locations = self._get_host_locations()
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {
            'x-ms-lease-id': _to_str(lease_id),
            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
        }

        if not fail_not_exist:
            try:
                self._perform_request(request)
                return True
            except AzureHttpError as ex:
                _dont_fail_not_exist(ex)
                return False
        else:
            self._perform_request(request)
            return True

    def _lease_container_impl(
            self, container_name, lease_action, lease_id, lease_duration,
            lease_break_period, proposed_lease_id, if_modified_since,
            if_unmodified_since, timeout):
        '''
        Establishes and manages a lease on a container.
        The Lease Container operation can be called in one of five modes
            Acquire, to request a new lease
            Renew, to renew an existing lease
            Change, to change the ID of an existing lease
            Release, to free the lease if it is no longer needed so that another
                client may immediately acquire a lease against the container
            Break, to end the lease but ensure that another client cannot acquire
                a new lease until the current lease period has expired

        :param str container_name:
            Name of existing container.
        :param str lease_action:
            Possible _LeaseActions values: acquire|renew|release|break|change
        :param str lease_id:
            Required if the container has an active lease.
        :param int lease_duration:
            Specifies the duration of the lease, in seconds, or negative one
            (-1) for a lease that never expires. A non-infinite lease can be
            between 15 and 60 seconds. A lease duration cannot be changed
            using renew or change. For backwards compatibility, the default is
            60, and the value is only used on an acquire operation.
        :param int lease_break_period:
            For a break operation, this is the proposed duration of
            seconds that the lease should continue before it is broken, between
            0 and 60 seconds. This break period is only used if it is shorter
            than the time remaining on the lease. If longer, the time remaining
            on the lease is used. A new lease will not be available before the
            break period has expired, but the lease may be held for longer than
            the break period. If this header does not appear with a break
            operation, a fixed-duration lease breaks after the remaining lease
            period elapses, and an infinite lease breaks immediately.
        :param str proposed_lease_id:
            Optional for Acquire, required for Change. Proposed lease ID, in a
            GUID string format. The Blob service returns 400 (Invalid request)
            if the proposed lease ID is not in the correct format.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return:
            Response headers returned from the service call.
        :rtype: dict(str, str)
        '''
        _validate_not_none('container_name', container_name)
        _validate_not_none('lease_action', lease_action)
        request = HTTPRequest()
        request.method = 'PUT'
        request.host_locations = self._get_host_locations()
        request.path = _get_path(container_name)
        request.query = {
            'restype': 'container',
            'comp': 'lease',
            'timeout': _int_to_str(timeout),
        }
        request.headers = {
            'x-ms-lease-id': _to_str(lease_id),
            'x-ms-lease-action': _to_str(lease_action),
            'x-ms-lease-duration': _to_str(lease_duration),
            'x-ms-lease-break-period': _to_str(lease_break_period),
            'x-ms-proposed-lease-id': _to_str(proposed_lease_id),
            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
        }

        return self._perform_request(request, _parse_lease)

    def acquire_container_lease(
            self, container_name, lease_duration=-1, proposed_lease_id=None,
            if_modified_since=None, if_unmodified_since=None, timeout=None):
        '''
        Requests a new lease. If the container does not have an active lease,
        the Blob service creates a lease on the container and returns a new
        lease ID.

        :param str container_name:
            Name of existing container.
        :param int lease_duration:
            Specifies the duration of the lease, in seconds, or negative one
            (-1) for a lease that never expires. A non-infinite lease can be
            between 15 and 60 seconds. A lease duration cannot be changed
            using renew or change. Default is -1 (infinite lease).
        :param str proposed_lease_id:
            Proposed lease ID, in a GUID string format. The Blob service returns
            400 (Invalid request) if the proposed lease ID is not in the correct format.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: the lease ID of the newly created lease.
        :return: str
        '''
        _validate_not_none('lease_duration', lease_duration)
        if lease_duration != -1 and \
                (lease_duration < 15 or lease_duration > 60):
            raise ValueError(_ERROR_INVALID_LEASE_DURATION)

        lease = self._lease_container_impl(container_name,
                                           _LeaseActions.Acquire,
                                           None,  # lease_id
                                           lease_duration,
                                           None,  # lease_break_period
                                           proposed_lease_id,
                                           if_modified_since,
                                           if_unmodified_since,
                                           timeout)
        return lease['id']

    def renew_container_lease(
            self, container_name, lease_id, if_modified_since=None,
            if_unmodified_since=None, timeout=None):
        '''
        Renews the lease. The lease can be renewed if the lease ID specified
        matches that associated with the container. Note that
        the lease may be renewed even if it has expired as long as the container
        has not been leased again since the expiration of that lease. When you
        renew a lease, the lease duration clock resets.
        
        :param str container_name:
            Name of existing container.
        :param str lease_id:
            Lease ID for active lease.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: the lease ID of the renewed lease.
        :return: str
        '''
        _validate_not_none('lease_id', lease_id)

        lease = self._lease_container_impl(container_name,
                                           _LeaseActions.Renew,
                                           lease_id,
                                           None,  # lease_duration
                                           None,  # lease_break_period
                                           None,  # proposed_lease_id
                                           if_modified_since,
                                           if_unmodified_since,
                                           timeout)
        return lease['id']

    def release_container_lease(
            self, container_name, lease_id, if_modified_since=None,
            if_unmodified_since=None, timeout=None):
        '''
        Release the lease. The lease may be released if the lease_id specified matches
        that associated with the container. Releasing the lease allows another client
        to immediately acquire the lease for the container as soon as the release is complete. 

        :param str container_name:
            Name of existing container.
        :param str lease_id:
            Lease ID for active lease.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        '''
        _validate_not_none('lease_id', lease_id)

        self._lease_container_impl(container_name,
                                   _LeaseActions.Release,
                                   lease_id,
                                   None,  # lease_duration
                                   None,  # lease_break_period
                                   None,  # proposed_lease_id
                                   if_modified_since,
                                   if_unmodified_since,
                                   timeout)

    def break_container_lease(
            self, container_name, lease_break_period=None,
            if_modified_since=None, if_unmodified_since=None, timeout=None):
        '''
        Break the lease, if the container has an active lease. Once a lease is
        broken, it cannot be renewed. Any authorized request can break the lease;
        the request is not required to specify a matching lease ID. When a lease
        is broken, the lease break period is allowed to elapse, during which time
        no lease operation except break and release can be performed on the container.
        When a lease is successfully broken, the response indicates the interval
        in seconds until a new lease can be acquired. 

        :param str container_name:
            Name of existing container.
        :param int lease_break_period:
            This is the proposed duration of seconds that the lease
            should continue before it is broken, between 0 and 60 seconds. This
            break period is only used if it is shorter than the time remaining
            on the lease. If longer, the time remaining on the lease is used.
            A new lease will not be available before the break period has
            expired, but the lease may be held for longer than the break
            period. If this header does not appear with a break
            operation, a fixed-duration lease breaks after the remaining lease
            period elapses, and an infinite lease breaks immediately.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        :return: Approximate time remaining in the lease period, in seconds.
        :return: int
        '''
        if (lease_break_period is not None) and (lease_break_period < 0 or lease_break_period > 60):
            raise ValueError(_ERROR_INVALID_LEASE_BREAK_PERIOD)

        lease = self._lease_container_impl(container_name,
                                           _LeaseActions.Break,
                                           None,  # lease_id
                                           None,  # lease_duration
                                           lease_break_period,
                                           None,  # proposed_lease_id
                                           if_modified_since,
                                           if_unmodified_since,
                                           timeout)
        return lease['time']

    def change_container_lease(
            self, container_name, lease_id, proposed_lease_id,
            if_modified_since=None, if_unmodified_since=None, timeout=None):
        '''
        Change the lease ID of an active lease. A change must include the current
        lease ID and a new lease ID.

        :param str container_name:
            Name of existing container.
        :param str lease_id:
            Lease ID for active lease.
        :param str proposed_lease_id:
            Proposed lease ID, in a GUID string format. The Blob service returns 400
            (Invalid request) if the proposed lease ID is not in the correct format.
        :param datetime if_modified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC. 
            Specify this header to perform the operation only
            if the resource has been modified since the specified time.
        :param datetime if_unmodified_since:
            A DateTime value. Azure expects the date value passed in to be UTC.
            If timezone is included, any non-UTC datetimes will be converted to UTC.
            If a date is passed in without timezone info, it is assumed to be UTC.
            Specify this header to perform the operation only if
            the resource has not been modified since the specified date/time.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        '''
        _validate_not_none('lease_id', lease_id)

        self._lease_container_impl(container_name,
                                   _LeaseActions.Change,
                                   lease_id,
                                   None,  # lease_duration
                                   None,  # lease_break_period
                                   proposed_lease_id,
                                   if_modified_since,
                                   if_unmodified_since,
                                   timeout)

    def list_blobs(self, container_name, prefix=None, num_results=None, include=None,
                   delimiter=None, marker=None, timeout=None):
        '''
        Returns a generator to list the blobs under the specified container.
        The generator will lazily follow the continuation tokens returned by
        the service and stop when all blobs have been returned or num_results is reached.

        If num_results is specified and the account has more than that number of 
        blobs, the generator will have a populated next_marker field once it 
        finishes. This marker can be used to create a new generator if more 
        results are desired.

        :param str container_name:
            Name of existing container.
        :param str prefix:
            Filters the results to return only blobs whose names
            begin with the specified prefix.
        :param int num_results:
            Specifies the maximum number of blobs to return,
            including all :class:`BlobPrefix` elements. If the request does not specify
            num_results or specifies a value greater than 5,000, the server will
            return up to 5,000 items. Setting num_results to a value less than
            or equal to zero results in error response code 400 (Bad Request).
        :param ~azure.storage.blob.models.Include include:
            Specifies one or more additional datasets to include in the response.
        :param str delimiter:
            When the request includes this parameter, the operation
            returns a :class:`~azure.storage.blob.models.BlobPrefix` element in the
            result list that acts as a placeholder for all blobs whose names begin
            with the same substring up to the appearance of the delimiter character.
            The delimiter may be a single character or a string.
        :param str marker:
            An opaque continuation token. This value can be retrieved from the 
            next_marker field of a previous generator object if num_results was 
            specified and that generator has finished enumerating results. If 
            specified, this generator will begin returning results from the point 
            where the previous generator stopped.
        :param int timeout:
            The timeout parameter is expressed in seconds.
        '''
        operation_context = _OperationContext(location_lock=True)
        args = (container_name,)
        kwargs = {'prefix': prefix, 'marker': marker, 'max_results': num_results,
                  'include': include, 'delimiter': delimiter, 'timeout': timeout,
                  '_context': operation_context}
        resp = self._list_blobs(*args, **kwargs)

        return ListGenerator(resp, self._list_blobs, args, kwargs)

    def _list_blobs(self, container_name, prefix=None, marker=None,
                    max_results=None, include=None, delimiter=None, timeout=None,
                    _context=None):
        '''
        Returns the list of blobs under the specified container.

        :param str container_name:
            Name of existing container.
        :parm str prefix:
            Filters the results to return only blobs whose names
            begin with the specified prefix.
        :param str marker:
            A string value that identifies the portion of the list
            to be returned with the next list operation. The operation returns
            a next_marker value within the response body if the list returned was
            not complete. The marker value may then be used in a subsequent
            call to request the next set of list items. The marker value is
            opaque to the client.
        :param int max_results:
            Specifies the maximum number of blobs to return,
            including all :class:`~azure.storage.blob.models.BlobPrefix` elements. If the request does not specify
            max_results or specifies a value greater than 5,000, the server will
            return up to 5,000 items. Setting max_results to a value less than
            or equal to zero results in error response code 400 (Bad Request).
        :param str include:
            Specifies one or more datasets to include in the
            response. To specify more than one of these options on the URI,
            you must separate each option with a comma. Valid values are:
                snapshots:
                    Specifies that snapshots should be included in the
                    enumeration. Snapshots are listed from oldest to newest in
                    the response.
                metadata:
                    Specifies that blob metadata be returned in the response.
                uncommittedblobs:
                    Specifies that blobs for which blocks have been uploaded,
                    but which have not been committed using Put Block List
                    (REST API), be included in the response.
                copy:
                    Version 2012-02-12 and newer. Specifies that metadata
                    related to any current or previous Copy Blob operation
                    should be included in the response.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



