webtap-tool 0.2.1__tar.gz → 0.2.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.
Potentially problematic release.
This version of webtap-tool might be problematic. Click here for more details.
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/CHANGELOG.md +24 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/PKG-INFO +1 -1
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/pyproject.toml +1 -1
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/setup/__init__.py +28 -8
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/setup/desktop.py +27 -4
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/setup/platform.py +58 -28
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/.gitignore +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/ARCHITECTURE.md +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/README.md +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/data/filters.json +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/extension/manifest.json +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/extension/popup.html +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/extension/popup.js +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/llms.txt +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/VISION.md +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/__init__.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/api.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/app.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/cdp/README.md +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/cdp/__init__.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/cdp/query.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/cdp/schema/README.md +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/cdp/schema/cdp_protocol.json +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/cdp/schema/cdp_version.json +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/cdp/session.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/DEVELOPER_GUIDE.md +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/TIPS.md +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/__init__.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/_builders.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/_errors.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/_tips.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/_utils.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/body.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/connection.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/console.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/events.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/fetch.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/filters.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/inspect.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/javascript.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/launch.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/navigation.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/network.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/commands/setup.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/filters.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/README.md +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/__init__.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/body.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/console.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/fetch.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/main.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/network.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/setup/chrome.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/setup/extension.py +0 -0
- {webtap_tool-0.2.1 → webtap_tool-0.2.3}/src/webtap/services/setup/filters.py +0 -0
|
@@ -15,6 +15,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
15
15
|
|
|
16
16
|
### Removed
|
|
17
17
|
|
|
18
|
+
## [0.2.3] - 2025-09-12
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- Refactored inline strings to constants in setup services for better maintainability
|
|
24
|
+
- Extracted all script templates, paths, and configuration values as module-level constants
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
### Removed
|
|
29
|
+
|
|
30
|
+
## [0.2.2] - 2025-09-12
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
- macOS Chrome Debug.app now launches Chrome directly to avoid Rosetta warnings on Apple Silicon
|
|
38
|
+
- Added LSArchitecturePriority to Info.plist for native architecture support
|
|
39
|
+
|
|
40
|
+
### Removed
|
|
41
|
+
|
|
18
42
|
## [0.2.1] - 2025-09-12
|
|
19
43
|
|
|
20
44
|
### Added
|
|
@@ -10,7 +10,26 @@ from .filters import FilterSetupService
|
|
|
10
10
|
from .extension import ExtensionSetupService
|
|
11
11
|
from .chrome import ChromeSetupService
|
|
12
12
|
from .desktop import DesktopSetupService
|
|
13
|
-
from .platform import get_platform_info, ensure_directories
|
|
13
|
+
from .platform import get_platform_info, ensure_directories, APP_NAME
|
|
14
|
+
|
|
15
|
+
# Old installation paths to clean up
|
|
16
|
+
OLD_EXTENSION_PATH = ".config/webtap/extension"
|
|
17
|
+
OLD_WRAPPER_PATH = ".local/bin/wrappers/google-chrome-stable"
|
|
18
|
+
OLD_DESKTOP_PATH = ".local/share/applications/google-chrome.desktop"
|
|
19
|
+
OLD_DEBUG_DIR = ".config/google-chrome-debug"
|
|
20
|
+
|
|
21
|
+
# Path components
|
|
22
|
+
WRAPPERS_DIR = "wrappers"
|
|
23
|
+
GOOGLE_CHROME_STABLE = "google-chrome-stable"
|
|
24
|
+
|
|
25
|
+
# Size formatting constants
|
|
26
|
+
KB_SIZE = 1024
|
|
27
|
+
SIZE_FORMAT_KB = "{:.1f} KB"
|
|
28
|
+
SIZE_FORMAT_EMPTY = "empty"
|
|
29
|
+
|
|
30
|
+
# Mount point command
|
|
31
|
+
MOUNTPOINT_CMD = "mountpoint"
|
|
32
|
+
MOUNTPOINT_CHECK_FLAG = "-q"
|
|
14
33
|
|
|
15
34
|
|
|
16
35
|
class SetupService:
|
|
@@ -108,11 +127,11 @@ class SetupService:
|
|
|
108
127
|
result = {}
|
|
109
128
|
|
|
110
129
|
# Check old extension location
|
|
111
|
-
old_extension_path = Path.home() /
|
|
130
|
+
old_extension_path = Path.home() / OLD_EXTENSION_PATH
|
|
112
131
|
if old_extension_path.exists():
|
|
113
132
|
# Calculate size
|
|
114
133
|
size = sum(f.stat().st_size for f in old_extension_path.rglob("*") if f.is_file())
|
|
115
|
-
size_str =
|
|
134
|
+
size_str = SIZE_FORMAT_KB.format(size / KB_SIZE) if size > 0 else SIZE_FORMAT_EMPTY
|
|
116
135
|
|
|
117
136
|
result["old_extension"] = {"path": str(old_extension_path), "size": size_str, "removed": False}
|
|
118
137
|
|
|
@@ -128,7 +147,7 @@ class SetupService:
|
|
|
128
147
|
result["old_extension"]["error"] = str(e)
|
|
129
148
|
|
|
130
149
|
# Check old Chrome wrapper location
|
|
131
|
-
old_wrapper_path = Path.home() /
|
|
150
|
+
old_wrapper_path = Path.home() / OLD_WRAPPER_PATH
|
|
132
151
|
if old_wrapper_path.exists():
|
|
133
152
|
result["old_wrapper"] = {"path": str(old_wrapper_path), "removed": False}
|
|
134
153
|
|
|
@@ -144,12 +163,13 @@ class SetupService:
|
|
|
144
163
|
result["old_wrapper"]["error"] = str(e)
|
|
145
164
|
|
|
146
165
|
# Check old desktop entry
|
|
147
|
-
old_desktop_path = Path.home() /
|
|
166
|
+
old_desktop_path = Path.home() / OLD_DESKTOP_PATH
|
|
148
167
|
if old_desktop_path.exists():
|
|
149
168
|
# Check if it's our override (contains reference to wrapper)
|
|
150
169
|
try:
|
|
151
170
|
content = old_desktop_path.read_text()
|
|
152
|
-
|
|
171
|
+
wrapper_ref = f"{WRAPPERS_DIR}/{GOOGLE_CHROME_STABLE}"
|
|
172
|
+
if wrapper_ref in content or APP_NAME in content.lower():
|
|
153
173
|
result["old_desktop"] = {"path": str(old_desktop_path), "removed": False}
|
|
154
174
|
|
|
155
175
|
if not dry_run:
|
|
@@ -162,11 +182,11 @@ class SetupService:
|
|
|
162
182
|
pass # If we can't read it, skip it
|
|
163
183
|
|
|
164
184
|
# Check for bindfs mount
|
|
165
|
-
debug_dir = Path.home() /
|
|
185
|
+
debug_dir = Path.home() / OLD_DEBUG_DIR
|
|
166
186
|
if debug_dir.exists():
|
|
167
187
|
try:
|
|
168
188
|
# Check if it's a mount point
|
|
169
|
-
output = subprocess.run([
|
|
189
|
+
output = subprocess.run([MOUNTPOINT_CMD, MOUNTPOINT_CHECK_FLAG, str(debug_dir)], capture_output=True)
|
|
170
190
|
if output.returncode == 0:
|
|
171
191
|
result["bindfs_mount"] = str(debug_dir)
|
|
172
192
|
except (FileNotFoundError, OSError):
|
|
@@ -62,6 +62,11 @@ MACOS_INFO_PLIST = """<?xml version="1.0" encoding="UTF-8"?>
|
|
|
62
62
|
<string>????</string>
|
|
63
63
|
<key>LSMinimumSystemVersion</key>
|
|
64
64
|
<string>10.12</string>
|
|
65
|
+
<key>LSArchitecturePriority</key>
|
|
66
|
+
<array>
|
|
67
|
+
<string>arm64</string>
|
|
68
|
+
<string>x86_64</string>
|
|
69
|
+
</array>
|
|
65
70
|
<key>CFBundleDocumentTypes</key>
|
|
66
71
|
<array>
|
|
67
72
|
<dict>
|
|
@@ -160,12 +165,30 @@ class DesktopSetupService:
|
|
|
160
165
|
macos_dir = contents_dir / "MacOS"
|
|
161
166
|
macos_dir.mkdir(parents=True, exist_ok=True)
|
|
162
167
|
|
|
163
|
-
# Create launcher script
|
|
168
|
+
# Create launcher script that directly launches Chrome
|
|
169
|
+
# This avoids Rosetta warnings from nested bash scripts
|
|
164
170
|
launcher_path = macos_dir / "Chrome Debug"
|
|
171
|
+
|
|
172
|
+
# Get Chrome path from platform info
|
|
173
|
+
chrome_path = self.chrome["path"]
|
|
174
|
+
profile_dir = self.paths["data_dir"] / "profiles" / "default"
|
|
175
|
+
|
|
165
176
|
launcher_content = f"""#!/bin/bash
|
|
166
|
-
# Chrome Debug app launcher
|
|
167
|
-
#
|
|
168
|
-
|
|
177
|
+
# Chrome Debug app launcher - direct Chrome execution
|
|
178
|
+
# Avoids Rosetta warnings by directly launching Chrome
|
|
179
|
+
|
|
180
|
+
PORT=${{WEBTAP_PORT:-9222}}
|
|
181
|
+
PROFILE_DIR="{profile_dir}"
|
|
182
|
+
mkdir -p "$PROFILE_DIR"
|
|
183
|
+
|
|
184
|
+
# Launch Chrome directly with debugging
|
|
185
|
+
exec "{chrome_path}" \\
|
|
186
|
+
--remote-debugging-port="$PORT" \\
|
|
187
|
+
--remote-allow-origins='*' \\
|
|
188
|
+
--user-data-dir="$PROFILE_DIR" \\
|
|
189
|
+
--no-first-run \\
|
|
190
|
+
--no-default-browser-check \\
|
|
191
|
+
"$@"
|
|
169
192
|
"""
|
|
170
193
|
launcher_path.write_text(launcher_content)
|
|
171
194
|
launcher_path.chmod(0o755)
|
|
@@ -7,6 +7,46 @@ from typing import Optional
|
|
|
7
7
|
|
|
8
8
|
import platformdirs
|
|
9
9
|
|
|
10
|
+
# Application constants
|
|
11
|
+
APP_NAME = "webtap"
|
|
12
|
+
APP_AUTHOR = "webtap"
|
|
13
|
+
|
|
14
|
+
# Directory names
|
|
15
|
+
BIN_DIR_NAME = ".local/bin"
|
|
16
|
+
WRAPPER_NAME = "chrome-debug"
|
|
17
|
+
TMP_RUNTIME_DIR = "/tmp"
|
|
18
|
+
|
|
19
|
+
# Chrome executable names for Linux
|
|
20
|
+
CHROME_NAMES_LINUX = [
|
|
21
|
+
"google-chrome",
|
|
22
|
+
"google-chrome-stable",
|
|
23
|
+
"chromium",
|
|
24
|
+
"chromium-browser",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
# Chrome paths for macOS
|
|
28
|
+
CHROME_PATHS_MACOS = [
|
|
29
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
30
|
+
"Applications/Google Chrome.app/Contents/MacOS/Google Chrome", # Relative to home
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
# Chrome paths for Linux
|
|
34
|
+
CHROME_PATHS_LINUX = [
|
|
35
|
+
"/usr/bin/google-chrome",
|
|
36
|
+
"/usr/bin/google-chrome-stable",
|
|
37
|
+
"/usr/bin/chromium",
|
|
38
|
+
"/usr/bin/chromium-browser",
|
|
39
|
+
"/snap/bin/chromium",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
# Platform identifiers
|
|
43
|
+
PLATFORM_DARWIN = "Darwin"
|
|
44
|
+
PLATFORM_LINUX = "Linux"
|
|
45
|
+
|
|
46
|
+
# Application directories
|
|
47
|
+
MACOS_APPLICATIONS_DIR = "Applications"
|
|
48
|
+
LINUX_APPLICATIONS_DIR = ".local/share/applications"
|
|
49
|
+
|
|
10
50
|
|
|
11
51
|
def get_platform_paths() -> dict[str, Path]:
|
|
12
52
|
"""Get platform-appropriate paths using platformdirs.
|
|
@@ -14,10 +54,7 @@ def get_platform_paths() -> dict[str, Path]:
|
|
|
14
54
|
Returns:
|
|
15
55
|
Dictionary of paths for config, data, cache, runtime, and state directories.
|
|
16
56
|
"""
|
|
17
|
-
|
|
18
|
-
app_author = "webtap"
|
|
19
|
-
|
|
20
|
-
dirs = platformdirs.PlatformDirs(app_name, app_author)
|
|
57
|
+
dirs = platformdirs.PlatformDirs(APP_NAME, APP_AUTHOR)
|
|
21
58
|
|
|
22
59
|
paths = {
|
|
23
60
|
"config_dir": Path(dirs.user_config_dir), # ~/.config/webtap or ~/Library/Application Support/webtap
|
|
@@ -31,7 +68,7 @@ def get_platform_paths() -> dict[str, Path]:
|
|
|
31
68
|
paths["runtime_dir"] = Path(dirs.user_runtime_dir)
|
|
32
69
|
except AttributeError:
|
|
33
70
|
# Fallback for platforms without runtime dir
|
|
34
|
-
paths["runtime_dir"] = Path(
|
|
71
|
+
paths["runtime_dir"] = Path(TMP_RUNTIME_DIR) / APP_NAME
|
|
35
72
|
|
|
36
73
|
return paths
|
|
37
74
|
|
|
@@ -44,21 +81,15 @@ def get_chrome_path() -> Optional[Path]:
|
|
|
44
81
|
"""
|
|
45
82
|
system = platform.system()
|
|
46
83
|
|
|
47
|
-
if system ==
|
|
84
|
+
if system == PLATFORM_DARWIN:
|
|
48
85
|
# macOS standard locations
|
|
49
86
|
candidates = [
|
|
50
|
-
Path(
|
|
51
|
-
Path.home() /
|
|
87
|
+
Path(CHROME_PATHS_MACOS[0]),
|
|
88
|
+
Path.home() / CHROME_PATHS_MACOS[1],
|
|
52
89
|
]
|
|
53
|
-
elif system ==
|
|
90
|
+
elif system == PLATFORM_LINUX:
|
|
54
91
|
# Linux standard locations
|
|
55
|
-
candidates = [
|
|
56
|
-
Path("/usr/bin/google-chrome"),
|
|
57
|
-
Path("/usr/bin/google-chrome-stable"),
|
|
58
|
-
Path("/usr/bin/chromium"),
|
|
59
|
-
Path("/usr/bin/chromium-browser"),
|
|
60
|
-
Path("/snap/bin/chromium"),
|
|
61
|
-
]
|
|
92
|
+
candidates = [Path(p) for p in CHROME_PATHS_LINUX]
|
|
62
93
|
else:
|
|
63
94
|
return None
|
|
64
95
|
|
|
@@ -67,7 +98,7 @@ def get_chrome_path() -> Optional[Path]:
|
|
|
67
98
|
return path
|
|
68
99
|
|
|
69
100
|
# Try to find in PATH
|
|
70
|
-
for name in
|
|
101
|
+
for name in CHROME_NAMES_LINUX:
|
|
71
102
|
if found := shutil.which(name):
|
|
72
103
|
return Path(found)
|
|
73
104
|
|
|
@@ -84,31 +115,30 @@ def get_platform_info() -> dict:
|
|
|
84
115
|
paths = get_platform_paths()
|
|
85
116
|
|
|
86
117
|
# Unified paths for both platforms
|
|
87
|
-
paths["bin_dir"] = Path.home() /
|
|
88
|
-
wrapper_name = "chrome-debug" # Same name on both platforms
|
|
118
|
+
paths["bin_dir"] = Path.home() / BIN_DIR_NAME # User space, no sudo needed
|
|
89
119
|
|
|
90
120
|
# Platform-specific launcher locations
|
|
91
|
-
if system ==
|
|
92
|
-
paths["applications_dir"] = Path.home() /
|
|
121
|
+
if system == PLATFORM_DARWIN:
|
|
122
|
+
paths["applications_dir"] = Path.home() / MACOS_APPLICATIONS_DIR
|
|
93
123
|
else: # Linux
|
|
94
|
-
paths["applications_dir"] = Path.home() /
|
|
124
|
+
paths["applications_dir"] = Path.home() / LINUX_APPLICATIONS_DIR
|
|
95
125
|
|
|
96
126
|
chrome_path = get_chrome_path()
|
|
97
127
|
|
|
98
128
|
return {
|
|
99
129
|
"system": system.lower(),
|
|
100
|
-
"is_macos": system ==
|
|
101
|
-
"is_linux": system ==
|
|
130
|
+
"is_macos": system == PLATFORM_DARWIN,
|
|
131
|
+
"is_linux": system == PLATFORM_LINUX,
|
|
102
132
|
"paths": paths,
|
|
103
133
|
"chrome": {
|
|
104
134
|
"path": chrome_path,
|
|
105
135
|
"found": chrome_path is not None,
|
|
106
|
-
"wrapper_name":
|
|
136
|
+
"wrapper_name": WRAPPER_NAME,
|
|
107
137
|
},
|
|
108
138
|
"capabilities": {
|
|
109
|
-
"desktop_files": system ==
|
|
110
|
-
"app_bundles": system ==
|
|
111
|
-
"bindfs": system ==
|
|
139
|
+
"desktop_files": system == PLATFORM_LINUX,
|
|
140
|
+
"app_bundles": system == PLATFORM_DARWIN,
|
|
141
|
+
"bindfs": system == PLATFORM_LINUX and shutil.which("bindfs") is not None,
|
|
112
142
|
},
|
|
113
143
|
}
|
|
114
144
|
|
|
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
|