fvpnctl 0.2.0__tar.gz → 0.2.2__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.
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/PKG-INFO +9 -3
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/README.md +7 -2
- fvpnctl-0.2.2/pyproject.toml +84 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/src/fvpnctl/__init__.py +1 -1
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/src/fvpnctl/cli.py +10 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/uv.lock +15 -19
- fvpnctl-0.2.0/pyproject.toml +0 -58
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/.github/workflows/ci.yml +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/.gitignore +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/.pre-commit-config.yaml +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/LICENSE +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/contrib/com.fvpnctl.headless.plist +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/docs/how-it-works.md +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/docs/superpowers/specs/2026-06-20-fortivpn-cli-via-cdp-design.md +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/src/fvpnctl/cdp.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/src/fvpnctl/controller.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/src/fvpnctl/errors.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/src/fvpnctl/keychain.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/src/fvpnctl/launcher.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/src/fvpnctl/monitor.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/tests/manual/test_live.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/tests/test_cdp.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/tests/test_cli.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/tests/test_controller.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/tests/test_errors.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/tests/test_keychain.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/tests/test_launcher.py +0 -0
- {fvpnctl-0.2.0 → fvpnctl-0.2.2}/tests/test_monitor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fvpnctl
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Control your FortiClient VPN from the macOS command line.
|
|
5
5
|
Project-URL: Homepage, https://github.com/mpasternak/fortivpn-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/mpasternak/fortivpn-cli
|
|
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
20
|
Classifier: Topic :: System :: Networking
|
|
21
21
|
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: setuptools<0; sys_platform == 'win32'
|
|
22
23
|
Description-Content-Type: text/markdown
|
|
23
24
|
|
|
24
25
|
# fvpnctl — control your FortiClient VPN from the macOS command line
|
|
@@ -31,7 +32,9 @@ handy for scripts, automation, and headless or over-SSH use. It works with a For
|
|
|
31
32
|
already have running, talking to it over a local debugging port.
|
|
32
33
|
|
|
33
34
|
- Zero runtime dependencies (Python standard library only).
|
|
34
|
-
- Python ≥ 3.11
|
|
35
|
+
- **macOS only** (Python ≥ 3.11). There is **no Windows support** — it drives the
|
|
36
|
+
macOS FortiClient.app, so `pip` / `uv` / `uvx` deliberately **refuse to install on
|
|
37
|
+
Windows**, and running it from a source checkout there exits with a clear error.
|
|
35
38
|
- Attach-only by default: commands attach to a running FortiClient; the one explicit
|
|
36
39
|
exception is `fvpnctl startserver`, an opt-in launcher you invoke yourself.
|
|
37
40
|
|
|
@@ -113,7 +116,10 @@ uv tool install . # install the `fvpnctl` command from the local tree
|
|
|
113
116
|
uv run fvpnctl list # or run it in place, without installing
|
|
114
117
|
```
|
|
115
118
|
|
|
116
|
-
Requirements: macOS, Python ≥ 3.11.
|
|
119
|
+
Requirements: macOS, Python ≥ 3.11. **Windows is not supported** — installation on
|
|
120
|
+
Windows fails on purpose (the package declares an unsatisfiable `win32` requirement),
|
|
121
|
+
and there is no Linux support for the runtime either (the CLI talks to macOS
|
|
122
|
+
FortiClient.app). Linux is used only by CI to run the mocked test suite.
|
|
117
123
|
|
|
118
124
|
---
|
|
119
125
|
|
|
@@ -8,7 +8,9 @@ handy for scripts, automation, and headless or over-SSH use. It works with a For
|
|
|
8
8
|
already have running, talking to it over a local debugging port.
|
|
9
9
|
|
|
10
10
|
- Zero runtime dependencies (Python standard library only).
|
|
11
|
-
- Python ≥ 3.11
|
|
11
|
+
- **macOS only** (Python ≥ 3.11). There is **no Windows support** — it drives the
|
|
12
|
+
macOS FortiClient.app, so `pip` / `uv` / `uvx` deliberately **refuse to install on
|
|
13
|
+
Windows**, and running it from a source checkout there exits with a clear error.
|
|
12
14
|
- Attach-only by default: commands attach to a running FortiClient; the one explicit
|
|
13
15
|
exception is `fvpnctl startserver`, an opt-in launcher you invoke yourself.
|
|
14
16
|
|
|
@@ -90,7 +92,10 @@ uv tool install . # install the `fvpnctl` command from the local tree
|
|
|
90
92
|
uv run fvpnctl list # or run it in place, without installing
|
|
91
93
|
```
|
|
92
94
|
|
|
93
|
-
Requirements: macOS, Python ≥ 3.11.
|
|
95
|
+
Requirements: macOS, Python ≥ 3.11. **Windows is not supported** — installation on
|
|
96
|
+
Windows fails on purpose (the package declares an unsatisfiable `win32` requirement),
|
|
97
|
+
and there is no Linux support for the runtime either (the CLI talks to macOS
|
|
98
|
+
FortiClient.app). Linux is used only by CI to run the mocked test suite.
|
|
94
99
|
|
|
95
100
|
---
|
|
96
101
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "fvpnctl"
|
|
3
|
+
version = "0.2.2"
|
|
4
|
+
requires-python = ">=3.11"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
description = "Control your FortiClient VPN from the macOS command line."
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "Michał Pasternak" }]
|
|
10
|
+
keywords = ["forticlient", "fortinet", "vpn", "ipsec", "macos", "cli"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: System Administrators",
|
|
15
|
+
"Operating System :: MacOS",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Topic :: System :: Networking",
|
|
21
|
+
]
|
|
22
|
+
# Zero runtime dependencies is a hard design requirement on supported platforms:
|
|
23
|
+
# the tool uses only the Python standard library (socket, json, urllib,
|
|
24
|
+
# subprocess, argparse). See the design spec sections 2 and 8 for the rationale
|
|
25
|
+
# (no third-party attack surface, trivially auditable, runs against any stock
|
|
26
|
+
# Python 3.11+).
|
|
27
|
+
#
|
|
28
|
+
# The single entry below is NOT a real dependency. fvpnctl is macOS-only (it
|
|
29
|
+
# drives the FortiClient.app debug port) and has no Windows support, so this is an
|
|
30
|
+
# intentionally unsatisfiable requirement gated to win32: on Windows pip/uv/uvx
|
|
31
|
+
# fail fast instead of installing something that cannot work. On macOS — and on
|
|
32
|
+
# Linux, where CI runs the platform-agnostic mocked test suite — the marker is
|
|
33
|
+
# false, so the dependency set stays empty.
|
|
34
|
+
#
|
|
35
|
+
# IMPORTANT: the constraint pins a PyPA-owned package (setuptools) to an
|
|
36
|
+
# impossible version, NOT a made-up package name. A non-existent placeholder name
|
|
37
|
+
# would be a dependency-confusion hole: an attacker could register that name on
|
|
38
|
+
# PyPI, and then `pip install fvpnctl` on Windows would *succeed* and pull in
|
|
39
|
+
# their code instead of failing. No PEP 440 version is < 0, so `setuptools<0` can
|
|
40
|
+
# never be satisfied by anyone — setuptools is PyPA-controlled and cannot be
|
|
41
|
+
# squatted — making this a permanently safe, unsatisfiable gate. cli.main() also
|
|
42
|
+
# refuses to run on win32 as a runtime backstop.
|
|
43
|
+
dependencies = [
|
|
44
|
+
"setuptools<0; sys_platform == 'win32'",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
Homepage = "https://github.com/mpasternak/fortivpn-cli"
|
|
49
|
+
Repository = "https://github.com/mpasternak/fortivpn-cli"
|
|
50
|
+
Issues = "https://github.com/mpasternak/fortivpn-cli/issues"
|
|
51
|
+
|
|
52
|
+
[project.scripts]
|
|
53
|
+
fvpnctl = "fvpnctl.cli:main"
|
|
54
|
+
|
|
55
|
+
[dependency-groups]
|
|
56
|
+
# Installed by default on `uv sync` so the test suite + lint/format run out of the
|
|
57
|
+
# box and reproducibly in CI (ruff is a real dev dep, not relied on from PATH).
|
|
58
|
+
dev = ["pytest>=8", "ruff>=0.13"]
|
|
59
|
+
|
|
60
|
+
[build-system]
|
|
61
|
+
requires = ["hatchling"]
|
|
62
|
+
build-backend = "hatchling.build"
|
|
63
|
+
|
|
64
|
+
[tool.hatch.build.targets.wheel]
|
|
65
|
+
packages = ["src/fvpnctl"]
|
|
66
|
+
|
|
67
|
+
[tool.uv]
|
|
68
|
+
# fvpnctl is macOS-only; CI additionally resolves on Linux to run the mocked,
|
|
69
|
+
# platform-agnostic test suite. Restrict universal locking to these so `uv lock`
|
|
70
|
+
# does not try (and fail) to resolve the intentionally-unsatisfiable win32 install
|
|
71
|
+
# guard declared in [project].dependencies.
|
|
72
|
+
environments = ["sys_platform == 'darwin'", "sys_platform == 'linux'"]
|
|
73
|
+
|
|
74
|
+
[tool.ruff]
|
|
75
|
+
line-length = 100
|
|
76
|
+
target-version = "py311"
|
|
77
|
+
|
|
78
|
+
[tool.ruff.lint]
|
|
79
|
+
# E/W pycodestyle, F pyflakes, I import sorting, UP pyupgrade, B bugbear.
|
|
80
|
+
select = ["E", "F", "I", "UP", "B", "W"]
|
|
81
|
+
|
|
82
|
+
[tool.pytest.ini_options]
|
|
83
|
+
testpaths = ["tests"]
|
|
84
|
+
addopts = "-q"
|
|
@@ -479,6 +479,16 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
479
479
|
"""
|
|
480
480
|
global _VERBOSE
|
|
481
481
|
|
|
482
|
+
if sys.platform == "win32":
|
|
483
|
+
# fvpnctl drives the macOS FortiClient.app debug port; there is no Windows
|
|
484
|
+
# support. The packaging metadata already refuses to *install* on win32
|
|
485
|
+
# (see pyproject.toml), but a source checkout run via `python -m` / `uv run`
|
|
486
|
+
# can still reach here — fail fast with a clear message instead of a
|
|
487
|
+
# confusing "FortiClient not found" later. (win32-only so the Linux CI that
|
|
488
|
+
# runs the mocked test suite via main() is unaffected.)
|
|
489
|
+
print("fvpnctl is macOS-only and has no Windows support.", file=sys.stderr)
|
|
490
|
+
return 1
|
|
491
|
+
|
|
482
492
|
parser = _build_parser()
|
|
483
493
|
args = parser.parse_args(argv)
|
|
484
494
|
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
version = 1
|
|
2
2
|
revision = 3
|
|
3
3
|
requires-python = ">=3.11"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
|
4
|
+
resolution-markers = [
|
|
5
|
+
"sys_platform == 'darwin'",
|
|
6
|
+
"sys_platform == 'linux'",
|
|
7
|
+
]
|
|
8
|
+
supported-markers = [
|
|
9
|
+
"sys_platform == 'darwin'",
|
|
10
|
+
"sys_platform == 'linux'",
|
|
12
11
|
]
|
|
13
12
|
|
|
14
13
|
[[package]]
|
|
15
14
|
name = "fvpnctl"
|
|
16
|
-
version = "0.2.
|
|
15
|
+
version = "0.2.2"
|
|
17
16
|
source = { editable = "." }
|
|
18
17
|
|
|
19
18
|
[package.dev-dependencies]
|
|
20
19
|
dev = [
|
|
21
|
-
{ name = "pytest" },
|
|
22
|
-
{ name = "ruff" },
|
|
20
|
+
{ name = "pytest", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
|
21
|
+
{ name = "ruff", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
|
23
22
|
]
|
|
24
23
|
|
|
25
24
|
[package.metadata]
|
|
25
|
+
requires-dist = [{ name = "setuptools", marker = "sys_platform == 'win32'", specifier = "<0" }]
|
|
26
26
|
|
|
27
27
|
[package.metadata.requires-dev]
|
|
28
28
|
dev = [
|
|
@@ -71,11 +71,10 @@ name = "pytest"
|
|
|
71
71
|
version = "9.1.1"
|
|
72
72
|
source = { registry = "https://pypi.org/simple" }
|
|
73
73
|
dependencies = [
|
|
74
|
-
{ name = "
|
|
75
|
-
{ name = "
|
|
76
|
-
{ name = "
|
|
77
|
-
{ name = "
|
|
78
|
-
{ name = "pygments" },
|
|
74
|
+
{ name = "iniconfig", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
|
75
|
+
{ name = "packaging", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
|
76
|
+
{ name = "pluggy", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
|
77
|
+
{ name = "pygments", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
|
79
78
|
]
|
|
80
79
|
sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" }
|
|
81
80
|
wheels = [
|
|
@@ -102,7 +101,4 @@ wheels = [
|
|
|
102
101
|
{ url = "https://files.pythonhosted.org/packages/f5/d1/5cf5909329fedb5d39d555ee818ba5cf4638e1a301b89785d34f2905bfcb/ruff-0.15.18-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a81beadbbff2c9c245561ae3f77b16709d87f35eec650d0501679239d3449b22", size = 10693187, upload-time = "2026-06-18T18:25:08.245Z" },
|
|
103
102
|
{ url = "https://files.pythonhosted.org/packages/fd/44/ff6c635cf2c4f4e7b618b6640da057376baa36014695487d88aed4794268/ruff-0.15.18-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2186d9e940ae332ab293623a75b5f4fe49565f449954d50a72a046683aa6b809", size = 11208721, upload-time = "2026-06-18T18:25:41.327Z" },
|
|
104
103
|
{ url = "https://files.pythonhosted.org/packages/88/d9/5baa2a30861adfb7022cf33c1e35b2fc18085b08c16f83eff4c7b99a5f48/ruff-0.15.18-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c2abf140438032bc77b2284a6c9944ecd8a19e5f1c7b52b1b8e4a0a80d19a7a", size = 11678599, upload-time = "2026-06-18T18:25:13.607Z" },
|
|
105
|
-
{ url = "https://files.pythonhosted.org/packages/c3/1a/0725a7cfdc32ff769efb96ee782bec882e16448c5d9e3be947ec4c04ce27/ruff-0.15.18-py3-none-win32.whl", hash = "sha256:02299e6e9fa5b297a3f6d5d10d7bcd655c925b028bb8b9d4588214549c6b9ec4", size = 10901903, upload-time = "2026-06-18T18:25:24.755Z" },
|
|
106
|
-
{ url = "https://files.pythonhosted.org/packages/f3/51/805d9f6fb7970505c3504794a5ec350f605361b807fef4dcf214ebd35e72/ruff-0.15.18-py3-none-win_amd64.whl", hash = "sha256:dac80dc8d26b2257dbefabed62f5d255c3937b4ccb122da1fc634794fa3578b3", size = 12041189, upload-time = "2026-06-18T18:25:17.915Z" },
|
|
107
|
-
{ url = "https://files.pythonhosted.org/packages/29/4c/67bb45e41609eb4726f1bfeb59e083cf91d14c696d4bd14c234a980be93d/ruff-0.15.18-py3-none-win_arm64.whl", hash = "sha256:b2c9257fcbd4a3e5b977a1904e6facca016bafe2edc17df24db67cfaee03b4e4", size = 11329958, upload-time = "2026-06-18T18:25:43.686Z" },
|
|
108
104
|
]
|
fvpnctl-0.2.0/pyproject.toml
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "fvpnctl"
|
|
3
|
-
version = "0.2.0"
|
|
4
|
-
requires-python = ">=3.11"
|
|
5
|
-
readme = "README.md"
|
|
6
|
-
description = "Control your FortiClient VPN from the macOS command line."
|
|
7
|
-
license = "MIT"
|
|
8
|
-
license-files = ["LICENSE"]
|
|
9
|
-
authors = [{ name = "Michał Pasternak" }]
|
|
10
|
-
keywords = ["forticlient", "fortinet", "vpn", "ipsec", "macos", "cli"]
|
|
11
|
-
classifiers = [
|
|
12
|
-
"Development Status :: 4 - Beta",
|
|
13
|
-
"Environment :: Console",
|
|
14
|
-
"Intended Audience :: System Administrators",
|
|
15
|
-
"Operating System :: MacOS",
|
|
16
|
-
"Programming Language :: Python :: 3",
|
|
17
|
-
"Programming Language :: Python :: 3.11",
|
|
18
|
-
"Programming Language :: Python :: 3.12",
|
|
19
|
-
"Programming Language :: Python :: 3.13",
|
|
20
|
-
"Topic :: System :: Networking",
|
|
21
|
-
]
|
|
22
|
-
# Zero runtime dependencies is a hard design requirement: the tool uses only the
|
|
23
|
-
# Python standard library (socket, json, urllib, subprocess, argparse). See the
|
|
24
|
-
# design spec sections 2 and 8 for the rationale (no third-party attack surface,
|
|
25
|
-
# trivially auditable, runs against any stock Python 3.11+).
|
|
26
|
-
dependencies = []
|
|
27
|
-
|
|
28
|
-
[project.urls]
|
|
29
|
-
Homepage = "https://github.com/mpasternak/fortivpn-cli"
|
|
30
|
-
Repository = "https://github.com/mpasternak/fortivpn-cli"
|
|
31
|
-
Issues = "https://github.com/mpasternak/fortivpn-cli/issues"
|
|
32
|
-
|
|
33
|
-
[project.scripts]
|
|
34
|
-
fvpnctl = "fvpnctl.cli:main"
|
|
35
|
-
|
|
36
|
-
[dependency-groups]
|
|
37
|
-
# Installed by default on `uv sync` so the test suite + lint/format run out of the
|
|
38
|
-
# box and reproducibly in CI (ruff is a real dev dep, not relied on from PATH).
|
|
39
|
-
dev = ["pytest>=8", "ruff>=0.13"]
|
|
40
|
-
|
|
41
|
-
[build-system]
|
|
42
|
-
requires = ["hatchling"]
|
|
43
|
-
build-backend = "hatchling.build"
|
|
44
|
-
|
|
45
|
-
[tool.hatch.build.targets.wheel]
|
|
46
|
-
packages = ["src/fvpnctl"]
|
|
47
|
-
|
|
48
|
-
[tool.ruff]
|
|
49
|
-
line-length = 100
|
|
50
|
-
target-version = "py311"
|
|
51
|
-
|
|
52
|
-
[tool.ruff.lint]
|
|
53
|
-
# E/W pycodestyle, F pyflakes, I import sorting, UP pyupgrade, B bugbear.
|
|
54
|
-
select = ["E", "F", "I", "UP", "B", "W"]
|
|
55
|
-
|
|
56
|
-
[tool.pytest.ini_options]
|
|
57
|
-
testpaths = ["tests"]
|
|
58
|
-
addopts = "-q"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fvpnctl-0.2.0 → fvpnctl-0.2.2}/docs/superpowers/specs/2026-06-20-fortivpn-cli-via-cdp-design.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
|