lecrapaud 2.3.0__tar.gz → 2.3.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.
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/PKG-INFO +1 -1
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/feature_selection.py +24 -5
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/model_selection.py +61 -15
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/experiment.py +1 -1
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/feature_selection.py +15 -1
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/pyproject.toml +2 -1
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/LICENSE +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/README.md +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/__init__.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/base.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/business_objective.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/column_suggester.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/config.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/context_search_space.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/__init__.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/README +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/env.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/script.py.mako +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_06_23_1748-f089dfb7e3ba_.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_06_24_1216-c62251b129ed_.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_06_24_1711-86457e2f333f_.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_06_25_1759-72aa496ca65b_.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_08_25_1434-7ed9963e732f_add_best_score_to_model_selection.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_08_28_1516-c36e9fee22b9_add_avg_precision_to_score.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_08_28_1622-8b11c1ba982e_change_name_column.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_10_25_0635-07e303521594_add_unique_constraint_to_score.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_10_26_1727-033e0f7eca4f_merge_score_and_model_trainings_into_.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_10_28_2006-0a8fb7826e9b_add_number_of_targets_and_remove_other_.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_12_16_1644-9a191ae1c27d_add_bias_to_score.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_12_20_1915-99108bd42b68_add_score_to_experiment.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_01_21_1814-a1b2c3d4e5f6_add_artifact_storage.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_01_21_1830-b2c3d4e5f6g7_migrate_files_to_db.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_01_26_1942-f723ecc52b89_rename_model_to_model_type.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_01_26_2120-080475ab231a_rename_model_selection_to_best_model.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_01_28_1427-dc9b28c3e796_fix_wrong_model_type_for_classification.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_01_28_1616-721327520692_remove_best_prefix_from_best_model.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_01_28_1721-0e47cb122c58_fix_method_names.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_03_31_1600-a1b2c3d4e5f7_add_state_to_experiments.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_05_29_2100-c1d2e3f4a5b6_add_resume_keys_to_experiments.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_05_29_2200-e3f4a5b6c7d8_add_studies_table.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_05_29_2210-f4a5b6c7d8e9_add_headline_score_to_models.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_05_30_1000-c3d4e5f6a7b8_add_production_experiment_to_studies.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_05_30_1030-d4e5f6a7b8c9_add_experiment_version_and_study_promotions.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_06_03_1300-p1q2r3s4t5u6_add_phase_step_to_experiments.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2026_06_03_1400-q1r2s3t4u5v6_size_nullable.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic.ini +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/session.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/directories.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/experiment.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/feature_engineering.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/feature_preprocessing.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/integrations/ollama_integration.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/integrations/openai_integration.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/integrations/sentry_integration.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/metrics.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/misc/tabpfn_tests.ipynb +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/misc/test-gpu-bilstm.ipynb +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/misc/test-gpu-resnet.ipynb +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/misc/test-gpu-transformers.ipynb +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/mixins.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/model.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/model_preprocessing.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/__init__.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/base.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/best_model.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/experiment_artifact.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/experiment_data.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/feature.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/feature_selection_rank.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/model.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/model_type.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/study.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/study_promotion.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/target.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/models/utils.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/pipeline.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/search_space.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/services/__init__.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/services/artifact_service.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/services/embedding_service.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/tabular_dl.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/torch_models.py +0 -0
- {lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/utils.py +0 -0
|
@@ -1634,11 +1634,30 @@ class FeatureSelector(LeCrapaudEstimatorMixin):
|
|
|
1634
1634
|
# utils
|
|
1635
1635
|
# TODO : can we use this to select the ideal number of features ?
|
|
1636
1636
|
def feature_selection_analysis(feature_selection_id: int, n_components: int = 5):
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1637
|
+
# `FS.features` is `lazy="select"` (changed from selectin to drop
|
|
1638
|
+
# the cascading explosion on API endpoints). Wrap the load + the
|
|
1639
|
+
# M2M materialisation inside one session so the access at line
|
|
1640
|
+
# below doesn't hit DetachedInstanceError. Same goes for
|
|
1641
|
+
# `.experiment.path` and `.target.name` — selectin'd at parent
|
|
1642
|
+
# level, so post-session access is fine for those.
|
|
1643
|
+
from lecrapaud.db.session import get_db
|
|
1644
|
+
from sqlalchemy.orm import selectinload as _selectin
|
|
1645
|
+
|
|
1646
|
+
with get_db() as _db:
|
|
1647
|
+
feature_selection = (
|
|
1648
|
+
_db.query(FeatureSelection)
|
|
1649
|
+
.options(_selectin(FeatureSelection.features))
|
|
1650
|
+
.filter(FeatureSelection.id == feature_selection_id)
|
|
1651
|
+
.first()
|
|
1652
|
+
)
|
|
1653
|
+
if feature_selection is None:
|
|
1654
|
+
raise ValueError(f"FeatureSelection {feature_selection_id} not found")
|
|
1655
|
+
# Materialise everything we need from the session BEFORE
|
|
1656
|
+
# the context manager exits (post-exit attribute access is
|
|
1657
|
+
# OK for selectin-loaded relationships).
|
|
1658
|
+
features = [f.name for f in feature_selection.features]
|
|
1659
|
+
experiment_dir = feature_selection.experiment.path
|
|
1660
|
+
target = feature_selection.target.name
|
|
1642
1661
|
target_number = target.split("_")[1]
|
|
1643
1662
|
|
|
1644
1663
|
train, val, train_scaled, val_scaled, _scaler_y = load_train_data(
|
|
@@ -119,6 +119,44 @@ def test_hardware():
|
|
|
119
119
|
warnings.filterwarnings("ignore", category=UserWarning, module="pydantic")
|
|
120
120
|
|
|
121
121
|
|
|
122
|
+
def _safe_concatenate(data_list, axis=0):
|
|
123
|
+
"""
|
|
124
|
+
Safely concatenate data regardless of whether it's numpy arrays or pandas objects.
|
|
125
|
+
|
|
126
|
+
This function detects the data type and uses the appropriate concatenation method:
|
|
127
|
+
- np.concatenate for numpy arrays
|
|
128
|
+
- pd.concat for pandas Series/DataFrames
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
data_list: List of data objects to concatenate
|
|
132
|
+
axis: Axis along which to concatenate
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Concatenated data using the appropriate method
|
|
136
|
+
"""
|
|
137
|
+
if not data_list:
|
|
138
|
+
raise ValueError("Cannot concatenate empty list")
|
|
139
|
+
|
|
140
|
+
# Check the type of the first non-None element
|
|
141
|
+
first_data = next((d for d in data_list if d is not None), None)
|
|
142
|
+
if first_data is None:
|
|
143
|
+
raise ValueError("All data elements are None")
|
|
144
|
+
|
|
145
|
+
# Determine the data type and use appropriate concatenation method
|
|
146
|
+
if isinstance(first_data, np.ndarray):
|
|
147
|
+
# Use numpy concatenation for numpy arrays
|
|
148
|
+
return np.concatenate(data_list, axis=axis)
|
|
149
|
+
elif isinstance(first_data, (pd.DataFrame, pd.Series)):
|
|
150
|
+
# Use pandas concatenation for pandas objects
|
|
151
|
+
return pd.concat(data_list, axis=axis)
|
|
152
|
+
else:
|
|
153
|
+
# For other types, try pandas first, fallback to numpy
|
|
154
|
+
try:
|
|
155
|
+
return pd.concat(data_list, axis=axis)
|
|
156
|
+
except (TypeError, ValueError):
|
|
157
|
+
return np.concatenate(data_list, axis=axis)
|
|
158
|
+
|
|
159
|
+
|
|
122
160
|
def trainable_cv(
|
|
123
161
|
params,
|
|
124
162
|
x_train,
|
|
@@ -152,13 +190,13 @@ def trainable_cv(
|
|
|
152
190
|
in `LeCrapaudModel.fit_boosting._sort_for_ranking`.
|
|
153
191
|
"""
|
|
154
192
|
# Combine train and validation data for cross-validation
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
193
|
+
# Use safe concatenation to handle mixed data types properly
|
|
194
|
+
x_train_val = _safe_concatenate([x_train, x_val], axis=0)
|
|
195
|
+
y_train_val = _safe_concatenate([y_train, y_val], axis=0)
|
|
196
|
+
|
|
197
|
+
# Store original index for later use if needed (only for pandas objects)
|
|
198
|
+
original_index = None
|
|
199
|
+
if hasattr(x_train_val, 'index'):
|
|
162
200
|
original_index = x_train_val.index.copy()
|
|
163
201
|
# Reset index for proper iloc indexing with CV splits
|
|
164
202
|
x_train_val = x_train_val.reset_index(drop=True)
|
|
@@ -557,6 +595,19 @@ class ModelSelector(LeCrapaudEstimatorMixin):
|
|
|
557
595
|
|
|
558
596
|
if self.target_number is not None:
|
|
559
597
|
self.features = self.experiment.get_features(self.target_number)
|
|
598
|
+
# Feature selection can legitimately end up keeping nothing
|
|
599
|
+
# (over-strict thresholds, too few samples, all-constant
|
|
600
|
+
# columns). Training on a (N, 0) matrix raises the opaque
|
|
601
|
+
# sklearn "Found array with 0 feature(s)" deep in the fit
|
|
602
|
+
# call — fail fast here with an actionable message instead.
|
|
603
|
+
if not self.features:
|
|
604
|
+
raise ValueError(
|
|
605
|
+
f"Feature selection produced 0 features for "
|
|
606
|
+
f"TARGET_{self.target_number} (experiment "
|
|
607
|
+
f"{self.experiment_id}). Cannot train on an empty "
|
|
608
|
+
f"feature matrix — check the input data or relax the "
|
|
609
|
+
f"feature-selection thresholds."
|
|
610
|
+
)
|
|
560
611
|
|
|
561
612
|
self.all_features = self.experiment.get_all_features(
|
|
562
613
|
date_column=self.date_column, group_column=self.group_column
|
|
@@ -865,14 +916,9 @@ class ModelSelector(LeCrapaudEstimatorMixin):
|
|
|
865
916
|
|
|
866
917
|
# Always evaluate on test set (no cross-validation here)
|
|
867
918
|
# The hyperopt already did CV if needed to find best params.
|
|
868
|
-
#
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
x_train_full = np.concatenate([x_train, x_val], axis=0)
|
|
872
|
-
y_train_full = np.concatenate([y_train, y_val], axis=0)
|
|
873
|
-
else:
|
|
874
|
-
x_train_full = pd.concat([x_train, x_val], axis=0)
|
|
875
|
-
y_train_full = pd.concat([y_train, y_val], axis=0)
|
|
919
|
+
# Use safe concatenation to handle mixed data types properly
|
|
920
|
+
x_train_full = _safe_concatenate([x_train, x_val], axis=0)
|
|
921
|
+
y_train_full = _safe_concatenate([y_train, y_val], axis=0)
|
|
876
922
|
# Combine the per-row ranking groups the same way for the final
|
|
877
923
|
# fit (train+val together, test on its own). `None` when not ranking.
|
|
878
924
|
train_full_groups = None
|
|
@@ -444,7 +444,7 @@ class Experiment(Base):
|
|
|
444
444
|
own_contribs = self._headline_contributions()
|
|
445
445
|
if not own_contribs:
|
|
446
446
|
if self.state == self.STATE_COMPLETED:
|
|
447
|
-
logger.
|
|
447
|
+
logger.warning(
|
|
448
448
|
f"Completed experiment {self.id} has no usable scores "
|
|
449
449
|
f"(no headline / rmse / logloss on any Best Model)"
|
|
450
450
|
)
|
|
@@ -97,7 +97,21 @@ class FeatureSelection(Base):
|
|
|
97
97
|
"Feature",
|
|
98
98
|
secondary=lecrapaud_feature_selection_association,
|
|
99
99
|
back_populates="feature_selections",
|
|
100
|
-
lazy="selectin
|
|
100
|
+
# `lazy="select"` (default) instead of `selectin`. The M2M
|
|
101
|
+
# association explodes the query cost when an Experiment is
|
|
102
|
+
# loaded (via the cascading selectin from
|
|
103
|
+
# Experiment.feature_selections → each FS → features here).
|
|
104
|
+
# For a 12-target / ~200-feature run, this is ~2400 Feature
|
|
105
|
+
# rows + the join table — pure cost for any API endpoint
|
|
106
|
+
# that doesn't render features.
|
|
107
|
+
# Trade-off: accessing `fs.features` AFTER the session closes
|
|
108
|
+
# raises DetachedInstanceError. All internal lecrapaud
|
|
109
|
+
# accesses already happen inside `@with_db` (get_features,
|
|
110
|
+
# get_all_features); the one utility that didn't is now
|
|
111
|
+
# wrapped explicitly. External consumers that need the M2M
|
|
112
|
+
# outside a session should pass `selectinload(FS.features)`
|
|
113
|
+
# in their query.
|
|
114
|
+
lazy="select",
|
|
101
115
|
)
|
|
102
116
|
|
|
103
117
|
__table_args__ = (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "lecrapaud"
|
|
3
|
-
version = "2.3.
|
|
3
|
+
version = "2.3.2"
|
|
4
4
|
description = "Framework for machine and deep learning, with regression, classification and time series analysis"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Pierre H. Gallet"}
|
|
@@ -94,4 +94,5 @@ requires = ["poetry-core"]
|
|
|
94
94
|
[tool.pytest.ini_options]
|
|
95
95
|
markers = [
|
|
96
96
|
"order: reorder test execution",
|
|
97
|
+
"slow: trains real models end-to-end; deselect for a fast loop with -m 'not slow'",
|
|
97
98
|
]
|
|
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
|
{lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_06_23_1748-f089dfb7e3ba_.py
RENAMED
|
File without changes
|
{lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_06_24_1216-c62251b129ed_.py
RENAMED
|
File without changes
|
{lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_06_24_1711-86457e2f333f_.py
RENAMED
|
File without changes
|
{lecrapaud-2.3.0 → lecrapaud-2.3.2}/lecrapaud/db/alembic/versions/2025_06_25_1759-72aa496ca65b_.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
|
|
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
|