diff --git a/ci/github/helpers/install_7zip.bash b/ci/github/helpers/install_7zip.bash new file mode 100755 index 00000000000..f30532a8ec8 --- /dev/null +++ b/ci/github/helpers/install_7zip.bash @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Installs the latest version of 7zip plugin +# + +# http://redsymbol.net/articles/unofficial-bash-strict-mode/ +set -o errexit # abort on nonzero exitstatus +set -o nounset # abort on unbound variable +set -o pipefail # don't hide errors within pipes +IFS=$'\n\t' + +exec "$( dirname -- "$0"; )"/../../../scripts/install_7zip.bash diff --git a/ci/github/integration-testing/dynamic-sidecar.bash b/ci/github/integration-testing/dynamic-sidecar.bash index 611fc3fd52e..568fd23bcd0 100755 --- a/ci/github/integration-testing/dynamic-sidecar.bash +++ b/ci/github/integration-testing/dynamic-sidecar.bash @@ -9,6 +9,7 @@ install() { make devenv # shellcheck source=/dev/null source .venv/bin/activate + sudo ./ci/github/helpers/install_7zip.bash pushd services/dynamic-sidecar make install-ci popd diff --git a/ci/github/integration-testing/webserver.bash b/ci/github/integration-testing/webserver.bash index 71bdd149cf4..7c9a303d8fd 100755 --- a/ci/github/integration-testing/webserver.bash +++ b/ci/github/integration-testing/webserver.bash @@ -9,6 +9,7 @@ install() { make devenv # shellcheck source=/dev/null source .venv/bin/activate + sudo ./ci/github/helpers/install_7zip.bash pushd services/web/server make install-ci popd diff --git a/ci/github/unit-testing/dynamic-sidecar.bash b/ci/github/unit-testing/dynamic-sidecar.bash index 86d449e00dd..3816782d5ee 100755 --- a/ci/github/unit-testing/dynamic-sidecar.bash +++ b/ci/github/unit-testing/dynamic-sidecar.bash @@ -9,6 +9,7 @@ install() { make devenv # shellcheck source=/dev/null source .venv/bin/activate + sudo ./ci/github/helpers/install_7zip.bash pushd services/dynamic-sidecar make install-ci popd diff --git a/ci/github/unit-testing/service-library.bash b/ci/github/unit-testing/service-library.bash index 86bd4fdb86c..e7845743303 100755 --- a/ci/github/unit-testing/service-library.bash +++ b/ci/github/unit-testing/service-library.bash @@ -10,6 +10,7 @@ install_all() { make devenv # shellcheck source=/dev/null source .venv/bin/activate + sudo ./ci/github/helpers/install_7zip.bash pushd packages/service-library make "install-ci[all]" popd diff --git a/packages/aws-library/requirements/_base.txt b/packages/aws-library/requirements/_base.txt index ab1ba69c3e5..c4c997b5983 100644 --- a/packages/aws-library/requirements/_base.txt +++ b/packages/aws-library/requirements/_base.txt @@ -313,8 +313,6 @@ referencing==0.29.3 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.8.1 diff --git a/packages/service-library/requirements/_base.in b/packages/service-library/requirements/_base.in index 7ac1ce0da04..7961b097098 100644 --- a/packages/service-library/requirements/_base.in +++ b/packages/service-library/requirements/_base.in @@ -27,7 +27,6 @@ pydantic pyinstrument pyyaml redis -repro-zipfile tenacity toolz tqdm diff --git a/packages/service-library/requirements/_base.txt b/packages/service-library/requirements/_base.txt index 9c66cf51cab..6ace2b77f35 100644 --- a/packages/service-library/requirements/_base.txt +++ b/packages/service-library/requirements/_base.txt @@ -223,8 +223,6 @@ referencing==0.29.3 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via -r requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.8.1 diff --git a/packages/service-library/src/servicelib/archiving_utils.py b/packages/service-library/src/servicelib/archiving_utils.py deleted file mode 100644 index a46665b2c23..00000000000 --- a/packages/service-library/src/servicelib/archiving_utils.py +++ /dev/null @@ -1,482 +0,0 @@ -import asyncio -import fnmatch -import functools -import logging -import types -import zipfile -from collections.abc import Awaitable, Callable, Iterator -from contextlib import AsyncExitStack, contextmanager, suppress -from functools import partial -from pathlib import Path -from typing import Any, Final - -import tqdm -from models_library.basic_types import IDStr -from pydantic import NonNegativeFloat -from repro_zipfile import ReproducibleZipFile # type: ignore[import-untyped] -from tqdm.contrib.logging import logging_redirect_tqdm, tqdm_logging_redirect - -from .file_utils import remove_directory -from .logging_utils import log_catch -from .pools import non_blocking_process_pool_executor, non_blocking_thread_pool_executor -from .progress_bar import ProgressBarData - -_MIN: Final[int] = 60 # secs -_MAX_UNARCHIVING_WORKER_COUNT: Final[int] = 2 -_CHUNK_SIZE: Final[int] = 1024 * 8 -_UNIT_MULTIPLIER: Final[NonNegativeFloat] = 1024.0 - -_logger = logging.getLogger(__name__) - - -class ArchiveError(Exception): - """ - Error raised while archiving or unarchiving - """ - - -def _human_readable_size(size, decimal_places=3): - human_readable_file_size = float(size) - unit = "B" - for t_unit in ["B", "KiB", "MiB", "GiB", "TiB"]: - if human_readable_file_size < _UNIT_MULTIPLIER: - unit = t_unit - break - human_readable_file_size /= _UNIT_MULTIPLIER - - return f"{human_readable_file_size:.{decimal_places}f}{unit}" - - -def _compute_tqdm_miniters(byte_size: int) -> float: - """ensures tqdm minimal iteration is 1 %""" - return min(byte_size / 100.0, 1.0) - - -def _strip_undecodable_in_path(path: Path) -> Path: - return Path(str(path).encode(errors="replace").decode("utf-8")) - - -def _iter_files_to_compress( - dir_path: Path, exclude_patterns: set[str] | None -) -> Iterator[Path]: - exclude_patterns = exclude_patterns if exclude_patterns else set() - # NOTE: make sure to sort paths othrwise between different runs - # the zip will have a different structure and hash - for path in sorted(dir_path.rglob("*")): - if path.is_file() and not any( - fnmatch.fnmatch(f"{path}", x) for x in exclude_patterns - ): - yield path - - -def _strip_directory_from_path(input_path: Path, to_strip: Path) -> Path: - _to_strip = f"{to_strip}/" - return Path(str(input_path).replace(_to_strip, "")) - - -class _FastZipFileReader(ReproducibleZipFile): - """ - Used to gain a speed boost of several orders of magnitude. - - When opening archives the `_RealGetContents` is called - generating the list of files contained in the zip archive. - This is done by the constructor. - - If the archive contains a very large amount, the file scan operation - can take up to seconds. This was observed with 10000+ files. - - When opening the zip file in the background worker the entire file - list generation can be skipped because the `zipfile.ZipFile.open` - is used passing `ZipInfo` object as file to decompress. - Using a `ZipInfo` object does nto require to have the list of - files contained in the archive. - """ - - def _RealGetContents(self): # noqa: N802 - """method disabled""" - - -_TQDM_FILE_OPTIONS: Final[dict[str, Any]] = { - "unit": "byte", - "unit_scale": True, - "unit_divisor": 1024, - "colour": "yellow", - "miniters": 1, -} -_TQDM_MULTI_FILES_OPTIONS: Final[dict[str, Any]] = _TQDM_FILE_OPTIONS | { - "unit": "file", - "unit_divisor": 1000, -} - - -def _zipfile_single_file_extract_worker( - zip_file_path: Path, - file_in_archive: zipfile.ZipInfo, - destination_folder: Path, - is_dir: bool, # noqa: FBT001 -) -> Path: - """Extracts file_in_archive from the archive zip_file_path -> destination_folder/file_in_archive - - Extracts in chunks to avoid memory pressure on zip/unzip - returns: a path to extracted file or directory - """ - with _FastZipFileReader(zip_file_path) as zf: - # assemble destination and ensure it exits - destination_path = destination_folder / file_in_archive.filename - - if is_dir: - destination_path.mkdir(parents=True, exist_ok=True) - return destination_path - desc = f"decompressing {zip_file_path}:{file_in_archive.filename} -> {destination_path}\n" - with zf.open(name=file_in_archive) as zip_fp, destination_path.open( - "wb" - ) as dest_fp, tqdm_logging_redirect( - total=file_in_archive.file_size, - desc=desc, - **( - _TQDM_FILE_OPTIONS - | {"miniters": _compute_tqdm_miniters(file_in_archive.file_size)} - ), - ) as pbar: - while chunk := zip_fp.read(_CHUNK_SIZE): - dest_fp.write(chunk) - pbar.update(len(chunk)) - return destination_path - - -def _ensure_destination_subdirectories_exist( - zip_file_handler: ReproducibleZipFile, destination_folder: Path -) -> None: - # assemble full destination paths - full_destination_paths = { - destination_folder / entry.filename for entry in zip_file_handler.infolist() - } - # extract all possible subdirectories - subdirectories = {x.parent for x in full_destination_paths} - # create all subdirectories before extracting - for subdirectory in subdirectories: - Path(subdirectory).mkdir(parents=True, exist_ok=True) - - -async def unarchive_dir( - archive_to_extract: Path, - destination_folder: Path, - *, - max_workers: int = _MAX_UNARCHIVING_WORKER_COUNT, - progress_bar: ProgressBarData | None = None, - log_cb: Callable[[str], Awaitable[None]] | None = None, -) -> set[Path]: - """Extracts zipped file archive_to_extract to destination_folder, - preserving all relative files and folders inside the archive - - Returns a set with all the paths extracted from archive. It includes - all tree leafs, which might include files or empty folders - - - NOTE: ``destination_folder`` is fully deleted after error - - ::raise ArchiveError - """ - if not progress_bar: - progress_bar = ProgressBarData( - num_steps=1, description=IDStr(f"extracting {archive_to_extract.name}") - ) - async with AsyncExitStack() as zip_stack: - zip_file_handler = zip_stack.enter_context( - ReproducibleZipFile( # pylint: disable=consider-using-with - archive_to_extract, - mode="r", - ) - ) - zip_stack.enter_context(logging_redirect_tqdm()) - process_pool = zip_stack.enter_context( - non_blocking_process_pool_executor(max_workers=max_workers) - ) - - # running in process poll is not ideal for concurrency issues - # to avoid race conditions all subdirectories where files will be extracted need to exist - # creating them before the extraction is under way avoids the issue - # the following avoids race conditions while unzippin in parallel - _ensure_destination_subdirectories_exist( - zip_file_handler=zip_file_handler, - destination_folder=destination_folder, - ) - - futures: list[asyncio.Future] = [ - asyncio.get_event_loop().run_in_executor( - process_pool, - # --------- - _zipfile_single_file_extract_worker, - archive_to_extract, - zip_entry, - destination_folder, - zip_entry.is_dir(), - ) - for zip_entry in zip_file_handler.infolist() - ] - - try: - extracted_paths: list[Path] = [] - total_file_size = sum( - zip_entry.file_size for zip_entry in zip_file_handler.infolist() - ) - async with AsyncExitStack() as progress_stack: - sub_prog = await progress_stack.enter_async_context( - progress_bar.sub_progress( - steps=total_file_size, description=IDStr("...") - ) - ) - tqdm_progress = progress_stack.enter_context( - tqdm.tqdm( - desc=f"decompressing {archive_to_extract} -> {destination_folder} [{len(futures)} file{'s' if len(futures) > 1 else ''}" - f"/{_human_readable_size(archive_to_extract.stat().st_size)}]\n", - total=total_file_size, - **_TQDM_MULTI_FILES_OPTIONS, - ) - ) - for future in asyncio.as_completed(futures): - extracted_path = await future - extracted_file_size = extracted_path.stat().st_size - if tqdm_progress.update(extracted_file_size) and log_cb: - with log_catch(_logger, reraise=False): - await log_cb(f"{tqdm_progress}") - await sub_prog.update(extracted_file_size) - extracted_paths.append(extracted_path) - - except Exception as err: - for f in futures: - f.cancel() - - # wait until all tasks are cancelled - await asyncio.wait( - futures, timeout=2 * _MIN, return_when=asyncio.ALL_COMPLETED - ) - - # now we can cleanup - if destination_folder.exists() and destination_folder.is_dir(): - await remove_directory(destination_folder, ignore_errors=True) - - msg = ( - f"Failed unarchiving {archive_to_extract} -> {destination_folder} due to {type(err)}." - f"Details: {err}" - ) - raise ArchiveError(msg) from err - - # NOTE: extracted_paths includes all tree leafs, which might include files and empty folders - return { - p - for p in extracted_paths - if p.is_file() or (p.is_dir() and not any(p.glob("*"))) - } - - -@contextmanager -def _progress_enabled_zip_write_handler( - zip_file_handler: ReproducibleZipFile, progress_bar: tqdm.tqdm -) -> Iterator[ReproducibleZipFile]: - """This function overrides the default zip write fct to allow to get progress using tqdm library""" - - def _write_with_progress( - original_write_fct, - self, # pylint: disable=unused-argument # noqa: ARG001 - data, - pbar, - ): - pbar.update(len(data)) - return original_write_fct(data) - - # Replace original write() with a wrapper to track progress - assert zip_file_handler.fp # nosec - old_write_method = zip_file_handler.fp.write - zip_file_handler.fp.write = types.MethodType( - partial(_write_with_progress, old_write_method, pbar=progress_bar), - zip_file_handler.fp, - ) - try: - yield zip_file_handler - finally: - zip_file_handler.fp.write = old_write_method - - -def _add_to_archive( - dir_to_compress: Path, - destination: Path, - compress: bool, # noqa: FBT001 - store_relative_path: bool, # noqa: FBT001 - update_progress, - loop, - exclude_patterns: set[str] | None = None, -) -> None: - compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED - folder_size_bytes = sum( - file.stat().st_size - for file in _iter_files_to_compress(dir_to_compress, exclude_patterns) - ) - desc = f"compressing {dir_to_compress} -> {destination}" - with tqdm_logging_redirect( - desc=f"{desc}\n", - total=folder_size_bytes, - **( - _TQDM_FILE_OPTIONS | {"miniters": _compute_tqdm_miniters(folder_size_bytes)} - ), - ) as progress_bar, _progress_enabled_zip_write_handler( - ReproducibleZipFile(destination, "w", compression=compression), progress_bar - ) as zip_file_handler: - for file_to_add in _iter_files_to_compress(dir_to_compress, exclude_patterns): - progress_bar.set_description(f"{desc}/{file_to_add.name}\n") - file_name_in_archive = ( - _strip_directory_from_path(file_to_add, dir_to_compress) - if store_relative_path - else file_to_add - ) - - # because surrogates are not allowed in zip files, - # replacing them will ensure errors will not happen. - escaped_file_name_in_archive = _strip_undecodable_in_path( - file_name_in_archive - ) - - zip_file_handler.write(file_to_add, escaped_file_name_in_archive) - asyncio.run_coroutine_threadsafe( - update_progress(file_to_add.stat().st_size), loop - ) - - -async def _update_progress(prog: ProgressBarData, delta: float) -> None: - await prog.update(delta) - - -async def archive_dir( - dir_to_compress: Path, - destination: Path, - *, - compress: bool, - store_relative_path: bool, - exclude_patterns: set[str] | None = None, - progress_bar: ProgressBarData | None = None, -) -> None: - """ - When archiving, undecodable bytes in filenames will be escaped, - zipfile does not like them. - When unarchiveing, the **escaped version** of the file names - will be created. - - The **exclude_patterns** is a set of patterns created using - Unix shell-style wildcards to exclude files and directories. - - destination: Path deleted if errors - - ::raise ArchiveError - """ - if not progress_bar: - progress_bar = ProgressBarData( - num_steps=1, description=IDStr(f"compressing {dir_to_compress.name}") - ) - - async with AsyncExitStack() as stack: - folder_size_bytes = sum( - file.stat().st_size - for file in _iter_files_to_compress(dir_to_compress, exclude_patterns) - ) - sub_progress = await stack.enter_async_context( - progress_bar.sub_progress(folder_size_bytes, description=IDStr("...")) - ) - thread_pool = stack.enter_context( - non_blocking_thread_pool_executor(max_workers=1) - ) - try: - await asyncio.get_event_loop().run_in_executor( - thread_pool, - # --------- - _add_to_archive, - dir_to_compress, - destination, - compress, - store_relative_path, - functools.partial(_update_progress, sub_progress), - asyncio.get_event_loop(), - exclude_patterns, - ) - except Exception as err: - if destination.is_file(): - destination.unlink(missing_ok=True) - - msg = ( - f"Failed archiving {dir_to_compress} -> {destination} due to {type(err)}." - f"Details: {err}" - ) - raise ArchiveError(msg) from err - - except BaseException: - if destination.is_file(): - destination.unlink(missing_ok=True) - raise - - -def is_leaf_path(p: Path) -> bool: - """Tests whether a path corresponds to a file or empty folder, i.e. - some leaf item in a file-system tree structure - """ - return p.is_file() or (p.is_dir() and not any(p.glob("*"))) - - -class PrunableFolder: - """ - Use in conjunction with unarchive on the dest_dir to achieve - an update of a folder content without deleting updated files - - folder = PrunableFolder(target_dir) - - unarchived = await archive_dir(destination=target_dir, ... ) - - folder.prune(exclude=unarchived) - - """ - - def __init__(self, folder: Path): - self.basedir = folder - self.before_relpaths: set = set() - self.capture() - - def capture(self) -> None: - # captures leaf paths in folder at this moment - self.before_relpaths = { - p.relative_to(self.basedir) - for p in self.basedir.rglob("*") - if is_leaf_path(p) - } - - def prune(self, exclude: set[Path]) -> None: - """ - Deletes all paths in folder skipping the exclude set - """ - assert all(self.basedir in p.parents for p in exclude) # nosec - - after_relpaths = {p.relative_to(self.basedir) for p in exclude} - to_delete = self.before_relpaths.difference(after_relpaths) - - for p in to_delete: - path = self.basedir / p - assert path.exists() # nosec - - if path.is_file(): - path.unlink() - elif path.is_dir(): - # prevents deleting non-empty folders - with suppress(OSError): - path.rmdir() - - # second pass to delete empty folders - # after deleting files, some folders might have been left empty - for p in self.basedir.rglob("*"): - if p.is_dir() and p not in exclude and not any(p.glob("*")): - p.rmdir() - - -__all__ = ( - "archive_dir", - "ArchiveError", - "is_leaf_path", - "PrunableFolder", - "unarchive_dir", -) diff --git a/packages/service-library/src/servicelib/archiving_utils/__init__.py b/packages/service-library/src/servicelib/archiving_utils/__init__.py new file mode 100644 index 00000000000..ae6e3cdc80b --- /dev/null +++ b/packages/service-library/src/servicelib/archiving_utils/__init__.py @@ -0,0 +1,11 @@ +from ._errors import ArchiveError +from ._interface_7zip import archive_dir, unarchive_dir +from ._prunable_folder import PrunableFolder, is_leaf_path + +__all__ = ( + "archive_dir", + "ArchiveError", + "is_leaf_path", + "PrunableFolder", + "unarchive_dir", +) diff --git a/packages/service-library/src/servicelib/archiving_utils/_errors.py b/packages/service-library/src/servicelib/archiving_utils/_errors.py new file mode 100644 index 00000000000..1f9153ebf50 --- /dev/null +++ b/packages/service-library/src/servicelib/archiving_utils/_errors.py @@ -0,0 +1,4 @@ +class ArchiveError(Exception): + """ + Error raised while archiving or unarchiving + """ diff --git a/packages/service-library/src/servicelib/archiving_utils/_interface_7zip.py b/packages/service-library/src/servicelib/archiving_utils/_interface_7zip.py new file mode 100644 index 00000000000..f7031840d2f --- /dev/null +++ b/packages/service-library/src/servicelib/archiving_utils/_interface_7zip.py @@ -0,0 +1,330 @@ +import asyncio +import asyncio.subprocess +import logging +import os +import re +from collections.abc import Awaitable, Callable +from contextlib import AsyncExitStack +from pathlib import Path +from typing import Final + +import tqdm +from models_library.basic_types import IDStr +from pydantic import NonNegativeInt +from servicelib.logging_utils import log_catch +from tqdm.contrib.logging import tqdm_logging_redirect + +from ..file_utils import shutil_move +from ..progress_bar import ProgressBarData +from ._errors import ArchiveError +from ._tdqm_utils import ( + TQDM_FILE_OPTIONS, + TQDM_MULTI_FILES_OPTIONS, + compute_tqdm_miniters, + human_readable_size, +) +from ._utils import iter_files_to_compress + +_logger = logging.getLogger(__name__) + +_TOTAL_BYTES_RE: Final[str] = r" (\d+)\s*bytes" +_FILE_COUNT_RE: Final[str] = r" (\d+)\s*files" +_PROGRESS_PERCENT_RE: Final[str] = r" (?:100|\d?\d)% " +_ALL_DONE_RE: Final[str] = r"Everything is Ok" + +_7ZIP_PATH: Final[Path] = Path("/usr/bin/7z") + +_TABLE_HEADER_START: Final[str] = "------------------- " +_FILE_PERMISSIONS: Final[str] = " ..... " + + +class ArchiveInfoParser: + def __init__(self) -> None: + self.total_bytes: NonNegativeInt | None = None + self.file_count: NonNegativeInt | None = None + + async def parse_chunk(self, chunk: str) -> None: + # search for ` NUMBER bytes ` -> set byte size + if self.total_bytes is None and (match := re.search(_TOTAL_BYTES_RE, chunk)): + self.total_bytes = int(match.group(1)) + + # search for ` NUMBER files` -> set file count + if self.file_count is None and (match := re.search(_FILE_COUNT_RE, chunk)): + self.file_count = int(match.group(1)) + + def get_parsed_values(self) -> tuple[NonNegativeInt, NonNegativeInt]: + if self.total_bytes is None: + msg = f"Unexpected value for {self.total_bytes=}. Should not be None" + raise ArchiveError(msg) + + if self.file_count is None: + msg = f"Unexpected value for {self.file_count=}. Should not be None" + raise ArchiveError(msg) + + return (self.total_bytes, self.file_count) + + +class ProgressParser: + def __init__( + self, decompressed_bytes: Callable[[NonNegativeInt], Awaitable[None]] + ) -> None: + self.decompressed_bytes = decompressed_bytes + self.total_bytes: NonNegativeInt | None = None + + # in range 0% -> 100% + self.percent: NonNegativeInt | None = None + self.finished: bool = False + self.finished_emitted: bool = False + + self.emitted_total: NonNegativeInt = 0 + + def _prase_progress(self, chunk: str) -> None: + # search for " NUMBER bytes" -> set byte size + if self.total_bytes is None and (match := re.search(_TOTAL_BYTES_RE, chunk)): + self.total_bytes = int(match.group(1)) + + # search for ` dd% ` -> update progress (as last entry inside the string) + if matches := re.findall(_PROGRESS_PERCENT_RE, chunk): + self.percent = int(matches[-1].strip().strip("%")) + + # search for `Everything is Ok` -> set 100% and finish + if re.search(_ALL_DONE_RE, chunk, re.IGNORECASE): + self.finished = True + + async def parse_chunk(self, chunk: str) -> None: + self._prase_progress(chunk) + + if self.total_bytes is not None and self.percent is not None: + # total bytes decompressed + current_bytes_progress = int(self.percent * self.total_bytes / 100) + + # only emit an update if something changed since before + bytes_diff = current_bytes_progress - self.emitted_total + if self.emitted_total == 0 or bytes_diff > 0: + await self.decompressed_bytes(bytes_diff) + + self.emitted_total = current_bytes_progress + + # if finished emit the remaining diff + if self.total_bytes and self.finished and not self.finished_emitted: + + await self.decompressed_bytes(self.total_bytes - self.emitted_total) + self.finished_emitted = True + + +async def _stream_output_reader( + stream: asyncio.StreamReader, + *, + output_handlers: list[Callable[[str], Awaitable[None]]] | None, + chunk_size: NonNegativeInt = 16, + lookbehind_buffer_size: NonNegativeInt = 40, +) -> str: + # NOTE: content is not read line by line but chunk by chunk to avoid missing progress updates + # small chunks are read and of size `chunk_size` and a bigger chunk of + # size `lookbehind_buffer_size` + `chunk_size` is emitted + # The goal is to not split any important search in half, thus giving a change to the + # `output_handlers` to properly handle it + + # NOTE: at the time of writing this, the biggest possible thing to capture search would be: + # ~`9.1TiB` -> literally ` 9999999999999 bytes ` equal to 21 characters to capture, + # with the above defaults we the "emitted chunk" is more than double in size + # There are no foreseeable issued due to the size of inputs to be captured. + + if output_handlers is None: + output_handlers = [] + + command_output = "" + lookbehind_buffer = "" + + while True: + read_chunk = await stream.read(chunk_size) + + if not read_chunk: + # process remaining buffer if any + if lookbehind_buffer: + await asyncio.gather( + *[handler(lookbehind_buffer) for handler in output_handlers] + ) + break + + # `errors=replace`: avoids getting stuck when can't parse utf-8 + chunk = read_chunk.decode("utf-8", errors="replace") + + command_output += chunk + chunk_to_emit = lookbehind_buffer + chunk + lookbehind_buffer = chunk_to_emit[-lookbehind_buffer_size:] + + await asyncio.gather(*[handler(chunk_to_emit) for handler in output_handlers]) + + return command_output + + +async def _run_cli_command( + command: str, + *, + output_handlers: list[Callable[[str], Awaitable[None]]] | None = None, +) -> str: + """ + Raises: + ArchiveError: when it fails to execute the command + """ + + process = await asyncio.create_subprocess_shell( + command, + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.STDOUT, + ) + assert process.stdout # nosec + + command_output, _ = await asyncio.gather( + asyncio.create_task( + _stream_output_reader(process.stdout, output_handlers=output_handlers) + ), + process.wait(), + ) + + if process.returncode != os.EX_OK: + msg = f"Could not run '{command}' error: '{command_output}'" + raise ArchiveError(msg) + + return command_output + + +async def archive_dir( + dir_to_compress: Path, + destination: Path, + *, + compress: bool, + progress_bar: ProgressBarData | None = None, +) -> None: + if progress_bar is None: + progress_bar = ProgressBarData( + num_steps=1, description=IDStr(f"compressing {dir_to_compress.name}") + ) + + options = " ".join( + [ + "a", # archive + "-tzip", # type of archive + "-bsp1", # used for parsing progress + f"-mx={9 if compress else 0}", # compression level + # guarantees archive reproducibility + "-r", # recurse into subdirectories if needed. + "-mtm=off", # Don't store last modification time + "-mtc=off", # Don't store file creation time + "-mta=off", # Don't store file access time + ] + ) + command = f"{_7ZIP_PATH} {options} {destination} {dir_to_compress}/*" + + folder_size_bytes = sum( + file.stat().st_size for file in iter_files_to_compress(dir_to_compress) + ) + + async with AsyncExitStack() as exit_stack: + sub_progress = await exit_stack.enter_async_context( + progress_bar.sub_progress(folder_size_bytes, description=IDStr("...")) + ) + + tqdm_progress = exit_stack.enter_context( + tqdm_logging_redirect( + desc=f"compressing {dir_to_compress} -> {destination}\n", + total=folder_size_bytes, + **( + TQDM_FILE_OPTIONS + | {"miniters": compute_tqdm_miniters(folder_size_bytes)} + ), + ) + ) + + async def progress_handler(byte_progress: NonNegativeInt) -> None: + tqdm_progress.update(byte_progress) + await sub_progress.update(byte_progress) + + await _run_cli_command( + command, output_handlers=[ProgressParser(progress_handler).parse_chunk] + ) + + # 7zip automatically adds .zip extension if it's missing form the archive name + if not destination.exists(): + await shutil_move(f"{destination}.zip", destination) + + +def _extract_file_names_from_archive(command_output: str) -> set[str]: + file_name_start: NonNegativeInt | None = None + + for line in command_output.splitlines(): + if line.startswith(_TABLE_HEADER_START): + file_name_start = line.rfind(" ") + 1 + break + + lines_with_file_name: list[str] = [ + line for line in command_output.splitlines() if _FILE_PERMISSIONS in line + ] + + if lines_with_file_name and file_name_start is None: + msg = ( + f"Excepted to detect a table header since files were detected {lines_with_file_name=}." + f" Command output:\n{command_output}" + ) + raise ArchiveError(msg) + + return {line[file_name_start:] for line in lines_with_file_name} + + +async def unarchive_dir( + archive_to_extract: Path, + destination_folder: Path, + *, + progress_bar: ProgressBarData | None = None, + log_cb: Callable[[str], Awaitable[None]] | None = None, +) -> set[Path]: + if progress_bar is None: + progress_bar = ProgressBarData( + num_steps=1, description=IDStr(f"extracting {archive_to_extract.name}") + ) + + # get archive information + archive_info_parser = ArchiveInfoParser() + list_output = await _run_cli_command( + f"{_7ZIP_PATH} l {archive_to_extract}", + output_handlers=[archive_info_parser.parse_chunk], + ) + file_names_in_archive = _extract_file_names_from_archive(list_output) + total_bytes, file_count = archive_info_parser.get_parsed_values() + + async with AsyncExitStack() as exit_stack: + sub_prog = await exit_stack.enter_async_context( + progress_bar.sub_progress(steps=total_bytes, description=IDStr("...")) + ) + + tqdm_progress = exit_stack.enter_context( + tqdm.tqdm( + desc=f"decompressing {archive_to_extract} -> {destination_folder} [{file_count} file{'' if file_count == 1 else 's'}" + f"/{human_readable_size(archive_to_extract.stat().st_size)}]\n", + total=total_bytes, + **TQDM_MULTI_FILES_OPTIONS, + ) + ) + + # extract archive + async def progress_handler(byte_progress: NonNegativeInt) -> None: + if tqdm_progress.update(byte_progress) and log_cb: + with log_catch(_logger, reraise=False): + await log_cb(f"{tqdm_progress}") + await sub_prog.update(byte_progress) + + options = " ".join( + [ + "x", # extract + "-bsp1", # used for parsing progress + "-y", # reply yes to all + ] + ) + await _run_cli_command( + f"{_7ZIP_PATH} {options} {archive_to_extract} -o{destination_folder}", + output_handlers=[ProgressParser(progress_handler).parse_chunk], + ) + + return {destination_folder / x for x in file_names_in_archive} diff --git a/packages/service-library/src/servicelib/archiving_utils/_prunable_folder.py b/packages/service-library/src/servicelib/archiving_utils/_prunable_folder.py new file mode 100644 index 00000000000..b9c74ec0f2e --- /dev/null +++ b/packages/service-library/src/servicelib/archiving_utils/_prunable_folder.py @@ -0,0 +1,62 @@ +from contextlib import suppress +from pathlib import Path + + +def is_leaf_path(p: Path) -> bool: + """Tests whether a path corresponds to a file or empty folder, i.e. + some leaf item in a file-system tree structure + """ + return p.is_file() or (p.is_dir() and not any(p.glob("*"))) + + +class PrunableFolder: + """ + Use in conjunction with unarchive on the dest_dir to achieve + an update of a folder content without deleting updated files + + folder = PrunableFolder(target_dir) + + unarchived = await archive_dir(destination=target_dir, ... ) + + folder.prune(exclude=unarchived) + + """ + + def __init__(self, folder: Path): + self.basedir = folder + self.before_relpaths: set = set() + self.capture() + + def capture(self) -> None: + # captures leaf paths in folder at this moment + self.before_relpaths = { + p.relative_to(self.basedir) + for p in self.basedir.rglob("*") + if is_leaf_path(p) + } + + def prune(self, exclude: set[Path]) -> None: + """ + Deletes all paths in folder skipping the exclude set + """ + assert all(self.basedir in p.parents for p in exclude) # nosec + + after_relpaths = {p.relative_to(self.basedir) for p in exclude} + to_delete = self.before_relpaths.difference(after_relpaths) + + for p in to_delete: + path = self.basedir / p + assert path.exists() # nosec + + if path.is_file(): + path.unlink() + elif path.is_dir(): + # prevents deleting non-empty folders + with suppress(OSError): + path.rmdir() + + # second pass to delete empty folders + # after deleting files, some folders might have been left empty + for p in self.basedir.rglob("*"): + if p.is_dir() and p not in exclude and not any(p.glob("*")): + p.rmdir() diff --git a/packages/service-library/src/servicelib/archiving_utils/_tdqm_utils.py b/packages/service-library/src/servicelib/archiving_utils/_tdqm_utils.py new file mode 100644 index 00000000000..430b446ab17 --- /dev/null +++ b/packages/service-library/src/servicelib/archiving_utils/_tdqm_utils.py @@ -0,0 +1,33 @@ +from typing import Any, Final + +from pydantic import NonNegativeFloat + +_UNIT_MULTIPLIER: Final[NonNegativeFloat] = 1024.0 +TQDM_FILE_OPTIONS: Final[dict[str, Any]] = { + "unit": "byte", + "unit_scale": True, + "unit_divisor": 1024, + "colour": "yellow", + "miniters": 1, +} +TQDM_MULTI_FILES_OPTIONS: Final[dict[str, Any]] = TQDM_FILE_OPTIONS | { + "unit": "file", + "unit_divisor": 1000, +} + + +def human_readable_size(size, decimal_places=3): + human_readable_file_size = float(size) + unit = "B" + for t_unit in ["B", "KiB", "MiB", "GiB", "TiB"]: + if human_readable_file_size < _UNIT_MULTIPLIER: + unit = t_unit + break + human_readable_file_size /= _UNIT_MULTIPLIER + + return f"{human_readable_file_size:.{decimal_places}f}{unit}" + + +def compute_tqdm_miniters(byte_size: int) -> float: + """ensures tqdm minimal iteration is 1 %""" + return min(byte_size / 100.0, 1.0) diff --git a/packages/service-library/src/servicelib/archiving_utils/_utils.py b/packages/service-library/src/servicelib/archiving_utils/_utils.py new file mode 100644 index 00000000000..0d85001e190 --- /dev/null +++ b/packages/service-library/src/servicelib/archiving_utils/_utils.py @@ -0,0 +1,10 @@ +from collections.abc import Iterator +from pathlib import Path + + +def iter_files_to_compress(dir_path: Path) -> Iterator[Path]: + # NOTE: make sure to sort paths othrwise between different runs + # the zip will have a different structure and hash + for path in sorted(dir_path.rglob("*")): + if path.is_file(): + yield path diff --git a/packages/service-library/src/servicelib/file_utils.py b/packages/service-library/src/servicelib/file_utils.py index a52854c26e7..2d4f4742833 100644 --- a/packages/service-library/src/servicelib/file_utils.py +++ b/packages/service-library/src/servicelib/file_utils.py @@ -21,6 +21,7 @@ async def read(self, size: int = -1) -> bytes: _shutil_rmtree = sync_to_async(shutil.rmtree) +shutil_move = sync_to_async(shutil.move) async def _rm(path: Path, *, ignore_errors: bool): diff --git a/packages/service-library/tests/archiving_utils/conftest.py b/packages/service-library/tests/archiving_utils/conftest.py new file mode 100644 index 00000000000..c091ac9550f --- /dev/null +++ b/packages/service-library/tests/archiving_utils/conftest.py @@ -0,0 +1,56 @@ +# pylint: disable=redefined-outer-name +# pylint: disable=unused-argument + +from collections.abc import AsyncIterable +from concurrent.futures import ProcessPoolExecutor +from pathlib import Path + +import numpy as np +import pytest +from faker import Faker +from helpers import print_tree +from PIL import Image +from servicelib.file_utils import remove_directory + + +def _process_and_save_image(image_path: Path) -> None: + random_image = np.random.rand(900, 900, 3) * 255 # noqa: NPY002 + im_out = Image.fromarray(random_image.astype("uint8")).convert("RGB") + im_out.save(image_path) + + +@pytest.fixture +async def mixed_file_types(tmp_path: Path, faker: Faker) -> AsyncIterable[Path]: + base_dir = tmp_path / "mixed_types_dir" + base_dir.mkdir() + + # mixed small text files and binary files + (base_dir / "empty").mkdir() + (base_dir / "d1").mkdir() + (base_dir / "d1" / "f1.txt").write_text(faker.text()) + (base_dir / "d1" / "b2.bin").write_bytes(faker.json_bytes()) + (base_dir / "d1" / "sd1").mkdir() + (base_dir / "d1" / "sd1" / "f1.txt").write_text(faker.text()) + (base_dir / "d1" / "sd1" / "b2.bin").write_bytes(faker.json_bytes()) + (base_dir / "images").mkdir() + + # images cause issues with zipping, below content produced different + # hashes for zip files + + image_paths: list[Path] = [] + for i in range(2): + image_dir = base_dir / f"images{i}" + image_dir.mkdir() + for n in range(50): + image_paths.append(image_dir / f"out{n}.jpg") # noqa: PERF401 + + with ProcessPoolExecutor() as executor: + executor.map(_process_and_save_image, image_paths) + + print("mixed_types_dir ---") + print_tree(base_dir) + + yield base_dir + + await remove_directory(base_dir) + assert not base_dir.exists() diff --git a/packages/service-library/tests/archiving_utils/helpers.py b/packages/service-library/tests/archiving_utils/helpers.py new file mode 100644 index 00000000000..7c4e146756a --- /dev/null +++ b/packages/service-library/tests/archiving_utils/helpers.py @@ -0,0 +1,8 @@ +from pathlib import Path + + +def print_tree(path: Path, level=0): + tab = " " * level + print(f"{tab}{'+' if path.is_dir() else '-'} {path if level==0 else path.name}") + for p in path.glob("*"): + print_tree(p, level + 1) diff --git a/packages/service-library/tests/archiving_utils/test_archiving__interface_7zip.py b/packages/service-library/tests/archiving_utils/test_archiving__interface_7zip.py new file mode 100644 index 00000000000..e05340734ba --- /dev/null +++ b/packages/service-library/tests/archiving_utils/test_archiving__interface_7zip.py @@ -0,0 +1,88 @@ +# pylint: disable=redefined-outer-name +# pylint: disable=unused-argument + +import json +from pathlib import Path + +import pytest +from pydantic import NonNegativeInt +from servicelib.archiving_utils._interface_7zip import ( + ProgressParser, + _extract_file_names_from_archive, + archive_dir, + unarchive_dir, +) + + +@pytest.fixture +async def archive_path(tmp_path: Path) -> Path: + return tmp_path / "mixed_types_dir.zip" + + +@pytest.fixture +def unpacked_archive(tmp_path: Path) -> Path: + path = tmp_path / "unpacked_dir" + path.mkdir() + return path + + +@pytest.fixture +def data_archive_utils(package_tests_dir: Path) -> Path: + path = package_tests_dir / "data" / "archive_utils" + assert path.exists() + assert path.is_dir() + return path + + +@pytest.mark.parametrize( + "progress_stdout, expected_size", + [ + ("compress_stdout.json", 434866026), + ("decompress_stdout.json", 434902745), + ], +) +async def test_compress_progress_parser( + data_archive_utils: Path, progress_stdout: str, expected_size: NonNegativeInt +): + stdout_path = data_archive_utils / progress_stdout + assert stdout_path.exists() + stdout_entries: list[str] = json.loads(stdout_path.read_text()) + + detected_entries: list[NonNegativeInt] = [] + + async def progress_handler(byte_progress: NonNegativeInt) -> None: + detected_entries.append(byte_progress) + + parser = ProgressParser(progress_handler) + for chunk in stdout_entries: + await parser.parse_chunk(chunk) + + print(detected_entries) + assert sum(detected_entries) == expected_size + + +@pytest.mark.parametrize("compress", [True, False]) +async def test_archive_unarchive( + mixed_file_types: Path, archive_path: Path, unpacked_archive: Path, compress: bool +): + await archive_dir(mixed_file_types, archive_path, compress=compress) + + await unarchive_dir(archive_path, unpacked_archive) + + +@pytest.mark.parametrize( + "file_name, expected_file_count", + [ + ("list_edge_case.txt", 3), + ("list_stdout.txt", 674), + ], +) +def test__extract_file_names_from_archive( + data_archive_utils: Path, file_name: str, expected_file_count: NonNegativeInt +): + archive_list_stdout_path = data_archive_utils / file_name + assert archive_list_stdout_path.exists() + + archive_list_stdout_path.read_text() + files = _extract_file_names_from_archive(archive_list_stdout_path.read_text()) + assert len(files) == expected_file_count diff --git a/packages/service-library/tests/test_archiving_utils.py b/packages/service-library/tests/archiving_utils/test_archiving_utils.py similarity index 55% rename from packages/service-library/tests/test_archiving_utils.py rename to packages/service-library/tests/archiving_utils/test_archiving_utils.py index fdbb9c4c2fd..3aab7383644 100644 --- a/packages/service-library/tests/test_archiving_utils.py +++ b/packages/service-library/tests/archiving_utils/test_archiving_utils.py @@ -5,32 +5,19 @@ import asyncio import hashlib -import itertools import os import secrets import string import tempfile -from collections.abc import AsyncIterable, Callable, Iterable, Iterator +from collections.abc import Callable, Iterable from concurrent.futures import ProcessPoolExecutor -from dataclasses import dataclass from pathlib import Path -import numpy import pytest from faker import Faker -from PIL import Image from pydantic import ByteSize, TypeAdapter from pytest_benchmark.plugin import BenchmarkFixture -from servicelib import archiving_utils -from servicelib.archiving_utils import ArchiveError, archive_dir, unarchive_dir -from servicelib.file_utils import remove_directory - - -def _print_tree(path: Path, level=0): - tab = " " * level - print(f"{tab}{'+' if path.is_dir() else '-'} {path if level==0 else path.name}") - for p in path.glob("*"): - _print_tree(p, level + 1) +from servicelib.archiving_utils import archive_dir, unarchive_dir @pytest.fixture @@ -89,41 +76,6 @@ def get_dirs_and_subdris_in_path(path_to_scan: Path) -> list[Path]: yield temp_dir_path -@pytest.fixture -def exclude_patterns_validation_dir(tmp_path: Path, faker: Faker) -> Path: - """Directory with well known structure""" - base_dir = tmp_path / "exclude_patterns_validation_dir" - base_dir.mkdir() - (base_dir / "empty").mkdir() - (base_dir / "d1").mkdir() - (base_dir / "d1" / "f1").write_text(faker.text()) - (base_dir / "d1" / "f2.txt").write_text(faker.text()) - (base_dir / "d1" / "sd1").mkdir() - (base_dir / "d1" / "sd1" / "f1").write_text(faker.text()) - (base_dir / "d1" / "sd1" / "f2.txt").write_text(faker.text()) - - print("exclude_patterns_validation_dir ---") - _print_tree(base_dir) - return base_dir - - -def __raise_error(*arts, **kwargs) -> None: - raise ArchiveError("raised as requested") - - -@pytest.fixture -def zipfile_single_file_extract_worker_raises_error() -> Iterator[None]: - # NOTE: cannot MagicMock cannot be serialized via pickle used by - # multiprocessing, also `__raise_error` cannot be defined in the - # context fo this function or it cannot be pickled - - # pylint: disable=protected-access - old_func = archiving_utils._zipfile_single_file_extract_worker - archiving_utils._zipfile_single_file_extract_worker = __raise_error - yield - archiving_utils._zipfile_single_file_extract_worker = old_func - - # UTILS @@ -141,8 +93,8 @@ def get_all_files_in_dir(dir_path: Path) -> set[Path]: def _compute_hash(file_path: Path) -> tuple[Path, str]: - with open(file_path, "rb") as file_to_hash: - file_hash = hashlib.md5() + with Path.open(file_path, "rb") as file_to_hash: + file_hash = hashlib.md5() # noqa: S324 chunk = file_to_hash.read(8192) while chunk: file_hash.update(chunk) @@ -163,7 +115,7 @@ async def compute_hashes(file_paths: list[Path]) -> dict[Path, str]: ] # pylint: disable=unnecessary-comprehension # see return value of _compute_hash it is a tuple, mapping list[Tuple[Path,str]] to Dict[Path, str] here - return {k: v for k, v in await asyncio.gather(*tasks)} + return dict(await asyncio.gather(*tasks)) def full_file_path_from_dir_and_subdirs(dir_path: Path) -> list[Path]: @@ -174,15 +126,10 @@ def _escape_undecodable_str(s: str) -> str: return s.encode(errors="replace").decode("utf-8") -def _escape_undecodable_path(path: Path) -> Path: - return Path(_escape_undecodable_str(str(path))) - - async def assert_same_directory_content( dir_to_compress: Path, output_dir: Path, inject_relative_path: Path | None = None, - unsupported_replace: bool = False, ) -> None: def _relative_path(input_path: Path) -> Path: assert inject_relative_path is not None @@ -191,9 +138,6 @@ def _relative_path(input_path: Path) -> Path: input_set = get_all_files_in_dir(dir_to_compress) output_set = get_all_files_in_dir(output_dir) - if unsupported_replace: - input_set = {_escape_undecodable_path(x) for x in input_set} - if inject_relative_path is not None: input_set = {_relative_path(x) for x in input_set} @@ -209,9 +153,6 @@ def _relative_path(input_path: Path) -> Path: await compute_hashes(full_file_path_from_dir_and_subdirs(dir_to_compress)) ).items() } - dir_to_compress_hashes = { - _escape_undecodable_path(k): v for k, v in dir_to_compress_hashes.items() - } # computing the hashes for output_dir and map in a dict # with the name starting from the root of the directory and md5sum @@ -235,10 +176,9 @@ def assert_unarchived_paths( unarchived_paths: set[Path], src_dir: Path, dst_dir: Path, - is_saved_as_relpath: bool, - unsupported_replace: bool = False, ): - is_file_or_emptydir = lambda p: p.is_file() or (p.is_dir() and not any(p.glob("*"))) + def is_file_or_emptydir(path: Path) -> bool: + return path.is_file() or path.is_dir() and not any(path.glob("*")) # all unarchivedare under dst_dir assert all(dst_dir in f.parents for f in unarchived_paths) @@ -248,8 +188,6 @@ def assert_unarchived_paths( # trim basedir and compare relative paths (alias 'tails') against src_dir basedir = str(dst_dir) - if not is_saved_as_relpath: - basedir += str(src_dir) got_tails = {os.path.relpath(f, basedir) for f in unarchived_paths} expected_tails = { @@ -257,8 +195,8 @@ def assert_unarchived_paths( for f in src_dir.rglob("*") if is_file_or_emptydir(f) } - if unsupported_replace: - expected_tails = {_escape_undecodable_str(x) for x in expected_tails} + expected_tails = {_escape_undecodable_str(x) for x in expected_tails} + got_tails = {x.replace("�", "?") for x in got_tails} assert got_tails == expected_tails @@ -280,22 +218,15 @@ async def test_archiving_utils_against_sample( assert isinstance(p, Path), p await archive_dir( - dir_to_compress=destination, - destination=tmp_path / "test_it.zip", - compress=True, - store_relative_path=True, + dir_to_compress=destination, destination=tmp_path / "test_it.zip", compress=True ) -@pytest.mark.parametrize( - "compress,store_relative_path", - itertools.product([True, False], repeat=2), -) +@pytest.mark.parametrize("compress", [True, False]) async def test_archive_unarchive_same_structure_dir( dir_with_random_content: Path, tmp_path: Path, compress: bool, - store_relative_path: bool, ): temp_dir_one = tmp_path / "one" temp_dir_two = tmp_path / "two" @@ -308,7 +239,6 @@ async def test_archive_unarchive_same_structure_dir( await archive_dir( dir_to_compress=dir_with_random_content, destination=archive_file, - store_relative_path=store_relative_path, compress=compress, ) @@ -320,32 +250,29 @@ async def test_archive_unarchive_same_structure_dir( unarchived_paths, src_dir=dir_with_random_content, dst_dir=temp_dir_two, - is_saved_as_relpath=store_relative_path, ) - await assert_same_directory_content( - dir_with_random_content, - temp_dir_two, - None if store_relative_path else dir_with_random_content, - ) + await assert_same_directory_content(dir_with_random_content, temp_dir_two, None) -@pytest.mark.parametrize( - "compress,store_relative_path", - itertools.product([True, False], repeat=2), -) +@pytest.mark.parametrize("compress", [True, False]) async def test_unarchive_in_same_dir_as_archive( dir_with_random_content: Path, tmp_path: Path, compress: bool, - store_relative_path: bool, ): archive_file = tmp_path / "archive.zip" + existing_files: set[Path] = set() + for i in range(10): + # add some other files to the folder + existing = tmp_path / f"exiting-file-{i}" + existing.touch() + existing_files.add(existing) + await archive_dir( dir_to_compress=dir_with_random_content, destination=archive_file, - store_relative_path=store_relative_path, compress=compress, ) @@ -355,28 +282,22 @@ async def test_unarchive_in_same_dir_as_archive( archive_file.unlink() # delete before comparing contents + # remove existing files now that the listing was complete + for file in existing_files: + file.unlink() + assert_unarchived_paths( unarchived_paths, src_dir=dir_with_random_content, dst_dir=tmp_path, - is_saved_as_relpath=store_relative_path, ) - await assert_same_directory_content( - dir_with_random_content, - tmp_path, - None if store_relative_path else dir_with_random_content, - ) + await assert_same_directory_content(dir_with_random_content, tmp_path, None) -@pytest.mark.parametrize( - "compress,store_relative_path", - itertools.product([True, False], repeat=2), -) +@pytest.mark.parametrize("compress", [True, False]) async def test_regression_unsupported_characters( - tmp_path: Path, - compress: bool, - store_relative_path: bool, + tmp_path: Path, compress: bool ) -> None: archive_path = tmp_path / "archive.zip" dir_to_archive = tmp_path / "to_compress" @@ -397,7 +318,6 @@ def _create_file(file_name: str, content: str) -> None: await archive_dir( dir_to_compress=dir_to_archive, destination=archive_path, - store_relative_path=store_relative_path, compress=compress, ) @@ -409,15 +329,12 @@ def _create_file(file_name: str, content: str) -> None: unarchived_paths, src_dir=dir_to_archive, dst_dir=dst_dir, - is_saved_as_relpath=store_relative_path, - unsupported_replace=True, ) await assert_same_directory_content( dir_to_compress=dir_to_archive, output_dir=dst_dir, - inject_relative_path=None if store_relative_path else dir_to_archive, - unsupported_replace=True, + inject_relative_path=None, ) @@ -430,138 +347,16 @@ def _create_file(file_name: str, content: str) -> None: } -@dataclass(frozen=True) -class ExcludeParams: - exclude_patterns: set[str] - expected_result: set[Path] - - -# + /exclude_patterns_validation_dir -# + empty -# + d1 -# - f2.txt -# + sd1 -# - f2.txt -# - f1 -# - f1 -@pytest.mark.parametrize( - "params", - [ - ExcludeParams( - exclude_patterns={"/d1*"}, - expected_result=EMPTY_SET, - ), - ExcludeParams( - exclude_patterns={"/d1/sd1*"}, - expected_result={ - Path("d1/f2.txt"), - Path("d1/f1"), - }, - ), - ExcludeParams( - exclude_patterns={"d1*"}, - expected_result=EMPTY_SET, - ), - ExcludeParams( - exclude_patterns={"*d1*"}, - expected_result=EMPTY_SET, - ), - ExcludeParams( - exclude_patterns={"*.txt"}, - expected_result={ - Path("d1/f1"), - Path("d1/sd1/f1"), - }, - ), - ExcludeParams( - exclude_patterns={"/absolute/path/does/not/exist*"}, - expected_result=ALL_ITEMS_SET, - ), - ExcludeParams( - exclude_patterns={"/../../this/is/ignored*"}, - expected_result=ALL_ITEMS_SET, - ), - ExcludeParams( - exclude_patterns={"*relative/path/does/not/exist"}, - expected_result=ALL_ITEMS_SET, - ), - ], -) -async def test_archive_unarchive_check_exclude( - params: ExcludeParams, - exclude_patterns_validation_dir: Path, - tmp_path: Path, -): - temp_dir_one = tmp_path / "one" - temp_dir_two = tmp_path / "two" - - temp_dir_one.mkdir() - temp_dir_two.mkdir() - - archive_file = temp_dir_one / "archive.zip" - - # make exclude_patterns work relative to test directory - exclude_patterns = { - f"{exclude_patterns_validation_dir}/{x.strip('/') if x.startswith('/') else x}" - for x in params.exclude_patterns - } - - await archive_dir( - dir_to_compress=exclude_patterns_validation_dir, - destination=archive_file, - store_relative_path=True, - compress=False, - exclude_patterns=exclude_patterns, - ) - - unarchived_paths: set[Path] = await unarchive_dir( - archive_to_extract=archive_file, destination_folder=temp_dir_two - ) - - relative_unarchived_paths = {x.relative_to(temp_dir_two) for x in unarchived_paths} - - assert ( - relative_unarchived_paths == params.expected_result - ), f"Exclude rules: {exclude_patterns=}" - - -async def test_unarchive_dir_raises_error( - zipfile_single_file_extract_worker_raises_error: None, - dir_with_random_content: Path, - tmp_path: Path, -): - temp_dir_one = tmp_path / "one" - temp_dir_two = tmp_path / "two" - - temp_dir_one.mkdir() - temp_dir_two.mkdir() - - archive_file = temp_dir_one / "archive.zip" - - await archive_dir( - dir_to_compress=dir_with_random_content, - destination=archive_file, - store_relative_path=True, - compress=True, - ) - - with pytest.raises(ArchiveError, match=r"^.*raised as requested.*$"): - await archiving_utils.unarchive_dir(archive_file, temp_dir_two) - - file_suffix = 0 async def _archive_dir_performance( input_path: Path, destination_path: Path, compress: bool ): - global file_suffix # pylint: disable=global-statement + global file_suffix # pylint: disable=global-statement # noqa: PLW0603 await archive_dir( - input_path, - destination_path / f"archive_{file_suffix}.zip", - compress=compress, - store_relative_path=True, + input_path, destination_path / f"archive_{file_suffix}.zip", compress=compress ) file_suffix += 1 @@ -607,56 +402,9 @@ def _touch_all_files_in_path(path_to_archive: Path) -> None: path.touch() -@pytest.fixture -async def mixed_file_types(tmp_path: Path, faker: Faker) -> AsyncIterable[Path]: - base_dir = tmp_path / "mixed_types_dir" - base_dir.mkdir() - - # mixed small text files and binary files - (base_dir / "empty").mkdir() - (base_dir / "d1").mkdir() - (base_dir / "d1" / "f1.txt").write_text(faker.text()) - (base_dir / "d1" / "b2.bin").write_bytes(faker.json_bytes()) - (base_dir / "d1" / "sd1").mkdir() - (base_dir / "d1" / "sd1" / "f1.txt").write_text(faker.text()) - (base_dir / "d1" / "sd1" / "b2.bin").write_bytes(faker.json_bytes()) - (base_dir / "images").mkdir() - - # images cause issues with zipping, below content produced different - # hashes for zip files - for i in range(2): - image_dir = base_dir / f"images{i}" - image_dir.mkdir() - for n in range(50): - a = numpy.random.rand(900, 900, 3) * 255 # noqa: NPY002 - im_out = Image.fromarray(a.astype("uint8")).convert("RGB") - image_path = image_dir / f"out{n}.jpg" - im_out.save(image_path) - - print("mixed_types_dir ---") - _print_tree(base_dir) - - yield base_dir - - await remove_directory(base_dir) - assert not base_dir.exists() - - -@pytest.mark.parametrize( - "store_relative_path, compress", - [ - # test that all possible combinations still work - pytest.param(False, False, id="no_relative_path_no_compress"), - pytest.param(False, True, id="no_relative_path_with_compression"), - pytest.param(True, False, id="nodeports_options"), - pytest.param(True, True, id="with_relative_path_with_compression"), - ], -) +@pytest.mark.parametrize("compress", [False]) async def test_regression_archive_hash_does_not_change( - mixed_file_types: Path, - tmp_path: Path, - store_relative_path: bool, - compress: bool, + mixed_file_types: Path, tmp_path: Path, compress: bool ): destination_path = tmp_path / "archives_to_compare" destination_path.mkdir(parents=True, exist_ok=True) @@ -667,22 +415,32 @@ async def test_regression_archive_hash_does_not_change( assert not second_archive.exists() assert first_archive != second_archive - await archive_dir( - mixed_file_types, - first_archive, - compress=compress, - store_relative_path=store_relative_path, - ) + await archive_dir(mixed_file_types, first_archive, compress=compress) + assert first_archive.exists() _touch_all_files_in_path(mixed_file_types) - await archive_dir( - mixed_file_types, - second_archive, - compress=compress, - store_relative_path=store_relative_path, - ) + await archive_dir(mixed_file_types, second_archive, compress=compress) + assert second_archive.exists() _, first_hash = _compute_hash(first_archive) _, second_hash = _compute_hash(second_archive) assert first_hash == second_hash + + +@pytest.mark.parametrize("compress", [True, False]) +async def test_archive_empty_folder(tmp_path: Path, compress: bool): + archive_path = tmp_path / "zip_archive" + assert not archive_path.exists() + + empty_folder_path = tmp_path / "empty" + empty_folder_path.mkdir(parents=True, exist_ok=True) + extract_to_path = tmp_path / "extracted_to" + extract_to_path.mkdir(parents=True, exist_ok=True) + + await archive_dir(empty_folder_path, archive_path, compress=compress) + + detected_files = await unarchive_dir(archive_path, extract_to_path) + assert detected_files == set() + + await assert_same_directory_content(empty_folder_path, extract_to_path) diff --git a/packages/service-library/tests/test_archiving_utils_extra.py b/packages/service-library/tests/archiving_utils/test_archiving_utils_extra.py similarity index 87% rename from packages/service-library/tests/test_archiving_utils_extra.py rename to packages/service-library/tests/archiving_utils/test_archiving_utils_extra.py index bc2959c2e5b..16cb33b5d45 100644 --- a/packages/service-library/tests/test_archiving_utils_extra.py +++ b/packages/service-library/tests/archiving_utils/test_archiving_utils_extra.py @@ -6,6 +6,7 @@ from pathlib import Path import pytest +from helpers import print_tree from servicelib.archiving_utils import ( PrunableFolder, archive_dir, @@ -14,13 +15,6 @@ ) -def _print_tree(path: Path, level=0): - tab = " " * level - print(f"{tab}{'+' if path.is_dir() else '-'} {path if level==0 else path.name}") - for p in path.glob("*"): - _print_tree(p, level + 1) - - @pytest.fixture def state_dir(tmp_path) -> Path: """Folder with some data, representing a given state""" @@ -37,7 +31,7 @@ def state_dir(tmp_path) -> Path: (base_dir / "d1" / "d1_1" / "d1_1_1" / "f6").touch() print("state-dir ---") - _print_tree(base_dir) + print_tree(base_dir) # + /tmp/pytest-of-crespo/pytest-95/test_override_and_prune_from_a1/original # + empty # + d1 @@ -69,7 +63,7 @@ def new_state_dir(tmp_path) -> Path: # f6 deleted -> d1/d1_1/d2_2 remains empty and should be pruned print("new-state-dir ---") - _print_tree(base_dir) + print_tree(base_dir) # + /tmp/pytest-of-crespo/pytest-95/test_override_and_prune_from_a1/updated # + d1 # + d1_1 @@ -125,7 +119,7 @@ def test_override_and_prune_folder(state_dir: Path, new_state_dir: Path): assert old_paths != got_paths print("after ----") - _print_tree(state_dir) + print_tree(state_dir) @pytest.mark.parametrize( @@ -139,18 +133,10 @@ async def test_override_and_prune_from_archive( compress: bool, ): download_file = tmp_path / "download.zip" - expected_paths = { - p.relative_to(new_state_dir) - for p in new_state_dir.rglob("*") - if is_leaf_path(p) - } # archive new_state_dir -> download.zip await archive_dir( - dir_to_compress=new_state_dir, - destination=download_file, - compress=compress, - store_relative_path=True, # <=== relative! + dir_to_compress=new_state_dir, destination=download_file, compress=compress ) folder = PrunableFolder(state_dir) diff --git a/packages/service-library/tests/conftest.py b/packages/service-library/tests/conftest.py index 7527ee67a14..4f05756fa16 100644 --- a/packages/service-library/tests/conftest.py +++ b/packages/service-library/tests/conftest.py @@ -33,7 +33,7 @@ @pytest.fixture(scope="session") -def here(): +def package_tests_dir(): return Path(sys.argv[0] if __name__ == "__main__" else __file__).resolve().parent @@ -45,12 +45,12 @@ def package_dir() -> Path: @pytest.fixture(scope="session") -def osparc_simcore_root_dir(here) -> Path: - root_dir = here.parent.parent.parent.resolve() +def osparc_simcore_root_dir(package_tests_dir: Path) -> Path: + root_dir = package_tests_dir.parent.parent.parent.resolve() assert root_dir.exists(), "Is this service within osparc-simcore repo?" - assert any(root_dir.glob("packages/service-library")), ( - "%s not look like rootdir" % root_dir - ) + assert any( + root_dir.glob("packages/service-library") + ), f"{root_dir} not look like rootdir" return root_dir diff --git a/packages/service-library/tests/data/archive_utils/compress_stdout.json b/packages/service-library/tests/data/archive_utils/compress_stdout.json new file mode 100644 index 00000000000..6787eefe50f --- /dev/null +++ b/packages/service-library/tests/data/archive_utils/compress_stdout.json @@ -0,0 +1,148 @@ +[ + "\n7-Zip 23.01 (x6", + "\n7-Zip 23.01 (x64) : Copyright (", + "4) : Copyright (c) 1999-2023 Igo", + "c) 1999-2023 Igor Pavlov : 2023-", + "r Pavlov : 2023-06-20\n 64-bit lo", + "06-20\n 64-bit locale=en_US.UTF-8", + "cale=en_US.UTF-8 Threads:12 OPEN", + " Threads:12 OPEN_MAX:1024\n\nScann", + "_MAX:1024\n\nScanning the drive:\n ", + "ing the drive:\n 0M Scan /tmp/p", + " 0M Scan /tmp/pytest-of-silenth", + "ytest-of-silenthk/pytest-470/tes", + "k/pytest-470/test_something0/", + "test_something0/\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + " ", + " ", + " \b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b9 fold", + "\b\b\b\b\b\b\b\b\b\b9 folders, 204 files, ", + "ers, 204 files, 434866026 bytes ", + "434866026 bytes (415 MiB)\n\n", + "ytes (415 MiB)\n\nCreating archive", + "Creating archive: /tmp/pytest-of", + ": /tmp/pytest-of-silenthk/pytest", + "-silenthk/pytest-470/test_someth", + "-470/test_something0/mixed_types", + "ing0/mixed_types_dir.zip\n\nAdd ne", + "_dir.zip\n\nAdd new data to archiv", + "w data to archive: 9 folders, 20", + "e: 9 folders, 204 files, 4348660", + "4 files, 434866026 bytes (415 Mi", + "26 bytes (415 MiB)\n\n 0%", + " (415 MiB)\n\n 0%\b\b\b\b \b\b\b\b 8%", + "\b\b\b\b \b\b\b\b 8% 28 + mixed_type", + " 28 + mixed_types_dir/images0/ou", + "s_dir/images0/out3.jpg", + "images0/out3.jpg\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b\b\b ", + " ", + " \b\b\b\b\b\b\b\b\b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 1", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b 19% 49 + mixed_ty", + "9% 49 + mixed_types_dir/images0/", + "pes_dir/images0/out49.jpg", + "mages0/out49.jpg\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b\b\b\b ", + " ", + " \b\b\b\b\b\b\b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 30% 71 + mixed", + "\b 30% 71 + mixed_types_dir/image", + "_types_dir/images1/out23.jpg", + "mages1/out23.jpg\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b\b\b\b ", + " ", + " \b\b\b\b\b\b\b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 41% 92 + mixed", + "\b 41% 92 + mixed_types_dir/image", + "_types_dir/images1/out42.jpg", + "mages1/out42.jpg\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b\b\b\b ", + " ", + " \b\b\b\b\b\b\b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 52% 112 + mixe", + "\b 52% 112 + mixed_types_dir/imag", + "d_types_dir/images2/out15.jpg", + "mages2/out15.jpg\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b\b\b\b\b ", + " ", + " \b\b\b\b\b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 63% 136 + m", + "\b\b\b\b 63% 136 + mixed_types_dir/i", + "ixed_types_dir/images2/out37.jpg", + "mages2/out37.jpg\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b\b\b\b\b ", + " ", + " \b\b\b\b\b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 74% 160 + m", + "\b\b\b\b 74% 160 + mixed_types_dir/i", + "ixed_types_dir/images3/out13.jpg", + "mages3/out13.jpg\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b\b\b\b\b ", + " ", + " \b\b\b\b\b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 85% 180 + m", + "\b\b\b\b 85% 180 + mixed_types_dir/i", + "ixed_types_dir/images3/out31.jpg", + "mages3/out31.jpg\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b\b\b\b\b ", + " ", + " \b\b\b\b\b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 96% 204 + m", + "\b\b\b\b 96% 204 + mixed_types_dir/i", + "ixed_types_dir/images3/out9.jpg", + "images3/out9.jpg\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b\b\b\b ", + " ", + " \b\b\b\b\b\b\b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\nFiles read fro", + "\b\nFiles read from disk: 204\nArch", + "m disk: 204\nArchive size: 434902", + "ive size: 434902745 bytes (415 M", + "745 bytes (415 MiB)\nEverything i", + "iB)\nEverything is Ok\n", + "verything is Ok\n" +] diff --git a/packages/service-library/tests/data/archive_utils/decompress_stdout.json b/packages/service-library/tests/data/archive_utils/decompress_stdout.json new file mode 100644 index 00000000000..3d38437b7de --- /dev/null +++ b/packages/service-library/tests/data/archive_utils/decompress_stdout.json @@ -0,0 +1,53 @@ +[ + "\n7-Zip 23.01 (x6", + "\n7-Zip 23.01 (x64) : Copyright (", + "4) : Copyright (c) 1999-2023 Igo", + "c) 1999-2023 Igor Pavlov : 2023-", + "r Pavlov : 2023-06-20\n 64-bit lo", + "06-20\n 64-bit locale=en_US.UTF-8", + "cale=en_US.UTF-8 Threads:12 OPEN", + " Threads:12 OPEN_MAX:1024\n\nScann", + "_MAX:1024\n\nScanning the drive fo", + "ing the drive for archives:\n 0M", + "r archives:\n 0M Scan /tmp/pytes", + " Scan /tmp/pytest-of-silenthk/py", + "t-of-silenthk/pytest-470/test_so", + "test-470/test_something0/\b\b\b\b\b\b\b", + "mething0/\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b ", + " ", + " ", + " \b\b\b\b\b\b\b\b\b\b\b\b\b", + " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b1 file, 43490274", + "1 file, 434902745 bytes (415 MiB", + "5 bytes (415 MiB)\n\nExtracting ar", + ")\n\nExtracting archive: /tmp/pyte", + "chive: /tmp/pytest-of-silenthk/p", + "st-of-silenthk/pytest-470/test_s", + "ytest-470/test_something0/mixed_", + "omething0/mixed_types_dir.zip\n--", + "types_dir.zip\n--\nPath = /tmp/pyt", + "\nPath = /tmp/pytest-of-silenthk/", + "est-of-silenthk/pytest-470/test_", + "pytest-470/test_something0/mixed", + "something0/mixed_types_dir.zip\nT", + "_types_dir.zip\nType = zip\nPhysic", + "ype = zip\nPhysical Size = 434902", + "al Size = 434902745\n\n 0%", + " 434902745\n\n 0%\b\b\b\b \b\b\b\b 62%", + "\b\b\b\b \b\b\b\b 62% 137", + " \b\b\b\b 62% 137\b\b\b\b\b\b\b\b ", + "\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\bEverythi", + "\b\b\b\b\b\b\b\bEverything is Ok\n\nFolder", + "ng is Ok\n\nFolders: 9\nFiles: 204\n", + "s: 9\nFiles: 204\nSize: 4348", + "Size: 434866026\nCompressed", + "66026\nCompressed: 434902745\n", + "ssed: 434902745\n" +] diff --git a/packages/service-library/tests/data/archive_utils/list_edge_case.txt b/packages/service-library/tests/data/archive_utils/list_edge_case.txt new file mode 100644 index 00000000000..81831dafbd4 --- /dev/null +++ b/packages/service-library/tests/data/archive_utils/list_edge_case.txt @@ -0,0 +1,24 @@ +7-Zip (z) 24.09 (x64) : Copyright (c) 1999-2024 Igor Pavlov : 2024-11-28 + 64-bit locale=en_US.UTF-8 Threads:12 OPEN_MAX:1024, ASM + +Scanning the drive for archives: +1 file, 672 bytes (1 KiB) + +Listing archive: /tmp/pytest-of-silenthk/pytest-654/test_override_and_prune_from_a0/download.zip + +-- +Path = /tmp/pytest-of-silenthk/pytest-654/test_override_and_prune_from_a0/download.zip +Type = zip +Physical Size = 672 + + Date Time Attr Size Compressed Name +------------------- ----- ------------ ------------ ------------------------ +1980-01-01 00:00:00 D.... 0 0 d1 +1980-01-01 00:00:00 D.... 0 0 d1/d1_1 +1980-01-01 00:00:00 D.... 0 0 d1/d1_1/d1_2 +1980-01-01 00:00:00 ..... 0 0 d1/d1_1/d1_2/f5 +1980-01-01 00:00:00 D.... 0 0 d1/empty +1980-01-01 00:00:00 ..... 1 1 d1/f1 +1980-01-01 00:00:00 ..... 1 1 d1/f2 +------------------- ----- ------------ ------------ ------------------------ +1980-01-01 00:00:00 2 2 3 files, 4 folders diff --git a/packages/service-library/tests/data/archive_utils/list_stdout.txt b/packages/service-library/tests/data/archive_utils/list_stdout.txt new file mode 100644 index 00000000000..c2a0b0cba8f --- /dev/null +++ b/packages/service-library/tests/data/archive_utils/list_stdout.txt @@ -0,0 +1,1026 @@ +7-Zip (z) 24.09 (x64) : Copyright (c) 1999-2024 Igor Pavlov : 2024-11-28 + 64-bit locale=en_US.UTF-8 Threads:12 OPEN_MAX:1024, ASM + +Scanning the drive for archives: +1 file, 155072 bytes (152 KiB) + +Listing archive: /tmp/pytest-of-silenthk/pytest-636/test_unarchive_in_same_dir_as_0/archive.zip + +-- +Path = /tmp/pytest-of-silenthk/pytest-636/test_unarchive_in_same_dir_as_0/archive.zip +Type = zip +Physical Size = 155072 + + Date Time Attr Size Compressed Name +------------------- ----- ------------ ------------ ------------------------ +1980-01-01 00:00:00 D.... 0 0 study_data +1980-01-01 00:00:00 ..... 9 9 study_data/AHmPWWlG.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/BTdF +1980-01-01 00:00:00 ..... 4 4 study_data/IUDS/BTdF/sFXYkFAy.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/BzQs +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/BzQs/VOth +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/BzQs/VOth/KpMSFqyA.bin +1980-01-01 00:00:00 ..... 3 3 study_data/IUDS/BzQs/VOth/UPSYGkEP.bin +1980-01-01 00:00:00 ..... 4 4 study_data/IUDS/BzQs/VOth/vJfXMQIC.bin +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/BzQs/XuBDjZTP.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/BzQs/ZqbM +1980-01-01 00:00:00 ..... 3 3 study_data/IUDS/BzQs/ZqbM/mYzAqZjT.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/BzQs/ZqbM/mjFG +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/BzQs/ZqbM/mjFG/YbWExhbk.bin +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/BzQs/ZqbM/mjFG/eVYoddih.bin +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/BzQs/ZqbM/mjFG/rxCDPVFF.bin +1980-01-01 00:00:00 ..... 4 4 study_data/IUDS/BzQs/ZqbM/ogZtYPfy.bin +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/BzQs/ZqbM/xabFpebj.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/BzQs/oZeQ +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/BzQs/oZeQ/MQnS +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/BzQs/oZeQ/MQnS/iAimSiwK.bin +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/BzQs/oZeQ/MQnS/rOKJEsBI.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/BzQs/oZeQ/ZGdi +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/BzQs/oZeQ/ZGdi/wTDcGUje.bin +1980-01-01 00:00:00 ..... 8 8 study_data/IUDS/BzQs/oZeQ/ZxDtLxeH.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/BzQs/oZeQ/tMVI +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/BzQs/oZeQ/tMVI/dFqNULMW.bin +1980-01-01 00:00:00 ..... 6 6 study_data/IUDS/BzQs/oZeQ/tMVI/puxktrPH.bin +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/BzQs/oZeQ/vuWuSluC.bin +1980-01-01 00:00:00 ..... 3 3 study_data/IUDS/BzQs/oZeQ/wuzXQmhi.bin +1980-01-01 00:00:00 ..... 8 8 study_data/IUDS/HohXRGhf.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/Mpid +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/QUar/Mpid/NdzntSjX.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/Xzlt +1980-01-01 00:00:00 ..... 8 8 study_data/IUDS/QUar/Xzlt/btqHuExZ.bin +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/QUar/Xzlt/tcsoZMZI.bin +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/QUar/Xzlt/vCcJUSMG.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/bEEU +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/QUar/bEEU/AhluzLDS.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/bEEU/BLtJ +1980-01-01 00:00:00 ..... 3 3 study_data/IUDS/QUar/bEEU/BLtJ/AxpLtAvu.bin +1980-01-01 00:00:00 ..... 8 8 study_data/IUDS/QUar/bEEU/BLtJ/QYgKRbpp.bin +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/QUar/bEEU/BLtJ/YuuHpxZk.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/bEEU/BLtJ/awey +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/QUar/bEEU/BLtJ/awey/lOvujXaN.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/bEEU/BLtJ/jITF +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/QUar/bEEU/BLtJ/jITF/IoCtRjhp.bin +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/QUar/bEEU/BLtJ/jITF/QXNYHPqc.bin +1980-01-01 00:00:00 ..... 8 8 study_data/IUDS/QUar/bEEU/BLtJ/jITF/pvMObkYX.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/bEEU/BLtJ/zlvM +1980-01-01 00:00:00 ..... 4 4 study_data/IUDS/QUar/bEEU/BLtJ/zlvM/ZeEhVZwY.bin +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/QUar/bEEU/BLtJ/zlvM/ihmHTbnN.bin +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/QUar/bEEU/BLtJ/zlvM/nzoiJZki.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/bEEU/lERU +1980-01-01 00:00:00 ..... 4 4 study_data/IUDS/QUar/bEEU/lERU/dnwRnFwU.bin +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/QUar/bEEU/lERU/hfWJOzkF.bin +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/QUar/bEEU/lERU/wQyzbHYT.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/bEEU/mxdh +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/QUar/bEEU/mxdh/rcTCsmge.bin +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/QUar/pNXEIcLo.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/qAhw +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/qAhw/SITz +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/QUar/qAhw/SITz/TMwTQtnA.bin +1980-01-01 00:00:00 ..... 6 6 study_data/IUDS/QUar/qAhw/SITz/jPEINHjF.bin +1980-01-01 00:00:00 ..... 6 6 study_data/IUDS/QUar/qAhw/SITz/qzixwQro.bin +1980-01-01 00:00:00 ..... 3 3 study_data/IUDS/QUar/qAhw/fQtJoGGb.bin +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/QUar/qAhw/sZTvMnTJ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/qAhw/uuGV +1980-01-01 00:00:00 ..... 5 5 study_data/IUDS/QUar/qAhw/uuGV/QIBfeuDc.bin +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/QUar/qAhw/uuGV/XylGuojB.bin +1980-01-01 00:00:00 ..... 3 3 study_data/IUDS/QUar/qAhw/uuGV/lRWSDcMi.bin +1980-01-01 00:00:00 ..... 8 8 study_data/IUDS/QUar/tFumcsJe.bin +1980-01-01 00:00:00 ..... 6 6 study_data/IUDS/QUar/tJPiMsqg.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/xIOs +1980-01-01 00:00:00 ..... 8 8 study_data/IUDS/QUar/xIOs/IHImoeXf.bin +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/QUar/xIOs/TjUtupqB.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/QUar/xIOs/UjGi +1980-01-01 00:00:00 ..... 5 5 study_data/IUDS/QUar/xIOs/UjGi/GnPWYhmo.bin +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/QUar/xIOs/UjGi/fYMJDnhQ.bin +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/QUar/xIOs/eqoWettf.bin +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/SjHMTgiT.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/VXBb +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/VXBb/DxYL +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/VXBb/DxYL/SgIxHBds.bin +1980-01-01 00:00:00 ..... 3 3 study_data/IUDS/VXBb/DxYL/qHPbvyxB.bin +1980-01-01 00:00:00 ..... 4 4 study_data/IUDS/VXBb/XRdZqAWz.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/VXBb/xgFE +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/VXBb/xgFE/lfGWtuHA.bin +1980-01-01 00:00:00 ..... 7 7 study_data/IUDS/VXBb/xgFE/wpTZWDnU.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/VXBb/ztKe +1980-01-01 00:00:00 ..... 6 6 study_data/IUDS/VXBb/ztKe/YPFIVOrf.bin +1980-01-01 00:00:00 ..... 8 8 study_data/IUDS/VXBb/ztKe/ZJeFsUho.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/WQYt +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/WQYt/BXSb +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/WQYt/BXSb/JquB +1980-01-01 00:00:00 ..... 8 8 study_data/IUDS/WQYt/BXSb/JquB/qLPVVqKb.bin +1980-01-01 00:00:00 ..... 4 4 study_data/IUDS/WQYt/BXSb/WKglhhgu.bin +1980-01-01 00:00:00 ..... 5 5 study_data/IUDS/WQYt/BXSb/cyIvOSrm.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/WQYt/BXSb/fDgN +1980-01-01 00:00:00 ..... 3 3 study_data/IUDS/WQYt/BXSb/fDgN/xZJLFXXA.bin +1980-01-01 00:00:00 ..... 3 3 study_data/IUDS/WQYt/BXSb/fDgN/ztqgmNPi.bin +1980-01-01 00:00:00 ..... 7 7 study_data/IUDS/WQYt/BXSb/iShVNXLq.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/WQYt/FTKI +1980-01-01 00:00:00 ..... 7 7 study_data/IUDS/WQYt/FTKI/MymnzjRJ.bin +1980-01-01 00:00:00 ..... 5 5 study_data/IUDS/WQYt/FTKI/hJQhANiY.bin +1980-01-01 00:00:00 ..... 4 4 study_data/IUDS/WQYt/PIChqQda.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/WQYt/PYnJ +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/WQYt/PYnJ/OUUqJvzT.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/WQYt/uDeE +1980-01-01 00:00:00 ..... 1 1 study_data/IUDS/WQYt/uDeE/eJKaqNsP.bin +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/aeGNkaky.bin +1980-01-01 00:00:00 ..... 5 5 study_data/IUDS/gfmgGgKA.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/uomJ +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/uomJ/NaUm +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/uomJ/NaUm/BEZkvGlg.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/uomJ/PzmA +1980-01-01 00:00:00 ..... 6 6 study_data/IUDS/uomJ/PzmA/GYiivuev.bin +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/uomJ/PzmA/tLaNwKAZ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/uomJ/herB +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/uomJ/herB/AJRh +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/uomJ/herB/AJRh/MptYwYYo.bin +1980-01-01 00:00:00 ..... 8 8 study_data/IUDS/uomJ/herB/AJRh/pFaGUjAA.bin +1980-01-01 00:00:00 ..... 7 7 study_data/IUDS/uomJ/herB/AJRh/tTrjnkTO.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/uomJ/herB/DSym +1980-01-01 00:00:00 ..... 4 4 study_data/IUDS/uomJ/herB/DSym/EXdWaQBd.bin +1980-01-01 00:00:00 ..... 5 5 study_data/IUDS/uomJ/herB/DSym/oIhKwNnt.bin +1980-01-01 00:00:00 D.... 0 0 study_data/IUDS/uomJ/herB/SQWH +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/uomJ/herB/SQWH/OEwPkHZt.bin +1980-01-01 00:00:00 ..... 10 10 study_data/IUDS/uomJ/herB/SQWH/aPnGhYff.bin +1980-01-01 00:00:00 ..... 9 9 study_data/IUDS/uomJ/herB/kbAwBsaM.bin +1980-01-01 00:00:00 ..... 5 5 study_data/IUDS/uomJ/herB/kfenzVnd.bin +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/uomJ/pnFMfLCF.bin +1980-01-01 00:00:00 ..... 2 2 study_data/IUDS/uomJ/tmiBHwha.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/AHax +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/AHax/HHcLYoHX.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/AHax/cida +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/AHax/cida/iqrXWDol.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/AHax/cida/xHZygVBV.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/AHax/mhSe +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/AHax/mhSe/obwrdfVP.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/AHax/sDKW +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/AHax/sDKW/JeOB +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/AHax/sDKW/JeOB/XHmHUMdy.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/AHax/sDKW/JeOB/wBPFRLuC.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/AHax/sDKW/JeOB/wlDKOFXa.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/AHax/sDKW/QpGGvMkO.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/AHax/sDKW/qxUp +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/AHax/sDKW/qxUp/eEHSZJTy.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/AHax/sDKW/qxUp/yDSPphdu.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/AHax/sDKW/soalSpuS.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/AHax/woay +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/AHax/woay/OglKDkgA.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/AHax/woay/uIposZJU.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/BEIS +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/BEIS/XvuCCPPA.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/BEIS/hIUw +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/BEIS/hIUw/SelMNQFB.bin +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/BEIS/hIUw/fQdPzOgJ.bin +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/BEIS/hIUw/mOwNunmp.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/BEIS/vOAA +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/BEIS/vOAA/NBvNlKaH.bin +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/BEIS/vOAA/UEfQylpF.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/CGwQ/HIdCWBFM.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/CGwQ/TMWUpAjs.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/ZlXG +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/ZlXG/OWdF +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/CGwQ/ZlXG/OWdF/OFmIkxCP.bin +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/CGwQ/ZlXG/OWdF/PSdnKriR.bin +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/CGwQ/ZlXG/OWdF/mLfXczgZ.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/CGwQ/ZlXG/skMTdATf.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/glLz +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/glLz/ARkM +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/CGwQ/glLz/ARkM/GGFrxYJI.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/glLz/HraQ +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/CGwQ/glLz/HraQ/AEpAUPee.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/glLz/HraQ/ALDS +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/CGwQ/glLz/HraQ/ALDS/brzjpmwy.bin +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/CGwQ/glLz/HraQ/ALDS/pxBGKyUS.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/CGwQ/glLz/HraQ/ALDS/xJlwYbab.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/CGwQ/glLz/HraQ/MatzghLB.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/glLz/HraQ/Pmff +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/CGwQ/glLz/HraQ/Pmff/gWotxMKq.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/CGwQ/glLz/HraQ/ZIxtYbBj.bin +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/CGwQ/glLz/HxaOrjyy.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/CGwQ/glLz/OwSpSFzU.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/glLz/acvd +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/CGwQ/glLz/acvd/CHiprfuO.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/CGwQ/glLz/acvd/NKEIGiVl.bin +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/CGwQ/glLz/acvd/dHvcDzKL.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/CGwQ/glLz/phrjYiFq.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/glLz/qrLX +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/glLz/qrLX/LtmA +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/CGwQ/glLz/qrLX/LtmA/DtJcuFIC.bin +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/CGwQ/glLz/qrLX/LtmA/onlSzKUy.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/CGwQ/glLz/qrLX/LtmA/tCLsDgeU.bin +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/CGwQ/glLz/qrLX/VEtnVRLJ.bin +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/CGwQ/glLz/qrLX/ZXFETwRa.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/glLz/qrLX/xweq +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/CGwQ/glLz/qrLX/xweq/cmAVxrwC.bin +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/CGwQ/glLz/qrLX/xweq/dYNGHiXH.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/CGwQ/glLz/qrLX/xweq/yfGkscwv.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/glLz/qrLX/yYXb +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/CGwQ/glLz/qrLX/yYXb/vAGAkkwI.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/CGwQ/gspMOvRJ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/CGwQ/kzvA +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/CGwQ/kzvA/UMDWfhuC.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/CGwQ/kzvA/gijIIvlb.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/DLUZ +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/DLUZ/EpGS +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/DLUZ/EpGS/UuTE +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/DLUZ/EpGS/UuTE/OAdlkjjY.bin +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/DLUZ/EpGS/fBUUjfUw.bin +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/DLUZ/EpGS/gNRfPaEP.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/DLUZ/EpGS/pMlZ +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/DLUZ/EpGS/pMlZ/LqjcxAZR.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/DLUZ/EpGS/pMlZ/SCpvaIYE.bin +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/DLUZ/EpGS/pMlZ/rdjkKAPe.bin +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/DLUZ/LghbzxaY.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/DLUZ/XOWB +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/DLUZ/XOWB/BhvokPZb.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/DLUZ/XOWB/lmPXYNjp.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/DLUZ/YspaXBKN.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/DLUZ/piPY +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/DLUZ/piPY/BLJhwTKs.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/DLUZ/piPY/GcXTairW.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/DLUZ/piPY/ltTOQpae.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/DLUZ/zUQl +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/DLUZ/zUQl/MKpwDeHY.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/DLUZ/zUQl/OuOU +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/DLUZ/zUQl/OuOU/EuuLsrvp.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/DLUZ/zUQl/OuOU/fZhWFKVP.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/DLUZ/zUQl/OuOU/usrVkWUt.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/VSTY/JyCeSjfx.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/LJil +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/VSTY/LJil/ZPsEjcSB.bin +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/VSTY/LJil/dlYKGjXI.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/LJil/uPYc +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/VSTY/LJil/uPYc/RxYReBnu.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/RRGz +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/RRGz/AzmB +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/VSTY/RRGz/AzmB/lKzwMJqx.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/RRGz/AzmB/oCKc +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/VSTY/RRGz/AzmB/oCKc/REnXtFrp.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/RRGz/MCux +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/VSTY/RRGz/MCux/BMfcVMQX.bin +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/VSTY/RRGz/dEZbdrPP.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/VSTY/RRGz/dkqruact.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/RRGz/mEKd +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/VSTY/RRGz/mEKd/DuKbgZkd.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/VSTY/RRGz/mEKd/JiPMEOqv.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/RRGz/mEKd/eGzJ +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/VSTY/RRGz/mEKd/eGzJ/XgIJzblX.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/RRGz/mEKd/ibgk +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/VSTY/RRGz/mEKd/ibgk/FGbingZo.bin +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/VSTY/RRGz/xGGsXkeo.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/uWlw +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/VSTY/uWlw/ApYpBPJI.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/VSTY/uWlw/GcQwkFLK.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/uWlw/SHln +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/VSTY/uWlw/SHln/YUHBaifP.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/VSTY/uWlw/hxumkOwg.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/uWlw/iiaQ +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/VSTY/uWlw/iiaQ/FIqMoOJZ.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/VSTY/uWlw/iiaQ/iXMMZzKE.bin +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/VSTY/uWlw/iiaQ/jIXXEQXU.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/VSTY/vAwh +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/VSTY/vAwh/xZynSKnG.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/VSTY/vkRNwRzu.bin +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/WMtOCTHZ.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/XGQGvNKr.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP/DpWM +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/ZaeP/DpWM/XlPYvxxH.bin +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/ZaeP/DpWM/pBlUsWKW.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/ZaeP/DpWM/wJeYcIpu.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP/FfHg +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP/FfHg/IiFy +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/ZaeP/FfHg/IiFy/eqgDEchG.bin +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/ZaeP/FfHg/PpIaxZzG.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/ZaeP/FfHg/iNWEDRER.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP/FfHg/upUk +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/ZaeP/FfHg/upUk/JPVjhyDQ.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/ZaeP/FfHg/upUk/KdZmxodV.bin +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/ZaeP/FfHg/yCWUuAXv.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP/aTPz +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/ZaeP/aTPz/OHcJTBRe.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/ZaeP/aTPz/uKwlCrJT.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP/mywl +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/ZaeP/mywl/ulwBbWcd.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP/ocjx +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP/ocjx/FLIp +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/ZaeP/ocjx/FLIp/NDoRNeuq.bin +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/ZaeP/ocjx/FLIp/UzzbUmmv.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP/ocjx/NPvz +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/ZaeP/ocjx/NPvz/UgrVBJXC.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/ZaeP/ocjx/NPvz/ZmunbBBl.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/ZaeP/ocjx/NyJP +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/ZaeP/ocjx/NyJP/ZyloaHjk.bin +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/ZaeP/ocjx/qVhCWfKD.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/ZaeP/vEesrCcd.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/nDgc +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/nDgc/JZsoYDwQ.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/nDgc/LgcnuLoA.bin +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/nDgc/ZKTtJeXV.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/FZiW +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/FZiW/GILE +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/FZiW/GILE/ADNa +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/spKz/FZiW/GILE/ADNa/NiLIdxMt.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/spKz/FZiW/GILE/ADNa/baAhcEWY.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/FZiW/GILE/HHAP +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/spKz/FZiW/GILE/HHAP/BUYkaaFj.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/spKz/FZiW/GILE/HHAP/RzldGmhm.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/spKz/FZiW/GILE/HHAP/iTeZtHOU.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/spKz/FZiW/GILE/VyXRfRVQ.bin +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/spKz/FZiW/GILE/eewCvNAN.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/spKz/FZiW/GILE/ktJXFPXz.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/FZiW/GILE/yfUb +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/spKz/FZiW/GILE/yfUb/dDKAfAZE.bin +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/spKz/FZiW/GILE/yfUb/umLeeGQL.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/spKz/FZiW/GILE/yfUb/xiyozONo.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/spKz/FZiW/HwEjOXIR.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/FZiW/LlQs +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/spKz/FZiW/LlQs/YUdnxKOj.bin +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/spKz/FZiW/LlQs/lMrWIHnc.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/spKz/FZiW/LlQs/pBSEzNZW.bin +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/spKz/ULYZNpys.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/spKz/eyDjAdhw.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/spKz/sXqJ/AdzfACXQ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ/OeNj +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/spKz/sXqJ/OeNj/AnRPduis.bin +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/spKz/sXqJ/OeNj/yqxpchNa.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/spKz/sXqJ/SdVPoeDT.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ/Tvjn +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/spKz/sXqJ/Tvjn/GOgsNtHV.bin +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/spKz/sXqJ/Tvjn/QIvObNkk.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/spKz/sXqJ/Tvjn/VGJjiFQh.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ/UONi +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ/UONi/Hpbv +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/spKz/sXqJ/UONi/Hpbv/FNLyKFpT.bin +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/spKz/sXqJ/UONi/Hpbv/bZCTbXJT.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ/UONi/NVpw +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/spKz/sXqJ/UONi/NVpw/OuKUROEq.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/spKz/sXqJ/UONi/NVpw/qoLOadUH.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/spKz/sXqJ/UONi/NVpw/uTUymCTi.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ/UONi/Witp +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/spKz/sXqJ/UONi/Witp/gxqwKKJq.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/spKz/sXqJ/UONi/Witp/iCBirjew.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/spKz/sXqJ/UONi/ztkcHHOi.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ/vmKv +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ/vmKv/CkGq +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/spKz/sXqJ/vmKv/CkGq/xquIKRuS.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ/vmKv/HJUM +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/spKz/sXqJ/vmKv/HJUM/BKgDBvHB.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/spKz/sXqJ/vmKv/HJUM/ZWekbYEG.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/spKz/sXqJ/vmKv/HJUM/nqFqJcpE.bin +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/spKz/sXqJ/vmKv/NDqtGaaA.bin +1980-01-01 00:00:00 ..... 6 6 study_data/PbDS/spKz/sXqJ/vmKv/pIiNhJaI.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/sXqJ/vmKv/sKnu +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/spKz/sXqJ/vmKv/sKnu/OoPxEOZr.bin +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/spKz/sXqJ/vmKv/sKnu/hEKmDTRd.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/wYGM +1980-01-01 00:00:00 ..... 3 3 study_data/PbDS/spKz/wYGM/KsgcCdPJ.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/spKz/wYGM/QfWEihJc.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/ymut +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/ymut/RdJe +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/spKz/ymut/RdJe/eOdgYdJr.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/spKz/ymut/RdJe/fGGivJke.bin +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/spKz/ymut/dWqXfuqB.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/ymut/eZsl +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/spKz/ymut/eZsl/rDnzlYzm.bin +1980-01-01 00:00:00 ..... 9 9 study_data/PbDS/spKz/ymut/eZsl/tirLLJuG.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/spKz/ymut/tHga +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/spKz/ymut/tHga/fJYTIXcQ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/tsdB +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/tsdB/BEIOYZmw.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/uNpG +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/uNpG/GKMS +1980-01-01 00:00:00 ..... 2 2 study_data/PbDS/uNpG/GKMS/eOlzfIGa.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/uNpG/GKMS/qrydULYI.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/uNpG/GKMS/zoQsaBgm.bin +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/uNpG/WBJhVela.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/uNpG/smez +1980-01-01 00:00:00 ..... 4 4 study_data/PbDS/uNpG/smez/SOePbQeI.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/uNpG/smez/auLnSzPS.bin +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/uNpG/smez/sCFLNyht.bin +1980-01-01 00:00:00 ..... 10 10 study_data/PbDS/vaxuZvrv.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/yWpC +1980-01-01 00:00:00 ..... 5 5 study_data/PbDS/yWpC/IIADldhb.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/yWpC/Khcd +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/yWpC/Khcd/JineYSCb.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/yWpC/Khcd/bcLvtLeS.bin +1980-01-01 00:00:00 D.... 0 0 study_data/PbDS/yWpC/mtZm +1980-01-01 00:00:00 ..... 7 7 study_data/PbDS/yWpC/mtZm/MGfhcHkp.bin +1980-01-01 00:00:00 ..... 8 8 study_data/PbDS/yWpC/mtZm/jhNrgOsG.bin +1980-01-01 00:00:00 ..... 1 1 study_data/PbDS/yWpC/mtZm/xeNdgdzs.bin +1980-01-01 00:00:00 ..... 10 10 study_data/XOKAMIFq.bin +1980-01-01 00:00:00 ..... 5 5 study_data/XepHHTJo.bin +1980-01-01 00:00:00 ..... 3 3 study_data/dWYwKvfQ.bin +1980-01-01 00:00:00 ..... 5 5 study_data/joLovHDU.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/EpFh/LXoatLgw.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/EpFh/NnqawJFg.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/EpFh/RGsGfOIB.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/eaVw +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/EpFh/eaVw/BvFicfle.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/EpFh/eaVw/ORBrGIiT.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/iEPO +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/iEPO/lxKE +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/EpFh/iEPO/lxKE/AOENgbsn.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/EpFh/iEPO/zRlZKSdY.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/Fasc +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/Fasc/YKrH +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/EpFh/nihR/Fasc/YKrH/aaXePFwS.bin +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/EpFh/nihR/Fasc/YKrH/gajMUskk.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/EpFh/nihR/Fasc/YKrH/raQuZNGJ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/Fasc/okiQ +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/EpFh/nihR/Fasc/okiQ/IrOtTJFx.bin +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/EpFh/nihR/Fasc/okiQ/MJYXQsyO.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/EpFh/nihR/Fasc/okiQ/sQqBpqzD.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/EpFh/nihR/Fasc/wIfZiuuw.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/NDVH +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/EpFh/nihR/NDVH/cZrDbzfN.bin +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/EpFh/nihR/UjcYcdmS.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/bRaj +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/EpFh/nihR/bRaj/NJXiXFYi.bin +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/EpFh/nihR/bRaj/ZlnPxYqP.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/EpFh/nihR/bWylLbEK.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/lttR +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/EpFh/nihR/lttR/CVhzbPeh.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/EpFh/nihR/lttR/QenoImvH.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/EpFh/nihR/lttR/fSMUpaRn.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/vOMj +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/vOMj/TdeW +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/EpFh/nihR/vOMj/TdeW/BGOoUuHE.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/EpFh/nihR/vOMj/TdeW/lUETxQqS.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/vOMj/TrFt +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/EpFh/nihR/vOMj/TrFt/EAbnIiTW.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/EpFh/nihR/vOMj/TrFt/bxFZtNfR.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/EpFh/nihR/vOMj/TrFt/eIAYdzIx.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/vOMj/cXzO +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/EpFh/nihR/vOMj/cXzO/DXgTlcXe.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/EpFh/nihR/vOMj/cXzO/IAurqNpE.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/EpFh/nihR/vOMj/cXzO/egEGKVeK.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/EpFh/nihR/vOMj/hwiZkldP.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/EpFh/nihR/vOMj/nGvUhWAB.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/vfaz +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/vfaz/PgeA +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/EpFh/nihR/vfaz/PgeA/fHiljXhM.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/EpFh/nihR/vfaz/PgeA/rRpgIYzk.bin +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/EpFh/nihR/vfaz/ZRzfDAuM.bin +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/EpFh/nihR/vfaz/ZapbujcM.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/EpFh/nihR/vfaz/gOXuIvuu.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/nihR/vfaz/iVFp +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/EpFh/nihR/vfaz/iVFp/IOekCIGU.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/JJGM +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/EpFh/pRYz/JJGM/YqcCLfOW.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/EpFh/pRYz/JJGM/iTVflTax.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/Nhgn +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/EpFh/pRYz/Nhgn/OgQQakzD.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/EpFh/pRYz/Nhgn/VfVAbEPf.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/Nhgn/Zgyp +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/EpFh/pRYz/Nhgn/Zgyp/FuMtJTPq.bin +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/EpFh/pRYz/Nhgn/Zgyp/GhpdjBRS.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/EpFh/pRYz/Nhgn/Zgyp/fDdYvwtf.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/EpFh/pRYz/Nhgn/jIjvPasH.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/Piyb +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/EpFh/pRYz/Piyb/HepLTRsV.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/Piyb/SnJA +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/EpFh/pRYz/Piyb/SnJA/Xgbdlvcn.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/EpFh/pRYz/Piyb/SnJA/lFhaivBK.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/EpFh/pRYz/Piyb/SnJA/rpSWLjju.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/Piyb/TNdn +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/EpFh/pRYz/Piyb/TNdn/ThNnMvHL.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/EpFh/pRYz/Piyb/TNdn/vdueObZq.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/Piyb/XFTc +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/EpFh/pRYz/Piyb/XFTc/FaEWOeaf.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/EpFh/pRYz/Piyb/XFTc/LwYirLla.bin +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/EpFh/pRYz/Piyb/XFTc/zWMuXdnl.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/EpFh/pRYz/Piyb/bQvsoZgn.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/EpFh/pRYz/SXRTSzwc.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/aPCU +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/EpFh/pRYz/aPCU/ZbYtlWbi.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/EpFh/pRYz/aPCU/bKLpLQyY.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/aPCU/iyBf +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/EpFh/pRYz/aPCU/iyBf/QXyLnltk.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/EpFh/pRYz/aPCU/iyBf/RRrvDFBm.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/EpFh/pRYz/aPCU/iyBf/tebfpNNw.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/aPCU/rCnj +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/EpFh/pRYz/aPCU/rCnj/BYopBjsq.bin +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/EpFh/pRYz/aPCU/rCnj/xTYMFVdC.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/EpFh/pRYz/aPCU/rCnj/ztmfWauD.bin +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/EpFh/pRYz/mNyxHHZU.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/EpFh/pRYz/vGfd +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/EpFh/pRYz/vGfd/UZEDmfRf.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/TRuJ +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/TRuJ/TBTCWVIF.bin +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/TRuJ/dgNWJGZZ.bin +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/WrBimZYN.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/cvNb +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/cvNb/DDBlyTVQ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/cvNb/ECqb +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/cvNb/ECqb/AflRnBHO.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/cvNb/ECqb/IHAoRRfi.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/cvNb/ECqb/UsOeOqKz.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/cvNb/UxyI +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/cvNb/UxyI/OoxFFTKz.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/cvNb/UxyI/PNZGMdcO.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/cvNb/fvXnBWEH.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/cvNb/jhhlxDpv.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/ezvwqwjA.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fCfx +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fCfx/XVtJ +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/fCfx/XVtJ/jHpzpKhm.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fCfx/luiD +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/fCfx/luiD/ANEnmJBQ.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/fCfx/luiD/crQEaRwE.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/fCfx/wfaBvFqN.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fCfx/zTyq +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/fCfx/zTyq/PmbqMjih.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/fCfx/zTyq/eQRdtxLq.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fVOY +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/fVOY/cqtsqGPc.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fVOY/upaM +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/fVOY/upaM/VAqByQwN.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/fVOY/upaM/tjhJjheI.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/BDCM +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/BDCM/Hmru +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/fvWH/BDCM/Hmru/moIBrKnl.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/BDCM/UVjo +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/fvWH/BDCM/UVjo/OaDqrgNV.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/fvWH/BDCM/UVjo/OzqXynvt.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/fvWH/BDCM/UVjo/waJTqlzv.bin +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/fvWH/BDCM/VFKVCKSd.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/BDCM/ZIVO +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/fvWH/BDCM/ZIVO/WLaoZCKE.bin +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/fvWH/BDCM/ZIVO/tebssNLZ.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/fvWH/BDCM/ZIVO/vTErengc.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/fvWH/BDCM/dZqOfgtH.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/fvWH/BDCM/lDeJqMxj.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/BUuY +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/fvWH/BUuY/KunOFMPo.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/BUuY/ULnx +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/fvWH/BUuY/ULnx/vhxhmSEG.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/BUuY/iKGS +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/fvWH/BUuY/iKGS/AsQkhisM.bin +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/fvWH/BUuY/iKGS/rnPnXFfC.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/fvWH/BUuY/iRImrZFN.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/fvWH/BUuY/oVZwPFrY.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/LgmT +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/LgmT/OGQK +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/fvWH/LgmT/OGQK/BIZlUBKq.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/LgmT/VbfA +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/fvWH/LgmT/VbfA/cDdTRWcK.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/fvWH/LgmT/VbfA/kfrpbyjT.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/fvWH/LgmT/VbfA/wtiJkSMT.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/LgmT/jJMb +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/fvWH/LgmT/jJMb/CPINYFLA.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/fvWH/LgmT/jJMb/MzrpZTbW.bin +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/fvWH/LgmT/oKTZaGbJ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/czeO +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/fvWH/czeO/CPduFCuG.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/czeO/HXOz +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/fvWH/czeO/HXOz/JSaRyCIc.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/czeO/Wftj +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/fvWH/czeO/Wftj/ZbHrtDgU.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/czeO/Wftj/uUYI +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/fvWH/czeO/Wftj/uUYI/pqtgCVkL.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/fvWH/czeO/Wftj/uUYI/sYHxXPZC.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/fvWH/czeO/Wftj/uUYI/xMRMwhnr.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/czeO/zeSB +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/fvWH/czeO/zeSB/blWgWcDu.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/fvWH/czeO/zeSB/mIFegvuO.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/fvWH/ddEffTHj.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/ifJn +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/fvWH/ifJn/XvjPxmxX.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/fvWH/ifJn/uBFNbsua.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/rdjg +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/fvWH/rdjg/ByRvZziY.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/rdjg/DGeD +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/fvWH/rdjg/DGeD/JrkFMQiv.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/rdjg/DGeD/QGJW +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/fvWH/rdjg/DGeD/QGJW/YgNpPJiJ.bin +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/fvWH/rdjg/DGeD/QGJW/ryLWzUvA.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/rdjg/DGeD/WjwU +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/fvWH/rdjg/DGeD/WjwU/qvgUfPjY.bin +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/fvWH/rdjg/DGeD/yLWxNwlk.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/fvWH/rdjg/ZncvEwJm.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/rdjg/ayGm +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/rdjg/ayGm/Myjs +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/fvWH/rdjg/ayGm/Myjs/ElPKkYsz.bin +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/fvWH/rdjg/ayGm/Myjs/SylqDbHW.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/fvWH/rdjg/ayGm/wvxnBOKO.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/fvWH/rdjg/ixqpZqUJ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/rdjg/qTMZ +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/fvWH/rdjg/qTMZ/BjNIiRos.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/rdjg/tnqV +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/rdjg/tnqV/GIQN +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/fvWH/rdjg/tnqV/GIQN/BNXmlOpW.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/fvWH/rdjg/tnqV/HeDz +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/fvWH/rdjg/tnqV/HeDz/HRwylvtC.bin +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/fvWH/rdjg/tnqV/HeDz/czUpsQdU.bin +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/fvWH/rdjg/tnqV/HeDz/kyCzCRzi.bin +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/fvWH/rdjg/tnqV/RGdcUwIl.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/fvWH/rdjg/tnqV/zoDphsOA.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/iAyO +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/iAyO/PPmxfTfO.bin +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/iAyO/ncBVNvYU.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/iAyO/zZvQefyZ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/okzR +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/okzR/Dsot +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/okzR/Dsot/LBtCFust.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/okzR/Dsot/PrMW +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/okzR/Dsot/PrMW/AgiwqkCG.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/okzR/Dsot/PrMW/GeuHheGI.bin +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/okzR/Dsot/PrMW/UfwYrxWD.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/okzR/IRSz +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/okzR/IRSz/pTkbQxLN.bin +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/okzR/IRSz/yYqHDOvE.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/okzR/IRSz/zFOu +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/okzR/IRSz/zFOu/XdozGxhV.bin +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/okzR/IRSz/zFOu/ZtiKJGpR.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/okzR/IRSz/zFOu/bnVtDjhd.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/okzR/MHHiWQHG.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/okzR/Wzwr +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/okzR/Wzwr/spDbzHGA.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/okzR/itZT +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/okzR/itZT/EvDG +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/okzR/itZT/EvDG/dBFvHSHR.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/okzR/itZT/EvDG/rKpmiQhv.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/okzR/itZT/EvDG/vvPVJrID.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/okzR/itZT/dnEVgLwz.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/okzR/itZT/sYqw +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/okzR/itZT/sYqw/TBgDoilL.bin +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/okzR/itZT/sYqw/TNvGZGAA.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/okzR/neiT +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/okzR/neiT/SUSkHYyZ.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/okzR/vbEclTGm.bin +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/okzR/zzNUNqQx.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/ygsr +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/ygsr/HYsw +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/ygsr/HYsw/BFOG +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/ygsr/HYsw/BFOG/RYrsjSMp.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/ygsr/HYsw/BFOG/umDeitsb.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/ygsr/HYsw/EUbu +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/ygsr/HYsw/EUbu/EiaIpHaR.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/ygsr/HYsw/EUbu/hTMxDopY.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/ygsr/HYsw/mmQS +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/ygsr/HYsw/mmQS/IKOfQKHg.bin +1980-01-01 00:00:00 ..... 6 6 study_data/qpBn/ygsr/HYsw/mmQS/aZjtUQrA.bin +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/ygsr/HYsw/mmQS/jMqXeEHK.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/ygsr/HYsw/zxBwxQBV.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/ygsr/LGnv +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/ygsr/LGnv/GLlLwZTX.bin +1980-01-01 00:00:00 ..... 3 3 study_data/qpBn/ygsr/LGnv/UfCliLsk.bin +1980-01-01 00:00:00 ..... 10 10 study_data/qpBn/ygsr/LGnv/hHkrHkUL.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/ygsr/MjyB +1980-01-01 00:00:00 ..... 4 4 study_data/qpBn/ygsr/MjyB/HrrNLNgt.bin +1980-01-01 00:00:00 ..... 1 1 study_data/qpBn/ygsr/MjyB/OUXOQcDk.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/ygsr/SxnX +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/ygsr/SxnX/IjbzJfYC.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/ygsr/SxnX/acHfxqVQ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/ygsr/aGQe +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/ygsr/aGQe/QlDFdseq.bin +1980-01-01 00:00:00 D.... 0 0 study_data/qpBn/ygsr/aGQe/WRkk +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/ygsr/aGQe/WRkk/bOZqMgPB.bin +1980-01-01 00:00:00 ..... 9 9 study_data/qpBn/ygsr/aGQe/WRkk/bnixlRLd.bin +1980-01-01 00:00:00 ..... 7 7 study_data/qpBn/ygsr/aGQe/WRkk/gdsfUcZg.bin +1980-01-01 00:00:00 ..... 8 8 study_data/qpBn/ygsr/aokwRxPP.bin +1980-01-01 00:00:00 ..... 5 5 study_data/qpBn/ygsr/hhOTTdxQ.bin +1980-01-01 00:00:00 ..... 2 2 study_data/qpBn/ygsr/miJahKEK.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/Acpw +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/Acpw/EpnwbdTq.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/Acpw/wYWyFKaq.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/HIzP +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/HIzP/ESRQdUty.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/HIzP/OviHEAXX.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/LhEi +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/LhEi/LUNRHjwM.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/LhEi/NIRc +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/LhEi/NIRc/kEJbKeND.bin +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/LhEi/TodIQghn.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/LhEi/mwAYhzaW.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/POfv +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/POfv/AXRE +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/POfv/AXRE/CDkdtsgj.bin +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/POfv/HDAOwLCZ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/POfv/KLzp +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/POfv/KLzp/VdcGHgWk.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/POfv/KLzp/XPdh +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/POfv/KLzp/XPdh/juyQHIhv.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/POfv/KLzp/btcF +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/POfv/KLzp/btcF/BKAqFTqk.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/POfv/KLzp/btcF/PNOtiDiM.bin +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/POfv/KLzp/btcF/itzrHoXN.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/POfv/KLzp/cvVCYhxN.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/POfv/KLzp/nqqdvauD.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/POfv/NQCY +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/POfv/NQCY/EtTR +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/POfv/NQCY/EtTR/WEwxmidz.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/POfv/NQCY/EtTR/qPYkbccP.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/POfv/NQCY/FjWFUbhU.bin +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/POfv/NQCY/kynTWzzv.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/POfv/NQCY/tUDwIPMP.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/POfv/XtKSaiuJ.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/POfv/iaDFjGee.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/POfv/mdwT +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/POfv/mdwT/BBDbHkfl.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/POfv/mdwT/PLRSafGv.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/POfv/mdwT/QBguVHuw.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/RdbQ +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/RdbQ/DFWrHCde.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/RdbQ/JGpd +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/RdbQ/JGpd/FRwxKDxR.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/RdbQ/JGpd/KxWJEhMk.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/RdbQ/UhGv +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/RdbQ/UhGv/IRCOMMBy.bin +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/RdbQ/ZLvZQYqx.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/RdbQ/absq +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/RdbQ/absq/AvZV +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/RdbQ/absq/AvZV/bPvQjucH.bin +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/RdbQ/absq/AvZV/hNEvuEaf.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/RdbQ/absq/SxKCmmAC.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/RdbQ/absq/YltmgmGJ.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/RdbQ/absq/jjTLOtNg.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/RdbQ/bLSC +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/RdbQ/bLSC/vlUMpRaC.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/RdbQ/bcAj +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/RdbQ/bcAj/YHeLwylR.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/RdbQ/bcAj/gjuz +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/RdbQ/bcAj/gjuz/OlAQxxZn.bin +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/RdbQ/yShZVhRx.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/USmD/CYIJMHTQ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/GwqG +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/USmD/GwqG/LwRhfSYy.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/CzQS +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/USmD/XUAi/CzQS/ECyfvMPP.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/CzQS/gXuZ +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/USmD/XUAi/CzQS/gXuZ/SMztWfWu.bin +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/USmD/XUAi/CzQS/gXuZ/XyqGnwfe.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/CzQS/uzau +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/USmD/XUAi/CzQS/uzau/tQdbfTUz.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/USmD/XUAi/CzQS/uzau/xJpRStbn.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/eKGQ +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/USmD/XUAi/eKGQ/bvxMMcMf.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/USmD/XUAi/eKGQ/yzgjWMmk.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/fNJe +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/USmD/XUAi/fNJe/ALUQxkdU.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/XUAi/fNJe/jxxVZAdj.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/llRd +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/llRd/YSPZ +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/XUAi/llRd/YSPZ/TUXRRGxX.bin +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/USmD/XUAi/llRd/fPvMvIlh.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/USmD/XUAi/llRd/lebTeotH.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/USmD/XUAi/llRd/vxhOIIuv.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/llRd/xAUr +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/USmD/XUAi/llRd/xAUr/knVguTBT.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/USmD/XUAi/llRd/xAUr/uwxqvNka.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/USmD/XUAi/loRxYivv.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/ulEW +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/USmD/XUAi/ulEW/SuVIOWyh.bin +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/USmD/XUAi/ulEW/XkxHykGg.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/USmD/XUAi/ulEW/nfVdyMUw.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/ulEW/xAew +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/XUAi/ulEW/xAew/cwtCecYJ.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/XUAi/ulEW/xAew/rEFHmxkm.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/XUAi/yNha +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/USmD/XUAi/yNha/bOsbDHyJ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/ozop +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/ozop/CXCA +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/USmD/ozop/CXCA/BzzozBSL.bin +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/USmD/ozop/CXCA/ClmSOpKS.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/USmD/ozop/CXCA/LcBHApWy.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/ozop/SgtE +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/USmD/ozop/SgtE/kPNoxogl.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/ozop/SgtE/xwPG +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/USmD/ozop/SgtE/xwPG/aXMUqvZN.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/USmD/ozop/SgtE/xwPG/umvZCqer.bin +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/USmD/ozop/WFdSxlTh.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/ozop/ZMpw +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/USmD/ozop/ZMpw/jcCtZKws.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/ozop/ZMpw/tlFYaZCt.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/ozop/cPxsEwJV.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/ozop/dbII +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/USmD/ozop/dbII/NtBmtMvW.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/ozop/dbII/eSVCosqx.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/USmD/ozop/dbII/zRYDeXZm.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/uCqd +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/USmD/uCqd/WrTcNrGB.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/uCqd/iDmi +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/USmD/uCqd/iDmi/ctTntudZ.bin +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/USmD/uCqd/iDmi/ndkzpoGj.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/USmD/uCqd/sYyNwIRR.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/uCqd/wraW +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/USmD/uCqd/wraW/BJhtXoSu.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/uCqd/wraW/vXnzUKZb.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/vRYX +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/vRYX/BGrN +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/USmD/vRYX/BGrN/IoUGwuUD.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/USmD/vRYX/BGrN/YtRvveQM.bin +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/USmD/vRYX/BGrN/buUGPGfb.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/vRYX/GaNe +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/USmD/vRYX/GaNe/DXYDeayc.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/vRYX/GaNe/GqWx +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/vRYX/GaNe/GqWx/Teyvodjh.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/vRYX/GaNe/IOjS +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/vRYX/GaNe/IOjS/lGEFiHiE.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/USmD/vRYX/GaNe/IOjS/tTMLUMaS.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/vRYX/GaNe/oqPr +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/USmD/vRYX/GaNe/oqPr/OKRWYOYc.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/USmD/vRYX/GaNe/oqPr/nmEjhwDT.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/USmD/vRYX/GaNe/wrZMvSnM.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/USmD/vRYX/RRschtqY.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/vRYX/boCn +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/vRYX/boCn/EOpa +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/USmD/vRYX/boCn/EOpa/NwzrILUw.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/USmD/vRYX/boCn/EOpa/ZjKmZctR.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/USmD/vRYX/boCn/EOpa/dEOipIDj.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/USmD/vRYX/boCn/IeKkCoAV.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/vRYX/boCn/VudF +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/USmD/vRYX/boCn/VudF/AruRmTRk.bin +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/USmD/vRYX/boCn/VudF/VQvUHRya.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/USmD/vRYX/boCn/VudF/plDmzuSc.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/USmD/vRYX/boCn/tnTlTGiF.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/vRYX/boCn/xBcN +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/USmD/vRYX/boCn/xBcN/bOsKUOoc.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/USmD/vRYX/boCn/yEpXrJVa.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/zIcb +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/USmD/zIcb/WpAY +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/USmD/zIcb/WpAY/lHlOwyFi.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/USmD/zIcb/cFuoWFdJ.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/USmD/zIcb/uBiHbUJK.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/USmD/zIcb/xgcyYiiL.bin +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/ViRVnhhf.bin +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/WCGgYjGh.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/ceIx +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/ceIx/LaQSJcHt.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/ceIx/Sglf +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/ceIx/Sglf/EkLaRHDo.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/ceIx/dFGRwIAH.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/ceIx/pLVNhVWe.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/ceIx/zews +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/ceIx/zews/dRjoROCk.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/ceIx/zews/wVSOdwuw.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/FfFT +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/fLXx/FfFT/DdihJHdA.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/FfFT/Pset +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/FfFT/Pset/ADAg +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/fLXx/FfFT/Pset/ADAg/DRmLclJC.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/fLXx/FfFT/Pset/ADAg/LXUOVICl.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/fLXx/FfFT/Pset/ADAg/XDAoDxZR.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/fLXx/FfFT/Pset/rrlgLQDL.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/FfFT/UYUm +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/FfFT/UYUm/BXHK +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/fLXx/FfFT/UYUm/BXHK/oIYsrINY.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/FfFT/UYUm/DJch +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/fLXx/FfFT/UYUm/DJch/FNGWtnKI.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/fLXx/FfFT/UYUm/DJch/RWdAlyEc.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/FfFT/UYUm/YMky +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/fLXx/FfFT/UYUm/YMky/XlXjGKoT.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/fLXx/FfFT/UYUm/ldbqxWdp.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/fLXx/FfFT/aXhwCehn.bin +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/fLXx/FfFT/dlTzXRDP.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/FfFT/iboZ +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/fLXx/FfFT/iboZ/GDEZqkvO.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/fLXx/HsMLxCMl.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/IWnb +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/fLXx/IWnb/JlupqKdX.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/fLXx/IWnb/dMoDDgkQ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/KseZ +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/KseZ/WPca +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/fLXx/KseZ/WPca/HOtTPTDC.bin +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/fLXx/KseZ/odiFVaUP.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/CKam +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/CKam/BGjm +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/fLXx/dVHb/CKam/BGjm/HWqAptzI.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/fLXx/dVHb/CKam/BGjm/JpfAaIcT.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/fLXx/dVHb/CKam/JIVLfOiO.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/CKam/YWmE +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/fLXx/dVHb/CKam/YWmE/FjPJNgfr.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/fLXx/dVHb/CKam/YWmE/TqlCbTcz.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/CKam/ppeR +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/fLXx/dVHb/CKam/ppeR/UmKObOvw.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/fLXx/dVHb/CKam/ppeR/eUyYgIRh.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/fLXx/dVHb/CKam/rjdxIAok.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/fLXx/dVHb/CKam/yrSbdSFl.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/GPpQ +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/GPpQ/MVul +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/fLXx/dVHb/GPpQ/MVul/KrhCsTmh.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/fLXx/dVHb/GPpQ/MVul/hfKKPzuD.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/GPpQ/aFyT +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/fLXx/dVHb/GPpQ/aFyT/FvXdEuCl.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/fLXx/dVHb/GPpQ/crlNFfms.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/GPpQ/pyIb +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/fLXx/dVHb/GPpQ/pyIb/Iwtfunmc.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/fLXx/dVHb/GPpQ/pyIb/unfvnyEf.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/JXAl +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/fLXx/dVHb/JXAl/CNWlEmmk.bin +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/fLXx/dVHb/JXAl/CiJaaDVr.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/NngI +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/fLXx/dVHb/NngI/EWyiUwSJ.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/fLXx/dVHb/NngI/cGnduzmA.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/fLXx/dVHb/NngI/iTvVIdiE.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/jxyr +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/fLXx/dVHb/jxyr/NIwGVQpZ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/jxyr/QvvI +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/fLXx/dVHb/jxyr/QvvI/scAdGHep.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/dVHb/jxyr/TLsn +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/fLXx/dVHb/jxyr/TLsn/LuZVIJco.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/fLXx/dVHb/jxyr/TLsn/VnTgENac.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/fLXx/dVHb/vmuEpVPC.bin +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/fLXx/dVHb/vxFhUwiR.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/kSpx +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/kSpx/AdiK +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/fLXx/kSpx/AdiK/GgxIEAoN.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/fLXx/kSpx/AdiK/hZHtLEkK.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/fLXx/kSpx/CDIkzrjN.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/fLXx/kSpx/ZPdzQyJH.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/kSpx/ipbz +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/fLXx/kSpx/ipbz/QrrWumws.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/kSpx/zzMD +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/fLXx/kSpx/zzMD/VRRvrRUJ.bin +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/fLXx/ovnEwMrg.bin +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/fLXx/tHyCNhag.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/fLXx/wwXc +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/fLXx/wwXc/ErxxemRI.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/fLXx/wwXc/MBpSxmbC.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/kOBq/DjjNWBVS.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/YHOK +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/kOBq/YHOK/ClMGEJcO.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/YHOK/JFPN +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/kOBq/YHOK/JFPN/CXHkniPg.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/kOBq/YHOK/JFPN/wyDztIYn.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/kOBq/YHOK/OOGnEThQ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/cDyu +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/kOBq/cDyu/DcJnYVol.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/kOBq/cDyu/ZHnoEmiQ.bin +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/kOBq/cDyu/qrzOfmei.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/eZfF +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/kOBq/eZfF/FlQyDdMp.bin +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/kOBq/eZfF/JZGqOprZ.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/kOBq/eZfF/TzjRcpze.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/eZfF/ZkqU +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/kOBq/eZfF/ZkqU/lhbmRZqV.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/oGUp +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/kOBq/oGUp/xDbYyYKq.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/qoOh +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/kOBq/qoOh/DIiwKncu.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/qoOh/JYOh +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/kOBq/qoOh/JYOh/aGwzkhgO.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/qoOh/YmjG +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/kOBq/qoOh/YmjG/ZDhBFhAC.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/kOBq/qoOh/YmjG/abwzVKhE.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/qoOh/YmjG/joWP +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/kOBq/qoOh/YmjG/joWP/HBzOXCgv.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/kOBq/qoOh/YmjG/joWP/XOlAZqGM.bin +1980-01-01 00:00:00 ..... 4 4 study_data/ubAC/kOBq/qoOh/YmjG/joWP/oKOMIiZO.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/qoOh/YmjG/kOXv +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/kOBq/qoOh/YmjG/kOXv/rIUqcFjB.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/kOBq/qoOh/YmjG/xrfOEKHm.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/qoOh/rjRb +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/kOBq/qoOh/rjRb/ANoPqbto.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/kOBq/qoOh/rjRb/CFVRAMHg.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/kOBq/qoOh/rjRb/qhaXWWfe.bin +1980-01-01 00:00:00 ..... 7 7 study_data/ubAC/kOBq/qoOh/uCNvXcNG.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/qoOh/vgxj +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/kOBq/qoOh/vgxj/CHeyRvYA.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/qoOh/vgxj/DKsK +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/kOBq/qoOh/vgxj/DKsK/GyfDoGVz.bin +1980-01-01 00:00:00 ..... 3 3 study_data/ubAC/kOBq/qoOh/vgxj/DKsK/wYcLhbeH.bin +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/kOBq/qoOh/vgxj/WrKNtSDQ.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/qoOh/vgxj/qwcJ +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/kOBq/qoOh/vgxj/qwcJ/TpRTQvlG.bin +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/kOBq/qoOh/vjxEPbkr.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/kOBq/tuDhdTPG.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/vpzD +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/kOBq/vpzD/lOvizAnH.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/zQHX +1980-01-01 00:00:00 ..... 9 9 study_data/ubAC/kOBq/zQHX/BsiELuck.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/kOBq/zQHX/RtNEETKG.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/kOBq/zQHX/beZa +1980-01-01 00:00:00 ..... 5 5 study_data/ubAC/kOBq/zQHX/beZa/FFNfhEyY.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/kOBq/zQHX/beZa/NXyvddMj.bin +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/kOBq/zQHX/beZa/jACFjCUV.bin +1980-01-01 00:00:00 ..... 10 10 study_data/ubAC/lehSaCiB.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/qHWo +1980-01-01 00:00:00 ..... 2 2 study_data/ubAC/qHWo/CbEoHmnm.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/qHWo/OenX +1980-01-01 00:00:00 ..... 8 8 study_data/ubAC/qHWo/OenX/YWXonYoC.bin +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/qHWo/ysQCnyrv.bin +1980-01-01 00:00:00 D.... 0 0 study_data/ubAC/qTJi +1980-01-01 00:00:00 ..... 1 1 study_data/ubAC/qTJi/cVJuZYms.bin +1980-01-01 00:00:00 ..... 6 6 study_data/ubAC/tmyQpgmN.bin +------------------- ----- ------------ ------------ ------------------------ +1980-01-01 00:00:00 3622 3622 674 files, 335 folders diff --git a/packages/simcore-sdk/requirements/_base.txt b/packages/simcore-sdk/requirements/_base.txt index b00b9f66957..c13586c4bd1 100644 --- a/packages/simcore-sdk/requirements/_base.txt +++ b/packages/simcore-sdk/requirements/_base.txt @@ -358,8 +358,6 @@ referencing==0.29.3 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.8.1 diff --git a/scripts/install_7zip.bash b/scripts/install_7zip.bash new file mode 100755 index 00000000000..6328940a4a3 --- /dev/null +++ b/scripts/install_7zip.bash @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Installs 7zip +# + +# http://redsymbol.net/articles/unofficial-bash-strict-mode/ +set -o errexit # abort on nonzero exitstatus +set -o nounset # abort on unbound variable +set -o pipefail # don't hide errors within pipes +IFS=$'\n\t' + +TARGETARCH="${TARGETARCH:-amd64}" + +case "${TARGETARCH}" in \ + "amd64") ARCH="x64" ;; \ + "arm64") ARCH="arm64" ;; \ + *) echo "Unsupported architecture: ${TARGETARCH}" && exit 1 ;; \ +esac + +SEVEN_ZIP_VERSION="2409" +## 7z compression +echo "create install dir" +rm -rf /tmp/7zip +mkdir -p /tmp/7zip +cd /tmp/7zip + +curl -LO https://www.7-zip.org/a/7z${SEVEN_ZIP_VERSION}-linux-${ARCH}.tar.xz +tar -xvf 7z${SEVEN_ZIP_VERSION}-linux-${ARCH}.tar.xz +cp 7zz /usr/bin/7z + +echo "remove install dir" +rm -rf /tmp/7zip + +echo "test installation" +7z --help diff --git a/services/agent/requirements/_base.txt b/services/agent/requirements/_base.txt index 95f8e56d4cb..7e4a6e2b4db 100644 --- a/services/agent/requirements/_base.txt +++ b/services/agent/requirements/_base.txt @@ -186,9 +186,9 @@ opentelemetry-instrumentation-fastapi==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_fastapi.in opentelemetry-instrumentation-httpx==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_fastapi.in -opentelemetry-instrumentation-logging==0.48b0 +opentelemetry-instrumentation-logging==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in -opentelemetry-instrumentation-redis==0.48b0 +opentelemetry-instrumentation-redis==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in opentelemetry-instrumentation-requests==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in @@ -351,8 +351,6 @@ referencing==0.35.1 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.4 diff --git a/services/api-server/requirements/_base.txt b/services/api-server/requirements/_base.txt index a49ef21c613..ccc9b001a80 100644 --- a/services/api-server/requirements/_base.txt +++ b/services/api-server/requirements/_base.txt @@ -707,10 +707,6 @@ redis==5.2.0 # -c requirements/../../../requirements/constraints.txt # -r requirements/../../../packages/service-library/requirements/_base.in # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in -repro-zipfile==0.3.1 - # via - # -r requirements/../../../packages/service-library/requirements/_base.in - # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.4 diff --git a/services/autoscaling/requirements/_base.txt b/services/autoscaling/requirements/_base.txt index 9600358f524..0f13c0e7eaf 100644 --- a/services/autoscaling/requirements/_base.txt +++ b/services/autoscaling/requirements/_base.txt @@ -189,7 +189,7 @@ h11==0.14.0 # uvicorn httpcore==1.0.7 # via httpx -httpx==0.28.0 +httpx==0.28.1 # via # -c requirements/../../../packages/aws-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt # -c requirements/../../../packages/aws-library/requirements/../../../packages/models-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt @@ -609,10 +609,6 @@ referencing==0.35.1 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via - # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in - # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.4 diff --git a/services/autoscaling/requirements/_test.txt b/services/autoscaling/requirements/_test.txt index 28a6d7a45e9..a5de3c064b3 100644 --- a/services/autoscaling/requirements/_test.txt +++ b/services/autoscaling/requirements/_test.txt @@ -93,7 +93,7 @@ httpcore==1.0.7 # via # -c requirements/_base.txt # httpx -httpx==0.28.0 +httpx==0.28.1 # via # -c requirements/../../../requirements/constraints.txt # -c requirements/_base.txt diff --git a/services/catalog/requirements/_base.txt b/services/catalog/requirements/_base.txt index 04a30b02856..e8500375a38 100644 --- a/services/catalog/requirements/_base.txt +++ b/services/catalog/requirements/_base.txt @@ -447,8 +447,6 @@ referencing==0.35.1 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.4 diff --git a/services/clusters-keeper/requirements/_base.txt b/services/clusters-keeper/requirements/_base.txt index ea2355739bd..9284af99ada 100644 --- a/services/clusters-keeper/requirements/_base.txt +++ b/services/clusters-keeper/requirements/_base.txt @@ -187,7 +187,7 @@ h11==0.14.0 # uvicorn httpcore==1.0.7 # via httpx -httpx==0.28.0 +httpx==0.28.1 # via # -c requirements/../../../packages/aws-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt # -c requirements/../../../packages/aws-library/requirements/../../../packages/models-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt @@ -607,10 +607,6 @@ referencing==0.35.1 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via - # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in - # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.4 diff --git a/services/clusters-keeper/requirements/_test.txt b/services/clusters-keeper/requirements/_test.txt index 1f80746a22a..c3fc6f9e590 100644 --- a/services/clusters-keeper/requirements/_test.txt +++ b/services/clusters-keeper/requirements/_test.txt @@ -112,7 +112,7 @@ httpcore==1.0.7 # via # -c requirements/_base.txt # httpx -httpx==0.28.0 +httpx==0.28.1 # via # -c requirements/../../../requirements/constraints.txt # -c requirements/_base.txt diff --git a/services/dask-sidecar/requirements/_base.txt b/services/dask-sidecar/requirements/_base.txt index 20d9a1196c0..c564683d8c3 100644 --- a/services/dask-sidecar/requirements/_base.txt +++ b/services/dask-sidecar/requirements/_base.txt @@ -445,9 +445,7 @@ referencing==0.35.1 # jsonschema # jsonschema-specifications repro-zipfile==0.3.1 - # via - # -r requirements/../../../packages/service-library/requirements/_base.in - # -r requirements/_base.in + # via -r requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.4 diff --git a/services/datcore-adapter/requirements/_base.txt b/services/datcore-adapter/requirements/_base.txt index 7e0a7936e48..a3bfb49c0e7 100644 --- a/services/datcore-adapter/requirements/_base.txt +++ b/services/datcore-adapter/requirements/_base.txt @@ -371,8 +371,6 @@ referencing==0.29.3 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/director-v2/requirements/_base.txt b/services/director-v2/requirements/_base.txt index b27992058e3..407e941fb3a 100644 --- a/services/director-v2/requirements/_base.txt +++ b/services/director-v2/requirements/_base.txt @@ -804,10 +804,6 @@ referencing==0.29.3 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via - # -r requirements/../../../packages/service-library/requirements/_base.in - # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/director/requirements/_base.txt b/services/director/requirements/_base.txt index ced8f7909f0..fbef4ce0fc9 100644 --- a/services/director/requirements/_base.txt +++ b/services/director/requirements/_base.txt @@ -394,8 +394,6 @@ referencing==0.29.3 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.4 diff --git a/services/dynamic-scheduler/requirements/_base.txt b/services/dynamic-scheduler/requirements/_base.txt index dd73276b15a..2a490843db1 100644 --- a/services/dynamic-scheduler/requirements/_base.txt +++ b/services/dynamic-scheduler/requirements/_base.txt @@ -263,9 +263,9 @@ opentelemetry-instrumentation-fastapi==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_fastapi.in opentelemetry-instrumentation-httpx==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_fastapi.in -opentelemetry-instrumentation-logging==0.48b0 +opentelemetry-instrumentation-logging==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in -opentelemetry-instrumentation-redis==0.48b0 +opentelemetry-instrumentation-redis==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in opentelemetry-instrumentation-requests==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in @@ -458,8 +458,6 @@ referencing==0.35.1 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via # nicegui diff --git a/services/dynamic-sidecar/Dockerfile b/services/dynamic-sidecar/Dockerfile index a5173e7f19a..6b96c64da25 100644 --- a/services/dynamic-sidecar/Dockerfile +++ b/services/dynamic-sidecar/Dockerfile @@ -32,6 +32,7 @@ RUN \ curl \ gnupg \ lsb-release \ + xz-utils \ && mkdir -p /etc/apt/keyrings \ && curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg \ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \ @@ -41,7 +42,6 @@ RUN \ docker-ce-cli=${DOCKER_APT_VERSION} \ docker-compose-plugin=${DOCKER_COMPOSE_APT_VERSION} \ gosu \ - libcap2-bin \ ca-certificates \ # required by python-magic libmagic1 \ @@ -56,6 +56,12 @@ RUN \ RUN \ --mount=type=bind,source=scripts/install_rclone.bash,target=install_rclone.bash \ ./install_rclone.bash +# install 7zip +ARG TARGETARCH +ENV TARGETARCH=${TARGETARCH} +RUN \ + --mount=type=bind,source=scripts/install_7zip.bash,target=install_7zip.bash \ + ./install_7zip.bash RUN AWS_CLI_VERSION="2.11.11" \ && curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-${AWS_CLI_VERSION}.zip" -o "awscliv2.zip" \ diff --git a/services/dynamic-sidecar/docker/entrypoint.sh b/services/dynamic-sidecar/docker/entrypoint.sh index 89a33fb8a74..73815d447dd 100755 --- a/services/dynamic-sidecar/docker/entrypoint.sh +++ b/services/dynamic-sidecar/docker/entrypoint.sh @@ -105,7 +105,4 @@ echo " $SC_USER_NAME rights : $(id "$SC_USER_NAME")" echo " local dir : $(ls -al)" echo " volumes dir : $(ls -al "${DYNAMIC_SIDECAR_DY_VOLUMES_MOUNT_DIR}")" -echo "$INFO" "Available permissions" -capsh --print - exec gosu "$SC_USER_NAME" "$@" diff --git a/services/dynamic-sidecar/requirements/_base.txt b/services/dynamic-sidecar/requirements/_base.txt index 02aab36cf3b..45c1909c42c 100644 --- a/services/dynamic-sidecar/requirements/_base.txt +++ b/services/dynamic-sidecar/requirements/_base.txt @@ -328,11 +328,11 @@ opentelemetry-instrumentation-fastapi==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_fastapi.in opentelemetry-instrumentation-httpx==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_fastapi.in -opentelemetry-instrumentation-logging==0.48b0 +opentelemetry-instrumentation-logging==0.49b2 # via # -r requirements/../../../packages/service-library/requirements/_base.in # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in -opentelemetry-instrumentation-redis==0.48b0 +opentelemetry-instrumentation-redis==0.49b2 # via # -r requirements/../../../packages/service-library/requirements/_base.in # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in @@ -628,10 +628,6 @@ referencing==0.35.1 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via - # -r requirements/../../../packages/service-library/requirements/_base.in - # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.4 diff --git a/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/core/utils.py b/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/core/utils.py index 4e6f9ee0df5..3993ce37a56 100644 --- a/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/core/utils.py +++ b/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/core/utils.py @@ -49,7 +49,7 @@ def _close_transport(proc: Process): async def async_command( command: str, - timeout: float | None = None, + timeout: float | None = None, # noqa: ASYNC109 pipe_as_input: str | None = None, env_vars: dict[str, str] | None = None, ) -> CommandResult: diff --git a/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/modules/nodeports.py b/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/modules/nodeports.py index 0ad00f2c18d..72537baad29 100644 --- a/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/modules/nodeports.py +++ b/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/modules/nodeports.py @@ -1,7 +1,6 @@ import json import logging import os -import shutil import sys import time from asyncio import CancelledError @@ -12,17 +11,16 @@ from pathlib import Path from typing import cast -import aiofiles.os import magic from aiofiles.tempfile import TemporaryDirectory as AioTemporaryDirectory from models_library.basic_types import IDStr from models_library.projects import ProjectIDStr from models_library.projects_nodes_io import NodeIDStr from models_library.services_types import ServicePortKey -from pydantic import ByteSize +from pydantic import ByteSize, TypeAdapter from servicelib.archiving_utils import PrunableFolder, archive_dir, unarchive_dir from servicelib.async_utils import run_sequentially_in_context -from servicelib.file_utils import remove_directory +from servicelib.file_utils import remove_directory, shutil_move from servicelib.logging_utils import log_context from servicelib.progress_bar import ProgressBarData from servicelib.utils import limited_gather @@ -46,7 +44,7 @@ class PortTypeName(str, Enum): _FILE_TYPE_PREFIX = "data:" _KEY_VALUE_FILE_NAME = "key_values.json" -logger = logging.getLogger(__name__) +_logger = logging.getLogger(__name__) # OUTPUTS section @@ -95,14 +93,14 @@ async def upload_outputs( # pylint:disable=too-many-statements # noqa: PLR0915 port_notifier: PortNotifier, ) -> None: # pylint: disable=too-many-branches - logger.debug("uploading data to simcore...") + _logger.debug("uploading data to simcore...") start_time = time.perf_counter() settings: ApplicationSettings = get_settings() PORTS: Nodeports = await node_ports_v2.ports( user_id=settings.DY_SIDECAR_USER_ID, project_id=ProjectIDStr(settings.DY_SIDECAR_PROJECT_ID), - node_uuid=NodeIDStr(settings.DY_SIDECAR_NODE_ID), + node_uuid=TypeAdapter(NodeIDStr).validate_python(settings.DY_SIDECAR_NODE_ID), r_clone_settings=None, io_log_redirect_cb=io_log_redirect_cb, aws_s3_cli_settings=None, @@ -138,7 +136,7 @@ async def upload_outputs( # pylint:disable=too-many-statements # noqa: PLR0915 if is_file_type(port.property_type): src_folder = outputs_path / port.key files_and_folders_list = list(src_folder.rglob("*")) - logger.debug("Discovered files to upload %s", files_and_folders_list) + _logger.debug("Discovered files to upload %s", files_and_folders_list) if not files_and_folders_list: ports_values[port.key] = (None, None) @@ -177,7 +175,6 @@ async def _archive_dir_notified( dir_to_compress=dir_to_compress, destination=destination, compress=False, - store_relative_path=True, progress_bar=sub_progress, ) except CancelledError: @@ -213,9 +210,9 @@ async def _archive_dir_notified( if port.key in data and data[port.key] is not None: ports_values[port.key] = (data[port.key], None) else: - logger.debug("Port %s not found in %s", port.key, data) + _logger.debug("Port %s not found in %s", port.key, data) else: - logger.debug("No file %s to fetch port values from", data_file) + _logger.debug("No file %s to fetch port values from", data_file) if archiving_tasks: await limited_gather(*archiving_tasks, limit=4) @@ -228,8 +225,8 @@ async def _archive_dir_notified( elapsed_time = time.perf_counter() - start_time total_bytes = sum(_get_size_of_value(x) for x in ports_values.values()) - logger.info("Uploaded %s bytes in %s seconds", total_bytes, elapsed_time) - logger.debug(_CONTROL_TESTMARK_DY_SIDECAR_NODEPORT_UPLOADED_MESSAGE) + _logger.info("Uploaded %s bytes in %s seconds", total_bytes, elapsed_time) + _logger.debug(_CONTROL_TESTMARK_DY_SIDECAR_NODEPORT_UPLOADED_MESSAGE) # INPUTS section @@ -240,9 +237,6 @@ def _is_zip_file(file_path: Path) -> bool: return f"{mime_type}" == "application/zip" -_shutil_move = aiofiles.os.wrap(shutil.move) - - async def _get_data_from_port( port: Port, *, target_dir: Path, progress_bar: ProgressBarData ) -> tuple[Port, ItemConcreteValue | None, ByteSize]: @@ -250,7 +244,7 @@ async def _get_data_from_port( steps=2 if is_file_type(port.property_type) else 1, description=IDStr("getting data"), ) as sub_progress: - with log_context(logger, logging.DEBUG, f"getting {port.key=}"): + with log_context(_logger, logging.DEBUG, f"getting {port.key=}"): port_data = await port.get(sub_progress) if is_file_type(port.property_type): @@ -261,42 +255,49 @@ async def _get_data_from_port( if not downloaded_file or not downloaded_file.exists(): # the link may be empty # remove files all files from disk when disconnecting port - logger.debug("removing contents of dir %s", final_path) - await remove_directory( - final_path, only_children=True, ignore_errors=True - ) + with log_context( + _logger, logging.DEBUG, f"removing contents of dir '{final_path}'" + ): + await remove_directory( + final_path, only_children=True, ignore_errors=True + ) return port, None, ByteSize(0) transferred_bytes = downloaded_file.stat().st_size # in case of valid file, it is either uncompressed and/or moved to the final directory - with log_context(logger, logging.DEBUG, "creating directory"): + with log_context(_logger, logging.DEBUG, "creating directory"): final_path.mkdir(exist_ok=True, parents=True) port_data = f"{final_path}" - dest_folder = PrunableFolder(final_path) - if _is_zip_file(downloaded_file): - # unzip updated data to dest_path - logger.debug("unzipping %s", downloaded_file) - unarchived: set[Path] = await unarchive_dir( - archive_to_extract=downloaded_file, - destination_folder=final_path, - progress_bar=sub_progress, - ) + archive_files: set[Path] - dest_folder.prune(exclude=unarchived) - - logger.debug("all unzipped in %s", final_path) + if _is_zip_file(downloaded_file): + with log_context( + _logger, + logging.DEBUG, + f"unzipping '{downloaded_file}' to {final_path}", + ): + archive_files = await unarchive_dir( + archive_to_extract=downloaded_file, + destination_folder=final_path, + progress_bar=sub_progress, + ) else: - logger.debug("moving %s", downloaded_file) - final_path = final_path / Path(downloaded_file).name - await _shutil_move(str(downloaded_file), final_path) + # move archive to directory as is + final_path = final_path / downloaded_file.name + + with log_context( + _logger, logging.DEBUG, f"moving {downloaded_file} to {final_path}" + ): + final_path.parent.mkdir(exist_ok=True, parents=True) + await shutil_move(downloaded_file, final_path) - # NOTE: after the download the current value of the port - # makes sure previously downloaded files are removed - dest_folder.prune(exclude={final_path}) + archive_files = {final_path} - logger.debug("all moved to %s", final_path) + # NOTE: after the port content changes, make sure old files + # which are no longer part of the port, are removed + PrunableFolder(final_path).prune(exclude=archive_files) else: transferred_bytes = sys.getsizeof(port_data) @@ -312,14 +313,14 @@ async def download_target_ports( progress_bar: ProgressBarData, port_notifier: PortNotifier | None, ) -> ByteSize: - logger.debug("retrieving data from simcore...") + _logger.debug("retrieving data from simcore...") start_time = time.perf_counter() settings: ApplicationSettings = get_settings() PORTS: Nodeports = await node_ports_v2.ports( user_id=settings.DY_SIDECAR_USER_ID, project_id=ProjectIDStr(settings.DY_SIDECAR_PROJECT_ID), - node_uuid=NodeIDStr(settings.DY_SIDECAR_NODE_ID), + node_uuid=TypeAdapter(NodeIDStr).validate_python(settings.DY_SIDECAR_NODE_ID), r_clone_settings=None, io_log_redirect_cb=io_log_redirect_cb, aws_s3_cli_settings=None, @@ -386,7 +387,7 @@ async def _get_date_from_port_notified( data_file.write_text(json.dumps(data)) elapsed_time = time.perf_counter() - start_time - logger.info( + _logger.info( "Downloaded %s in %s seconds", total_transfered_bytes.human_readable(decimal=True), elapsed_time, diff --git a/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/modules/user_services_preferences/_packaging.py b/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/modules/user_services_preferences/_packaging.py index bdffd81a4a9..4c711e34f9a 100644 --- a/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/modules/user_services_preferences/_packaging.py +++ b/services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/modules/user_services_preferences/_packaging.py @@ -20,7 +20,7 @@ async def dir_to_bytes(source: Path) -> bytes: async with aiofiles.tempfile.TemporaryDirectory() as tmp_dir: archive_path = Path(tmp_dir) / "archive" - await archive_dir(source, archive_path, compress=True, store_relative_path=True) + await archive_dir(source, archive_path, compress=True) archive_size = archive_path.stat().st_size if archive_size > _MAX_PREFERENCES_TOTAL_SIZE: diff --git a/services/efs-guardian/requirements/_base.txt b/services/efs-guardian/requirements/_base.txt index 558b6f5b43e..906e7e2581e 100644 --- a/services/efs-guardian/requirements/_base.txt +++ b/services/efs-guardian/requirements/_base.txt @@ -588,10 +588,6 @@ referencing==0.29.3 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via - # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in - # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.2 diff --git a/services/invitations/requirements/_base.txt b/services/invitations/requirements/_base.txt index 4aad9be2472..c9528eb09f8 100644 --- a/services/invitations/requirements/_base.txt +++ b/services/invitations/requirements/_base.txt @@ -204,9 +204,9 @@ opentelemetry-instrumentation-fastapi==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_fastapi.in opentelemetry-instrumentation-httpx==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_fastapi.in -opentelemetry-instrumentation-logging==0.47b0 +opentelemetry-instrumentation-logging==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in -opentelemetry-instrumentation-redis==0.47b0 +opentelemetry-instrumentation-redis==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in opentelemetry-instrumentation-requests==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in @@ -373,8 +373,6 @@ referencing==0.35.1 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.4 diff --git a/services/payments/requirements/_base.txt b/services/payments/requirements/_base.txt index e021ae5074c..b8fd65acb18 100644 --- a/services/payments/requirements/_base.txt +++ b/services/payments/requirements/_base.txt @@ -268,9 +268,9 @@ opentelemetry-instrumentation-fastapi==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_fastapi.in opentelemetry-instrumentation-httpx==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_fastapi.in -opentelemetry-instrumentation-logging==0.48b0 +opentelemetry-instrumentation-logging==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in -opentelemetry-instrumentation-redis==0.48b0 +opentelemetry-instrumentation-redis==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in opentelemetry-instrumentation-requests==0.49b2 # via -r requirements/../../../packages/service-library/requirements/_base.in @@ -464,8 +464,6 @@ referencing==0.35.1 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via opentelemetry-exporter-otlp-proto-http rich==13.9.4 diff --git a/services/resource-usage-tracker/requirements/_base.txt b/services/resource-usage-tracker/requirements/_base.txt index 45848d96288..b1071e5b5f0 100644 --- a/services/resource-usage-tracker/requirements/_base.txt +++ b/services/resource-usage-tracker/requirements/_base.txt @@ -630,10 +630,6 @@ referencing==0.29.3 # jsonschema-specifications regex==2023.12.25 # via dateparser -repro-zipfile==0.3.1 - # via - # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in - # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.2 # via # httmock diff --git a/services/storage/requirements/_base.txt b/services/storage/requirements/_base.txt index 203572eef60..18c2388a7dd 100644 --- a/services/storage/requirements/_base.txt +++ b/services/storage/requirements/_base.txt @@ -586,10 +586,6 @@ referencing==0.29.3 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via - # -r requirements/../../../packages/aws-library/requirements/../../../packages/service-library/requirements/_base.in - # -r requirements/../../../packages/service-library/requirements/_base.in requests==2.32.2 # via opentelemetry-exporter-otlp-proto-http rich==13.7.1 diff --git a/services/web/Dockerfile b/services/web/Dockerfile index 542d0b34ed2..5ccdef01f15 100644 --- a/services/web/Dockerfile +++ b/services/web/Dockerfile @@ -25,13 +25,22 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=private \ set -eux && \ apt-get update && \ apt-get install -y --no-install-recommends \ - libmagic1 \ + curl \ gosu \ + libmagic1 \ + xz-utils \ && apt-get clean -y \ && rm -rf /var/lib/apt/lists/* \ # verify that the binary works && gosu nobody true +# install 7zip +ARG TARGETARCH +ENV TARGETARCH=${TARGETARCH} +RUN \ + --mount=type=bind,source=scripts/install_7zip.bash,target=install_7zip.bash \ + ./install_7zip.bash + # simcore-user uid=8004(scu) gid=8004(scu) groups=8004(scu) ENV SC_USER_ID=8004 \ diff --git a/services/web/server/requirements/_base.txt b/services/web/server/requirements/_base.txt index 810e6e29fad..62a83465800 100644 --- a/services/web/server/requirements/_base.txt +++ b/services/web/server/requirements/_base.txt @@ -683,10 +683,6 @@ redis==5.0.4 # -r requirements/../../../../packages/service-library/requirements/_base.in # -r requirements/../../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in # -r requirements/_base.in -repro-zipfile==0.3.1 - # via - # -r requirements/../../../../packages/service-library/requirements/_base.in - # -r requirements/../../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in requests==2.32.2 # via # opentelemetry-exporter-otlp-proto-http diff --git a/services/web/server/src/simcore_service_webserver/exporter/_formatter/archive.py b/services/web/server/src/simcore_service_webserver/exporter/_formatter/archive.py index 27ce55b5959..7fde251f0cc 100644 --- a/services/web/server/src/simcore_service_webserver/exporter/_formatter/archive.py +++ b/services/web/server/src/simcore_service_webserver/exporter/_formatter/archive.py @@ -21,10 +21,7 @@ async def _compress_dir( raise SDSException(msg) await archive_dir( - dir_to_compress=folder_to_zip, - destination=archive_name, - compress=True, - store_relative_path=True, + dir_to_compress=folder_to_zip, destination=archive_name, compress=True ) return archive_name diff --git a/tests/swarm-deploy/requirements/_test.txt b/tests/swarm-deploy/requirements/_test.txt index e18b8c99a1b..1dedde81a5d 100644 --- a/tests/swarm-deploy/requirements/_test.txt +++ b/tests/swarm-deploy/requirements/_test.txt @@ -573,10 +573,6 @@ referencing==0.29.3 # via # jsonschema # jsonschema-specifications -repro-zipfile==0.3.1 - # via - # -r requirements/../../../packages/service-library/requirements/_base.in - # -r requirements/../../../packages/simcore-sdk/requirements/../../../packages/service-library/requirements/_base.in requests==2.32.3 # via # -r requirements/../../../packages/postgres-database/requirements/_migration.txt