labnotes 0.0.16__tar.gz → 0.0.18__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.
- {labnotes-0.0.16 → labnotes-0.0.18}/PKG-INFO +9 -1
- {labnotes-0.0.16 → labnotes-0.0.18}/README.md +8 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/context.md +8 -0
- labnotes-0.0.18/src/labnotes/create_experiment.py +32 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/experiments.py +16 -4
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/models.py +1 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/read_experiment_config.py +7 -4
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/start_experiment.py +3 -2
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/open_tables.py +4 -1
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/summarize_experiments.py +2 -1
- {labnotes-0.0.16 → labnotes-0.0.18}/.gitignore +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/CHANGELOG.md +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/MIGRATIONS.md +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/pyproject.toml +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/__init__.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/asset_url.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/cell_progress.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/cli.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/context_guide.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/count_runs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/create_app.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/data_html.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/default_config_text.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/drain_watch.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/format_value.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/init.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/list_experiments.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/list_runs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/load_config.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/load_experiment.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/notebook_kernel.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/open_experiments.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/open_runs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/output_html.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/parse_run_view.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/pivot_cells.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/print_rows.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/python_blocks.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/read_config.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/read_design.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/read_note.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/read_path.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/render_markdown.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/run_columns.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/__init__.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/describe_event.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/execute_run.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/lock_path.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/new_run_id.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/param_args.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/param_grid.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/plan_runs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/run_experiment.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/run_folder.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/run_headless.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/shell_command.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/stop_then_kill.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/runner/write_run_json.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/saved_outputs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/serve_app.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/server.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/sort_href.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/sql_quote.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/static/labnotes.css +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/static/row-link.js +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/static/run-cell.js +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/static/view-toggle.js +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/stop_idle_kernels.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/study_progress.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/summarize_design.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/__init__.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/experiment_rows.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/file_prefix.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/iso_time.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/list_experiment_runs.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/path_glob.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/path_pattern.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/read_experiment.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/read_file.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tables/read_run.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/templates/base.html +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/templates/experiment.html +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/templates/index.html +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/templates/macros.html +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tui/__init__.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tui/format_elapsed.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tui/run_app.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/src/labnotes/tui/run_tui.py +0 -0
- {labnotes-0.0.16 → labnotes-0.0.18}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: labnotes
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.18
|
|
4
4
|
Summary: Browse experiment designs, notes, and run data from a folder.
|
|
5
5
|
Project-URL: Repository, https://github.com/thekevinscott/labnotes
|
|
6
6
|
Author-email: Kevin Scott <me@thekevinscott.com>
|
|
@@ -69,10 +69,15 @@ labnotes experiments foo runs # foo's runs, oldest first
|
|
|
69
69
|
|
|
70
70
|
Each takes `--format table` (the default) or `--format json`.
|
|
71
71
|
|
|
72
|
+
`labnotes experiments new [NAME]` creates an experiment folder with a starter
|
|
73
|
+
`experiment.toml`, picking a random name if you give none. `new` itself can't
|
|
74
|
+
be an experiment name.
|
|
75
|
+
|
|
72
76
|
`labnotes experiments foo run` runs `foo` from its `experiment.toml`, in the
|
|
73
77
|
experiments folder:
|
|
74
78
|
|
|
75
79
|
```toml
|
|
80
|
+
name = "Model and effort"
|
|
76
81
|
command = "uv run scripts/study.py --output {run_dir}"
|
|
77
82
|
repeats = 5
|
|
78
83
|
|
|
@@ -81,6 +86,9 @@ model = ["opus", "sonnet"]
|
|
|
81
86
|
effort = ["low", "high"]
|
|
82
87
|
```
|
|
83
88
|
|
|
89
|
+
`name` is optional: a display name for the experiment, shown in the live view
|
|
90
|
+
and as `display_name` in `experiments`. The folder name stays the key, so
|
|
91
|
+
renaming the experiment means editing `name`.
|
|
84
92
|
Each combination of `[params]` runs `repeats` times, round-robin. Only runs
|
|
85
93
|
that exit 0 count, so running again fills in what failed or never ran.
|
|
86
94
|
Each run gets a new run folder. `command` runs in a shell from the root, with
|
|
@@ -46,10 +46,15 @@ labnotes experiments foo runs # foo's runs, oldest first
|
|
|
46
46
|
|
|
47
47
|
Each takes `--format table` (the default) or `--format json`.
|
|
48
48
|
|
|
49
|
+
`labnotes experiments new [NAME]` creates an experiment folder with a starter
|
|
50
|
+
`experiment.toml`, picking a random name if you give none. `new` itself can't
|
|
51
|
+
be an experiment name.
|
|
52
|
+
|
|
49
53
|
`labnotes experiments foo run` runs `foo` from its `experiment.toml`, in the
|
|
50
54
|
experiments folder:
|
|
51
55
|
|
|
52
56
|
```toml
|
|
57
|
+
name = "Model and effort"
|
|
53
58
|
command = "uv run scripts/study.py --output {run_dir}"
|
|
54
59
|
repeats = 5
|
|
55
60
|
|
|
@@ -58,6 +63,9 @@ model = ["opus", "sonnet"]
|
|
|
58
63
|
effort = ["low", "high"]
|
|
59
64
|
```
|
|
60
65
|
|
|
66
|
+
`name` is optional: a display name for the experiment, shown in the live view
|
|
67
|
+
and as `display_name` in `experiments`. The folder name stays the key, so
|
|
68
|
+
renaming the experiment means editing `name`.
|
|
61
69
|
Each combination of `[params]` runs `repeats` times, round-robin. Only runs
|
|
62
70
|
that exit 0 count, so running again fills in what failed or never ran.
|
|
63
71
|
Each run gets a new run folder. `command` runs in a shell from the root, with
|
|
@@ -36,10 +36,15 @@ labnotes experiments foo runs # foo's runs, oldest first
|
|
|
36
36
|
|
|
37
37
|
Each takes `--format table` (the default) or `--format json`; use `--format json` when you parse the output.
|
|
38
38
|
|
|
39
|
+
`labnotes experiments new [NAME]` creates an experiment folder with a starter
|
|
40
|
+
`experiment.toml`, picking a random name if you give none. `new` itself can't
|
|
41
|
+
be an experiment name.
|
|
42
|
+
|
|
39
43
|
`labnotes experiments foo run` runs `foo` from its `experiment.toml`, in the
|
|
40
44
|
experiments folder:
|
|
41
45
|
|
|
42
46
|
```toml
|
|
47
|
+
name = "Model and effort"
|
|
43
48
|
command = "uv run scripts/study.py --output {run_dir}"
|
|
44
49
|
repeats = 5
|
|
45
50
|
|
|
@@ -48,6 +53,9 @@ model = ["opus", "sonnet"]
|
|
|
48
53
|
effort = ["low", "high"]
|
|
49
54
|
```
|
|
50
55
|
|
|
56
|
+
`name` is optional: a display name for the experiment, shown in the live view
|
|
57
|
+
and as `display_name` in `experiments`. The folder name stays the key, so
|
|
58
|
+
renaming the experiment means editing `name`.
|
|
51
59
|
Each combination of `[params]` runs `repeats` times, round-robin. Only runs
|
|
52
60
|
that exit 0 count, so running again fills in what failed or never ran.
|
|
53
61
|
Each run gets a new run folder. `command` runs in a shell from the root, with
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from labnotes.models import LabnotesConfig
|
|
4
|
+
from labnotes.runner.new_run_id import new_run_id
|
|
5
|
+
|
|
6
|
+
STARTER = """\
|
|
7
|
+
# Runs from the project root. {run_dir} becomes the run's folder.
|
|
8
|
+
command = "uv run script.py --output {run_dir}"
|
|
9
|
+
repeats = 1
|
|
10
|
+
|
|
11
|
+
# Each combination runs `repeats` times, passed as --name value.
|
|
12
|
+
[params]
|
|
13
|
+
# model = ["opus", "sonnet"]
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_experiment(config: LabnotesConfig, name: str | None) -> Path:
|
|
18
|
+
def folder(candidate: str) -> Path:
|
|
19
|
+
return config.root / config.experiments.replace("{experiment}", candidate)
|
|
20
|
+
|
|
21
|
+
if name is None:
|
|
22
|
+
name = new_run_id(lambda candidate: folder(candidate).exists())
|
|
23
|
+
if name == "new":
|
|
24
|
+
raise ValueError("new is reserved; pick another name.")
|
|
25
|
+
if "/" in name or name.startswith("."):
|
|
26
|
+
raise ValueError(f"{name} can't be an experiment name.")
|
|
27
|
+
path = folder(name)
|
|
28
|
+
if path.exists():
|
|
29
|
+
raise ValueError(f"{name} already exists at {path}.")
|
|
30
|
+
path.mkdir(parents=True)
|
|
31
|
+
(path / "experiment.toml").write_text(STARTER, encoding="utf-8")
|
|
32
|
+
return path
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import sys
|
|
3
|
-
from functools import partial
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
|
|
6
5
|
import click
|
|
7
6
|
|
|
7
|
+
from labnotes.create_experiment import create_experiment
|
|
8
8
|
from labnotes.load_config import load_config
|
|
9
9
|
from labnotes.print_rows import print_rows
|
|
10
10
|
from labnotes.read_config import CONFIG_FILE
|
|
@@ -14,9 +14,12 @@ from labnotes.tables.experiment_rows import experiment_rows
|
|
|
14
14
|
from labnotes.tui.run_tui import run_tui
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
@click.command(
|
|
17
|
+
@click.command(
|
|
18
|
+
help="List experiments, show one, list its runs, or run it."
|
|
19
|
+
" `new [NAME]` creates one."
|
|
20
|
+
)
|
|
18
21
|
@click.argument("name", required=False)
|
|
19
|
-
@click.argument("action", required=False,
|
|
22
|
+
@click.argument("action", required=False, metavar="[runs|run]")
|
|
20
23
|
@click.option(
|
|
21
24
|
"--format",
|
|
22
25
|
"output_format",
|
|
@@ -58,9 +61,16 @@ def experiments(
|
|
|
58
61
|
f"No {CONFIG_FILE} here. Run labnotes init, or pass -c PATH."
|
|
59
62
|
)
|
|
60
63
|
match name, action:
|
|
64
|
+
case "new", _:
|
|
65
|
+
try:
|
|
66
|
+
path = create_experiment(config, action)
|
|
67
|
+
except ValueError as error:
|
|
68
|
+
raise click.ClickException(str(error)) from error
|
|
69
|
+
click.echo(f"Created {path / 'experiment.toml'}")
|
|
70
|
+
return
|
|
61
71
|
case str(), "run":
|
|
62
72
|
live = sys.stdout.isatty() and sys.stderr.isatty() and not no_tui
|
|
63
|
-
drive =
|
|
73
|
+
drive = run_tui if live else lambda start, title: run_headless(start)
|
|
64
74
|
try:
|
|
65
75
|
results = start_experiment(
|
|
66
76
|
config, name, experiment_config, concurrency, drive
|
|
@@ -70,6 +80,8 @@ def experiments(
|
|
|
70
80
|
failed = sum(result["exit_code"] != 0 for result in results)
|
|
71
81
|
click.echo(f"{len(results) - failed} passed, {failed} failed.")
|
|
72
82
|
ctx.exit(1 if failed else 0)
|
|
83
|
+
if action not in (None, "runs"):
|
|
84
|
+
raise click.UsageError(f"Unknown action {action}. Use runs or run.")
|
|
73
85
|
rows = asyncio.run(experiment_rows(config, name, action))
|
|
74
86
|
if rows is None:
|
|
75
87
|
raise click.ClickException(f"No experiment named {name}.")
|
|
@@ -4,7 +4,7 @@ from pathlib import Path
|
|
|
4
4
|
|
|
5
5
|
from labnotes.models import ExperimentConfig
|
|
6
6
|
|
|
7
|
-
SETTINGS = {"command", "repeats", "params"}
|
|
7
|
+
SETTINGS = {"name", "command", "repeats", "params"}
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def read_experiment_config(path: Path) -> ExperimentConfig:
|
|
@@ -16,6 +16,9 @@ def read_experiment_config(path: Path) -> ExperimentConfig:
|
|
|
16
16
|
unknown = sorted(values.keys() - SETTINGS)
|
|
17
17
|
if unknown:
|
|
18
18
|
raise ValueError(f"{path}: unknown keys {', '.join(unknown)}")
|
|
19
|
+
name = values.get("name")
|
|
20
|
+
if name is not None and (not isinstance(name, str) or not name.strip()):
|
|
21
|
+
raise ValueError(f"{path}: name must be a string")
|
|
19
22
|
command = values.get("command")
|
|
20
23
|
if not isinstance(command, str) or not command.strip():
|
|
21
24
|
raise ValueError(f"{path}: command must be a string")
|
|
@@ -25,11 +28,11 @@ def read_experiment_config(path: Path) -> ExperimentConfig:
|
|
|
25
28
|
params = values.get("params", {})
|
|
26
29
|
if not isinstance(params, dict):
|
|
27
30
|
raise ValueError(f"{path}: params must be a table, like [params]")
|
|
28
|
-
for
|
|
31
|
+
for param, options in params.items():
|
|
29
32
|
if not isinstance(options, list) or not options:
|
|
30
|
-
raise ValueError(f"{path}: params.{
|
|
33
|
+
raise ValueError(f"{path}: params.{param} must be a non-empty list")
|
|
31
34
|
try:
|
|
32
35
|
json.dumps(params)
|
|
33
36
|
except TypeError as error:
|
|
34
37
|
raise ValueError(f"{path}: params can't hold dates or times") from error
|
|
35
|
-
return ExperimentConfig(command, repeats, params)
|
|
38
|
+
return ExperimentConfig(command, repeats, params, name)
|
|
@@ -15,7 +15,7 @@ def start_experiment(
|
|
|
15
15
|
name: str,
|
|
16
16
|
experiment_config: Path | None,
|
|
17
17
|
concurrency: int,
|
|
18
|
-
drive: Callable[[Start], list[dict[str, object]]],
|
|
18
|
+
drive: Callable[[Start, str], list[dict[str, object]]],
|
|
19
19
|
) -> list[dict[str, object]]:
|
|
20
20
|
if experiment_config is None:
|
|
21
21
|
folder = config.experiments.replace("{experiment}", name)
|
|
@@ -27,6 +27,7 @@ def start_experiment(
|
|
|
27
27
|
lock.parent.mkdir(parents=True, exist_ok=True)
|
|
28
28
|
try:
|
|
29
29
|
with FileLock(lock, blocking=False):
|
|
30
|
-
|
|
30
|
+
start = partial(run_experiment, config, name, experiment, concurrency)
|
|
31
|
+
return drive(start, experiment.name or name)
|
|
31
32
|
except Timeout as error:
|
|
32
33
|
raise ValueError(f"{name} is already running ({lock} is held).") from error
|
|
@@ -12,7 +12,10 @@ from labnotes.tables.read_run import read_run
|
|
|
12
12
|
EXPERIMENTS = """
|
|
13
13
|
CREATE TABLE experiment_configs (experiment TEXT PRIMARY KEY, config TEXT);
|
|
14
14
|
CREATE VIEW experiments AS
|
|
15
|
-
SELECT
|
|
15
|
+
SELECT
|
|
16
|
+
names.name,
|
|
17
|
+
coalesce(experiment_configs.config ->> 'name', names.name) AS display_name,
|
|
18
|
+
experiment_configs.config
|
|
16
19
|
FROM (
|
|
17
20
|
SELECT experiment AS name FROM experiment_configs
|
|
18
21
|
UNION SELECT experiment FROM files
|
|
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
|