modAL 1.2.5.dev8__tar.gz → 1.2.5.dev10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/PKG-INFO +1 -1
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_functions.py +3 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_partial_function.py +4 -1
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/function_utils.py +2 -2
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/app.py +19 -3
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/client.pyi +2 -2
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/experimental/__init__.py +6 -1
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/experimental/flash.py +86 -12
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/experimental/flash.pyi +38 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/functions.pyi +1 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/runner.py +1 -1
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_version/__init__.py +1 -1
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/LICENSE +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/README.md +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/__init__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/__main__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_billing.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_clustered_functions.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_clustered_functions.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_container_entrypoint.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_grpc_client.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_ipython.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_load_context.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_location.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_object.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_output.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_pty.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_resolver.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_resources.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_runtime/__init__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_runtime/asgi.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_runtime/execution_context.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_runtime/telemetry.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_serialization.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_traceback.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_tunnel.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_tunnel.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_type_manager.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/__init__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/app_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/async_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/blob_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/deprecation.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/docker_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/git_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/hash_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/http_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/logger.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/mount_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/name_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/package_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/shell_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_utils/time_utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_vendor/__init__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_vendor/tblib.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/_watcher.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/app.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/billing.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/builder/2023.12.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/builder/2024.04.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/builder/2024.10.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/builder/2025.06.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/builder/README.md +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/builder/base-images.json +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/call_graph.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/__init__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/_download.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/_traceback.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/app.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/cluster.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/config.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/container.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/dict.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/entry_point.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/environment.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/import_refs.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/launch.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/network_file_system.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/profile.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/programs/__init__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/programs/launch_instance_ssh.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/programs/run_marimo.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/programs/vscode.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/queues.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/run.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/secret.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/shell.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/token.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/utils.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cli/volume.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/client.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cls.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/cls.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/config.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/container_process.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/container_process.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/dict.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/dict.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/environments.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/environments.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/exception.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/experimental/ipython.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/file_io.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/file_io.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/file_pattern_matcher.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/functions.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/gpu.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/image.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/image.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/io_streams.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/io_streams.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/mount.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/mount.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/network_file_system.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/network_file_system.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/object.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/object.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/output.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/parallel_map.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/parallel_map.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/partial_function.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/partial_function.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/proxy.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/proxy.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/py.typed +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/queue.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/queue.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/retries.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/runner.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/running_app.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/sandbox.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/sandbox.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/schedule.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/scheduler_placement.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/secret.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/secret.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/serving.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/serving.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/snapshot.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/snapshot.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/stream_type.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/token_flow.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/token_flow.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/volume.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal/volume.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal.egg-info/requires.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal.egg-info/top_level.txt +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_docs/__init__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/__init__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/api.proto +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/api_grpc.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/api_pb2.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/py.typed +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/sandbox_router.proto +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/sandbox_router_grpc.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/sandbox_router_pb2.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/sandbox_router_pb2.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/sandbox_router_pb2_grpc.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/sandbox_router_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/task_command_router.proto +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/modal_version/__main__.py +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/pyproject.toml +0 -0
- {modal-1.2.5.dev8 → modal-1.2.5.dev10}/setup.cfg +0 -0
|
@@ -701,6 +701,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
701
701
|
_experimental_proxy_ip: Optional[str] = None,
|
|
702
702
|
_experimental_custom_scaling_factor: Optional[float] = None,
|
|
703
703
|
restrict_output: bool = False,
|
|
704
|
+
http_config: Optional[api_pb2.HTTPConfig] = None,
|
|
704
705
|
) -> "_Function":
|
|
705
706
|
"""mdmd:hidden
|
|
706
707
|
|
|
@@ -1046,6 +1047,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1046
1047
|
function_schema=function_schema,
|
|
1047
1048
|
supported_input_formats=supported_input_formats,
|
|
1048
1049
|
supported_output_formats=supported_output_formats,
|
|
1050
|
+
http_config=http_config,
|
|
1049
1051
|
)
|
|
1050
1052
|
|
|
1051
1053
|
if isinstance(gpu, list):
|
|
@@ -1083,6 +1085,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1083
1085
|
untrusted=function_definition.untrusted,
|
|
1084
1086
|
supported_input_formats=supported_input_formats,
|
|
1085
1087
|
supported_output_formats=supported_output_formats,
|
|
1088
|
+
http_config=http_config,
|
|
1086
1089
|
)
|
|
1087
1090
|
|
|
1088
1091
|
ranked_functions = []
|
|
@@ -46,6 +46,7 @@ class _PartialFunctionFlags(enum.IntFlag):
|
|
|
46
46
|
BATCHED = 64
|
|
47
47
|
CONCURRENT = 128
|
|
48
48
|
CLUSTERED = 256 # Experimental: Clustered functions
|
|
49
|
+
HTTP_WEB_INTERFACE = 512 # Experimental: HTTP server
|
|
49
50
|
|
|
50
51
|
@staticmethod
|
|
51
52
|
def all() -> int:
|
|
@@ -76,6 +77,7 @@ class _PartialFunctionParams:
|
|
|
76
77
|
target_concurrent_inputs: Optional[int] = None
|
|
77
78
|
build_timeout: Optional[int] = None
|
|
78
79
|
rdma: Optional[bool] = None
|
|
80
|
+
http_config: Optional[api_pb2.HTTPConfig] = None
|
|
79
81
|
|
|
80
82
|
def update(self, other: "_PartialFunctionParams") -> None:
|
|
81
83
|
"""Update self with params set in other."""
|
|
@@ -158,8 +160,9 @@ class _PartialFunction(typing.Generic[P, ReturnType, OriginalReturnType]):
|
|
|
158
160
|
raise InvalidError("Interface decorators cannot be combined with lifecycle decorators.")
|
|
159
161
|
|
|
160
162
|
has_web_interface = self.flags & _PartialFunctionFlags.WEB_INTERFACE
|
|
163
|
+
has_http_web_interface = self.flags & _PartialFunctionFlags.HTTP_WEB_INTERFACE
|
|
161
164
|
has_callable_interface = self.flags & _PartialFunctionFlags.CALLABLE_INTERFACE
|
|
162
|
-
if has_web_interface and has_callable_interface:
|
|
165
|
+
if (has_web_interface or has_http_web_interface) and has_callable_interface:
|
|
163
166
|
self.registered = True # Hacky, avoid false-positive warning
|
|
164
167
|
raise InvalidError("Callable decorators cannot be combined with web interface decorators.")
|
|
165
168
|
|
|
@@ -75,8 +75,8 @@ def is_global_object(object_qual_name: str):
|
|
|
75
75
|
return "<locals>" not in object_qual_name.split(".")
|
|
76
76
|
|
|
77
77
|
|
|
78
|
-
def is_flash_object(experimental_options: Optional[dict[str, Any]]) -> bool:
|
|
79
|
-
return experimental_options.get("flash", False)
|
|
78
|
+
def is_flash_object(experimental_options: Optional[dict[str, Any]], http_config: Optional[api_pb2.HTTPConfig]) -> bool:
|
|
79
|
+
return bool(experimental_options and experimental_options.get("flash", False)) or http_config is not None
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
def is_method_fn(object_qual_name: str):
|
|
@@ -827,7 +827,7 @@ class _App:
|
|
|
827
827
|
batch_max_size = f.params.batch_max_size
|
|
828
828
|
batch_wait_ms = f.params.batch_wait_ms
|
|
829
829
|
if f.flags & _PartialFunctionFlags.CONCURRENT:
|
|
830
|
-
verify_concurrent_params(params=f.params, is_flash=is_flash_object(experimental_options))
|
|
830
|
+
verify_concurrent_params(params=f.params, is_flash=is_flash_object(experimental_options, None))
|
|
831
831
|
max_concurrent_inputs = f.params.max_concurrent_inputs
|
|
832
832
|
target_concurrent_inputs = f.params.target_concurrent_inputs
|
|
833
833
|
else:
|
|
@@ -1025,11 +1025,17 @@ class _App:
|
|
|
1025
1025
|
def wrapper(wrapped_cls: Union[CLS_T, _PartialFunction]) -> CLS_T:
|
|
1026
1026
|
local_state = self._local_state
|
|
1027
1027
|
# Check if the decorated object is a class
|
|
1028
|
+
http_config = None
|
|
1028
1029
|
if isinstance(wrapped_cls, _PartialFunction):
|
|
1029
1030
|
wrapped_cls.registered = True
|
|
1030
1031
|
user_cls = wrapped_cls.user_cls
|
|
1032
|
+
if wrapped_cls.flags & _PartialFunctionFlags.HTTP_WEB_INTERFACE:
|
|
1033
|
+
http_config = wrapped_cls.params.http_config
|
|
1031
1034
|
if wrapped_cls.flags & _PartialFunctionFlags.CONCURRENT:
|
|
1032
|
-
verify_concurrent_params(
|
|
1035
|
+
verify_concurrent_params(
|
|
1036
|
+
params=wrapped_cls.params,
|
|
1037
|
+
is_flash=is_flash_object(experimental_options or {}, http_config=http_config),
|
|
1038
|
+
)
|
|
1033
1039
|
max_concurrent_inputs = wrapped_cls.params.max_concurrent_inputs
|
|
1034
1040
|
target_concurrent_inputs = wrapped_cls.params.target_concurrent_inputs
|
|
1035
1041
|
else:
|
|
@@ -1039,6 +1045,7 @@ class _App:
|
|
|
1039
1045
|
if wrapped_cls.flags & _PartialFunctionFlags.CLUSTERED:
|
|
1040
1046
|
cluster_size = wrapped_cls.params.cluster_size
|
|
1041
1047
|
rdma = wrapped_cls.params.rdma
|
|
1048
|
+
|
|
1042
1049
|
else:
|
|
1043
1050
|
cluster_size = None
|
|
1044
1051
|
rdma = None
|
|
@@ -1083,10 +1090,17 @@ class _App:
|
|
|
1083
1090
|
"The `@modal.concurrent` decorator cannot be used on methods; decorate the class instead."
|
|
1084
1091
|
)
|
|
1085
1092
|
|
|
1093
|
+
for method in _find_partial_methods_for_user_cls(
|
|
1094
|
+
user_cls, _PartialFunctionFlags.HTTP_WEB_INTERFACE
|
|
1095
|
+
).values():
|
|
1096
|
+
method.registered = True # Avoid warning about not registering the method (hacky!)
|
|
1097
|
+
raise InvalidError(
|
|
1098
|
+
"The `@modal.http_server` decorator cannot be used on methods; decorate the class instead."
|
|
1099
|
+
)
|
|
1100
|
+
|
|
1086
1101
|
info = FunctionInfo(None, serialized=serialized, user_cls=user_cls)
|
|
1087
1102
|
|
|
1088
1103
|
i6pn_enabled = i6pn or cluster_size is not None
|
|
1089
|
-
|
|
1090
1104
|
cls_func = _Function.from_local(
|
|
1091
1105
|
info,
|
|
1092
1106
|
app=self,
|
|
@@ -1117,6 +1131,7 @@ class _App:
|
|
|
1117
1131
|
block_network=block_network,
|
|
1118
1132
|
restrict_modal_access=restrict_modal_access,
|
|
1119
1133
|
max_inputs=max_inputs,
|
|
1134
|
+
http_config=http_config,
|
|
1120
1135
|
i6pn_enabled=i6pn_enabled,
|
|
1121
1136
|
cluster_size=cluster_size,
|
|
1122
1137
|
rdma=rdma,
|
|
@@ -1130,6 +1145,7 @@ class _App:
|
|
|
1130
1145
|
self._add_function(cls_func, is_web_endpoint=False)
|
|
1131
1146
|
|
|
1132
1147
|
cls: _Cls = _Cls.from_local(user_cls, self, cls_func)
|
|
1148
|
+
|
|
1133
1149
|
for method_name, partial_function in cls._method_partials.items():
|
|
1134
1150
|
if partial_function.params.webhook_config is not None:
|
|
1135
1151
|
full_name = f"{user_cls.__name__}.{method_name}"
|
|
@@ -32,7 +32,7 @@ class _Client:
|
|
|
32
32
|
server_url: str,
|
|
33
33
|
client_type: int,
|
|
34
34
|
credentials: typing.Optional[tuple[str, str]],
|
|
35
|
-
version: str = "1.2.5.
|
|
35
|
+
version: str = "1.2.5.dev10",
|
|
36
36
|
):
|
|
37
37
|
"""mdmd:hidden
|
|
38
38
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -163,7 +163,7 @@ class Client:
|
|
|
163
163
|
server_url: str,
|
|
164
164
|
client_type: int,
|
|
165
165
|
credentials: typing.Optional[tuple[str, str]],
|
|
166
|
-
version: str = "1.2.5.
|
|
166
|
+
version: str = "1.2.5.dev10",
|
|
167
167
|
):
|
|
168
168
|
"""mdmd:hidden
|
|
169
169
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -19,7 +19,12 @@ from ..cls import _Cls
|
|
|
19
19
|
from ..exception import InvalidError
|
|
20
20
|
from ..image import DockerfileSpec, ImageBuilderVersion, _Image, _ImageRegistryConfig
|
|
21
21
|
from ..secret import _Secret
|
|
22
|
-
from .flash import
|
|
22
|
+
from .flash import ( # noqa: F401
|
|
23
|
+
flash_forward,
|
|
24
|
+
flash_get_containers,
|
|
25
|
+
flash_prometheus_autoscaler,
|
|
26
|
+
http_server,
|
|
27
|
+
)
|
|
23
28
|
|
|
24
29
|
|
|
25
30
|
def stop_fetching_inputs():
|
|
@@ -7,9 +7,10 @@ import sys
|
|
|
7
7
|
import time
|
|
8
8
|
import traceback
|
|
9
9
|
from collections import defaultdict
|
|
10
|
-
from typing import Any, Optional
|
|
10
|
+
from typing import Any, Callable, Optional, Union
|
|
11
11
|
from urllib.parse import urlparse
|
|
12
12
|
|
|
13
|
+
from modal._partial_function import _PartialFunctionFlags
|
|
13
14
|
from modal.cls import _Cls
|
|
14
15
|
from modal.dict import _Dict
|
|
15
16
|
from modal_proto import api_pb2
|
|
@@ -28,15 +29,17 @@ class _FlashManager:
|
|
|
28
29
|
self,
|
|
29
30
|
client: _Client,
|
|
30
31
|
port: int,
|
|
31
|
-
process: Optional[subprocess.Popen] = None,
|
|
32
|
+
process: Optional[subprocess.Popen] = None, # to be deprecated
|
|
32
33
|
health_check_url: Optional[str] = None,
|
|
34
|
+
startup_timeout: int = 30,
|
|
33
35
|
h2_enabled: bool = False,
|
|
34
36
|
):
|
|
35
37
|
self.client = client
|
|
36
38
|
self.port = port
|
|
39
|
+
self.process = process
|
|
37
40
|
# Health check is not currently being used
|
|
38
41
|
self.health_check_url = health_check_url
|
|
39
|
-
self.
|
|
42
|
+
self.startup_timeout = startup_timeout
|
|
40
43
|
self.tunnel_manager = _forward_tunnel(port, h2_enabled=h2_enabled, client=client)
|
|
41
44
|
self.stopped = False
|
|
42
45
|
self.num_failures = 0
|
|
@@ -49,10 +52,15 @@ class _FlashManager:
|
|
|
49
52
|
|
|
50
53
|
start_time = time.monotonic()
|
|
51
54
|
|
|
55
|
+
def check_process_is_running() -> Optional[Exception]:
|
|
56
|
+
if process is not None and process.poll() is not None:
|
|
57
|
+
return Exception(f"Process {process.pid} exited with code {process.returncode}")
|
|
58
|
+
return None
|
|
59
|
+
|
|
52
60
|
while time.monotonic() - start_time < timeout:
|
|
53
61
|
try:
|
|
54
|
-
if
|
|
55
|
-
return False,
|
|
62
|
+
if error := check_process_is_running():
|
|
63
|
+
return False, error
|
|
56
64
|
with socket.create_connection(("localhost", self.port), timeout=0.5):
|
|
57
65
|
return True, None
|
|
58
66
|
except (ConnectionRefusedError, OSError):
|
|
@@ -101,6 +109,7 @@ class _FlashManager:
|
|
|
101
109
|
|
|
102
110
|
async def _run_heartbeat(self, host: str, port: int):
|
|
103
111
|
first_registration = True
|
|
112
|
+
start_time = time.monotonic()
|
|
104
113
|
while True:
|
|
105
114
|
try:
|
|
106
115
|
port_check_resp, port_check_error = await self.is_port_connection_healthy(process=self.process)
|
|
@@ -122,12 +131,15 @@ class _FlashManager:
|
|
|
122
131
|
)
|
|
123
132
|
first_registration = False
|
|
124
133
|
else:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
if first_registration and (time.monotonic() - start_time < self.startup_timeout):
|
|
135
|
+
continue
|
|
136
|
+
else:
|
|
137
|
+
logger.error(
|
|
138
|
+
f"[Modal Flash] Deregistering container {self.task_id} on {self.tunnel.url} "
|
|
139
|
+
f"due to error: {port_check_error}, num_failures: {self.num_failures}"
|
|
140
|
+
)
|
|
141
|
+
self.num_failures += 1
|
|
142
|
+
await self.client.stub.FlashContainerDeregister(api_pb2.FlashContainerDeregisterRequest())
|
|
131
143
|
|
|
132
144
|
except asyncio.CancelledError:
|
|
133
145
|
logger.warning("[Modal Flash] Shutting down...")
|
|
@@ -171,6 +183,7 @@ async def flash_forward(
|
|
|
171
183
|
port: int,
|
|
172
184
|
process: Optional[subprocess.Popen] = None,
|
|
173
185
|
health_check_url: Optional[str] = None,
|
|
186
|
+
startup_timeout: int = 30,
|
|
174
187
|
h2_enabled: bool = False,
|
|
175
188
|
) -> _FlashManager:
|
|
176
189
|
"""
|
|
@@ -180,7 +193,14 @@ async def flash_forward(
|
|
|
180
193
|
"""
|
|
181
194
|
client = await _Client.from_env()
|
|
182
195
|
|
|
183
|
-
manager = _FlashManager(
|
|
196
|
+
manager = _FlashManager(
|
|
197
|
+
client,
|
|
198
|
+
port,
|
|
199
|
+
process=process,
|
|
200
|
+
health_check_url=health_check_url,
|
|
201
|
+
startup_timeout=startup_timeout,
|
|
202
|
+
h2_enabled=h2_enabled,
|
|
203
|
+
)
|
|
184
204
|
await manager._start()
|
|
185
205
|
return manager
|
|
186
206
|
|
|
@@ -618,3 +638,57 @@ async def flash_get_containers(app_name: str, cls_name: str) -> list[dict[str, A
|
|
|
618
638
|
req = api_pb2.FlashContainerListRequest(function_id=fn.object_id)
|
|
619
639
|
resp = await client.stub.FlashContainerList(req)
|
|
620
640
|
return resp.containers
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
def _http_server(
|
|
644
|
+
port: Optional[int] = None,
|
|
645
|
+
*,
|
|
646
|
+
proxy_regions: list[str] = [], # The regions to proxy the HTTP server to.
|
|
647
|
+
startup_timeout: int = 30, # Maximum number of seconds to wait for the HTTP server to start.
|
|
648
|
+
exit_grace_period: Optional[int] = None, # The time to wait for the HTTP server to exit gracefully.
|
|
649
|
+
):
|
|
650
|
+
"""Decorator for Flash-enabled HTTP servers on Modal classes.
|
|
651
|
+
|
|
652
|
+
Args:
|
|
653
|
+
port: The local port to forward to the HTTP server.
|
|
654
|
+
proxy_regions: The regions to proxy the HTTP server to.
|
|
655
|
+
startup_timeout: The maximum time to wait for the HTTP server to start.
|
|
656
|
+
exit_grace_period: The time to wait for the HTTP server to exit gracefully.
|
|
657
|
+
|
|
658
|
+
"""
|
|
659
|
+
if port is None:
|
|
660
|
+
raise InvalidError(
|
|
661
|
+
"Positional arguments are not allowed. Did you forget parentheses? Suggestion: `@modal.http_server()`."
|
|
662
|
+
)
|
|
663
|
+
if not isinstance(port, int) or port < 1 or port > 65535:
|
|
664
|
+
raise InvalidError("First argument of `@http_server` must be a local port, such as `@http_server(8000)`.")
|
|
665
|
+
if startup_timeout <= 0:
|
|
666
|
+
raise InvalidError("The `startup_timeout` argument of `@http_server` must be positive.")
|
|
667
|
+
if exit_grace_period is not None and exit_grace_period < 0:
|
|
668
|
+
raise InvalidError("The `exit_grace_period` argument of `@http_server` must be non-negative.")
|
|
669
|
+
|
|
670
|
+
from modal._partial_function import _PartialFunction, _PartialFunctionParams
|
|
671
|
+
|
|
672
|
+
params = _PartialFunctionParams(
|
|
673
|
+
http_config=api_pb2.HTTPConfig(
|
|
674
|
+
port=port,
|
|
675
|
+
proxy_regions=proxy_regions,
|
|
676
|
+
startup_timeout=startup_timeout or 0,
|
|
677
|
+
exit_grace_period=exit_grace_period or 0,
|
|
678
|
+
)
|
|
679
|
+
)
|
|
680
|
+
|
|
681
|
+
def wrapper(obj: Union[Callable[..., Any], _PartialFunction]) -> _PartialFunction:
|
|
682
|
+
flags = _PartialFunctionFlags.HTTP_WEB_INTERFACE
|
|
683
|
+
|
|
684
|
+
if isinstance(obj, _PartialFunction):
|
|
685
|
+
pf = obj.stack(flags, params)
|
|
686
|
+
else:
|
|
687
|
+
pf = _PartialFunction(obj, flags, params)
|
|
688
|
+
pf.validate_obj_compatibility("`http_server`")
|
|
689
|
+
return pf
|
|
690
|
+
|
|
691
|
+
return wrapper
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
http_server = synchronize_api(_http_server, target_module=__name__)
|
|
@@ -10,6 +10,7 @@ class _FlashManager:
|
|
|
10
10
|
port: int,
|
|
11
11
|
process: typing.Optional[subprocess.Popen] = None,
|
|
12
12
|
health_check_url: typing.Optional[str] = None,
|
|
13
|
+
startup_timeout: int = 30,
|
|
13
14
|
h2_enabled: bool = False,
|
|
14
15
|
):
|
|
15
16
|
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
@@ -37,6 +38,7 @@ class FlashManager:
|
|
|
37
38
|
port: int,
|
|
38
39
|
process: typing.Optional[subprocess.Popen] = None,
|
|
39
40
|
health_check_url: typing.Optional[str] = None,
|
|
41
|
+
startup_timeout: int = 30,
|
|
40
42
|
h2_enabled: bool = False,
|
|
41
43
|
): ...
|
|
42
44
|
|
|
@@ -94,6 +96,7 @@ class __flash_forward_spec(typing_extensions.Protocol):
|
|
|
94
96
|
port: int,
|
|
95
97
|
process: typing.Optional[subprocess.Popen] = None,
|
|
96
98
|
health_check_url: typing.Optional[str] = None,
|
|
99
|
+
startup_timeout: int = 30,
|
|
97
100
|
h2_enabled: bool = False,
|
|
98
101
|
) -> FlashManager:
|
|
99
102
|
"""Forward a port to the Modal Flash service, exposing that port as a stable web endpoint.
|
|
@@ -108,6 +111,7 @@ class __flash_forward_spec(typing_extensions.Protocol):
|
|
|
108
111
|
port: int,
|
|
109
112
|
process: typing.Optional[subprocess.Popen] = None,
|
|
110
113
|
health_check_url: typing.Optional[str] = None,
|
|
114
|
+
startup_timeout: int = 30,
|
|
111
115
|
h2_enabled: bool = False,
|
|
112
116
|
) -> FlashManager:
|
|
113
117
|
"""Forward a port to the Modal Flash service, exposing that port as a stable web endpoint.
|
|
@@ -382,3 +386,37 @@ class __flash_get_containers_spec(typing_extensions.Protocol):
|
|
|
382
386
|
...
|
|
383
387
|
|
|
384
388
|
flash_get_containers: __flash_get_containers_spec
|
|
389
|
+
|
|
390
|
+
def _http_server(
|
|
391
|
+
port: typing.Optional[int] = None,
|
|
392
|
+
*,
|
|
393
|
+
proxy_regions: list[str] = [],
|
|
394
|
+
startup_timeout: int = 30,
|
|
395
|
+
exit_grace_period: typing.Optional[int] = None,
|
|
396
|
+
):
|
|
397
|
+
"""Decorator for Flash-enabled HTTP servers on Modal classes.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
port: The local port to forward to the HTTP server.
|
|
401
|
+
proxy_regions: The regions to proxy the HTTP server to.
|
|
402
|
+
startup_timeout: The maximum time to wait for the HTTP server to start.
|
|
403
|
+
exit_grace_period: The time to wait for the HTTP server to exit gracefully.
|
|
404
|
+
"""
|
|
405
|
+
...
|
|
406
|
+
|
|
407
|
+
def http_server(
|
|
408
|
+
port: typing.Optional[int] = None,
|
|
409
|
+
*,
|
|
410
|
+
proxy_regions: list[str] = [],
|
|
411
|
+
startup_timeout: int = 30,
|
|
412
|
+
exit_grace_period: typing.Optional[int] = None,
|
|
413
|
+
):
|
|
414
|
+
"""Decorator for Flash-enabled HTTP servers on Modal classes.
|
|
415
|
+
|
|
416
|
+
Args:
|
|
417
|
+
port: The local port to forward to the HTTP server.
|
|
418
|
+
proxy_regions: The regions to proxy the HTTP server to.
|
|
419
|
+
startup_timeout: The maximum time to wait for the HTTP server to start.
|
|
420
|
+
exit_grace_period: The time to wait for the HTTP server to exit gracefully.
|
|
421
|
+
"""
|
|
422
|
+
...
|
|
@@ -113,6 +113,7 @@ class Function(
|
|
|
113
113
|
_experimental_proxy_ip: typing.Optional[str] = None,
|
|
114
114
|
_experimental_custom_scaling_factor: typing.Optional[float] = None,
|
|
115
115
|
restrict_output: bool = False,
|
|
116
|
+
http_config: typing.Optional[modal_proto.api_pb2.HTTPConfig] = None,
|
|
116
117
|
) -> Function:
|
|
117
118
|
"""mdmd:hidden
|
|
118
119
|
|
|
@@ -628,7 +628,7 @@ async def _interactive_shell(
|
|
|
628
628
|
try:
|
|
629
629
|
if pty:
|
|
630
630
|
container_process = await sandbox._exec(
|
|
631
|
-
*sandbox_cmds, pty_info=get_pty_info(shell=True) if pty else None
|
|
631
|
+
*sandbox_cmds, pty_info=get_pty_info(shell=True) if pty else None, text=False
|
|
632
632
|
)
|
|
633
633
|
await container_process.attach()
|
|
634
634
|
else:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|