controlzero 1.4.5__tar.gz → 1.4.6__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.
- {controlzero-1.4.5 → controlzero-1.4.6}/CHANGELOG.md +17 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/PKG-INFO +1 -1
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/__init__.py +1 -1
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/_internal/enforcer.py +13 -2
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/hosted_policy.py +10 -2
- {controlzero-1.4.5 → controlzero-1.4.6}/pyproject.toml +1 -1
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_glob_matching.py +83 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_refresh.py +6 -1
- {controlzero-1.4.5 → controlzero-1.4.6}/.gitignore +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/Dockerfile.test +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/LICENSE +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/README.md +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/_internal/__init__.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/_internal/bundle.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/_internal/dlp_scanner.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/_internal/hook_extractors.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/_internal/tool_extractors.json +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/_internal/types.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/audit_local.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/audit_remote.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/__init__.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/main.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/autogen.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/claude-code.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/codex-cli.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/cost-cap.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/crewai.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/cursor.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/gemini-cli.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/generic.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/langchain.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/mcp.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/cli/templates/rag.yaml +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/client.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/device.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/enrollment.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/errors.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/__init__.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/anthropic.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/autogen.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/braintrust.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/crewai/__init__.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/crewai/agent.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/crewai/crew.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/crewai/task.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/crewai/tool.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/google.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/google_adk/__init__.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/google_adk/agent.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/google_adk/tool.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/langchain/__init__.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/langchain/agent.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/langchain/callbacks.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/langchain/chain.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/langchain/graph.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/langchain/modern.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/langchain/tool.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/langfuse.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/litellm.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/openai.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/pydantic_ai.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/integrations/vercel_ai.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/policy_loader.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/controlzero/tamper.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/examples/hello_world.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/conftest.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/integrations/__init__.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/integrations/test_google.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_action_canonicalization.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_agent_name_env.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_audit_remote.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_audit_sink_isolation.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_bundle_parser.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_bundle_translate.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_cli_carve_out.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_cli_extractor_integration.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_cli_hook.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_cli_hosted_refresh.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_cli_init.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_cli_init_templates.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_cli_tail.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_cli_test.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_cli_validate.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_coding_agent_hooks.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_conditions.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_default_action.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_device.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_dlp_scanner.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_enrollment.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_fail_closed_eval.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_hook_extractors.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_hosted_policy_e2e.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_hybrid_mode_strict.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_hybrid_mode_warn.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_install_hooks.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_local_mode_dict.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_local_mode_file_json.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_local_mode_file_yaml.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_log_fallback_stderr.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_log_options_ignored_hosted.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_log_rotation.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_no_policy_no_key.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_package_rename_shim.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_policy_freshness.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_policy_settings.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_quarantine.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_reason_code.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_sql_semantic_class.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_tamper.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_tamper_behavior.py +0 -0
- {controlzero-1.4.5 → controlzero-1.4.6}/tests/test_tamper_hook.py +0 -0
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.6 -- 2026-05-11
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **resources:["*"] no longer requires a caller resource** (T83).
|
|
8
|
+
Hosted policy bundles emit `resources:["*"]` for any rule that does
|
|
9
|
+
not scope by resource. The enforcer's resource gate previously
|
|
10
|
+
required a caller-supplied `context.resource` even when the rule's
|
|
11
|
+
resources list was the universal wildcard, causing every rule to be
|
|
12
|
+
silently skipped on calls that didn't pass a resource. Result: every
|
|
13
|
+
`cz.guard()` returned `deny` with `reason_code=NO_RULE_MATCH` regardless
|
|
14
|
+
of what the policy said. Now rules with `*` in their resources match
|
|
15
|
+
universally; non-wildcard resource patterns still require a caller
|
|
16
|
+
resource (no silent broadening). Three regression tests added in
|
|
17
|
+
`tests/test_glob_matching.py` including the exact bundle shape from
|
|
18
|
+
the customer reproduction.
|
|
19
|
+
|
|
3
20
|
## 1.4.5 -- 2026-05-05
|
|
4
21
|
|
|
5
22
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: controlzero
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.6
|
|
4
4
|
Summary: AI agent governance: policies, audit, and observability for tool calls. Works locally with no signup.
|
|
5
5
|
Project-URL: Homepage, https://controlzero.ai
|
|
6
6
|
Project-URL: Documentation, https://docs.controlzero.ai
|
|
@@ -253,8 +253,19 @@ class PolicyEvaluator:
|
|
|
253
253
|
if not any(_glob_any(rule.actions, a) for a in candidate_actions):
|
|
254
254
|
continue
|
|
255
255
|
if rule.resources:
|
|
256
|
-
|
|
257
|
-
|
|
256
|
+
# T83: a rule whose resources list contains "*" matches
|
|
257
|
+
# universally and must NOT require the caller to supply
|
|
258
|
+
# context.resource. The dashboard always emits
|
|
259
|
+
# resources:["*"] for unscoped rules, so prior to this
|
|
260
|
+
# fix every cz.guard() call without an explicit resource
|
|
261
|
+
# was skipping every rule and falling through to the
|
|
262
|
+
# default deny (Bryan deny-deny incident, 2026-05-10).
|
|
263
|
+
# Logic now: if any pattern in rule.resources is the
|
|
264
|
+
# universal "*", treat the gate as satisfied; otherwise
|
|
265
|
+
# require a caller-supplied resource and glob-match it.
|
|
266
|
+
if "*" not in rule.resources:
|
|
267
|
+
if not resource or not _glob_any(rule.resources, resource):
|
|
268
|
+
continue
|
|
258
269
|
if not self._conditions_match(rule.conditions, context, args):
|
|
259
270
|
continue
|
|
260
271
|
# Prefer the rule-declared reason_code (only synthetic
|
|
@@ -409,5 +409,13 @@ def _parse_and_translate(
|
|
|
409
409
|
|
|
410
410
|
|
|
411
411
|
def _compute_etag(blob: bytes) -> str:
|
|
412
|
-
"""Fallback ETag when the server doesn't provide one.
|
|
413
|
-
|
|
412
|
+
"""Fallback ETag when the server doesn't provide one.
|
|
413
|
+
|
|
414
|
+
Returns the full 64-char hex sha256 of the bundle blob. The backend
|
|
415
|
+
stores and serves the full hex string in its ETag header, so the
|
|
416
|
+
SDK must hash to the same width for `If-None-Match` to ever match.
|
|
417
|
+
Truncating to 32 chars (the prior shape) silently broke the 304
|
|
418
|
+
short-circuit, surfacing as Bryan's investigation finding 1 in
|
|
419
|
+
docs/investigations/bryan-db-read-only-fail-closed-2026-05-08.md.
|
|
420
|
+
"""
|
|
421
|
+
return hashlib.sha256(blob).hexdigest()
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "controlzero"
|
|
7
|
-
version = "1.4.
|
|
7
|
+
version = "1.4.6"
|
|
8
8
|
description = "AI agent governance: policies, audit, and observability for tool calls. Works locally with no signup."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "Apache-2.0"}
|
|
@@ -116,3 +116,86 @@ def test_universal_wildcard(tmp_log):
|
|
|
116
116
|
assert cz.guard("anything").allowed
|
|
117
117
|
assert cz.guard("anything", method="anything").allowed
|
|
118
118
|
cz.close()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ---------------------------------------------------------------------
|
|
122
|
+
# T83 regression: resources:["*"] must NOT require a caller resource.
|
|
123
|
+
# ---------------------------------------------------------------------
|
|
124
|
+
# Pre-T83 the dashboard's universal-resource shape (every rule emitted
|
|
125
|
+
# resources:["*"]) skipped every rule when callers passed no
|
|
126
|
+
# context.resource, falling through to default deny. Bryan deny-deny
|
|
127
|
+
# incident, 2026-05-10. The exact bundle Bryan ran against is the
|
|
128
|
+
# fixture below.
|
|
129
|
+
|
|
130
|
+
def test_resources_wildcard_matches_without_context_resource(tmp_log):
|
|
131
|
+
cz = Client(
|
|
132
|
+
policy={
|
|
133
|
+
"rules": [
|
|
134
|
+
{
|
|
135
|
+
"id": "rule-0",
|
|
136
|
+
"allow": "database:read",
|
|
137
|
+
"resources": ["*"],
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
log_path=str(tmp_log),
|
|
142
|
+
)
|
|
143
|
+
# SELECT classifies as database:read via sql_semantic_class.
|
|
144
|
+
r = cz.guard("database", method="read", args={"sql": "SELECT id FROM orders"})
|
|
145
|
+
assert r.decision == "allow", f"resources:['*'] without context.resource should match; got {r.decision} ({r.reason})"
|
|
146
|
+
cz.close()
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_bryan_db_read_only_full_bundle_shape(tmp_log):
|
|
150
|
+
"""End-to-end against the EXACT rule shape from Bryan's published bundle.
|
|
151
|
+
|
|
152
|
+
This is the smoking-gun reproduction:
|
|
153
|
+
- rule-0 allow database:read (should fire on SELECT)
|
|
154
|
+
- rule-1 deny database:exec (should fire on DROP via canonical class)
|
|
155
|
+
- rule-2 deny database:delete (separate guard rail)
|
|
156
|
+
All rules carry resources:["*"]. Pre-T83 every call returned deny.
|
|
157
|
+
"""
|
|
158
|
+
cz = Client(
|
|
159
|
+
policy={
|
|
160
|
+
"rules": [
|
|
161
|
+
{"id": "rule-0", "allow": "database:read", "resources": ["*"]},
|
|
162
|
+
{"id": "rule-1", "deny": "database:exec", "resources": ["*"]},
|
|
163
|
+
{"id": "rule-2", "deny": "database:delete", "resources": ["*"]},
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
log_path=str(tmp_log),
|
|
167
|
+
)
|
|
168
|
+
# SELECT must allow.
|
|
169
|
+
r = cz.guard("database", method="read", args={"sql": "SELECT id FROM orders"})
|
|
170
|
+
assert r.decision == "allow", f"SELECT should allow, got {r.decision} ({r.reason})"
|
|
171
|
+
|
|
172
|
+
# DROP TABLE: caller passes method="exec" so candidate_actions
|
|
173
|
+
# contains database:exec which matches rule-1 deny.
|
|
174
|
+
r2 = cz.guard("database", method="exec", args={"sql": "DROP TABLE orders"})
|
|
175
|
+
assert r2.decision == "deny", f"DROP via method=exec should deny, got {r2.decision} ({r2.reason})"
|
|
176
|
+
cz.close()
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def test_specific_resource_pattern_still_requires_caller_resource(tmp_log):
|
|
180
|
+
"""T83 must NOT regress non-wildcard resource scoping. A rule that
|
|
181
|
+
names a concrete resource pattern should still skip when the caller
|
|
182
|
+
passes no resource."""
|
|
183
|
+
cz = Client(
|
|
184
|
+
policy={
|
|
185
|
+
"rules": [
|
|
186
|
+
{"id": "scoped", "allow": "fs:read", "resources": ["/home/*"]},
|
|
187
|
+
{"deny": "*"},
|
|
188
|
+
],
|
|
189
|
+
},
|
|
190
|
+
log_path=str(tmp_log),
|
|
191
|
+
)
|
|
192
|
+
# No resource in context -- scoped rule must NOT match, fall through to deny.
|
|
193
|
+
r = cz.guard("fs", method="read")
|
|
194
|
+
assert r.decision == "deny", f"scoped rule must not match without context.resource, got {r.decision}"
|
|
195
|
+
# With matching resource, allow.
|
|
196
|
+
r2 = cz.guard("fs", method="read", context={"resource": "/home/alice/notes.txt"})
|
|
197
|
+
assert r2.decision == "allow"
|
|
198
|
+
# With non-matching resource, deny via fall-through.
|
|
199
|
+
r3 = cz.guard("fs", method="read", context={"resource": "/etc/passwd"})
|
|
200
|
+
assert r3.decision == "deny"
|
|
201
|
+
cz.close()
|
|
@@ -140,7 +140,12 @@ def mock_backend(tmp_path, monkeypatch):
|
|
|
140
140
|
import hashlib
|
|
141
141
|
|
|
142
142
|
def current_etag() -> str:
|
|
143
|
-
|
|
143
|
+
# Match the SDK's _compute_etag (full 64-char hex). The earlier
|
|
144
|
+
# [:32] truncation here mirrored the bug in hosted_policy.py
|
|
145
|
+
# that PR #374 fixed; keeping the truncation here would make
|
|
146
|
+
# the mock backend's ETag perpetually mismatch the SDK's
|
|
147
|
+
# If-None-Match and the 304 short-circuit would never fire.
|
|
148
|
+
return hashlib.sha256(backend.bundle_bytes).hexdigest()
|
|
144
149
|
|
|
145
150
|
class Handler(BaseHTTPRequestHandler):
|
|
146
151
|
def _bearer_ok(self):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|