# Path: wsgidav/util.py
# BASE_LOGGER_NAME = "wsgidav"
# PYTHON_VERSION = "{}.{}.{}".format(
#     sys.version_info[0], sys.version_info[1], sys.version_info[2]
# )
#     READ_ALL = True
# MAX_FINITE_TIMEOUT_LIMIT = 10 * 365 * 24 * 60 * 60  # approx 10 years
# _MIME_TYPES = {
#     ".oga": "audio/ogg",
#     ".ogg": "audio/ogg",
#     ".ogv": "video/ogg",
#     ".webm": "video/webm",
#     # https://mailarchive.ietf.org/arch/msg/media-types/DA8UuKX2dyaVxWh-oevy-t3Vg9Q/
#     ".yml": "application/yaml",
#     ".yaml": "application/yaml",
# }
# class NO_DEFAULT:
# class SubAppStartResponse:
# def is_basestring(s):
# def is_bytes(s):
# def is_str(s):
# def to_bytes(s, encoding="utf8"):
# def to_str(s, encoding="utf8"):
# def to_set(val, *, or_none=False, raise_error=False) -> set:
# def get_dict_value(d, key_path, default=NO_DEFAULT):
# def purge_passwords(d, *, in_place=False):
#     def _purge(v):
# def check_tags(tags, known, *, msg=None, raise_error=True, required=False):
# def unicode_to_wsgi(u):
# def wsgi_to_bytes(s):
# def re_encode_wsgi(s: str, *, encoding="utf-8", fallback=False) -> str:
# def get_rfc1123_time(secs=None):
# def get_rfc3339_time(secs=None):
# def get_log_time(secs=None):
# def parse_time_string(timestring):
# def _parse_gmt_time(timestring):
# def init_logging(config):
# def get_module_logger(moduleName, *, default_to_verbose=False):
# def deep_update(d, u):
# def dynamic_import_class(name):
# def dynamic_instantiate_class(class_name, options, *, expand=None, raise_error=True):
#     def _expand(v):
# def dynamic_instantiate_class_from_opts(options, *, expand=None):
# def removeprefix(s: str, prefix: str, ignore_case: bool = False) -> str:
# def save_split(s, sep, maxsplit):
# def pop_path(path):
# def pop_path2(path):
# def shift_path(script_name, path_info):
# def split_namespace(clark_name):
# def to_unicode_safe(s):
# def safe_re_encode(s, encoding_to, *, errors="backslashreplace"):
# def string_repr(s):
# def get_file_extension(path):
# def byte_number_string(
#     number, *, thousands_sep=True, partition=False, base1024=True, append_bytes=True
# ):
# def fix_path(path, root, *, expand_vars=True, must_exist=True, allow_none=True):
# def get_content_length(environ):
# def read_and_discard_input(environ):
# def fail(value, context_info=None, *, src_exception=None, err_condition=None):
#     def __init__(self):
#     def status(self):
#     def response_headers(self):
#     def exc_info(self):
#     def __call__(self, status, response_headers, exc_info=None):
# def join_uri(uri, *segments):
# def get_uri_name(uri: str) -> str:
# def get_uri_parent(uri: str) -> Optional[str]:
# def is_child_uri(parent_uri: str, child_uri: str) -> bool:
# def is_equal_or_child_uri(parent_uri, child_uri):
# def make_complete_url(environ, local_uri=None):
# def update_headers_in_place(target, new_items) -> None:
# def parse_xml_body(environ, *, allow_empty=False):
# def send_status_response(
#     environ, start_response, e, *, add_headers=None, is_head=False
# ):
# def send_multi_status_response(environ, start_response, multistatus_elem):
# def add_property_response(multistatus_elem, href, prop_list):
# def calc_hexdigest(s):
# def calc_base64(s):
# def checked_etag(etag, *, allow_none=False):
# def parse_if_match_header(value):
# def get_file_etag(file_path):
# def obtain_content_ranges(rangetext, filesize):
# def read_timeout_value_header(timeoutvalue):
# def evaluate_http_conditionals(dav_res, last_modified, entitytag, environ):
# def parse_if_header_dict(environ):
# def test_if_header_dict(dav_res, dictIf, fullurl, locktokenlist, entitytag):
# def guess_mime_type(url):


import queue
from wsgidav import util
        res = self.unread
        self.unread = b""
        # Get next chunk, cumulating requested size as needed
        while res == b"" or size < 0 or (size > 0 and len(res) < size):
            try:
                # Read pending data, blocking if neccessary
                # (but handle the case that close() is called while waiting)
                res += self.queue.get(True, 0.1)
            except queue.Empty:
                # There was no pending data: wait for more, unless close() was called
                if self.is_closed:
                    break
        # Deliver `size` bytes from buffer
        if size > 0 and len(res) > size:
            self.unread = res[size:]
            res = res[:size]
        # print("FileLikeQueue.read({}) => {} bytes".format(size, len(res)))
        assert type(res) is bytes
        return res

    def write(self, chunk):
        """Put a chunk of bytes (or an iterable) to the queue.

        May block if max_size number of chunks is reached.
        """
        assert type(chunk) is bytes
        if self.is_closed:
            raise ValueError("Cannot write to closed object")
        # print("FileLikeQueue.write(), n={}".format(len(chunk)))
        # Add chunk to queue (blocks if queue is full)

# Path: wsgidav/util.py
# BASE_LOGGER_NAME = "wsgidav"
# PYTHON_VERSION = "{}.{}.{}".format(
#     sys.version_info[0], sys.version_info[1], sys.version_info[2]
# )
#     READ_ALL = True
# MAX_FINITE_TIMEOUT_LIMIT = 10 * 365 * 24 * 60 * 60  # approx 10 years
# _MIME_TYPES = {
#     ".oga": "audio/ogg",
#     ".ogg": "audio/ogg",
#     ".ogv": "video/ogg",
#     ".webm": "video/webm",
#     # https://mailarchive.ietf.org/arch/msg/media-types/DA8UuKX2dyaVxWh-oevy-t3Vg9Q/
#     ".yml": "application/yaml",
#     ".yaml": "application/yaml",
# }
# class NO_DEFAULT:
# class SubAppStartResponse:
# def is_basestring(s):
# def is_bytes(s):
# def is_str(s):
# def to_bytes(s, encoding="utf8"):
# def to_str(s, encoding="utf8"):
# def to_set(val, *, or_none=False, raise_error=False) -> set:
# def get_dict_value(d, key_path, default=NO_DEFAULT):
# def purge_passwords(d, *, in_place=False):
#     def _purge(v):
# def check_tags(tags, known, *, msg=None, raise_error=True, required=False):
# def unicode_to_wsgi(u):
# def wsgi_to_bytes(s):
# def re_encode_wsgi(s: str, *, encoding="utf-8", fallback=False) -> str:
# def get_rfc1123_time(secs=None):
# def get_rfc3339_time(secs=None):
# def get_log_time(secs=None):
# def parse_time_string(timestring):
# def _parse_gmt_time(timestring):
# def init_logging(config):
# def get_module_logger(moduleName, *, default_to_verbose=False):
# def deep_update(d, u):
# def dynamic_import_class(name):
# def dynamic_instantiate_class(class_name, options, *, expand=None, raise_error=True):
#     def _expand(v):
# def dynamic_instantiate_class_from_opts(options, *, expand=None):
# def removeprefix(s: str, prefix: str, ignore_case: bool = False) -> str:
# def save_split(s, sep, maxsplit):
# def pop_path(path):
# def pop_path2(path):
# def shift_path(script_name, path_info):
# def split_namespace(clark_name):
# def to_unicode_safe(s):
# def safe_re_encode(s, encoding_to, *, errors="backslashreplace"):
# def string_repr(s):
# def get_file_extension(path):
# def byte_number_string(
#     number, *, thousands_sep=True, partition=False, base1024=True, append_bytes=True
# ):
# def fix_path(path, root, *, expand_vars=True, must_exist=True, allow_none=True):
# def get_content_length(environ):
# def read_and_discard_input(environ):
# def fail(value, context_info=None, *, src_exception=None, err_condition=None):
#     def __init__(self):
#     def status(self):
#     def response_headers(self):
#     def exc_info(self):
#     def __call__(self, status, response_headers, exc_info=None):
# def join_uri(uri, *segments):
# def get_uri_name(uri: str) -> str:
# def get_uri_parent(uri: str) -> Optional[str]:
# def is_child_uri(parent_uri: str, child_uri: str) -> bool:
# def is_equal_or_child_uri(parent_uri, child_uri):
# def make_complete_url(environ, local_uri=None):
# def update_headers_in_place(target, new_items) -> None:
# def parse_xml_body(environ, *, allow_empty=False):
# def send_status_response(
#     environ, start_response, e, *, add_headers=None, is_head=False
# ):
# def send_multi_status_response(environ, start_response, multistatus_elem):
# def add_property_response(multistatus_elem, href, prop_list):
# def calc_hexdigest(s):
# def calc_base64(s):
# def checked_etag(etag, *, allow_none=False):
# def parse_if_match_header(value):
# def get_file_etag(file_path):
# def obtain_content_ranges(rangetext, filesize):
# def read_timeout_value_header(timeoutvalue):
# def evaluate_http_conditionals(dav_res, last_modified, entitytag, environ):
# def parse_if_header_dict(environ):
# def test_if_header_dict(dav_res, dictIf, fullurl, locktokenlist, entitytag):
# def guess_mime_type(url):


# Path: wsgidav/stream_tools.py
import queue
from wsgidav import util

        res = self.unread
        self.unread = b""
        # Get next chunk, cumulating requested size as needed
        while res == b"" or size < 0 or (size > 0 and len(res) < size):
            try:
                # Read pending data, blocking if neccessary
                # (but handle the case that close() is called while waiting)
                res += self.queue.get(True, 0.1)
            except queue.Empty:
                # There was no pending data: wait for more, unless close() was called
                if self.is_closed:
                    break
        # Deliver `size` bytes from buffer
        if size > 0 and len(res) > size:
            self.unread = res[size:]
            res = res[:size]
        # print("FileLikeQueue.read({}) => {} bytes".format(size, len(res)))
        assert type(res) is bytes
        return res

    def write(self, chunk):
        """Put a chunk of bytes (or an iterable) to the queue.

        May block if max_size number of chunks is reached.
        """
        assert type(chunk) is bytes
        if self.is_closed:
            raise ValueError("Cannot write to closed object")
        # print("FileLikeQueue.write(), n={}".format(len(chunk)))
        # Add chunk to queue (blocks if queue is full)

        if util.is_basestring(chunk):