imbi-api 2.9.2__tar.gz → 2.9.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.
- {imbi_api-2.9.2 → imbi_api-2.9.3}/PKG-INFO +1 -1
- {imbi_api-2.9.2 → imbi_api-2.9.3}/pyproject.toml +1 -1
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/commit_sync/service.py +58 -24
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/project_commit_sync.py +8 -1
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_commit_sync_service.py +24 -2
- {imbi_api-2.9.2 → imbi_api-2.9.3}/uv.lock +1 -1
- {imbi_api-2.9.2 → imbi_api-2.9.3}/.github/workflows/deploy.yaml +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/.github/workflows/docs.yaml +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/.github/workflows/testing.yaml +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/.gitignore +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/.pre-commit-config.yaml +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/.python-version +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/CLAUDE.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/CODE_REVIEW_PUNCHLIST.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/LICENSE +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/README.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/coderabbit.yaml +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/compose.yaml +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0001-record-architecture-decisions.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0002-authentication-and-authorization-architecture.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0003-email-sending-architecture.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0004-phase-5-authentication-enhancements.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0005-file-upload-storage-architecture.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0006-project-identity-and-multi-type.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0007-relationship-blueprints.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0008-plugin-system-architecture.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0009-database-driven-oauth-providers.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0010-identity-plugin-architecture.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0011-graph-based-project-scoring.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0012-plugin-manifest-service-template.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0013-deployment-plugin-type.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0014-generic-plugin-entity-abstraction.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0015-cyclonedx-1.7-sbom-standard.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/configuration.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/index.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/docs/restore-backup.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/justfile +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/mkdocs.yml +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/mypy.ini +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/app.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/authorization_codes.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/local_auth.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/login_providers.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/membership.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/models.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/oauth.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/oauth_clients.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/password.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/permissions.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/seed.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/sessions.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/tokens.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/auth/totp.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/backfill_embeddings.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/blueprint_attributes.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/commit_sync/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/commit_sync/queue.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/domain/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/domain/models.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/domain/scoring.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/client.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/dependencies.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/models.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/templates/base.html +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/templates/base.txt +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/templates/password_reset.html +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/templates/password_reset.txt +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/templates/welcome.html +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/templates/welcome.txt +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/email/templates.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/_credentials.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/_helpers.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/_json_fields.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/_pagination.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/_request_urls.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/admin.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/admin_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/api_keys.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/auth.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/auth_providers.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/blueprints.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/client_credentials.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/comments.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/dashboard.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/document_templates.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/documents.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/environments.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/events.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/graph_query.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/identity_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/link_definitions.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/local_auth.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/mcp_servers.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/mfa.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/oauth_metadata.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/operations_log.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/organizations.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/plugin_edges.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/plugin_entities.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/project_analysis.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/project_configuration.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/project_deployments.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/project_logs.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/project_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/project_type_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/project_types.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/projects.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/pull_requests.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/releases.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/roles.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/sa_api_keys.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/scoring.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/scoring_policies.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/search.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/service_accounts.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/service_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/status.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/tags.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/teams.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/third_party_services.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/uploads.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/user_activity.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/users.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/endpoints/webhooks.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/entrypoint.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/graph_sql.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/identity/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/identity/endpoints.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/identity/errors.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/identity/flows.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/identity/host_integration.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/identity/models.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/identity/repository.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/identity/resolution.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/identity/state.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/identity/sweeper.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/lifespans.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/llm/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/llm/dependencies.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/mcp_test.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/middleware/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/middleware/rate_limit.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/models.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/openapi.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/patch.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/plugins/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/plugins/assignment_writer.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/plugins/assignments.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/plugins/credentials.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/plugins/installer.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/plugins/lifecycle.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/plugins/lifecycle_dispatch.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/plugins/reload.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/plugins/resolution.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/plugins/schemas.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/prompts/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/prompts/release_notes_system.md +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/py.typed +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/relationships.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/sbom.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/scoring/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/scoring/queue.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/settings.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/storage/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/storage/client.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/storage/dependencies.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/storage/thumbnails.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/src/imbi_api/storage/validation.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_api_key_auth.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_authentication.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_authorization.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_encryption.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_login_providers.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_membership.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_oauth.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_oauth_server.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_permissions.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_seed.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_sessions.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/auth/test_totp.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/clickhouse/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/clickhouse/test_client.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/clickhouse/test_init.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/clickhouse/test_privacy.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/email/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/email/test_client.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/email/test_init.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/email/test_integration.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/email/test_models.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/email/test_templates.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_admin.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_admin_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_api_keys.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_auth.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_auth_providers.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_blueprints.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_client_credentials.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_comments.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_credentials.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_dashboard.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_document_templates.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_documents.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_environments.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_events.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_graph_query.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_init.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_json_fields.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_link_definitions.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_local_auth.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_mcp_servers.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_mfa.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_operations_log.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_organizations.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_pagination.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_plugin_label_validation.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_project_analysis.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_project_commit_sync.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_project_configuration.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_project_deployments.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_project_logs.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_project_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_project_response_surfacing.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_project_type_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_project_types.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_projects.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_projects_helpers.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_pull_requests.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_releases.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_request_urls.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_roles.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_sa_api_keys.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_scoring.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_scoring_policies.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_search.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_service_accounts.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_service_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_service_writeback.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_status.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_tags.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_teams.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_third_party_services.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_uploads.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_user_activity.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_users.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/endpoints/test_webhooks.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/fixtures/sbom/npm-realistic.json +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/fixtures/sbom/pypi-realistic.json +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/fixtures/sbom/tiny.json +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/identity/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/identity/test_endpoints.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/identity/test_errors.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/identity/test_flows.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/identity/test_host_integration.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/identity/test_repository.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/identity/test_resolution.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/identity/test_state.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/identity/test_sweeper.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/middleware/test_rate_limit.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/storage/__init__.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/storage/test_client.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/storage/test_init.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/storage/test_thumbnails.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/storage/test_validation.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/support.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_app.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_assignment_writer.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_backfill_embeddings.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_blueprint_attributes.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_blueprints.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_commit_sync_queue.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_entrypoint.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_graph_sql.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_init.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_installer.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_lifecycle_dispatch.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_lifespans.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_models.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_openapi.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_patch.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_plugin_schemas.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_plugins.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_sbom.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_scoring_queue.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_scoring_triggers.py +0 -0
- {imbi_api-2.9.2 → imbi_api-2.9.3}/tests/test_settings.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: imbi-api
|
|
3
|
-
Version: 2.9.
|
|
3
|
+
Version: 2.9.3
|
|
4
4
|
Summary: Imbi is a DevOps Service Management Platform designed to provide an efficient way to manage a large environment that contains many services and applications.
|
|
5
5
|
Author-email: Alex Campbell <alexc@aweber.com>, Dave Shawley <daves@aweber.com>, "Gavin M. Roy" <gavinr@aweber.com>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "imbi-api"
|
|
3
|
-
version = "2.9.
|
|
3
|
+
version = "2.9.3"
|
|
4
4
|
description = "Imbi is a DevOps Service Management Platform designed to provide an efficient way to manage a large environment that contains many services and applications."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.14"
|
|
@@ -13,6 +13,7 @@ node so the UI can poll it without a dedicated status store.
|
|
|
13
13
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
|
+
import asyncio
|
|
16
17
|
import datetime
|
|
17
18
|
import logging
|
|
18
19
|
import typing
|
|
@@ -33,6 +34,12 @@ _COMMIT_SYNC_SLUG = 'github-commit-sync'
|
|
|
33
34
|
# Persisted error strings are truncated so a noisy upstream message can't
|
|
34
35
|
# bloat the Project node.
|
|
35
36
|
_MAX_ERROR_LEN = 500
|
|
37
|
+
# Apache AGE aborts a SET with "Entity failed to be updated: <n>"
|
|
38
|
+
# (heap_update -> TM_Updated) when another transaction updates the same
|
|
39
|
+
# Project vertex concurrently. The worker's authoritative status writes
|
|
40
|
+
# retry the transient conflict so they still land under contention.
|
|
41
|
+
_STATUS_WRITE_RETRIES = 3
|
|
42
|
+
_STATUS_RETRY_BACKOFF = 0.05
|
|
36
43
|
|
|
37
44
|
SyncState = typing.Literal['idle', 'queued', 'running', 'success', 'failed']
|
|
38
45
|
|
|
@@ -210,6 +217,11 @@ def _now_iso() -> str:
|
|
|
210
217
|
return datetime.datetime.now(datetime.UTC).isoformat()
|
|
211
218
|
|
|
212
219
|
|
|
220
|
+
def _is_write_conflict(exc: Exception) -> bool:
|
|
221
|
+
"""True if *exc* is AGE's concurrent-update conflict (TM_Updated)."""
|
|
222
|
+
return 'failed to be updated' in str(exc)
|
|
223
|
+
|
|
224
|
+
|
|
213
225
|
async def set_status(
|
|
214
226
|
db: graph.Graph,
|
|
215
227
|
project_id: str,
|
|
@@ -219,8 +231,17 @@ async def set_status(
|
|
|
219
231
|
commits: int = 0,
|
|
220
232
|
tags: int = 0,
|
|
221
233
|
error: str = '',
|
|
234
|
+
retry: bool = True,
|
|
222
235
|
) -> None:
|
|
223
|
-
"""Persist last-sync state on the ``Project`` node (best-effort).
|
|
236
|
+
"""Persist last-sync state on the ``Project`` node (best-effort).
|
|
237
|
+
|
|
238
|
+
*retry* re-attempts the write when AGE reports a transient concurrent
|
|
239
|
+
update, so the worker's authoritative transitions (running -> success/
|
|
240
|
+
failed) still land if a webhook touches the project mid-write. The
|
|
241
|
+
enqueue endpoint passes ``retry=False`` for its optimistic ``queued``
|
|
242
|
+
write: dropping that on conflict is correct, since the worker's newer
|
|
243
|
+
``running`` write must win rather than be clobbered back to ``queued``.
|
|
244
|
+
"""
|
|
224
245
|
query: typing.LiteralString = """
|
|
225
246
|
MATCH (p:Project {{id: {project_id}}})
|
|
226
247
|
SET p.commit_sync_status = {status},
|
|
@@ -231,26 +252,39 @@ async def set_status(
|
|
|
231
252
|
p.commit_sync_error = {error}
|
|
232
253
|
RETURN p.id AS id
|
|
233
254
|
"""
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
['id']
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
255
|
+
params = {
|
|
256
|
+
'project_id': project_id,
|
|
257
|
+
'status': status,
|
|
258
|
+
'at': _now_iso(),
|
|
259
|
+
'by': requested_by,
|
|
260
|
+
'commits': commits,
|
|
261
|
+
'tags': tags,
|
|
262
|
+
'error': error[:_MAX_ERROR_LEN],
|
|
263
|
+
}
|
|
264
|
+
attempts = _STATUS_WRITE_RETRIES if retry else 1
|
|
265
|
+
for attempt in range(attempts):
|
|
266
|
+
try:
|
|
267
|
+
await db.execute(query, params, ['id'])
|
|
268
|
+
return
|
|
269
|
+
except Exception as exc: # noqa: BLE001
|
|
270
|
+
conflict = _is_write_conflict(exc)
|
|
271
|
+
if retry and conflict and attempt + 1 < attempts:
|
|
272
|
+
await asyncio.sleep(_STATUS_RETRY_BACKOFF * (attempt + 1))
|
|
273
|
+
continue
|
|
274
|
+
if conflict:
|
|
275
|
+
LOGGER.debug(
|
|
276
|
+
'commit-sync status write for %s lost a concurrent '
|
|
277
|
+
'update (status=%s); leaving the newer state in place',
|
|
278
|
+
project_id,
|
|
279
|
+
status,
|
|
280
|
+
)
|
|
281
|
+
else:
|
|
282
|
+
LOGGER.warning(
|
|
283
|
+
'Failed to persist commit-sync status for project %s',
|
|
284
|
+
project_id,
|
|
285
|
+
exc_info=True,
|
|
286
|
+
)
|
|
287
|
+
return
|
|
254
288
|
|
|
255
289
|
|
|
256
290
|
def _opt_str(value: object) -> str | None:
|
|
@@ -277,7 +311,7 @@ async def read_status(db: graph.Graph, project_id: str) -> CommitSyncStatus:
|
|
|
277
311
|
MATCH (p:Project {{id: {project_id}}})
|
|
278
312
|
RETURN p.commit_sync_status AS status,
|
|
279
313
|
p.commit_sync_at AS at,
|
|
280
|
-
p.commit_sync_by AS
|
|
314
|
+
p.commit_sync_by AS requested_by,
|
|
281
315
|
p.commit_sync_commits AS commits,
|
|
282
316
|
p.commit_sync_tags AS tags,
|
|
283
317
|
p.commit_sync_error AS error
|
|
@@ -285,7 +319,7 @@ async def read_status(db: graph.Graph, project_id: str) -> CommitSyncStatus:
|
|
|
285
319
|
records = await db.execute(
|
|
286
320
|
query,
|
|
287
321
|
{'project_id': project_id},
|
|
288
|
-
['status', 'at', '
|
|
322
|
+
['status', 'at', 'requested_by', 'commits', 'tags', 'error'],
|
|
289
323
|
)
|
|
290
324
|
if not records:
|
|
291
325
|
return CommitSyncStatus()
|
|
@@ -307,5 +341,5 @@ async def read_status(db: graph.Graph, project_id: str) -> CommitSyncStatus:
|
|
|
307
341
|
commits_synced=_opt_int(graph.parse_agtype(row.get('commits'))),
|
|
308
342
|
tags_synced=_opt_int(graph.parse_agtype(row.get('tags'))),
|
|
309
343
|
error=_opt_str(graph.parse_agtype(row.get('error'))),
|
|
310
|
-
requested_by=_opt_str(graph.parse_agtype(row.get('
|
|
344
|
+
requested_by=_opt_str(graph.parse_agtype(row.get('requested_by'))),
|
|
311
345
|
)
|
|
@@ -60,8 +60,15 @@ async def sync_commits_and_tags(
|
|
|
60
60
|
valkey_client, org_slug, project_id, requested_by
|
|
61
61
|
)
|
|
62
62
|
if enqueued:
|
|
63
|
+
# Optimistic, best-effort: if the worker has already flipped the
|
|
64
|
+
# project to ``running``, that newer write must win -- so this one
|
|
65
|
+
# does not retry the concurrent-update conflict.
|
|
63
66
|
await service.set_status(
|
|
64
|
-
db,
|
|
67
|
+
db,
|
|
68
|
+
project_id,
|
|
69
|
+
status='queued',
|
|
70
|
+
requested_by=requested_by,
|
|
71
|
+
retry=False,
|
|
65
72
|
)
|
|
66
73
|
return CommitSyncEnqueueResponse(enqueued=enqueued)
|
|
67
74
|
|
|
@@ -130,13 +130,35 @@ class StatusTests(unittest.IsolatedAsyncioTestCase):
|
|
|
130
130
|
self.assertEqual(7, params['commits'])
|
|
131
131
|
self.assertEqual('alice', params['by'])
|
|
132
132
|
|
|
133
|
+
async def test_set_status_retries_on_write_conflict(self) -> None:
|
|
134
|
+
db = mock.AsyncMock()
|
|
135
|
+
db.execute.side_effect = [
|
|
136
|
+
Exception('Entity failed to be updated: 3'),
|
|
137
|
+
[{'id': '"p1"'}],
|
|
138
|
+
]
|
|
139
|
+
with mock.patch.object(service.asyncio, 'sleep'):
|
|
140
|
+
await service.set_status(db, 'p1', status='running')
|
|
141
|
+
self.assertEqual(2, db.execute.await_count)
|
|
142
|
+
|
|
143
|
+
async def test_set_status_no_retry_drops_conflict(self) -> None:
|
|
144
|
+
db = mock.AsyncMock()
|
|
145
|
+
db.execute.side_effect = Exception('Entity failed to be updated: 3')
|
|
146
|
+
await service.set_status(db, 'p1', status='queued', retry=False)
|
|
147
|
+
db.execute.assert_awaited_once()
|
|
148
|
+
|
|
149
|
+
async def test_set_status_swallows_unrelated_error(self) -> None:
|
|
150
|
+
db = mock.AsyncMock()
|
|
151
|
+
db.execute.side_effect = Exception('boom')
|
|
152
|
+
await service.set_status(db, 'p1', status='running')
|
|
153
|
+
db.execute.assert_awaited_once()
|
|
154
|
+
|
|
133
155
|
async def test_read_status_idle_when_unset(self) -> None:
|
|
134
156
|
db = mock.AsyncMock()
|
|
135
157
|
db.execute.return_value = [
|
|
136
158
|
{
|
|
137
159
|
'status': None,
|
|
138
160
|
'at': None,
|
|
139
|
-
'
|
|
161
|
+
'requested_by': None,
|
|
140
162
|
'commits': None,
|
|
141
163
|
'tags': None,
|
|
142
164
|
'error': None,
|
|
@@ -153,7 +175,7 @@ class StatusTests(unittest.IsolatedAsyncioTestCase):
|
|
|
153
175
|
{
|
|
154
176
|
'status': '"success"',
|
|
155
177
|
'at': '"2026-06-04T12:00:00+00:00"',
|
|
156
|
-
'
|
|
178
|
+
'requested_by': '"alice"',
|
|
157
179
|
'commits': 12,
|
|
158
180
|
'tags': 4,
|
|
159
181
|
'error': '""',
|
|
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
|
{imbi_api-2.9.2 → imbi_api-2.9.3}/docs/adr/0002-authentication-and-authorization-architecture.md
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
|
|
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
|