fal 1.7.1__tar.gz → 1.7.3__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.
Potentially problematic release.
This version of fal might be problematic. Click here for more details.
- {fal-1.7.1/fal.egg-info → fal-1.7.3}/PKG-INFO +1 -1
- {fal-1.7.1 → fal-1.7.3/fal.egg-info}/PKG-INFO +1 -1
- {fal-1.7.1 → fal-1.7.3}/src/fal/_fal_version.py +2 -2
- {fal-1.7.1 → fal-1.7.3}/src/fal/api.py +1 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/file/providers/fal.py +252 -133
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/utils/retry.py +3 -0
- {fal-1.7.1 → fal-1.7.3}/.gitignore +0 -0
- {fal-1.7.1 → fal-1.7.3}/Makefile +0 -0
- {fal-1.7.1 → fal-1.7.3}/README.md +0 -0
- {fal-1.7.1 → fal-1.7.3}/docs/conf.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/docs/index.rst +0 -0
- {fal-1.7.1 → fal-1.7.3}/fal.egg-info/SOURCES.txt +0 -0
- {fal-1.7.1 → fal-1.7.3}/fal.egg-info/dependency_links.txt +0 -0
- {fal-1.7.1 → fal-1.7.3}/fal.egg-info/entry_points.txt +0 -0
- {fal-1.7.1 → fal-1.7.3}/fal.egg-info/requires.txt +0 -0
- {fal-1.7.1 → fal-1.7.3}/fal.egg-info/top_level.txt +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/README.md +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/pyproject.toml +0 -0
- {fal-1.7.1 → fal-1.7.3}/openapi_rest.config.yaml +0 -0
- {fal-1.7.1 → fal-1.7.3}/pyproject.toml +0 -0
- {fal-1.7.1 → fal-1.7.3}/setup.cfg +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/__main__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/_serialization.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/_version.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/app.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/apps.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/auth/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/auth/auth0.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/auth/local.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/_utils.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/apps.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/auth.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/create.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/debug.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/deploy.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/doctor.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/keys.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/main.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/parser.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/run.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/runners.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/cli/secrets.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/config.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/console/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/console/icons.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/console/ux.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/container.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/exceptions/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/exceptions/_base.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/exceptions/_cuda.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/exceptions/auth.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/files.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/flags.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/logging/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/logging/isolate.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/logging/style.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/logging/trace.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/logging/user.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/py.typed +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/rest_client.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/sdk.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/sync.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/exceptions.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/file/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/file/file.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/file/providers/gcp.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/file/providers/r2.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/file/providers/s3.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/file/types.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/image/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/image/image.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/image/safety_checker.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/optimize.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/types.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/utils/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/toolkit/utils/download_utils.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/utils.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/src/fal/workflows.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/assets/cat.png +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/cli/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/cli/test_apps.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/cli/test_auth.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/cli/test_deploy.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/cli/test_keys.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/cli/test_run.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/cli/test_secrets.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/conftest.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/integration_test.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/mainify_package/__init__.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/mainify_package/impl.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/mainify_package/utils.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/mainify_target.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/test_apps.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/test_stability.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/toolkit/file_test.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/toolkit/image_test.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/toolkit/test_types.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tests/toolkit/utils/retry.py +0 -0
- {fal-1.7.1 → fal-1.7.3}/tools/demo_script.py +0 -0
|
@@ -159,24 +159,27 @@ class FalFileRepositoryBase(FileRepository):
|
|
|
159
159
|
result = json.load(response)
|
|
160
160
|
|
|
161
161
|
upload_url = result["upload_url"]
|
|
162
|
-
self._upload_file(upload_url, file)
|
|
163
|
-
|
|
164
|
-
return result["file_url"]
|
|
165
162
|
except HTTPError as e:
|
|
166
163
|
raise FileUploadException(
|
|
167
164
|
f"Error initiating upload. Status {e.status}: {e.reason}"
|
|
168
165
|
)
|
|
169
166
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
167
|
+
try:
|
|
168
|
+
req = Request(
|
|
169
|
+
upload_url,
|
|
170
|
+
method="PUT",
|
|
171
|
+
data=file.data,
|
|
172
|
+
headers={"Content-Type": file.content_type},
|
|
173
|
+
)
|
|
177
174
|
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
with urlopen(req):
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
return result["file_url"]
|
|
179
|
+
except HTTPError as e:
|
|
180
|
+
raise FileUploadException(
|
|
181
|
+
f"Error uploading file. Status {e.status}: {e.reason}"
|
|
182
|
+
)
|
|
180
183
|
|
|
181
184
|
|
|
182
185
|
@dataclass
|
|
@@ -202,12 +205,12 @@ class MultipartUpload:
|
|
|
202
205
|
|
|
203
206
|
def __init__(
|
|
204
207
|
self,
|
|
205
|
-
|
|
208
|
+
file_name: str,
|
|
206
209
|
chunk_size: int | None = None,
|
|
207
210
|
content_type: str | None = None,
|
|
208
211
|
max_concurrency: int | None = None,
|
|
209
212
|
) -> None:
|
|
210
|
-
self.
|
|
213
|
+
self.file_name = file_name
|
|
211
214
|
self.chunk_size = chunk_size or self.MULTIPART_CHUNK_SIZE
|
|
212
215
|
self.content_type = content_type or "application/octet-stream"
|
|
213
216
|
self.max_concurrency = max_concurrency or self.MULTIPART_MAX_CONCURRENCY
|
|
@@ -227,7 +230,7 @@ class MultipartUpload:
|
|
|
227
230
|
},
|
|
228
231
|
data=json.dumps(
|
|
229
232
|
{
|
|
230
|
-
"file_name":
|
|
233
|
+
"file_name": self.file_name,
|
|
231
234
|
"content_type": self.content_type,
|
|
232
235
|
}
|
|
233
236
|
).encode(),
|
|
@@ -241,47 +244,29 @@ class MultipartUpload:
|
|
|
241
244
|
f"Error initiating upload. Status {exc.status}: {exc.reason}"
|
|
242
245
|
)
|
|
243
246
|
|
|
244
|
-
def
|
|
245
|
-
|
|
246
|
-
start = (part_number - 1) * self.chunk_size
|
|
247
|
-
f.seek(start)
|
|
248
|
-
data = f.read(self.chunk_size)
|
|
249
|
-
req = Request(
|
|
250
|
-
url,
|
|
251
|
-
method="PUT",
|
|
252
|
-
headers={"Content-Type": self.content_type},
|
|
253
|
-
data=data,
|
|
254
|
-
)
|
|
247
|
+
def upload_part(self, part_number: int, data: bytes) -> None:
|
|
248
|
+
url = f"{self._upload_url}&part_number={part_number}"
|
|
255
249
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
250
|
+
req = Request(
|
|
251
|
+
url,
|
|
252
|
+
method="PUT",
|
|
253
|
+
headers={"Content-Type": self.content_type},
|
|
254
|
+
data=data,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
try:
|
|
258
|
+
with urlopen(req) as resp:
|
|
259
|
+
self._parts.append(
|
|
260
|
+
{
|
|
259
261
|
"part_number": part_number,
|
|
260
262
|
"etag": resp.headers["ETag"],
|
|
261
263
|
}
|
|
262
|
-
except HTTPError as exc:
|
|
263
|
-
raise FileUploadException(
|
|
264
|
-
f"Error uploading part {part_number} to {url}. "
|
|
265
|
-
f"Status {exc.status}: {exc.reason}"
|
|
266
264
|
)
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
with concurrent.futures.ThreadPoolExecutor(
|
|
273
|
-
max_workers=self.max_concurrency
|
|
274
|
-
) as executor:
|
|
275
|
-
futures = []
|
|
276
|
-
for part_number in range(1, parts + 1):
|
|
277
|
-
upload_url = f"{self._upload_url}&part_number={part_number}"
|
|
278
|
-
futures.append(
|
|
279
|
-
executor.submit(self._upload_part, upload_url, part_number)
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
for future in concurrent.futures.as_completed(futures):
|
|
283
|
-
entry = future.result()
|
|
284
|
-
self._parts.append(entry)
|
|
265
|
+
except HTTPError as exc:
|
|
266
|
+
raise FileUploadException(
|
|
267
|
+
f"Error uploading part {part_number} to {url}. "
|
|
268
|
+
f"Status {exc.status}: {exc.reason}"
|
|
269
|
+
)
|
|
285
270
|
|
|
286
271
|
def complete(self):
|
|
287
272
|
url = self._upload_url
|
|
@@ -304,6 +289,82 @@ class MultipartUpload:
|
|
|
304
289
|
|
|
305
290
|
return self._file_url
|
|
306
291
|
|
|
292
|
+
@classmethod
|
|
293
|
+
def save(
|
|
294
|
+
cls,
|
|
295
|
+
file: FileData,
|
|
296
|
+
chunk_size: int | None = None,
|
|
297
|
+
max_concurrency: int | None = None,
|
|
298
|
+
):
|
|
299
|
+
import concurrent.futures
|
|
300
|
+
|
|
301
|
+
multipart = cls(
|
|
302
|
+
file.file_name,
|
|
303
|
+
chunk_size=chunk_size,
|
|
304
|
+
content_type=file.content_type,
|
|
305
|
+
max_concurrency=max_concurrency,
|
|
306
|
+
)
|
|
307
|
+
multipart.create()
|
|
308
|
+
|
|
309
|
+
parts = math.ceil(len(file.data) / multipart.chunk_size)
|
|
310
|
+
with concurrent.futures.ThreadPoolExecutor(
|
|
311
|
+
max_workers=multipart.max_concurrency
|
|
312
|
+
) as executor:
|
|
313
|
+
futures = []
|
|
314
|
+
for part_number in range(1, parts + 1):
|
|
315
|
+
start = (part_number - 1) * multipart.chunk_size
|
|
316
|
+
data = file.data[start : start + multipart.chunk_size]
|
|
317
|
+
futures.append(
|
|
318
|
+
executor.submit(multipart.upload_part, part_number, data)
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
for future in concurrent.futures.as_completed(futures):
|
|
322
|
+
future.result()
|
|
323
|
+
|
|
324
|
+
return multipart.complete()
|
|
325
|
+
|
|
326
|
+
@classmethod
|
|
327
|
+
def save_file(
|
|
328
|
+
cls,
|
|
329
|
+
file_path: str | Path,
|
|
330
|
+
chunk_size: int | None = None,
|
|
331
|
+
content_type: str | None = None,
|
|
332
|
+
max_concurrency: int | None = None,
|
|
333
|
+
) -> str:
|
|
334
|
+
import concurrent.futures
|
|
335
|
+
|
|
336
|
+
file_name = os.path.basename(file_path)
|
|
337
|
+
size = os.path.getsize(file_path)
|
|
338
|
+
|
|
339
|
+
multipart = cls(
|
|
340
|
+
file_name,
|
|
341
|
+
chunk_size=chunk_size,
|
|
342
|
+
content_type=content_type,
|
|
343
|
+
max_concurrency=max_concurrency,
|
|
344
|
+
)
|
|
345
|
+
multipart.create()
|
|
346
|
+
|
|
347
|
+
parts = math.ceil(size / multipart.chunk_size)
|
|
348
|
+
with concurrent.futures.ThreadPoolExecutor(
|
|
349
|
+
max_workers=multipart.max_concurrency
|
|
350
|
+
) as executor:
|
|
351
|
+
futures = []
|
|
352
|
+
for part_number in range(1, parts + 1):
|
|
353
|
+
|
|
354
|
+
def _upload_part(pn: int) -> None:
|
|
355
|
+
with open(file_path, "rb") as f:
|
|
356
|
+
start = (pn - 1) * multipart.chunk_size
|
|
357
|
+
f.seek(start)
|
|
358
|
+
data = f.read(multipart.chunk_size)
|
|
359
|
+
multipart.upload_part(pn, data)
|
|
360
|
+
|
|
361
|
+
futures.append(executor.submit(_upload_part, part_number))
|
|
362
|
+
|
|
363
|
+
for future in concurrent.futures.as_completed(futures):
|
|
364
|
+
future.result()
|
|
365
|
+
|
|
366
|
+
return multipart.complete()
|
|
367
|
+
|
|
307
368
|
|
|
308
369
|
class InternalMultipartUploadV3:
|
|
309
370
|
MULTIPART_THRESHOLD = 100 * 1024 * 1024
|
|
@@ -312,12 +373,12 @@ class InternalMultipartUploadV3:
|
|
|
312
373
|
|
|
313
374
|
def __init__(
|
|
314
375
|
self,
|
|
315
|
-
|
|
376
|
+
file_name: str,
|
|
316
377
|
chunk_size: int | None = None,
|
|
317
378
|
content_type: str | None = None,
|
|
318
379
|
max_concurrency: int | None = None,
|
|
319
380
|
) -> None:
|
|
320
|
-
self.
|
|
381
|
+
self.file_name = file_name
|
|
321
382
|
self.chunk_size = chunk_size or self.MULTIPART_CHUNK_SIZE
|
|
322
383
|
self.content_type = content_type or "application/octet-stream"
|
|
323
384
|
self.max_concurrency = max_concurrency or self.MULTIPART_MAX_CONCURRENCY
|
|
@@ -356,7 +417,7 @@ class InternalMultipartUploadV3:
|
|
|
356
417
|
**self.auth_headers,
|
|
357
418
|
"Accept": "application/json",
|
|
358
419
|
"Content-Type": self.content_type,
|
|
359
|
-
"X-Fal-File-Name":
|
|
420
|
+
"X-Fal-File-Name": self.file_name,
|
|
360
421
|
},
|
|
361
422
|
)
|
|
362
423
|
with urlopen(req) as response:
|
|
@@ -370,52 +431,32 @@ class InternalMultipartUploadV3:
|
|
|
370
431
|
)
|
|
371
432
|
|
|
372
433
|
@retry(max_retries=5, base_delay=1, backoff_type="exponential", jitter=True)
|
|
373
|
-
def
|
|
374
|
-
|
|
375
|
-
start = (part_number - 1) * self.chunk_size
|
|
376
|
-
f.seek(start)
|
|
377
|
-
data = f.read(self.chunk_size)
|
|
378
|
-
req = Request(
|
|
379
|
-
url,
|
|
380
|
-
method="PUT",
|
|
381
|
-
headers={
|
|
382
|
-
**self.auth_headers,
|
|
383
|
-
"Content-Type": self.content_type,
|
|
384
|
-
},
|
|
385
|
-
data=data,
|
|
386
|
-
)
|
|
434
|
+
def upload_part(self, part_number: int, data: bytes) -> None:
|
|
435
|
+
url = f"{self.access_url}/multipart/{self.upload_id}/{part_number}"
|
|
387
436
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
437
|
+
req = Request(
|
|
438
|
+
url,
|
|
439
|
+
method="PUT",
|
|
440
|
+
headers={
|
|
441
|
+
**self.auth_headers,
|
|
442
|
+
"Content-Type": self.content_type,
|
|
443
|
+
},
|
|
444
|
+
data=data,
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
try:
|
|
448
|
+
with urlopen(req) as resp:
|
|
449
|
+
self._parts.append(
|
|
450
|
+
{
|
|
391
451
|
"partNumber": part_number,
|
|
392
452
|
"etag": resp.headers["ETag"],
|
|
393
453
|
}
|
|
394
|
-
except HTTPError as exc:
|
|
395
|
-
raise FileUploadException(
|
|
396
|
-
f"Error uploading part {part_number} to {url}. "
|
|
397
|
-
f"Status {exc.status}: {exc.reason}"
|
|
398
454
|
)
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
with concurrent.futures.ThreadPoolExecutor(
|
|
405
|
-
max_workers=self.max_concurrency
|
|
406
|
-
) as executor:
|
|
407
|
-
futures = []
|
|
408
|
-
for part_number in range(1, parts + 1):
|
|
409
|
-
upload_url = (
|
|
410
|
-
f"{self.access_url}/multipart/{self.upload_id}/{part_number}"
|
|
411
|
-
)
|
|
412
|
-
futures.append(
|
|
413
|
-
executor.submit(self._upload_part, upload_url, part_number)
|
|
414
|
-
)
|
|
415
|
-
|
|
416
|
-
for future in concurrent.futures.as_completed(futures):
|
|
417
|
-
entry = future.result()
|
|
418
|
-
self._parts.append(entry)
|
|
455
|
+
except HTTPError as exc:
|
|
456
|
+
raise FileUploadException(
|
|
457
|
+
f"Error uploading part {part_number} to {url}. "
|
|
458
|
+
f"Status {exc.status}: {exc.reason}"
|
|
459
|
+
)
|
|
419
460
|
|
|
420
461
|
def complete(self) -> str:
|
|
421
462
|
url = f"{self.access_url}/multipart/{self.upload_id}/complete"
|
|
@@ -439,13 +480,106 @@ class InternalMultipartUploadV3:
|
|
|
439
480
|
|
|
440
481
|
return self.access_url
|
|
441
482
|
|
|
483
|
+
@classmethod
|
|
484
|
+
def save(
|
|
485
|
+
cls,
|
|
486
|
+
file: FileData,
|
|
487
|
+
chunk_size: int | None = None,
|
|
488
|
+
max_concurrency: int | None = None,
|
|
489
|
+
):
|
|
490
|
+
import concurrent.futures
|
|
491
|
+
|
|
492
|
+
multipart = cls(
|
|
493
|
+
file.file_name,
|
|
494
|
+
chunk_size=chunk_size,
|
|
495
|
+
content_type=file.content_type,
|
|
496
|
+
max_concurrency=max_concurrency,
|
|
497
|
+
)
|
|
498
|
+
multipart.create()
|
|
499
|
+
|
|
500
|
+
parts = math.ceil(len(file.data) / multipart.chunk_size)
|
|
501
|
+
with concurrent.futures.ThreadPoolExecutor(
|
|
502
|
+
max_workers=multipart.max_concurrency
|
|
503
|
+
) as executor:
|
|
504
|
+
futures = []
|
|
505
|
+
for part_number in range(1, parts + 1):
|
|
506
|
+
start = (part_number - 1) * multipart.chunk_size
|
|
507
|
+
data = file.data[start : start + multipart.chunk_size]
|
|
508
|
+
futures.append(
|
|
509
|
+
executor.submit(multipart.upload_part, part_number, data)
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
for future in concurrent.futures.as_completed(futures):
|
|
513
|
+
future.result()
|
|
514
|
+
|
|
515
|
+
return multipart.complete()
|
|
516
|
+
|
|
517
|
+
@classmethod
|
|
518
|
+
def save_file(
|
|
519
|
+
cls,
|
|
520
|
+
file_path: str | Path,
|
|
521
|
+
chunk_size: int | None = None,
|
|
522
|
+
content_type: str | None = None,
|
|
523
|
+
max_concurrency: int | None = None,
|
|
524
|
+
) -> str:
|
|
525
|
+
import concurrent.futures
|
|
526
|
+
|
|
527
|
+
file_name = os.path.basename(file_path)
|
|
528
|
+
size = os.path.getsize(file_path)
|
|
529
|
+
|
|
530
|
+
multipart = cls(
|
|
531
|
+
file_name,
|
|
532
|
+
chunk_size=chunk_size,
|
|
533
|
+
content_type=content_type,
|
|
534
|
+
max_concurrency=max_concurrency,
|
|
535
|
+
)
|
|
536
|
+
multipart.create()
|
|
537
|
+
|
|
538
|
+
parts = math.ceil(size / multipart.chunk_size)
|
|
539
|
+
with concurrent.futures.ThreadPoolExecutor(
|
|
540
|
+
max_workers=multipart.max_concurrency
|
|
541
|
+
) as executor:
|
|
542
|
+
futures = []
|
|
543
|
+
for part_number in range(1, parts + 1):
|
|
544
|
+
|
|
545
|
+
def _upload_part(pn: int) -> None:
|
|
546
|
+
with open(file_path, "rb") as f:
|
|
547
|
+
start = (pn - 1) * multipart.chunk_size
|
|
548
|
+
f.seek(start)
|
|
549
|
+
data = f.read(multipart.chunk_size)
|
|
550
|
+
multipart.upload_part(pn, data)
|
|
551
|
+
|
|
552
|
+
futures.append(executor.submit(_upload_part, part_number))
|
|
553
|
+
|
|
554
|
+
for future in concurrent.futures.as_completed(futures):
|
|
555
|
+
future.result()
|
|
556
|
+
|
|
557
|
+
return multipart.complete()
|
|
558
|
+
|
|
442
559
|
|
|
443
560
|
@dataclass
|
|
444
561
|
class FalFileRepositoryV2(FalFileRepositoryBase):
|
|
445
562
|
@retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
|
|
446
563
|
def save(
|
|
447
|
-
self,
|
|
564
|
+
self,
|
|
565
|
+
file: FileData,
|
|
566
|
+
multipart: bool | None = None,
|
|
567
|
+
multipart_threshold: int | None = None,
|
|
568
|
+
multipart_chunk_size: int | None = None,
|
|
569
|
+
multipart_max_concurrency: int | None = None,
|
|
570
|
+
object_lifecycle_preference: dict[str, str] | None = None,
|
|
448
571
|
) -> str:
|
|
572
|
+
if multipart is None:
|
|
573
|
+
threshold = multipart_threshold or MultipartUpload.MULTIPART_THRESHOLD
|
|
574
|
+
multipart = len(file.data) > threshold
|
|
575
|
+
|
|
576
|
+
if multipart:
|
|
577
|
+
return MultipartUpload.save(
|
|
578
|
+
file,
|
|
579
|
+
chunk_size=multipart_chunk_size,
|
|
580
|
+
max_concurrency=multipart_max_concurrency,
|
|
581
|
+
)
|
|
582
|
+
|
|
449
583
|
token = fal_v2_token_manager.get_token()
|
|
450
584
|
headers = {
|
|
451
585
|
"Authorization": f"{token.token_type} {token.token}",
|
|
@@ -472,23 +606,6 @@ class FalFileRepositoryV2(FalFileRepositoryBase):
|
|
|
472
606
|
f"Error initiating upload. Status {e.status}: {e.reason}"
|
|
473
607
|
)
|
|
474
608
|
|
|
475
|
-
def _save_multipart(
|
|
476
|
-
self,
|
|
477
|
-
file_path: str | Path,
|
|
478
|
-
chunk_size: int | None = None,
|
|
479
|
-
content_type: str | None = None,
|
|
480
|
-
max_concurrency: int | None = None,
|
|
481
|
-
) -> str:
|
|
482
|
-
multipart = MultipartUpload(
|
|
483
|
-
file_path,
|
|
484
|
-
chunk_size=chunk_size,
|
|
485
|
-
content_type=content_type,
|
|
486
|
-
max_concurrency=max_concurrency,
|
|
487
|
-
)
|
|
488
|
-
multipart.create()
|
|
489
|
-
multipart.upload()
|
|
490
|
-
return multipart.complete()
|
|
491
|
-
|
|
492
609
|
def save_file(
|
|
493
610
|
self,
|
|
494
611
|
file_path: str | Path,
|
|
@@ -504,7 +621,7 @@ class FalFileRepositoryV2(FalFileRepositoryBase):
|
|
|
504
621
|
multipart = os.path.getsize(file_path) > threshold
|
|
505
622
|
|
|
506
623
|
if multipart:
|
|
507
|
-
url =
|
|
624
|
+
url = MultipartUpload.save_file(
|
|
508
625
|
file_path,
|
|
509
626
|
chunk_size=multipart_chunk_size,
|
|
510
627
|
content_type=content_type,
|
|
@@ -605,8 +722,27 @@ class InternalFalFileRepositoryV3(FileRepository):
|
|
|
605
722
|
|
|
606
723
|
@retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
|
|
607
724
|
def save(
|
|
608
|
-
self,
|
|
725
|
+
self,
|
|
726
|
+
file: FileData,
|
|
727
|
+
multipart: bool | None = None,
|
|
728
|
+
multipart_threshold: int | None = None,
|
|
729
|
+
multipart_chunk_size: int | None = None,
|
|
730
|
+
multipart_max_concurrency: int | None = None,
|
|
731
|
+
object_lifecycle_preference: dict[str, str] | None = None,
|
|
609
732
|
) -> str:
|
|
733
|
+
if multipart is None:
|
|
734
|
+
threshold = (
|
|
735
|
+
multipart_threshold or InternalMultipartUploadV3.MULTIPART_THRESHOLD
|
|
736
|
+
)
|
|
737
|
+
multipart = len(file.data) > threshold
|
|
738
|
+
|
|
739
|
+
if multipart:
|
|
740
|
+
return InternalMultipartUploadV3.save(
|
|
741
|
+
file,
|
|
742
|
+
chunk_size=multipart_chunk_size,
|
|
743
|
+
max_concurrency=multipart_max_concurrency,
|
|
744
|
+
)
|
|
745
|
+
|
|
610
746
|
headers = {
|
|
611
747
|
**self.auth_headers,
|
|
612
748
|
"Accept": "application/json",
|
|
@@ -637,23 +773,6 @@ class InternalFalFileRepositoryV3(FileRepository):
|
|
|
637
773
|
"User-Agent": "fal/0.1.0",
|
|
638
774
|
}
|
|
639
775
|
|
|
640
|
-
def _save_multipart(
|
|
641
|
-
self,
|
|
642
|
-
file_path: str | Path,
|
|
643
|
-
chunk_size: int | None = None,
|
|
644
|
-
content_type: str | None = None,
|
|
645
|
-
max_concurrency: int | None = None,
|
|
646
|
-
) -> str:
|
|
647
|
-
multipart = InternalMultipartUploadV3(
|
|
648
|
-
file_path,
|
|
649
|
-
chunk_size=chunk_size,
|
|
650
|
-
content_type=content_type,
|
|
651
|
-
max_concurrency=max_concurrency,
|
|
652
|
-
)
|
|
653
|
-
multipart.create()
|
|
654
|
-
multipart.upload()
|
|
655
|
-
return multipart.complete()
|
|
656
|
-
|
|
657
776
|
def save_file(
|
|
658
777
|
self,
|
|
659
778
|
file_path: str | Path,
|
|
@@ -669,7 +788,7 @@ class InternalFalFileRepositoryV3(FileRepository):
|
|
|
669
788
|
multipart = os.path.getsize(file_path) > threshold
|
|
670
789
|
|
|
671
790
|
if multipart:
|
|
672
|
-
url =
|
|
791
|
+
url = MultipartUpload.save_file(
|
|
673
792
|
file_path,
|
|
674
793
|
chunk_size=multipart_chunk_size,
|
|
675
794
|
content_type=content_type,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import random
|
|
3
3
|
import time
|
|
4
|
+
import traceback
|
|
4
5
|
from typing import Any, Callable, Literal
|
|
5
6
|
|
|
6
7
|
BackoffType = Literal["exponential", "fixed"]
|
|
@@ -25,6 +26,8 @@ def retry(
|
|
|
25
26
|
print(f"Retrying {retries} of {max_retries}...")
|
|
26
27
|
if retries == max_retries:
|
|
27
28
|
print(f"Max retries reached. Raising exception: {e}")
|
|
29
|
+
traceback.print_exc()
|
|
30
|
+
|
|
28
31
|
raise e
|
|
29
32
|
|
|
30
33
|
if backoff_type == "exponential":
|
|
File without changes
|
{fal-1.7.1 → fal-1.7.3}/Makefile
RENAMED
|
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
|
{fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py
RENAMED
|
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
|
{fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py
RENAMED
|
File without changes
|
{fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.7.1 → fal-1.7.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py
RENAMED
|
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
|
|
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
|