usecli 0.1.43__tar.gz → 0.1.45__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.
- {usecli-0.1.43 → usecli-0.1.45}/PKG-INFO +1 -1
- {usecli-0.1.43 → usecli-0.1.45}/pyproject.toml +1 -1
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/init_command.py +8 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/config/colors.py +155 -13
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/ui/title.py +3 -2
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/shared/config/manager.py +8 -1
- {usecli-0.1.43 → usecli-0.1.45}/LICENSE +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/README.md +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/README.md +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/custom/README.md +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/custom/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/base/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/base/about_command.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/base/help_command.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/base/inspire_command.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/base/internal/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/core/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/core/utils.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/make/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/make/make_command.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/make/make_theme_command.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/config/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/base_command.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/error/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/error/handler.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/error/utils.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/exceptions/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/exceptions/base.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/exceptions/config.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/exceptions/usage.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/exceptions/validation.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/skill_generator.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/ui/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/ui/list.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/ui/title.txt +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/validators/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/validators/network.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/validators/numeric.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/validators/path.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/core/validators/string.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/services/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/services/command_service.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/templates/command.py.j2 +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/templates/theme.toml.j2 +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/templates/usecli.config.toml.j2 +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/themes/ayu_dark.toml +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/themes/catppuccin_frappe.toml +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/themes/catppuccin_latte.toml +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/themes/catppuccin_macchiato.toml +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/themes/catppuccin_mocha.toml +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/themes/default.toml +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/themes/dracula.toml +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/themes/gruvbox_dark.toml +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/themes/nord.toml +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/themes/tokyo_night.toml +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/utils/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/utils/interactive/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/utils/interactive/terminal_menu.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/menu.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/params.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/shared/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/shared/config/__init__.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/shared/config/globals.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/ui.py +0 -0
- {usecli-0.1.43 → usecli-0.1.45}/src/usecli/usecli.config.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "usecli"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.45"
|
|
4
4
|
description = "A powerful Python CLI framework for building beautiful, developer-friendly command-line tools."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Edward Boswell", email = "thememium@gmail.com" }]
|
|
@@ -103,15 +103,21 @@ class InitCommand(BaseCommand):
|
|
|
103
103
|
if not should_overwrite:
|
|
104
104
|
return "skipped"
|
|
105
105
|
|
|
106
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
106
107
|
config_path.write_text(config_content.rstrip() + "\n")
|
|
107
108
|
return "updated" if existed else "created"
|
|
108
109
|
|
|
110
|
+
def _should_skip_config_path(self, path: Path) -> bool:
|
|
111
|
+
return any(part in ConfigManager._SKIP_DIRS for part in path.parts)
|
|
112
|
+
|
|
109
113
|
def _resolve_config_path(self, value: str, project_root: Path) -> Path:
|
|
110
114
|
path = Path(value).expanduser()
|
|
111
115
|
if not path.is_absolute():
|
|
112
116
|
path = project_root / path
|
|
113
117
|
if path.exists() and path.is_dir():
|
|
114
118
|
return (path / USECLI_CONFIG_TOML).resolve()
|
|
119
|
+
if not path.exists() and path.suffix == "":
|
|
120
|
+
return (path / USECLI_CONFIG_TOML).resolve()
|
|
115
121
|
return path.resolve()
|
|
116
122
|
|
|
117
123
|
def _ensure_project_scripts(
|
|
@@ -707,6 +713,8 @@ include = ["{root_package}*"]
|
|
|
707
713
|
if commands_path.parent != project_root:
|
|
708
714
|
config_root = commands_path.parent
|
|
709
715
|
existing_config = ConfigManager(start_dir=config_root).usecli_config_path
|
|
716
|
+
if existing_config.exists() and self._should_skip_config_path(existing_config):
|
|
717
|
+
existing_config = config_root / USECLI_CONFIG_TOML
|
|
710
718
|
default_config_path = (
|
|
711
719
|
existing_config
|
|
712
720
|
if existing_config.exists()
|
|
@@ -15,8 +15,9 @@ import importlib.metadata
|
|
|
15
15
|
import importlib.util
|
|
16
16
|
import os
|
|
17
17
|
import sys
|
|
18
|
+
import time
|
|
18
19
|
from pathlib import Path
|
|
19
|
-
from typing import Any, Callable, Final, final
|
|
20
|
+
from typing import Any, Callable, Final, Protocol, cast, final
|
|
20
21
|
|
|
21
22
|
if sys.version_info >= (3, 11):
|
|
22
23
|
import tomllib
|
|
@@ -233,9 +234,11 @@ def _find_project_root(start_dir: Path | None = None) -> Path | None:
|
|
|
233
234
|
return git_root
|
|
234
235
|
|
|
235
236
|
|
|
236
|
-
def _load_usecli_config(
|
|
237
|
+
def _load_usecli_config(
|
|
238
|
+
project_root: Path | None,
|
|
239
|
+
) -> tuple[dict[str, Any], Path | None]:
|
|
237
240
|
if project_root is None:
|
|
238
|
-
return {}
|
|
241
|
+
return {}, None
|
|
239
242
|
|
|
240
243
|
config_path = project_root / USECLI_CONFIG_TOML
|
|
241
244
|
if not config_path.exists():
|
|
@@ -247,14 +250,14 @@ def _load_usecli_config(project_root: Path | None) -> dict[str, Any]:
|
|
|
247
250
|
if not config_path or not config_path.exists():
|
|
248
251
|
console_match = _find_usecli_config_for_console_script()
|
|
249
252
|
if console_match:
|
|
250
|
-
return _load_usecli_config_file(console_match)
|
|
253
|
+
return _load_usecli_config_file(console_match), console_match
|
|
251
254
|
package_match = _find_usecli_config_in_package()
|
|
252
255
|
if package_match:
|
|
253
256
|
config_path = package_match
|
|
254
257
|
if not config_path or not config_path.exists():
|
|
255
|
-
return {}
|
|
258
|
+
return {}, None
|
|
256
259
|
|
|
257
|
-
return _load_usecli_config_file(config_path)
|
|
260
|
+
return _load_usecli_config_file(config_path), config_path
|
|
258
261
|
|
|
259
262
|
|
|
260
263
|
def _load_usecli_config_file(config_path: Path) -> dict[str, Any]:
|
|
@@ -461,16 +464,16 @@ def _load_theme_file(theme_path: Path) -> dict[str, Any]:
|
|
|
461
464
|
return data
|
|
462
465
|
|
|
463
466
|
|
|
464
|
-
def _load_theme() -> tuple[dict[str, str], dict[str, str]]:
|
|
467
|
+
def _load_theme() -> tuple[dict[str, str], dict[str, str], str, Path | None]:
|
|
465
468
|
project_root = _find_project_root()
|
|
466
|
-
|
|
469
|
+
config_values, _ = _load_usecli_config(project_root)
|
|
467
470
|
|
|
468
471
|
theme_name = DEFAULT_THEME_NAME
|
|
469
|
-
config_theme =
|
|
472
|
+
config_theme = config_values.get("theme")
|
|
470
473
|
if isinstance(config_theme, str) and config_theme.strip():
|
|
471
474
|
theme_name = config_theme.strip()
|
|
472
475
|
|
|
473
|
-
theme_path = _resolve_theme_path(theme_name, project_root,
|
|
476
|
+
theme_path = _resolve_theme_path(theme_name, project_root, config_values)
|
|
474
477
|
theme_data = _load_theme_file(theme_path) if theme_path else {}
|
|
475
478
|
|
|
476
479
|
colors = _merge_theme_values(
|
|
@@ -480,14 +483,153 @@ def _load_theme() -> tuple[dict[str, str], dict[str, str]]:
|
|
|
480
483
|
)
|
|
481
484
|
ansi = _build_ansi_palette(colors)
|
|
482
485
|
|
|
483
|
-
return colors, ansi
|
|
486
|
+
return colors, ansi, theme_name, theme_path
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
_THEME_CACHE: dict[str, Any] = {
|
|
490
|
+
"context": None,
|
|
491
|
+
"cwd": None,
|
|
492
|
+
"config_path": None,
|
|
493
|
+
"config_sig": None,
|
|
494
|
+
"last_checked": 0.0,
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def _config_signature(path: Path) -> tuple[Path, int | None, int | None]:
|
|
499
|
+
try:
|
|
500
|
+
stat = path.stat()
|
|
501
|
+
except OSError:
|
|
502
|
+
return (path.resolve(), None, None)
|
|
503
|
+
return (path.resolve(), int(stat.st_mtime), int(stat.st_size))
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def _compute_theme_context() -> tuple[Path | None, Path | None, str, Path | None]:
|
|
507
|
+
project_root = _find_project_root()
|
|
508
|
+
config_values, config_path = _load_usecli_config(project_root)
|
|
509
|
+
theme_name = DEFAULT_THEME_NAME
|
|
510
|
+
config_theme = config_values.get("theme")
|
|
511
|
+
if isinstance(config_theme, str) and config_theme.strip():
|
|
512
|
+
theme_name = config_theme.strip()
|
|
513
|
+
theme_path = _resolve_theme_path(theme_name, project_root, config_values)
|
|
514
|
+
return (
|
|
515
|
+
project_root.resolve() if project_root else None,
|
|
516
|
+
config_path.resolve() if config_path else None,
|
|
517
|
+
theme_name,
|
|
518
|
+
theme_path.resolve() if theme_path else None,
|
|
519
|
+
)
|
|
484
520
|
|
|
485
521
|
|
|
486
|
-
|
|
522
|
+
def _theme_context() -> tuple[Path | None, Path | None, str, Path | None]:
|
|
523
|
+
now = time.monotonic()
|
|
524
|
+
cached_context = _THEME_CACHE.get("context")
|
|
525
|
+
cached_cwd = _THEME_CACHE.get("cwd")
|
|
526
|
+
cached_sig = _THEME_CACHE.get("config_sig")
|
|
527
|
+
cached_path = _THEME_CACHE.get("config_path")
|
|
528
|
+
|
|
529
|
+
cwd = Path.cwd().resolve()
|
|
530
|
+
if cached_context is not None and cached_cwd == cwd:
|
|
531
|
+
if cached_path is None:
|
|
532
|
+
return cached_context
|
|
533
|
+
if now - float(_THEME_CACHE.get("last_checked", 0.0)) < 0.25:
|
|
534
|
+
return cached_context
|
|
535
|
+
_THEME_CACHE["last_checked"] = now
|
|
536
|
+
current_sig = _config_signature(cached_path)
|
|
537
|
+
if current_sig == cached_sig:
|
|
538
|
+
return cached_context
|
|
539
|
+
|
|
540
|
+
context = _compute_theme_context()
|
|
541
|
+
_THEME_CACHE["context"] = context
|
|
542
|
+
_THEME_CACHE["cwd"] = cwd
|
|
543
|
+
config_path = context[1]
|
|
544
|
+
_THEME_CACHE["config_path"] = config_path
|
|
545
|
+
_THEME_CACHE["config_sig"] = _config_signature(config_path) if config_path else None
|
|
546
|
+
_THEME_CACHE["last_checked"] = now
|
|
547
|
+
return context
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
class _AnsiNamespace(Protocol):
|
|
551
|
+
PRIMARY: str
|
|
552
|
+
SECONDARY: str
|
|
553
|
+
ACCENT: str
|
|
554
|
+
FOREGROUND: str
|
|
555
|
+
FOREGROUND_MUTED: str
|
|
556
|
+
RESET: str
|
|
557
|
+
RED: str
|
|
558
|
+
GREEN: str
|
|
559
|
+
YELLOW: str
|
|
560
|
+
BLUE: str
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
class _ColorNamespace(Protocol):
|
|
564
|
+
ANSI: type[_AnsiNamespace]
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def _apply_theme(
|
|
568
|
+
color_class: _ColorNamespace, colors: dict[str, str], ansi: dict[str, str]
|
|
569
|
+
) -> None:
|
|
570
|
+
for key in (
|
|
571
|
+
"primary",
|
|
572
|
+
"secondary",
|
|
573
|
+
"accent",
|
|
574
|
+
"success",
|
|
575
|
+
"error",
|
|
576
|
+
"warning",
|
|
577
|
+
"info",
|
|
578
|
+
"foreground",
|
|
579
|
+
"foreground_muted",
|
|
580
|
+
"background",
|
|
581
|
+
"border",
|
|
582
|
+
"border_focus",
|
|
583
|
+
"command",
|
|
584
|
+
"option",
|
|
585
|
+
"link",
|
|
586
|
+
"prompt",
|
|
587
|
+
"panel_primary",
|
|
588
|
+
"panel_secondary",
|
|
589
|
+
"panel_accent",
|
|
590
|
+
):
|
|
591
|
+
setattr(color_class, key.upper(), colors[key])
|
|
592
|
+
|
|
593
|
+
ansi_class = color_class.ANSI
|
|
594
|
+
for key in (
|
|
595
|
+
"primary",
|
|
596
|
+
"secondary",
|
|
597
|
+
"accent",
|
|
598
|
+
"foreground",
|
|
599
|
+
"foreground_muted",
|
|
600
|
+
"reset",
|
|
601
|
+
"red",
|
|
602
|
+
"green",
|
|
603
|
+
"yellow",
|
|
604
|
+
"blue",
|
|
605
|
+
):
|
|
606
|
+
setattr(ansi_class, key.upper(), ansi[key])
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
def _ensure_theme_loaded(color_class: type[Any]) -> None:
|
|
610
|
+
global _THEME_CONTEXT
|
|
611
|
+
context = _theme_context()
|
|
612
|
+
if context == _THEME_CONTEXT:
|
|
613
|
+
return
|
|
614
|
+
colors, ansi, _, _ = _load_theme()
|
|
615
|
+
_THEME_CONTEXT = context
|
|
616
|
+
_THEME_COLORS.update(colors)
|
|
617
|
+
_THEME_ANSI.update(ansi)
|
|
618
|
+
_apply_theme(cast(_ColorNamespace, color_class), _THEME_COLORS, _THEME_ANSI)
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
_THEME_COLORS, _THEME_ANSI, _THEME_NAME, _THEME_PATH = _load_theme()
|
|
622
|
+
_THEME_CONTEXT: tuple[Path | None, Path | None, str, Path | None] = _theme_context()
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
class _ColorMeta(type):
|
|
626
|
+
def __getattribute__(cls, name: str) -> Any:
|
|
627
|
+
_ensure_theme_loaded(cls)
|
|
628
|
+
return super().__getattribute__(name)
|
|
487
629
|
|
|
488
630
|
|
|
489
631
|
@final
|
|
490
|
-
class COLOR:
|
|
632
|
+
class COLOR(metaclass=_ColorMeta):
|
|
491
633
|
"""Semantic color system for usecli CLI.
|
|
492
634
|
|
|
493
635
|
All colors are defined as hex color codes compatible with Rich console.
|
|
@@ -68,8 +68,9 @@ def get_project_name() -> str:
|
|
|
68
68
|
# First, try to get the title from the config
|
|
69
69
|
config = get_config()
|
|
70
70
|
title = config.get("title")
|
|
71
|
-
if title and title
|
|
72
|
-
|
|
71
|
+
if config.has_key("title") and isinstance(title, str) and title.strip():
|
|
72
|
+
normalized = title.strip()
|
|
73
|
+
return "useCli" if normalized == "usecli" else normalized
|
|
73
74
|
|
|
74
75
|
# Fall back to command name from pyproject.toml scripts
|
|
75
76
|
command_name = _get_script_command_name(Path.cwd())
|
|
@@ -582,8 +582,15 @@ _config_manager: ConfigManager | None = None
|
|
|
582
582
|
def get_config() -> ConfigManager:
|
|
583
583
|
"""Get the global ConfigManager instance."""
|
|
584
584
|
global _config_manager
|
|
585
|
+
current_root = find_project_root(Path.cwd())
|
|
586
|
+
if current_root is None:
|
|
587
|
+
current_root = Path.cwd().resolve()
|
|
585
588
|
if _config_manager is None:
|
|
586
|
-
_config_manager = ConfigManager()
|
|
589
|
+
_config_manager = ConfigManager(start_dir=Path.cwd())
|
|
590
|
+
else:
|
|
591
|
+
cached_root = _config_manager.project_root.resolve()
|
|
592
|
+
if cached_root != current_root.resolve():
|
|
593
|
+
_config_manager = ConfigManager(start_dir=Path.cwd())
|
|
587
594
|
return _config_manager
|
|
588
595
|
|
|
589
596
|
|
|
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
|
{usecli-0.1.43 → usecli-0.1.45}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py
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
|
|
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
|