kc-sdk-python 3.0.0__tar.gz → 4.0.0__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.
- {kc_sdk_python-3.0.0/kc_sdk_python.egg-info → kc_sdk_python-4.0.0}/PKG-INFO +10 -1
- {kc_sdk_python-3.0.0 → kc_sdk_python-4.0.0}/README.md +9 -0
- {kc_sdk_python-3.0.0 → kc_sdk_python-4.0.0}/kc_api.py +42 -22
- {kc_sdk_python-3.0.0 → kc_sdk_python-4.0.0/kc_sdk_python.egg-info}/PKG-INFO +10 -1
- {kc_sdk_python-3.0.0 → kc_sdk_python-4.0.0}/pyproject.toml +1 -1
- {kc_sdk_python-3.0.0 → kc_sdk_python-4.0.0}/LICENSE +0 -0
- {kc_sdk_python-3.0.0 → kc_sdk_python-4.0.0}/kc_sdk_python.egg-info/SOURCES.txt +0 -0
- {kc_sdk_python-3.0.0 → kc_sdk_python-4.0.0}/kc_sdk_python.egg-info/dependency_links.txt +0 -0
- {kc_sdk_python-3.0.0 → kc_sdk_python-4.0.0}/kc_sdk_python.egg-info/requires.txt +0 -0
- {kc_sdk_python-3.0.0 → kc_sdk_python-4.0.0}/kc_sdk_python.egg-info/top_level.txt +0 -0
- {kc_sdk_python-3.0.0 → kc_sdk_python-4.0.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kc-sdk-python
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: Kvindo Cloud Python SDK — typed client for managing Kvindo Cloud infrastructure (VMs, S3, Kubernetes, load balancers, VPCs, PostgreSQL) via the REST API
|
|
5
5
|
Author: Kvindo
|
|
6
6
|
License-Expression: MIT
|
|
@@ -45,6 +45,10 @@ balancers, VPCs, VPNs, and managed PostgreSQL.
|
|
|
45
45
|
A thin, typed client over the REST API: one resource client per resource type, all sharing the
|
|
46
46
|
same create / read / update / delete / list contract.
|
|
47
47
|
|
|
48
|
+
> **Using Claude Code?** This repo ships a [Claude Code skill](.claude/skills/kvindo-python-sdk/SKILL.md)
|
|
49
|
+
> that teaches Claude how to script Kvindo Cloud with this SDK — clone this repo (or otherwise have
|
|
50
|
+
> it on disk) and open Claude Code there to pick it up automatically.
|
|
51
|
+
|
|
48
52
|
## Install
|
|
49
53
|
|
|
50
54
|
```sh
|
|
@@ -59,6 +63,9 @@ Dependencies: `requests`, `marshmallow-dataclass`, `py-ulid`.
|
|
|
59
63
|
from kc_api import KcClient
|
|
60
64
|
|
|
61
65
|
client = KcClient("YOUR_API_TOKEN") # api_url defaults to https://cloud-api.kvindo.ru
|
|
66
|
+
# TLS certificate verification is on by default (verify_ssl=True). Pass
|
|
67
|
+
# verify_ssl=False only to point this SDK at a genuinely self-hosted instance
|
|
68
|
+
# with a self-signed cert.
|
|
62
69
|
|
|
63
70
|
# List (label-filtered, paginated)
|
|
64
71
|
resp = client.vms.get_by_labels({"env": "prod"}, max_page_size=50)
|
|
@@ -100,7 +107,9 @@ Part of the Kvindo Cloud developer toolchain:
|
|
|
100
107
|
|
|
101
108
|
- **[kc CLI](https://github.com/Kvindo/kc-cli)** — kubectl-style command-line client for Kvindo Cloud.
|
|
102
109
|
- **[terraform-provider-kvindo](https://github.com/Kvindo/terraform-provider-kvindo)** — Terraform provider ([Registry](https://registry.terraform.io/providers/kvindo/kvindo/latest)).
|
|
110
|
+
- **[kc-mcp-server](https://github.com/Kvindo/kc-mcp-server)** — MCP server for Kvindo Cloud ([npm](https://www.npmjs.com/package/kc-mcp-server)), for managing resources from Claude Desktop/Code and other MCP clients.
|
|
103
111
|
- **[Kvindo Cloud console](https://cloud.kvindo.com)** — web UI and API.
|
|
112
|
+
- **[Claude Code skill](.claude/skills/kvindo-python-sdk/SKILL.md)** — lets Claude script Kvindo Cloud with this SDK conversationally.
|
|
104
113
|
|
|
105
114
|
## License
|
|
106
115
|
|
|
@@ -11,6 +11,10 @@ balancers, VPCs, VPNs, and managed PostgreSQL.
|
|
|
11
11
|
A thin, typed client over the REST API: one resource client per resource type, all sharing the
|
|
12
12
|
same create / read / update / delete / list contract.
|
|
13
13
|
|
|
14
|
+
> **Using Claude Code?** This repo ships a [Claude Code skill](.claude/skills/kvindo-python-sdk/SKILL.md)
|
|
15
|
+
> that teaches Claude how to script Kvindo Cloud with this SDK — clone this repo (or otherwise have
|
|
16
|
+
> it on disk) and open Claude Code there to pick it up automatically.
|
|
17
|
+
|
|
14
18
|
## Install
|
|
15
19
|
|
|
16
20
|
```sh
|
|
@@ -25,6 +29,9 @@ Dependencies: `requests`, `marshmallow-dataclass`, `py-ulid`.
|
|
|
25
29
|
from kc_api import KcClient
|
|
26
30
|
|
|
27
31
|
client = KcClient("YOUR_API_TOKEN") # api_url defaults to https://cloud-api.kvindo.ru
|
|
32
|
+
# TLS certificate verification is on by default (verify_ssl=True). Pass
|
|
33
|
+
# verify_ssl=False only to point this SDK at a genuinely self-hosted instance
|
|
34
|
+
# with a self-signed cert.
|
|
28
35
|
|
|
29
36
|
# List (label-filtered, paginated)
|
|
30
37
|
resp = client.vms.get_by_labels({"env": "prod"}, max_page_size=50)
|
|
@@ -66,7 +73,9 @@ Part of the Kvindo Cloud developer toolchain:
|
|
|
66
73
|
|
|
67
74
|
- **[kc CLI](https://github.com/Kvindo/kc-cli)** — kubectl-style command-line client for Kvindo Cloud.
|
|
68
75
|
- **[terraform-provider-kvindo](https://github.com/Kvindo/terraform-provider-kvindo)** — Terraform provider ([Registry](https://registry.terraform.io/providers/kvindo/kvindo/latest)).
|
|
76
|
+
- **[kc-mcp-server](https://github.com/Kvindo/kc-mcp-server)** — MCP server for Kvindo Cloud ([npm](https://www.npmjs.com/package/kc-mcp-server)), for managing resources from Claude Desktop/Code and other MCP clients.
|
|
69
77
|
- **[Kvindo Cloud console](https://cloud.kvindo.com)** — web UI and API.
|
|
78
|
+
- **[Claude Code skill](.claude/skills/kvindo-python-sdk/SKILL.md)** — lets Claude script Kvindo Cloud with this SDK conversationally.
|
|
70
79
|
|
|
71
80
|
## License
|
|
72
81
|
|
|
@@ -46,7 +46,7 @@ logger = logging.getLogger(__name__)
|
|
|
46
46
|
# requests, marshmallow-dataclass and py-ulid.
|
|
47
47
|
def create_http_client_with_retries(
|
|
48
48
|
retry_statuses=[500, 502, 503, 504, 520, 521],
|
|
49
|
-
verify_ssl: bool =
|
|
49
|
+
verify_ssl: bool = True,
|
|
50
50
|
) -> requests.Session:
|
|
51
51
|
"""Build a `requests.Session` that retries idempotent failures with backoff.
|
|
52
52
|
|
|
@@ -55,8 +55,10 @@ def create_http_client_with_retries(
|
|
|
55
55
|
server-side; 520 = web server returned an unknown error;
|
|
56
56
|
521 = origin down (Cloudflare-specific).
|
|
57
57
|
verify_ssl: enable/disable TLS certificate verification. Defaults to
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
True — every real Kvindo Cloud API host (dev and public prod) has
|
|
59
|
+
a valid, publicly-trusted certificate. Pass False only to point
|
|
60
|
+
this SDK at a genuinely self-hosted instance with a self-signed
|
|
61
|
+
cert.
|
|
60
62
|
|
|
61
63
|
Returns:
|
|
62
64
|
A configured `requests.Session` (reuse it for connection pooling).
|
|
@@ -143,6 +145,10 @@ class KcApiModificationErrorCode(Enum):
|
|
|
143
145
|
"""deleteProtection=true; clear it before deleting."""
|
|
144
146
|
BadData = "BadData"
|
|
145
147
|
"""Request was malformed."""
|
|
148
|
+
QuotaExceeded = "QuotaExceeded"
|
|
149
|
+
"""The organization's quota for this resource type/parameter would be exceeded, counting
|
|
150
|
+
resources that are submitted but not yet reconciled ("holds"). Not retryable - the caller
|
|
151
|
+
must delete resources or raise the quota. HTTP 409."""
|
|
146
152
|
|
|
147
153
|
|
|
148
154
|
@dataclass
|
|
@@ -285,7 +291,7 @@ class KcResourceGetByLabelsResponse(object):
|
|
|
285
291
|
|
|
286
292
|
# HTTP statuses the API uses to carry a structured (deserializable) body. Anything
|
|
287
293
|
# outside this set is an unexpected transport/server failure and is raised instead.
|
|
288
|
-
_HANDLED_STATUS_CODES = [200, 400, 401, 403, 422]
|
|
294
|
+
_HANDLED_STATUS_CODES = [200, 400, 401, 403, 409, 422]
|
|
289
295
|
|
|
290
296
|
|
|
291
297
|
class KcResourceClient:
|
|
@@ -304,6 +310,7 @@ class KcResourceClient:
|
|
|
304
310
|
token: str,
|
|
305
311
|
api_url: str = "https://cloud-api.kvindo.ru",
|
|
306
312
|
log_extra: dict = None,
|
|
313
|
+
verify_ssl: bool = True,
|
|
307
314
|
):
|
|
308
315
|
"""
|
|
309
316
|
Args:
|
|
@@ -311,11 +318,16 @@ class KcResourceClient:
|
|
|
311
318
|
token: the bearer token; a leading "Bearer " prefix is stripped if present.
|
|
312
319
|
api_url: base URL of the Cloud API (no trailing slash).
|
|
313
320
|
log_extra: optional dict merged into every debug log record's `extra`.
|
|
321
|
+
verify_ssl: enable/disable TLS certificate verification for every
|
|
322
|
+
request this client makes. Defaults to True; pass False only
|
|
323
|
+
to point this SDK at a genuinely self-hosted instance with a
|
|
324
|
+
self-signed cert.
|
|
314
325
|
"""
|
|
315
326
|
self.__token = token.replace("Bearer ", "")
|
|
316
327
|
self.__resource_type = resource_type
|
|
317
328
|
self.__api_url = api_url
|
|
318
329
|
self.__log_extra = log_extra if log_extra is not None else {}
|
|
330
|
+
self.__verify_ssl = verify_ssl
|
|
319
331
|
|
|
320
332
|
def __headers(self) -> dict:
|
|
321
333
|
"""Standard auth + content-type headers for every request."""
|
|
@@ -342,7 +354,7 @@ class KcResourceClient:
|
|
|
342
354
|
"""
|
|
343
355
|
url = f"{self.__api_url}/api/v1/{self.__resource_type}/{id}"
|
|
344
356
|
|
|
345
|
-
response = create_http_client_with_retries().delete(url, headers=self.__headers())
|
|
357
|
+
response = create_http_client_with_retries(verify_ssl=self.__verify_ssl).delete(url, headers=self.__headers())
|
|
346
358
|
|
|
347
359
|
logger.debug(
|
|
348
360
|
f"Got {response.status_code} status code while making request DELETE {url}\nResponse body: {response.text}",
|
|
@@ -376,7 +388,7 @@ class KcResourceClient:
|
|
|
376
388
|
"""
|
|
377
389
|
url = f"{self.__api_url}/api/v1/{self.__resource_type}/{id}"
|
|
378
390
|
|
|
379
|
-
response = create_http_client_with_retries().get(url, headers=self.__headers())
|
|
391
|
+
response = create_http_client_with_retries(verify_ssl=self.__verify_ssl).get(url, headers=self.__headers())
|
|
380
392
|
|
|
381
393
|
logger.debug(
|
|
382
394
|
f"Got {response.status_code} status code while making request GET {url}\nResponse body: {response.text}",
|
|
@@ -418,7 +430,7 @@ class KcResourceClient:
|
|
|
418
430
|
}
|
|
419
431
|
|
|
420
432
|
url = create_url_with_query_params(url, params)
|
|
421
|
-
response = create_http_client_with_retries().get(url, headers=self.__headers())
|
|
433
|
+
response = create_http_client_with_retries(verify_ssl=self.__verify_ssl).get(url, headers=self.__headers())
|
|
422
434
|
|
|
423
435
|
logger.debug(
|
|
424
436
|
f"Got {response.status_code} status code while making request GET {url}\nResponse body: {response.text}",
|
|
@@ -447,7 +459,7 @@ class KcResourceClient:
|
|
|
447
459
|
"""
|
|
448
460
|
url = f"{self.__api_url}/api/v1/{self.__resource_type}/request/{request_id}"
|
|
449
461
|
|
|
450
|
-
response = create_http_client_with_retries().get(url, headers=self.__headers())
|
|
462
|
+
response = create_http_client_with_retries(verify_ssl=self.__verify_ssl).get(url, headers=self.__headers())
|
|
451
463
|
|
|
452
464
|
logger.debug(
|
|
453
465
|
f"Got {response.status_code} status code while making request GET {url}\nResponse body: {response.text}",
|
|
@@ -533,7 +545,7 @@ class KcResourceClient:
|
|
|
533
545
|
|
|
534
546
|
url = f"{self.__api_url}/api/v1/{self.__resource_type}"
|
|
535
547
|
|
|
536
|
-
response = create_http_client_with_retries().put(url, json=data, headers=self.__headers())
|
|
548
|
+
response = create_http_client_with_retries(verify_ssl=self.__verify_ssl).put(url, json=data, headers=self.__headers())
|
|
537
549
|
|
|
538
550
|
logger.debug(
|
|
539
551
|
f"Got {response.status_code} status code while making request PUT {url}\nRequest body: {data}\nResponse body: {response.text}",
|
|
@@ -624,18 +636,13 @@ class KcClient:
|
|
|
624
636
|
kubernetes_node_groups: KcResourceClient
|
|
625
637
|
kubernetes_users: KcResourceClient
|
|
626
638
|
kubernetes_user_roles: KcResourceClient
|
|
627
|
-
postgresqls: KcResourceClient
|
|
628
639
|
postgresql_standalones: KcResourceClient
|
|
629
|
-
postgresql_node_groups: KcResourceClient
|
|
630
640
|
postgresql_parameters_sets: KcResourceClient
|
|
631
|
-
etcd: KcResourceClient
|
|
632
|
-
etcd_node_group: KcResourceClient
|
|
633
641
|
open_vpns: KcResourceClient
|
|
634
642
|
open_vpn_users: KcResourceClient
|
|
635
643
|
open_vpn_user_settings: KcResourceClient
|
|
636
644
|
gitlabs: KcResourceClient
|
|
637
645
|
gitlab_runners: KcResourceClient
|
|
638
|
-
grafanas: KcResourceClient
|
|
639
646
|
ollamas: KcResourceClient
|
|
640
647
|
|
|
641
648
|
# IaM / org
|
|
@@ -658,6 +665,7 @@ class KcClient:
|
|
|
658
665
|
token: str,
|
|
659
666
|
api_url: str = "https://cloud-api.kvindo.ru",
|
|
660
667
|
log_extra: dict = None,
|
|
668
|
+
verify_ssl: bool = True,
|
|
661
669
|
):
|
|
662
670
|
"""
|
|
663
671
|
Args:
|
|
@@ -665,16 +673,21 @@ class KcClient:
|
|
|
665
673
|
api_url: base URL of the Cloud API (no trailing slash).
|
|
666
674
|
log_extra: optional dict merged into every debug log record's `extra`;
|
|
667
675
|
propagated to every per-resource client.
|
|
676
|
+
verify_ssl: enable/disable TLS certificate verification for every
|
|
677
|
+
request this client (and every per-resource client it builds)
|
|
678
|
+
makes. Defaults to True; pass False only to point this SDK at
|
|
679
|
+
a genuinely self-hosted instance with a self-signed cert.
|
|
668
680
|
"""
|
|
669
681
|
self.__log_extra = log_extra if log_extra is not None else {}
|
|
670
682
|
self.__token = token.replace("Bearer ", "")
|
|
671
683
|
self.__api_url = api_url
|
|
684
|
+
self.__verify_ssl = verify_ssl
|
|
672
685
|
# Cached response of get_transaction_collection_keys (lazy, fetched once).
|
|
673
686
|
self._transaction_collection_keys = None
|
|
674
687
|
|
|
675
688
|
def _r(resource_type: str) -> KcResourceClient:
|
|
676
|
-
"""Build a per-type client sharing this client's token/url/log_extra."""
|
|
677
|
-
return KcResourceClient(resource_type, token, api_url, log_extra)
|
|
689
|
+
"""Build a per-type client sharing this client's token/url/log_extra/verify_ssl."""
|
|
690
|
+
return KcResourceClient(resource_type, token, api_url, log_extra, verify_ssl)
|
|
678
691
|
|
|
679
692
|
# Compute
|
|
680
693
|
self.vms = _r("vm")
|
|
@@ -726,18 +739,13 @@ class KcClient:
|
|
|
726
739
|
self.kubernetes_node_groups = _r("kubernetes-node-group")
|
|
727
740
|
self.kubernetes_users = _r("kubernetes-user")
|
|
728
741
|
self.kubernetes_user_roles = _r("kubernetes-user-role")
|
|
729
|
-
self.postgresqls = _r("postgresql")
|
|
730
742
|
self.postgresql_standalones = _r("postgresql-standalone")
|
|
731
|
-
self.postgresql_node_groups = _r("postgresql-node-group")
|
|
732
743
|
self.postgresql_parameters_sets = _r("postgresql-parameters-set")
|
|
733
|
-
self.etcd = _r("etcd")
|
|
734
|
-
self.etcd_node_group = _r("etcd-node-group")
|
|
735
744
|
self.open_vpns = _r("open-vpn")
|
|
736
745
|
self.open_vpn_users = _r("open-vpn-user")
|
|
737
746
|
self.open_vpn_user_settings = _r("open-vpn-user-settings")
|
|
738
747
|
self.gitlabs = _r("gitlab")
|
|
739
748
|
self.gitlab_runners = _r("gitlab-runner")
|
|
740
|
-
self.grafanas = _r("grafana")
|
|
741
749
|
self.ollamas = _r("ollama")
|
|
742
750
|
|
|
743
751
|
# IaM / org
|
|
@@ -764,10 +772,22 @@ class KcClient:
|
|
|
764
772
|
|
|
765
773
|
Returns:
|
|
766
774
|
The raw list returned by the transaction-spec endpoint.
|
|
775
|
+
|
|
776
|
+
Raises:
|
|
777
|
+
Exception: on an unexpected HTTP status. Unlike the per-resource
|
|
778
|
+
methods, any non-200 here is treated as unhandled (this
|
|
779
|
+
endpoint has no typed error-code contract) — previously this
|
|
780
|
+
method cached whatever `.json()` returned regardless of status,
|
|
781
|
+
so a transient failure (e.g. an auth blip) got cached as if it
|
|
782
|
+
were the real key list, permanently, for this instance's life.
|
|
767
783
|
"""
|
|
768
784
|
if self._transaction_collection_keys is None:
|
|
769
785
|
url = f"{self.__api_url}/api/v1/internal/transaction-spec"
|
|
770
786
|
headers = {"Authorization": f"Bearer {self.__token}"}
|
|
771
|
-
response = create_http_client_with_retries().get(url, headers=headers)
|
|
787
|
+
response = create_http_client_with_retries(verify_ssl=self.__verify_ssl).get(url, headers=headers)
|
|
788
|
+
if response.status_code != 200:
|
|
789
|
+
raise Exception(
|
|
790
|
+
f"Got {response.status_code} status code while making request GET {url}\nResponse body: {response.text}"
|
|
791
|
+
)
|
|
772
792
|
self._transaction_collection_keys = response.json()
|
|
773
793
|
return self._transaction_collection_keys
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kc-sdk-python
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: Kvindo Cloud Python SDK — typed client for managing Kvindo Cloud infrastructure (VMs, S3, Kubernetes, load balancers, VPCs, PostgreSQL) via the REST API
|
|
5
5
|
Author: Kvindo
|
|
6
6
|
License-Expression: MIT
|
|
@@ -45,6 +45,10 @@ balancers, VPCs, VPNs, and managed PostgreSQL.
|
|
|
45
45
|
A thin, typed client over the REST API: one resource client per resource type, all sharing the
|
|
46
46
|
same create / read / update / delete / list contract.
|
|
47
47
|
|
|
48
|
+
> **Using Claude Code?** This repo ships a [Claude Code skill](.claude/skills/kvindo-python-sdk/SKILL.md)
|
|
49
|
+
> that teaches Claude how to script Kvindo Cloud with this SDK — clone this repo (or otherwise have
|
|
50
|
+
> it on disk) and open Claude Code there to pick it up automatically.
|
|
51
|
+
|
|
48
52
|
## Install
|
|
49
53
|
|
|
50
54
|
```sh
|
|
@@ -59,6 +63,9 @@ Dependencies: `requests`, `marshmallow-dataclass`, `py-ulid`.
|
|
|
59
63
|
from kc_api import KcClient
|
|
60
64
|
|
|
61
65
|
client = KcClient("YOUR_API_TOKEN") # api_url defaults to https://cloud-api.kvindo.ru
|
|
66
|
+
# TLS certificate verification is on by default (verify_ssl=True). Pass
|
|
67
|
+
# verify_ssl=False only to point this SDK at a genuinely self-hosted instance
|
|
68
|
+
# with a self-signed cert.
|
|
62
69
|
|
|
63
70
|
# List (label-filtered, paginated)
|
|
64
71
|
resp = client.vms.get_by_labels({"env": "prod"}, max_page_size=50)
|
|
@@ -100,7 +107,9 @@ Part of the Kvindo Cloud developer toolchain:
|
|
|
100
107
|
|
|
101
108
|
- **[kc CLI](https://github.com/Kvindo/kc-cli)** — kubectl-style command-line client for Kvindo Cloud.
|
|
102
109
|
- **[terraform-provider-kvindo](https://github.com/Kvindo/terraform-provider-kvindo)** — Terraform provider ([Registry](https://registry.terraform.io/providers/kvindo/kvindo/latest)).
|
|
110
|
+
- **[kc-mcp-server](https://github.com/Kvindo/kc-mcp-server)** — MCP server for Kvindo Cloud ([npm](https://www.npmjs.com/package/kc-mcp-server)), for managing resources from Claude Desktop/Code and other MCP clients.
|
|
103
111
|
- **[Kvindo Cloud console](https://cloud.kvindo.com)** — web UI and API.
|
|
112
|
+
- **[Claude Code skill](.claude/skills/kvindo-python-sdk/SKILL.md)** — lets Claude script Kvindo Cloud with this SDK conversationally.
|
|
104
113
|
|
|
105
114
|
## License
|
|
106
115
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "kc-sdk-python"
|
|
7
|
-
version = "
|
|
7
|
+
version = "4.0.0"
|
|
8
8
|
description = "Kvindo Cloud Python SDK — typed client for managing Kvindo Cloud infrastructure (VMs, S3, Kubernetes, load balancers, VPCs, PostgreSQL) via the REST API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|