Facade (congressgov)¶
Everything below is importable directly from congressgov (e.g. from congressgov import Bill,
get_client_from_env); it's re-exported from congressgov.services. Service classes like Bill and
Member are documented on the Services page instead of repeated here.
Client creation¶
Build API clients from environment configuration.
create_api_client ¶
create_api_client(*, api_key: str, base_url: str | None = None, request_store: RequestStore | str | bool | None = False, store_fail: bool = False) -> AuthenticatedClient
Return an AuthenticatedClient configured for the Congress.gov API.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_key
|
str
|
Congress.gov API key. |
required |
base_url
|
str | None
|
API base URL (default: |
None
|
request_store
|
RequestStore | str | bool | None
|
When |
False
|
store_fail
|
bool
|
Fall through to the network when the store errors. |
False
|
Source code in src/congressgov/services/client_factory.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | |
create_stored_api_client ¶
create_stored_api_client(*, api_key: str, base_url: str | None = None, request_store: RequestStore | str | bool | None = True, store_fail: bool = False) -> AuthenticatedClient
Return an authenticated client with request-store deduplication enabled.
Equivalent to create_api_client(..., request_store=True).
Source code in src/congressgov/services/client_factory.py
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | |
create_offline_client ¶
create_offline_client(*, base_url: str | None = None, request_store: RequestStore | str | bool | None = True) -> AuthenticatedClient
Return a client that serves API responses only from the request store.
No network requests are made. Useful for demos and CI when the store was populated by a prior online run.
Source code in src/congressgov/services/client_factory.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
get_client_from_env ¶
get_client_from_env(*, api_key_var: str = CONGRESS_API_KEY_ENV, base_url: str | None = None, token: str | None = None, load_dotenv: bool = True, request_store: RequestStore | str | bool | None = True, store_fail: bool = False, offline: bool = False) -> AuthenticatedClient
Create an authenticated client using CONGRESS_API_KEY (or api_key_var).
By default attaches a persistent request store (see CONGRESS_REQUEST_STORE
and CONGRESS_WORKSPACE). Pass request_store=False to disable deduplication.
Pass offline=True to serve responses only from the store (no API key required).
If load_dotenv is true and python-dotenv is installed, loads a .env
file from the current working directory before reading the environment.
Raises:
| Type | Description |
|---|---|
ValueError
|
If no API key is available and offline is False. |
Source code in src/congressgov/services/client_factory.py
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | |
Exceptions¶
Service-layer exceptions: MiddlewareError (base), with ClientNotFoundError,
ValidationError, APIError (and its RateLimitError/TimeoutError subclasses),
ExpansionError, RequestStoreError, and UnsupportedApiUrlError covering the
specific failure modes below.
from congressgov.services.exceptions import ClientNotFoundError, APIError
if client is None:
raise ClientNotFoundError("No client available for API calls")
try:
response = api_call()
except httpx.HTTPStatusError as e:
raise APIError("API request failed", status_code=e.response.status_code) from e
MiddlewareError ¶
MiddlewareError(message: str, details: Optional[dict[str, Any]] = None)
Bases: Exception
Base class for every congressgov.services exception, so callers can catch
all of them with a single except MiddlewareError.
Source code in src/congressgov/services/exceptions.py
27 28 29 30 | |
ClientNotFoundError ¶
ClientNotFoundError(message: str = 'No client available for API operations', **kwargs: Any)
Bases: MiddlewareError
Raised when a service method needs an API client and none was provided or configured on the instance.
Example
service = Bill() # No client configured service.get(congress=118, bill_type="hr", bill_number=1) ClientNotFoundError: No client available. Provide client parameter or configure service instance.
Source code in src/congressgov/services/exceptions.py
49 50 | |
ValidationError ¶
ValidationError(message: str, parameter: Optional[str] = None, value: Optional[Any] = None, constraint: Optional[str] = None, suggestions: Optional[list[str]] = None, valid_values: Optional[list[str]] = None, **kwargs: Any)
Bases: MiddlewareError
Raised for invalid input: missing/malformed/out-of-range parameters, or
invalid parameter combinations. Carries suggestions and valid_values so
the resulting message can point at likely typo fixes.
Example
service.get(bill_type="invalid") ValidationError: Invalid bill type: 'invalid' Did you mean: 'hr', 's'? Valid values: 'hr', 's', 'hjres', 'sjres', 'hconres', 'sconres', 'hres', 'sres'
Source code in src/congressgov/services/exceptions.py
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | |
APIError ¶
APIError(message: str = 'API request failed', status_code: Optional[int] = None, url: Optional[str] = None, method: Optional[str] = None, response_body: Optional[str] = None, **kwargs: Any)
Bases: MiddlewareError
Raised when an API request fails, wrapping the HTTP status code, URL, method, and response body for debugging.
Example
try: ... response = client.get("/invalid/endpoint") ... except httpx.HTTPStatusError as e: ... raise APIError("API request failed", status_code=404) from e
Source code in src/congressgov/services/exceptions.py
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | |
RateLimitError ¶
RateLimitError(message: str = 'API rate limit exceeded', limit: Optional[int] = None, remaining: Optional[int] = None, reset_time: Optional[str] = None, retry_after: Optional[int] = None, **kwargs: Any)
Bases: APIError
Raised when the Congress.gov API rate limit is exceeded. Carries limit,
remaining, reset_time, and retry_after for building retry logic.
Example
if rate_limit_exceeded: ... raise RateLimitError( ... "Rate limit exceeded", ... limit=1000, ... remaining=0, ... retry_after=60 ... )
Source code in src/congressgov/services/exceptions.py
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | |
TimeoutError ¶
TimeoutError(message: str = 'API request timed out', timeout: Optional[float] = None, elapsed: Optional[float] = None, **kwargs: Any)
Bases: APIError
Raised when an API request times out. Carries timeout (the configured
limit) and elapsed (how long it actually ran).
Example
try: ... response = client.get("/slow/endpoint", timeout=5.0) ... except httpx.TimeoutException as e: ... raise TimeoutError("Request timed out", timeout=5.0) from e
Source code in src/congressgov/services/exceptions.py
190 191 192 193 194 195 196 197 198 199 200 201 | |
UnsupportedApiUrlError ¶
UnsupportedApiUrlError(message: str, *, url: str | None = None)
Bases: MiddlewareError
Raised when a URL cannot be mapped to a known Congress.gov API route.
Source code in src/congressgov/services/exceptions.py
207 208 209 | |
RequestStoreError ¶
RequestStoreError(message: str, *, request_key: str | None = None, operation: str | None = None, **kwargs: Any)
Bases: MiddlewareError
Raised when the request store cannot read or write persisted responses.
By default the store fails closed (no network fallback). Pass
store_fail=True on the client or per-request to fall through to the API.
Source code in src/congressgov/services/exceptions.py
219 220 221 222 223 224 225 226 227 228 229 230 231 232 | |
ExpansionError ¶
ExpansionError(message: str, attribute: Optional[str] = None, target_type: Optional[str] = None, failed_attributes: Optional[list[str]] = None, **kwargs: Any)
Bases: MiddlewareError
Raised when expanding a model's related attributes (fetching them from the API) fails, due to missing parameters, an invalid attribute name, or an API failure mid-expansion.
Example
try: ... expanded = service.expand(bill, attributes=["actions"]) ... except ExpansionError as e: ... print(f"Failed to expand: {e.attribute}")
Source code in src/congressgov/services/exceptions.py
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | |
Workspace & storage¶
Congress.gov project workspace — shared root for all storage lanes.
WorkspacePaths
dataclass
¶
WorkspacePaths(root: Path)
Resolved paths under a single workspace root.
legacy_api_db ¶
legacy_api_db() -> Path
Pre-workspace blob store path (.congressgov/request_store.db).
Source code in src/congressgov/services/core/workspace/paths.py
57 58 59 | |
Workspace ¶
Workspace(paths: WorkspacePaths)
Single project workspace for API blobs, datasets, exports, and cache.
Example::
workspace = Workspace.open()
client = get_client_from_env(request_store=workspace.blob_connection())
graph = workspace.open_graph(118)
Source code in src/congressgov/services/core/workspace/__init__.py
41 42 | |
blob_connection ¶
blob_connection(name: str = 'api') -> str
Resolve a blob-lane connection via the store registry (and env overrides).
Source code in src/congressgov/services/core/workspace/__init__.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | |
write_export ¶
write_export(name: str, content: bytes | str, *, metadata: dict[str, object] | None = None) -> str
Write a generated artifact to the workspace exports lane.
Source code in src/congressgov/services/core/workspace/__init__.py
96 97 98 99 100 101 102 103 104 105 106 107 108 | |
default_workspace_root ¶
default_workspace_root() -> Path
Return the workspace root from CONGRESS_WORKSPACE or ./.congressgov.
Source code in src/congressgov/services/core/workspace/paths.py
72 73 74 | |
maybe_log_legacy_migration ¶
maybe_log_legacy_migration(paths: WorkspacePaths) -> None
Migrate or log when the legacy flat DB exists but the workspace API path does not.
Source code in src/congressgov/services/core/workspace/resolve.py
77 78 79 80 81 82 83 84 85 86 87 88 | |
migrate_legacy_blob_if_needed ¶
migrate_legacy_blob_if_needed(paths: WorkspacePaths) -> bool
Copy a legacy flat request_store.db into api/request_store.db.
Returns True when a migration was performed.
Source code in src/congressgov/services/core/workspace/resolve.py
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
resolve_blob_connection ¶
resolve_blob_connection(*, workspace: WorkspacePaths | None = None, override: str | None = None) -> str
Return the blob-lane connection string.
Precedence:
1. Explicit override or CONGRESS_REQUEST_STORE env var
2. Workspace API database (api/request_store.db)
3. Legacy flat .congressgov/request_store.db when it exists
Source code in src/congressgov/services/core/workspace/resolve.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | |
resolve_workspace ¶
resolve_workspace(root: str | Path | None = None) -> WorkspacePaths
Build :class:WorkspacePaths for root or the default workspace.
Source code in src/congressgov/services/core/workspace/resolve.py
15 16 17 18 19 20 21 | |
Request store¶
Persistent request store for Congress.gov API deduplication.
Every distinct API request is stored on first fetch. Repeat calls with the
same canonical key are served from storage unless force_fetch=True.
Quick start::
from congressgov._client import AuthenticatedClient
from congressgov.services.core.request_store import RequestStore, attach_request_store
client = AuthenticatedClient(base_url="https://api.congress.gov/v3", token=API_KEY)
store = RequestStore.open("sqlite:///.congressgov/request_store.db")
attach_request_store(client, store)
Backends:
- :memory: — in-memory (tests)
- sqlite:///path/to/store.db — persistent SQLite (default)
FileRequestStoreBackend ¶
FileRequestStoreBackend(directory: str | Path)
Persist responses as JSON files under a directory (stdlib only).
Source code in src/congressgov/services/core/request_store/backends/file.py
19 20 21 22 | |
MemoryRequestStoreBackend ¶
MemoryRequestStoreBackend()
Thread-safe in-memory backend implementing :class:RequestStoreBackend.
Source code in src/congressgov/services/core/request_store/backends/memory.py
16 17 18 19 | |
RequestStoreBackend ¶
Bases: Protocol
Canonical persistence interface for raw API responses.
Implementations may use SQLite, files, Redis, or other engines while exposing the same lookup/store contract.
get ¶
get(key: str) -> StoredResponse | None
Load a stored response by canonical request key.
Source code in src/congressgov/services/core/request_store/backends/base.py
21 22 23 | |
put ¶
put(key: str, response: StoredResponse) -> None
Persist a response under key.
Source code in src/congressgov/services/core/request_store/backends/base.py
25 26 27 | |
delete ¶
delete(key: str) -> bool
Remove a stored response. Returns True when a record existed.
Source code in src/congressgov/services/core/request_store/backends/base.py
29 30 31 | |
contains ¶
contains(key: str) -> bool
Return True when key exists in the backend.
Source code in src/congressgov/services/core/request_store/backends/base.py
33 34 35 | |
count ¶
count() -> int
Return total stored records.
Source code in src/congressgov/services/core/request_store/backends/base.py
37 38 39 | |
close ¶
close() -> None
Release backend resources.
Source code in src/congressgov/services/core/request_store/backends/base.py
41 42 43 | |
get_stats ¶
get_stats() -> dict[str, Any]
Return backend-specific statistics.
Source code in src/congressgov/services/core/request_store/backends/base.py
45 46 47 | |
SQLiteRequestStoreBackend ¶
SQLiteRequestStoreBackend(connection: str | Path)
Persistent SQLite backend implementing :class:RequestStoreBackend.
Source code in src/congressgov/services/core/request_store/backends/sqlite.py
20 21 22 23 24 25 26 27 28 29 30 | |
RequestKey
dataclass
¶
RequestKey(method: str, url: str, query: tuple[tuple[str, str], ...] = ())
Canonical identity for an API request.
digest ¶
digest() -> str
Stable string used as the storage backend key.
Source code in src/congressgov/services/core/request_store/models.py
18 19 20 21 | |
StoredResponse
dataclass
¶
StoredResponse(status_code: int, headers: dict[str, str], body: bytes, fetched_at: datetime = (lambda: datetime.now(timezone.utc))(), policy: str = 'moderate', request_key: str | None = None, source_updated_at: datetime | None = None)
Raw HTTP response persisted for a :class:RequestKey.
effective_updated_at
property
¶
effective_updated_at: datetime
Best available timestamp for change-detection/display purposes.
Note: TTL/staleness math (:func:request_store.policy.estimate_staleness)
deliberately uses fetched_at instead, since source_updated_at reflects
the API's own (often old) updateDate and would make freshly cached
responses look immediately stale.
ChangePolicy ¶
Bases: str, Enum
How quickly a stored response is considered stale.
PolicyConfig
dataclass
¶
PolicyConfig(default_policy: ChangePolicy = ChangePolicy.MODERATE, rules: tuple[PolicyRule, ...] = (lambda: DEFAULT_POLICY_RULES)(), overrides: dict[str, ChangePolicy] = dict(), closed_congress_permanent: bool = True)
Resolved policy configuration for the request store.
PolicyRule
dataclass
¶
PolicyRule(pattern: Pattern[str], policy: ChangePolicy)
Map URL path patterns to a :class:ChangePolicy.
StalenessEstimate
dataclass
¶
StalenessEstimate(policy: ChangePolicy, fetched_at: datetime, ttl_seconds: int | None, age_seconds: float, remaining_seconds: float | None, is_stale: bool, refresh_after: datetime | None, change_likelihood: float)
Estimated freshness of a stored response based on fetch time and policy.
RequestStore ¶
RequestStore(backend: RequestStoreBackend | str | None = None, *, config: StoreConfig | None = None, workspace_root: Path | None = None)
Persistent deduplicating store for raw API responses.
Network calls for the same canonical request are blocked when a fresh stored
response exists. Use force_fetch=True to bypass the store.
Source code in src/congressgov/services/core/request_store/store.py
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | |
get_sync ¶
get_sync(request, *, force_fetch: bool = False, store_fail: bool | None = None) -> tuple[StoredResponse | None, bool]
Lookup a stored response for a sync httpx request.
Returns (stored_response, is_leader). Followers should wait on the
in-flight gate before calling again.
Source code in src/congressgov/services/core/request_store/store.py
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | |
store ¶
store(request, response, *, store_fail: bool | None = None) -> None
Persist a successful API response.
Source code in src/congressgov/services/core/request_store/store.py
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | |
open
classmethod
¶
open(connection: str | None = None, **kwargs) -> RequestStore
Open the workspace default on-disk store when connection is omitted.
Source code in src/congressgov/services/core/request_store/store.py
296 297 298 299 300 301 302 303 | |
StoreConfig
dataclass
¶
StoreConfig(enabled: bool = True, store_fail: bool = False, policy: PolicyConfig = load_policy_config())
Runtime configuration for :class:RequestStore.
AsyncOfflineTransport ¶
AsyncOfflineTransport(store: RequestStore)
Bases: AsyncBaseTransport
Async offline-only transport backed by the request store.
Source code in src/congressgov/services/core/request_store/transport.py
152 153 | |
AsyncStoringTransport ¶
AsyncStoringTransport(transport: AsyncBaseTransport, store: RequestStore)
Bases: AsyncBaseTransport
Async transport wrapper that reads/writes through a :class:RequestStore.
Source code in src/congressgov/services/core/request_store/transport.py
81 82 83 84 85 86 87 | |
OfflineTransport ¶
OfflineTransport(store: RequestStore)
Bases: BaseTransport
Serve API responses from the request store without network access.
Source code in src/congressgov/services/core/request_store/transport.py
131 132 | |
StoringTransport ¶
StoringTransport(transport: BaseTransport, store: RequestStore)
Bases: BaseTransport
Sync transport wrapper that reads/writes through a :class:RequestStore.
Source code in src/congressgov/services/core/request_store/transport.py
27 28 29 30 31 32 33 | |
attach_offline_store ¶
attach_offline_store(client: Any, store: RequestStore | str | None = None, *, config: StoreConfig | None = None) -> Any
Attach store in offline-only mode (no network requests).
Source code in src/congressgov/services/core/request_store/client.py
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | |
attach_request_store ¶
attach_request_store(client: Any, store: RequestStore | str | None = None, *, config: StoreConfig | None = None, enabled: bool = True, store_fail: bool = False) -> Any
Wrap client's httpx transport so all API calls pass through store.
Works with AuthenticatedClient and Client from congressgov._client.
Call before any API traffic, or after set_httpx_client / set_async_httpx_client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
Any
|
API client instance. |
required |
store
|
RequestStore | str | None
|
:class: |
None
|
config
|
StoreConfig | None
|
Optional store configuration merged with store when provided. |
None
|
enabled
|
bool
|
When False, register store metadata without wrapping transport. |
True
|
store_fail
|
bool
|
Fall through to network when store read/write fails. |
False
|
Returns:
| Type | Description |
|---|---|
Any
|
The same client instance (mutated in place). |
Source code in src/congressgov/services/core/request_store/client.py
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | |
build_stored_client ¶
build_stored_client(client_factory: Callable[[], Any], store: RequestStore | str | None = None, **attach_kwargs: Any) -> Any
Create a client via client_factory and attach a request store.
Source code in src/congressgov/services/core/request_store/client.py
137 138 139 140 141 142 143 144 | |
fetch_options ¶
fetch_options(*, force_fetch: bool = False, store_fail: bool | None = None) -> Iterator[None]
Temporarily override fetch behavior for nested API calls.
Example
with fetch_options(force_fetch=True): bill = bill_service.get(congress=118, bill_type="hr", bill_number=1)
Source code in src/congressgov/services/core/request_store/context.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | |
create_backend ¶
create_backend(connection: Union[str, Path, None] = None, *, workspace_root: Path | None = None) -> RequestStoreBackend
Create a request-store backend from a connection string.
Supported forms:
- None with a workspace_root → the workspace's persistent SQLite blob
store (<workspace_root>/api/request_store.db), matching
:meth:RequestStore.open
- None with no workspace_root or ":memory:" → in-memory backend
- sqlite:///path/to/store.db → SQLite file
- filesystem path ending in .db → SQLite file
- file:///path/to/dir or directory path → JSON file per entry
- redis://host:port/db → Redis (requires redis package)
Source code in src/congressgov/services/core/request_store/factory.py
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
print_store_stats ¶
print_store_stats(store: RequestStore) -> None
Print a human-readable summary of store activity.
Source code in src/congressgov/services/core/request_store/introspection.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | |
summarize_store ¶
summarize_store(store: RequestStore) -> dict[str, Any]
Return combined runtime and backend statistics.
Source code in src/congressgov/services/core/request_store/introspection.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | |
normalize_query ¶
normalize_query(params: dict[str, Any] | list[tuple[str, Any]]) -> tuple[tuple[str, str], ...]
Return sorted, normalized query pairs for key generation.
Source code in src/congressgov/services/core/request_store/keys.py
16 17 18 19 20 21 22 23 24 25 26 27 | |
request_key_digest ¶
request_key_digest(request: Request) -> str
Digest string for storage lookup.
Source code in src/congressgov/services/core/request_store/keys.py
38 39 40 | |
request_key_from_httpx ¶
request_key_from_httpx(request: Request) -> RequestKey
Build a :class:RequestKey from an outgoing httpx request.
Source code in src/congressgov/services/core/request_store/keys.py
30 31 32 33 34 35 | |
current_congress ¶
current_congress(*, year: int | None = None) -> int
Estimate the current Congress number from the calendar year.
Source code in src/congressgov/services/core/request_store/policy.py
86 87 88 89 | |
estimate_refresh_after ¶
estimate_refresh_after(stored: StoredResponse, *, policy: ChangePolicy | None = None) -> datetime | None
Estimate when a stored entry becomes eligible for automatic refresh.
Returns None for permanent entries or when already stale.
Source code in src/congressgov/services/core/request_store/policy.py
199 200 201 202 203 204 205 206 207 208 209 | |
estimate_staleness ¶
estimate_staleness(stored: StoredResponse, *, policy: ChangePolicy | None = None, now: datetime | None = None) -> StalenessEstimate
Estimate how likely a stored response has changed since it was fetched.
change_likelihood ramps from 0.0 at fetch time to 1.0 at TTL expiry
(sigmoid curve). PERMANENT entries always report 0.0 unless already
forced stale by external logic.
Source code in src/congressgov/services/core/request_store/policy.py
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | |
is_stale ¶
is_stale(stored: StoredResponse, *, now: datetime | None = None, policy: ChangePolicy | None = None) -> bool
Return True when a stored response should be refreshed automatically.
PERMANENT entries never go stale unless force_fetch is used.
Source code in src/congressgov/services/core/request_store/policy.py
185 186 187 188 189 190 191 192 193 194 195 196 | |
load_policy_config ¶
load_policy_config(path: str | Path | None = None) -> PolicyConfig
Load :class:PolicyConfig from path or the bundled default JSON file.
Supports .json, .yaml, and .yml extensions.
Source code in src/congressgov/services/core/request_store/policy_loader.py
58 59 60 61 62 63 64 65 | |