riplex 0.3.2__tar.gz → 0.3.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.
- {riplex-0.3.2/src/riplex.egg-info → riplex-0.3.3}/PKG-INFO +1 -1
- {riplex-0.3.2 → riplex-0.3.3}/docs/getting-started/installation.md +1 -1
- {riplex-0.3.2 → riplex-0.3.3/src/riplex.egg-info}/PKG-INFO +1 -1
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/welcome.py +24 -27
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_cli/commands/setup.py +1 -1
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_updater.py +6 -6
- {riplex-0.3.2 → riplex-0.3.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/.github/agents/riplex.agent.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/.github/copilot-instructions.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/.github/workflows/publish.yml +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/.github/workflows/release.yml +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/.gitignore +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/MONOREPO_PLAN.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/PLANNED_FEATURES.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/README.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/REFACTOR_PLAN.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/docs/architecture.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/docs/changelog.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/docs/getting-started/configuration.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/docs/guide/lookup.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/docs/guide/orchestrate.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/docs/guide/organize.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/docs/guide/workflow.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/docs/index.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/docs/naming-rules.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/docs/reference/cli.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/issues/cross-disc-dvdcompare-matching.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/mkdocs.yml +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/plex_naming_rules.md +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/pyproject.toml +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/setup.cfg +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/__init__.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/cache.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/config.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/dedup.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/detect.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/disc/__init__.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/disc/analysis.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/disc/makemkv.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/disc/provider.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/formatter.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/lookup.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/manifest.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/matcher.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/metadata/__init__.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/metadata/planner.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/metadata/provider.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/metadata/sources/__init__.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/metadata/sources/tmdb.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/models.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/normalize.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/organizer.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/scanner.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/snapshot.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/splitter.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/tagger.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/title.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex/ui.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex.egg-info/SOURCES.txt +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex.egg-info/dependency_links.txt +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex.egg-info/entry_points.txt +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex.egg-info/requires.txt +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex.egg-info/top_level.txt +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/__init__.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/main.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/__init__.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/disc_detection.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/done.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/folder_picker.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/metadata.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/organize_done.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/organize_preview.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/progress.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/release.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/screens/selection.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_app/updater.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_cli/__init__.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_cli/commands/__init__.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_cli/commands/lookup.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_cli/commands/orchestrate.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_cli/commands/organize.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_cli/commands/rip.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_cli/formatting.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/src/riplex_cli/main.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/__init__.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/fixtures/makemkvcon_frozen_planet_ii_d2.txt +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/fixtures/makemkvcon_list.txt +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/snapshots/Batman Begins.snapshot.json +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/snapshots/Blade Runner (Blu-ray 4k).snapshot.json +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/snapshots/Blade Runner The Final Cut.snapshot.json +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/snapshots/Seven Worlds One Planet.snapshot.json +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/snapshots/The Dark Knight Rises.snapshot.json +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/snapshots/The Dark Knight.snapshot.json +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/snapshots/Waterworld.snapshot.json +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_cache.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_cli_utils.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_config.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_dedup.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_detect.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_disc_analysis.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_disc_provider.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_formatter.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_makemkv.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_matcher.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_normalize.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_organizer.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_planner.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_rip_guide.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_scanner.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_snapshot.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_splitter.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_tagger.py +0 -0
- {riplex-0.3.2 → riplex-0.3.3}/tests/test_ui.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: riplex
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Automates the tedious manual work around MakeMKV: figuring out what to rip, which MKV files are actually what, and organizing everything into Plex-compatible folder structures.
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -132,6 +132,6 @@ MakeMKV requires a registration key. A free beta key is available at https://for
|
|
|
132
132
|
|
|
133
133
|
### MKVToolNix (mkvmerge, mkvpropedit)
|
|
134
134
|
|
|
135
|
-
- **Windows**: `winget install
|
|
135
|
+
- **Windows**: `winget install MoritzBunkus.MKVToolNix` (or download from https://mkvtoolnix.download/)
|
|
136
136
|
- **macOS**: `brew install mkvtoolnix`
|
|
137
137
|
- **Linux**: `sudo apt install mkvtoolnix`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: riplex
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Automates the tedious manual work around MakeMKV: figuring out what to rip, which MKV files are actually what, and organizing everything into Plex-compatible folder structures.
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -38,6 +38,7 @@ class WelcomeScreen:
|
|
|
38
38
|
missing_tools.append("ffprobe")
|
|
39
39
|
if not has_mkvmerge:
|
|
40
40
|
missing_tools.append("mkvmerge")
|
|
41
|
+
self._missing_tools = missing_tools
|
|
41
42
|
|
|
42
43
|
status_rows = []
|
|
43
44
|
for label, ok in checks:
|
|
@@ -61,7 +62,7 @@ class WelcomeScreen:
|
|
|
61
62
|
ft.ElevatedButton(
|
|
62
63
|
"Install Missing Tools",
|
|
63
64
|
icon=ft.Icons.DOWNLOAD,
|
|
64
|
-
on_click=
|
|
65
|
+
on_click=self._on_install_click,
|
|
65
66
|
),
|
|
66
67
|
ft.TextButton(
|
|
67
68
|
"MakeMKV ↗",
|
|
@@ -286,15 +287,20 @@ class WelcomeScreen:
|
|
|
286
287
|
url = get_download_url(self._update_info)
|
|
287
288
|
webbrowser.open(url)
|
|
288
289
|
|
|
290
|
+
def _on_install_click(self, e):
|
|
291
|
+
"""Handle Install Missing Tools button click."""
|
|
292
|
+
self._install_status.value = "Starting installation..."
|
|
293
|
+
self.app.page.update()
|
|
294
|
+
self._install_tools(self._missing_tools)
|
|
295
|
+
|
|
289
296
|
def _install_tools(self, missing: list[str]):
|
|
290
297
|
"""Install missing tools via system package manager in background."""
|
|
291
298
|
import platform
|
|
292
299
|
import subprocess
|
|
293
|
-
import sys
|
|
294
300
|
|
|
295
301
|
system = platform.system()
|
|
296
302
|
packages = {
|
|
297
|
-
"Windows": {"makemkvcon": "
|
|
303
|
+
"Windows": {"makemkvcon": "GuinpinSoft.MakeMKV", "ffprobe": "Gyan.FFmpeg", "mkvmerge": "MoritzBunkus.MKVToolNix"},
|
|
298
304
|
"Darwin": {"makemkvcon": "makemkv", "ffprobe": "ffmpeg", "mkvmerge": "mkvtoolnix"},
|
|
299
305
|
}
|
|
300
306
|
|
|
@@ -306,34 +312,28 @@ class WelcomeScreen:
|
|
|
306
312
|
return
|
|
307
313
|
|
|
308
314
|
def _do_install():
|
|
309
|
-
async def _update_status(msg):
|
|
310
|
-
self._install_status.value = msg
|
|
311
|
-
self.app.page.update()
|
|
312
|
-
|
|
313
315
|
try:
|
|
314
316
|
if system == "Windows":
|
|
315
|
-
# Build a single winget command string to run elevated
|
|
316
317
|
cmds = " && ".join(
|
|
317
318
|
f'winget install --accept-source-agreements --accept-package-agreements {pkg}'
|
|
318
319
|
for pkg in to_install
|
|
319
320
|
)
|
|
320
|
-
self.
|
|
321
|
-
|
|
322
|
-
)
|
|
323
|
-
# Run elevated via powershell Start-Process
|
|
321
|
+
self._install_status.value = f"Installing {', '.join(to_install)}... (accept the admin prompt)"
|
|
322
|
+
self.app.page.update()
|
|
324
323
|
result = subprocess.run(
|
|
325
324
|
["powershell", "-Command",
|
|
326
|
-
f
|
|
327
|
-
|
|
325
|
+
f"Start-Process cmd -ArgumentList '/c {cmds} & pause' -Verb RunAs -Wait"],
|
|
326
|
+
capture_output=True,
|
|
327
|
+
text=True,
|
|
328
328
|
)
|
|
329
329
|
if result.returncode != 0:
|
|
330
|
-
raise subprocess.CalledProcessError(result.returncode, "winget")
|
|
330
|
+
raise subprocess.CalledProcessError(result.returncode, "winget", output=result.stdout, stderr=result.stderr)
|
|
331
331
|
elif system == "Darwin":
|
|
332
332
|
if shutil.which("brew"):
|
|
333
|
-
self.
|
|
333
|
+
self._install_status.value = "Installing via brew..."
|
|
334
|
+
self.app.page.update()
|
|
334
335
|
subprocess.run(["brew", "install"] + to_install, check=True)
|
|
335
336
|
else:
|
|
336
|
-
# No Homebrew — open download pages in browser
|
|
337
337
|
download_urls = {
|
|
338
338
|
"makemkv": "https://www.makemkv.com/download/",
|
|
339
339
|
"ffmpeg": "https://ffmpeg.org/download.html",
|
|
@@ -342,18 +342,15 @@ class WelcomeScreen:
|
|
|
342
342
|
for pkg in to_install:
|
|
343
343
|
if pkg in download_urls:
|
|
344
344
|
webbrowser.open(download_urls[pkg])
|
|
345
|
-
self.app.
|
|
346
|
-
|
|
347
|
-
)
|
|
345
|
+
self._install_status.value = "Opened download pages in your browser. Install the tools, then restart the app."
|
|
346
|
+
self.app.page.update()
|
|
348
347
|
return
|
|
349
348
|
|
|
350
|
-
self.app.
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
self.app.page.
|
|
355
|
-
lambda: _update_status(f"Install failed: {exc}. Try the manual links above.")
|
|
356
|
-
)
|
|
349
|
+
self._install_status.value = "Done! Restart the app for changes to take effect."
|
|
350
|
+
self.app.page.update()
|
|
351
|
+
except Exception as exc:
|
|
352
|
+
self._install_status.value = f"Install failed: {exc}. Try the manual links above."
|
|
353
|
+
self.app.page.update()
|
|
357
354
|
|
|
358
355
|
threading.Thread(target=_do_install, daemon=True).start()
|
|
359
356
|
|
|
@@ -12,7 +12,7 @@ def _offer_install(missing: list[str]) -> None:
|
|
|
12
12
|
|
|
13
13
|
system = platform.system()
|
|
14
14
|
packages: dict[str, dict[str, str]] = {
|
|
15
|
-
"Windows": {"makemkvcon": "
|
|
15
|
+
"Windows": {"makemkvcon": "GuinpinSoft.MakeMKV", "ffprobe": "Gyan.FFmpeg", "mkvmerge": "MoritzBunkus.MKVToolNix", "mkvpropedit": "MoritzBunkus.MKVToolNix"},
|
|
16
16
|
"Darwin": {"makemkvcon": "makemkv", "ffprobe": "ffmpeg", "mkvmerge": "mkvtoolnix", "mkvpropedit": "mkvtoolnix"},
|
|
17
17
|
"Linux": {"makemkvcon": "", "ffprobe": "ffmpeg", "mkvmerge": "mkvtoolnix", "mkvpropedit": "mkvtoolnix"},
|
|
18
18
|
}
|
|
@@ -142,13 +142,13 @@ class TestInstallToolsLogic:
|
|
|
142
142
|
def test_windows_package_mapping(self):
|
|
143
143
|
"""Verify correct winget package IDs for missing tools."""
|
|
144
144
|
packages = {
|
|
145
|
-
"makemkvcon": "
|
|
145
|
+
"makemkvcon": "GuinpinSoft.MakeMKV",
|
|
146
146
|
"ffprobe": "Gyan.FFmpeg",
|
|
147
|
-
"mkvmerge": "
|
|
147
|
+
"mkvmerge": "MoritzBunkus.MKVToolNix",
|
|
148
148
|
}
|
|
149
149
|
missing = ["ffprobe", "mkvmerge"]
|
|
150
150
|
to_install = sorted(set(packages[t] for t in missing if packages.get(t)))
|
|
151
|
-
assert to_install == ["Gyan.FFmpeg", "
|
|
151
|
+
assert to_install == ["Gyan.FFmpeg", "MoritzBunkus.MKVToolNix"]
|
|
152
152
|
|
|
153
153
|
def test_macos_package_mapping(self):
|
|
154
154
|
"""Verify correct brew package names for missing tools."""
|
|
@@ -164,9 +164,9 @@ class TestInstallToolsLogic:
|
|
|
164
164
|
def test_deduplicates_packages(self):
|
|
165
165
|
"""mkvmerge and mkvpropedit map to same package."""
|
|
166
166
|
packages = {
|
|
167
|
-
"mkvmerge": "
|
|
168
|
-
"mkvpropedit": "
|
|
167
|
+
"mkvmerge": "MoritzBunkus.MKVToolNix",
|
|
168
|
+
"mkvpropedit": "MoritzBunkus.MKVToolNix",
|
|
169
169
|
}
|
|
170
170
|
missing = ["mkvmerge", "mkvpropedit"]
|
|
171
171
|
to_install = sorted(set(packages[t] for t in missing if packages.get(t)))
|
|
172
|
-
assert to_install == ["
|
|
172
|
+
assert to_install == ["MoritzBunkus.MKVToolNix"]
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|