From d327f2e2b937d4b118b362d8012984a88d158bf9 Mon Sep 17 00:00:00 2001 From: allegroai <> Date: Tue, 22 Dec 2020 23:25:37 +0200 Subject: [PATCH] clearml initial version 0.17.0 --- README.md | 245 ++-- clearml/__init__.py | 6 +- clearml/automation/__init__.py | 3 +- clearml/automation/auto_scaler.py | 22 +- clearml/automation/aws_auto_scaler.py | 36 +- clearml/automation/controller.py | 4 +- clearml/automation/job.py | 2 +- clearml/automation/monitor.py | 10 +- clearml/automation/optimization.py | 8 +- clearml/backend_api/api_proxy.py | 2 +- clearml/backend_api/config/default/api.conf | 8 +- clearml/backend_api/session/client/client.py | 10 +- clearml/backend_api/session/defs.py | 20 +- clearml/backend_api/session/session.py | 32 +- clearml/backend_api/utils.py | 4 +- clearml/backend_config/config.py | 6 +- clearml/backend_config/defs.py | 10 +- clearml/backend_config/entry.py | 7 +- clearml/backend_config/environment.py | 4 + clearml/backend_config/log.py | 4 +- clearml/backend_interface/metrics/events.py | 5 +- .../backend_interface/metrics/interface.py | 5 +- clearml/backend_interface/metrics/reporter.py | 2 +- clearml/backend_interface/task/log.py | 6 +- clearml/backend_interface/task/populate.py | 317 +++++ .../backend_interface/task/repo/scriptinfo.py | 22 +- clearml/backend_interface/task/task.py | 74 +- clearml/binding/artifacts.py | 10 +- clearml/binding/environ_bind.py | 2 +- clearml/binding/frameworks/__init__.py | 4 +- clearml/binding/frameworks/tensorflow_bind.py | 44 +- clearml/cli/__init__.py | 1 + clearml/cli/config/__init__.py | 1 + .../default => cli/config}/__main__.py | 48 +- clearml/cli/task/__init__.py | 1 + clearml/cli/task/__main__.py | 119 ++ clearml/config/__init__.py | 5 +- clearml/config/default/logging.conf | 2 +- clearml/config/default/sdk.conf | 16 +- clearml/config/defs.py | 40 +- clearml/datasets/__init__.py | 6 + clearml/datasets/dataset.py | 1244 +++++++++++++++++ clearml/debugging/log.py | 2 +- clearml/debugging/trace.py | 12 +- clearml/errors.py | 2 +- clearml/external/kerastuner.py | 4 +- clearml/logger.py | 26 +- clearml/model.py | 30 +- clearml/storage/cache.py | 4 +- clearml/storage/helper.py | 39 +- clearml/storage/manager.py | 6 +- clearml/storage/util.py | 19 +- clearml/task.py | 275 ++-- clearml/utilities/args.py | 2 +- clearml/utilities/check_updates.py | 12 +- clearml/utilities/proxy_object.py | 19 +- clearml/utilities/resource_monitor.py | 8 +- clearml/utilities/seed.py | 2 +- clearml/version.py | 2 +- docs/clearml-task.md | 136 ++ docs/clearml.conf | 196 +++ docs/contributing.md | 41 +- docs/dataset_screenshots.gif | Bin 0 -> 458123 bytes docs/datasets.md | 139 ++ docs/logger.md | 56 +- docs/trains.conf | 18 +- .../manual_random_param_search_example.py | 4 +- examples/automation/requirements.txt | 2 +- examples/automation/task_piping_example.py | 4 +- examples/automation/toy_base_task.py | 2 +- examples/distributed/requirements.txt | 2 +- examples/distributed/subprocess_example.py | 6 +- .../autokeras/autokeras_imdb_example.py | 2 +- .../frameworks/autokeras/requirements.txt | 2 +- .../fastai/fastai_with_tensorboard.py | 4 +- examples/frameworks/fastai/requirements.txt | 2 +- examples/frameworks/ignite/cifar_ignite.py | 6 +- .../frameworks/keras/keras_tensorboard.py | 6 +- .../keras/legacy/keras_tensorboard.py | 6 +- .../frameworks/keras/legacy/requirements.txt | 2 +- .../frameworks/keras/manual_model_upload.py | 4 +- examples/frameworks/keras/requirements.txt | 2 +- .../kerastuner/keras_tuner_cifar.py | 4 +- .../frameworks/kerastuner/requirements.txt | 2 +- examples/frameworks/lightgbm/requirements.txt | 2 +- .../lightgbm/train_with_lightbgm.py | 4 +- .../matplotlib/matplotlib_example.py | 4 +- .../frameworks/matplotlib/requirements.txt | 2 +- .../frameworks/pytorch/manual_model_upload.py | 4 +- .../pytorch/pytorch_distributed_example.py | 6 +- .../frameworks/pytorch/pytorch_matplotlib.py | 4 +- examples/frameworks/pytorch/pytorch_mnist.py | 4 +- .../frameworks/pytorch/pytorch_tensorboard.py | 6 +- examples/frameworks/pytorch/requirements.txt | 2 +- .../pytorch/tensorboard_toy_pytorch.py | 2 +- .../frameworks/scikit-learn/requirements.txt | 2 +- .../scikit-learn/sklearn_joblib_example.py | 2 +- .../sklearn_matplotlib_example.py | 2 +- .../tensorboardx/pytorch_tensorboardX.py | 4 +- .../frameworks/tensorboardx/requirements.txt | 2 +- .../tensorflow/legacy/tensorboard_pr_curve.py | 4 +- .../tensorflow/legacy/tensorboard_toy.py | 4 +- .../tensorflow/legacy/tensorflow_eager.py | 4 +- .../legacy/tensorflow_mnist_with_summaries.py | 2 +- .../tensorflow/manual_model_upload.py | 4 +- .../frameworks/tensorflow/requirements.txt | 2 +- .../tensorflow/tensorboard_pr_curve.py | 2 +- .../frameworks/tensorflow/tensorboard_toy.py | 4 +- .../frameworks/tensorflow/tensorflow_mnist.py | 2 +- examples/frameworks/xgboost/requirements.txt | 2 +- examples/frameworks/xgboost/xgboost_sample.py | 2 +- .../base_template_keras_simple.py | 6 +- .../hyper_parameter_optimizer.py | 17 +- .../requirements.txt | 2 +- examples/pipeline/pipeline_controller.py | 4 +- examples/pipeline/requirements.txt | 2 +- examples/pipeline/step1_dataset_artifact.py | 2 +- examples/pipeline/step2_data_processing.py | 4 +- examples/pipeline/step3_train_model.py | 4 +- examples/reporting/3d_plots_reporting.py | 4 +- examples/reporting/artifacts.py | 2 +- examples/reporting/html_reporting.py | 4 +- examples/reporting/hyper_parameters.py | 20 +- examples/reporting/image_reporting.py | 4 +- .../reporting/manual_matplotlib_reporting.py | 56 +- .../matplotlib_automatic_reporting.py | 1 + .../reporting/matplotlib_manual_reporting.py | 55 + examples/reporting/media_reporting.py | 4 +- examples/reporting/model_config.py | 4 +- examples/reporting/pandas_reporting.py | 4 +- examples/reporting/plotly_reporting.py | 4 +- examples/reporting/requirements.txt | 2 +- examples/reporting/scalar_reporting.py | 4 +- .../scatter_hist_confusion_mat_reporting.py | 5 +- examples/reporting/text_reporting.py | 4 +- .../services/aws-autoscaler/aws_autoscaler.py | 12 +- .../services/aws-autoscaler/requirements.txt | 2 +- examples/services/cleanup/cleanup_service.py | 10 +- examples/services/cleanup/requirements.txt | 2 +- .../execute_jupyter_notebook_server.py | 31 +- .../services/jupyter-service/requirements.txt | 2 +- examples/services/monitoring/requirements.txt | 2 +- examples/services/monitoring/slack_alerts.py | 18 +- requirements.txt | 2 +- setup.py | 18 +- 145 files changed, 3136 insertions(+), 794 deletions(-) create mode 100644 clearml/backend_interface/task/populate.py create mode 100644 clearml/cli/__init__.py create mode 100644 clearml/cli/config/__init__.py rename clearml/{config/default => cli/config}/__main__.py (87%) create mode 100644 clearml/cli/task/__init__.py create mode 100644 clearml/cli/task/__main__.py create mode 100644 clearml/datasets/__init__.py create mode 100644 clearml/datasets/dataset.py create mode 100644 docs/clearml-task.md create mode 100644 docs/clearml.conf create mode 100644 docs/dataset_screenshots.gif create mode 100644 docs/datasets.md mode change 100644 => 120000 examples/reporting/manual_matplotlib_reporting.py create mode 120000 examples/reporting/matplotlib_automatic_reporting.py create mode 100644 examples/reporting/matplotlib_manual_reporting.py diff --git a/README.md b/README.md index 349e239d..96517a0a 100644 --- a/README.md +++ b/README.md @@ -1,143 +1,134 @@ -# Allegro Trains - new name is coming soon ;) -## Auto-Magical Experiment Manager, Version Control and ML-Ops for AI +
-## :confetti_ball: Now with Full ML/DL DevOps - See [TRAINS AGENT](https://github.com/allegroai/trains-agent) and [Services](https://github.com/allegroai/trains-server#trains-agent-services--) -## :station: [Documentation is here!](https://allegro.ai/docs) `wubba lubba dub dub` and a [Slack Channel](https://join.slack.com/t/allegroai-trains/shared_invite/enQtOTQyMTI1MzQxMzE4LTY5NTUxOTY1NmQ1MzQ5MjRhMGRhZmM4ODE5NTNjMTg2NTBlZGQzZGVkMWU3ZDg1MGE1MjQxNDEzMWU2NmVjZmY) :train2: -## Features: [AWS autoscaler wizard](https://allegro.ai/docs/examples/services/aws_autoscaler/aws_autoscaler/) :robot: [Hyper-Parameter Optimization](https://allegro.ai/docs/examples/optimization/hyper-parameter-optimization/examples_hyperparam_opt/) and :electric_plug: [Pipeline Controllers](https://allegro.ai/docs/examples/pipeline/pipeline_controller/) + -"Because it’s a jungle out there" -[![GitHub license](https://img.shields.io/github/license/allegroai/trains.svg)](https://img.shields.io/github/license/allegroai/trains.svg) -[![PyPI pyversions](https://img.shields.io/pypi/pyversions/trains.svg)](https://img.shields.io/pypi/pyversions/trains.svg) -[![PyPI version shields.io](https://img.shields.io/pypi/v/trains.svg)](https://img.shields.io/pypi/v/trains.svg) -[![PyPI status](https://img.shields.io/pypi/status/trains.svg)](https://pypi.python.org/pypi/trains/) +**ClearML - Auto-Magical Suite of tools to streamline your ML workflow +Experiment Manager, ML-Ops and Data-Management** + +[![GitHub license](https://img.shields.io/github/license/allegroai/trains.svg)](https://img.shields.io/github/license/allegroai/clearml.svg) +[![PyPI pyversions](https://img.shields.io/pypi/pyversions/clearml.svg)](https://img.shields.io/pypi/pyversions/clearml.svg) +[![PyPI version shields.io](https://img.shields.io/pypi/v/clearml.svg)](https://img.shields.io/pypi/v/clearml.svg) +[![PyPI status](https://img.shields.io/pypi/status/clearml.svg)](https://pypi.python.org/pypi/clearml/) [![Optuna](https://img.shields.io/badge/Optuna-integrated-blue)](https://optuna.org) -[![Slack Channel](https://img.shields.io/badge/slack-%23trains--community-blueviolet?logo=slack)](https://join.slack.com/t/allegroai-trains/shared_invite/zt-c0t13pty-aVUZZW1TSSSg2vyIGVPBhg) +[![Slack Channel](https://img.shields.io/badge/slack-%23clearml--community-blueviolet?logo=slack)](https://join.slack.com/t/allegroai-trains/shared_invite/zt-c0t13pty-aVUZZW1TSSSg2vyIGVPBhg) -### :point_right: Help improve Trains by filling our 2-min [user survey](https://allegro.ai/lp/trains-user-survey/) +
-Trains is our solution to a problem we share with countless other researchers and developers in the machine +--- +### ClearML +#### *Formerly known as Allegro Trains* +ClearML is a ML/DL development and production suite, it contains three main modules: + +- [Experiment Manager](#clearml-experiment-management) - Automagical experiment tracking, environments and results +- [ML-Ops](https://github.com/allegroai/trains-agent) - Automation, Pipelines & Orchestration solution for ML/DL jobs (K8s / Cloud / bare-metal) +- [Data-Management](https://github.com/allegroai/clearml/doc/clearml-data.md) - Fully differentiable data management & version control solution on top of object-storage + (S3/GS/Azure/NAS) + + +Instrumenting these components is the **ClearML-server**, see [Self-Hosting]() & [Free tier Hosting]() + + +--- +
+ +**[Signup](https://app.community.clear.ml) & [Start using](https://allegro.ai/clearml/docs/getting_started/getting_started/) in under 2 minutes** + +
+ +--- + + +## ClearML Experiment Manager + +**Adding only 2 lines to your code gets you the following** + +* Complete experiment setup log + * Full source control info including non-committed local changes + * Execution environment (including specific packages & versions) + * Hyper-parameters + * ArgParser for command line parameters with currently used values + * Explicit parameters dictionary + * Tensorflow Defines (absl-py) + * Hydra configuration and overrides + * Initial model weights file +* Full experiment output automatic capture + * stdout and stderr + * Resource Monitoring (CPU/GPU utilization, temperature, IO, network, etc.) + * Model snapshots (With optional automatic upload to central storage: Shared folder, S3, GS, Azure, Http) + * Artifacts log & store (Shared folder, S3, GS, Azure, Http) + * Tensorboard/TensorboardX scalars, metrics, histograms, **images, audio and video samples** + * [Matplotlib & Seaborn](https://github.com/allegroai/trains/tree/master/examples/frameworks/matplotlib) + * [ClearML Explicit Logging](https://allegro.ai/clearml/docs/examples/reporting/) interface for complete flexibility. +* Extensive platform support and integrations + * Supported ML/DL frameworks: [PyTorch](https://github.com/allegroai/trains/tree/master/examples/frameworks/pytorch)(incl' ignite/lightning), [Tensorflow](https://github.com/allegroai/trains/tree/master/examples/frameworks/tensorflow), [Keras](https://github.com/allegroai/trains/tree/master/examples/frameworks/keras), [AutoKeras](https://github.com/allegroai/trains/tree/master/examples/frameworks/autokeras), [XGBoost](https://github.com/allegroai/trains/tree/master/examples/frameworks/xgboost) and [Scikit-Learn](https://github.com/allegroai/trains/tree/master/examples/frameworks/scikit-learn) + * Seamless integration (including version control) with **Jupyter Notebook** + and [*PyCharm* remote debugging](https://github.com/allegroai/trains-pycharm-plugin) + +#### [Start using ClearML](https://allegro.ai/clearml/docs/getting_started/getting_started/) + +```bash +pip install clearml +``` + +Add two lines to your code: +```python +from clearml import Task +task = Task(project_name='examples', task_name='hello world') +``` + +You are done, everything your process outputs is now automagically logged into ClearML. +
Next step automation! **Learn more on ClearML two clicks automation [here]()** + +## ClearML Architecture + +The ClearML run-time components: + +* The ClearML Python Package for integrating ClearML into your existing scripts by adding just two lines of code, and optionally extending your experiments and other workflows with ClearML powerful and versatile set of classes and methods. +* The ClearML Server storing experiment, model, and workflow data, and supporting the Web UI experiment manager, and ML-Ops automation for reproducibility and tuning. It is available as a hosted service and open source for you to deploy your own ClearML Server. +* The ClearML Agent for ML-Ops orchestration, experiment and workflow reproducibility, and scalability. + +clearml-architecture + +## Additional Modules + +- [clearml-session](https://github.com/allegroai/clearml-session) - **Launch remote JupyterLab / VSCode-server inside any docker, on Cloud/On-Prem machines** +- [clearml-task](https://github.com/allegroai/clearml/doc/clearml-task.md) - Run any codebase on remote machines with full remote logging of Tensorboard, Matplotlib & Console outputs +- [clearml-data](https://github.com/allegroai/clearml/doc/clearml-data.md) - **CLI for managing and versioning your datasets, including creating / uploading / downloading of data from S3/GS/Azure/NAS** +- [AWS Auto-Scaler](examples/services/aws-autoscaler/aws_autoscaler.py) - Automatically spin EC2 instances based on your workloads with preconfigured budget! No need for K8s! +- [Hyper-Parameter Optimization](examples/services/hyper-parameter-optimization/hyper_parameter_optimizer.py) - Optimize any code with black-box approach and state of the art Bayesian optimization algorithms +- [Automation Pipeline](examples/pipeline/pipeline_controller.py) - Build pipelines based on existing experiments / jobs, supports building pipelines of pipelines! +- [Slack Integration](examples/services/monitoring/slack_alerts.py) - Report experiments progress / failure directly to Slack (fully customizable!) + +## Why ClearML? + +ClearML is our solution to a problem we share with countless other researchers and developers in the machine learning/deep learning universe: Training production-grade deep learning models is a glorious but messy process. -Trains tracks and controls the process by associating code version control, research projects, +ClearML tracks and controls the process by associating code version control, research projects, performance metrics, and model provenance. -We designed Trains specifically to require effortless integration so that teams can preserve their existing methods -and practices. Use it on a daily basis to boost collaboration and visibility, or use it to automatically collect -your experimentation logs, outputs, and data to one centralized server. +We designed ClearML specifically to require effortless integration so that teams can preserve their existing methods +and practices. -**We have a demo server up and running at [https://demoapp.trains.allegro.ai](https://demoapp.trains.allegro.ai).** - -### :steam_locomotive: [Getting Started Tutorial](https://allegro.ai/blog/setting-up-allegro-ai-platform/) :rocket: - -**You can try out Trains and [test your code](#integrate-trains), with no additional setup.** - - - -## Trains Automatically Logs Everything -**With only two lines of code, this is what you are getting:** - -* Git repository, branch, commit id, entry point and local git diff -* Python environment (including specific packages & versions) -* stdout and stderr -* Resource Monitoring (CPU/GPU utilization, temperature, IO, network, etc.) -* Hyper-parameters - * ArgParser for command line parameters with currently used values - * Explicit parameters dictionary - * Tensorflow Defines (absl-py) -* Initial model weights file -* Model snapshots (With optional automatic upload to central storage: Shared folder, S3, GS, Azure, Http) -* Artifacts log & store (Shared folder, S3, GS, Azure, Http) -* Tensorboard/TensorboardX scalars, metrics, histograms, **images, audio and video** -* [Matplotlib & Seaborn](https://github.com/allegroai/trains/tree/master/examples/frameworks/matplotlib) -* Supported frameworks: [PyTorch](https://github.com/allegroai/trains/tree/master/examples/frameworks/pytorch), [Tensorflow](https://github.com/allegroai/trains/tree/master/examples/frameworks/tensorflow), [Keras](https://github.com/allegroai/trains/tree/master/examples/frameworks/keras), [AutoKeras](https://github.com/allegroai/trains/tree/master/examples/frameworks/autokeras), [XGBoost](https://github.com/allegroai/trains/tree/master/examples/frameworks/xgboost) and [Scikit-Learn](https://github.com/allegroai/trains/tree/master/examples/frameworks/scikit-learn) (MxNet is coming soon) -* Seamless integration (including version control) with **Jupyter Notebook** - and [*PyCharm* remote debugging](https://github.com/allegroai/trains-pycharm-plugin) - -**Additionally, log data explicitly using [Trains Explicit Logging](https://allegro.ai/docs/examples/reporting/).** - -## Using Trains - -Trains is a two part solution: - -1. Trains [python package](https://pypi.org/project/trains/) auto-magically connects with your code - - **Trains requires only two lines of code for full integration.** - - To connect your code with Trains: - - - Install Trains - - pip install trains -
- Add optional cloud storage support (S3/GoogleStorage/Azure): - - ```bash - pip install trains[s3] - pip install trains[gs] - pip install trains[azure] - ``` - -
- - - Add the following lines to your code - - from trains import Task - task = Task.init(project_name="my project", task_name="my task") - - * If project_name is not provided, the repository name will be used instead - * If task_name (experiment) is not provided, the current filename will be used instead - - - Run your code. When Trains connects to the server, a link is printed. For example - - Trains Results page: - https://demoapp.trains.allegro.ai/projects/76e5e2d45e914f52880621fe64601e85/experiments/241f06ae0f5c4b27b8ce8b64890ce152/output/log - - - Open the link and view your experiment parameters, model and tensorboard metrics - - **See examples [here](https://allegro.ai/docs/examples/examples_overview/)** - -2. [Trains Server](https://github.com/allegroai/trains-server) for logging, querying, control and UI ([Web-App](https://github.com/allegroai/trains-web)) - - **We already have a demo server up and running for you at [https://demoapp.trains.allegro.ai](https://demoapp.trains.allegro.ai).** - - **You can try out Trains without the need to install your own *trains-server*, just add the two lines of code, and it will automatically connect to the Trains demo-server.** - - *Note that the demo server resets every 24 hours and all of the logged data is deleted.* - - When you are ready to use your own Trains server, go ahead and [install *trains-server*](https://github.com/allegroai/trains-server). - - - - -## Configuring Your Own Trains server - -1. Install and run *trains-server* (see [Installing the Trains Server](https://github.com/allegroai/trains-server)) - -2. Run the initial configuration wizard for your Trains installation and follow the instructions to setup Trains package -(http://**_trains-server-ip_**:__port__ and user credentials) - - trains-init - -After installing and configuring, you can access your configuration file at `~/trains.conf` - -Sample configuration file available [here](https://github.com/allegroai/trains/blob/master/docs/trains.conf). + - Use it on a daily basis to boost collaboration and visibility in your team + - Create a remote job from any experiment with a click of a button + - Automate processes and create pipelines to collect your experimentation logs, outputs, and data + - Store all you data on any object-storage solution, with the simplest interface possible + - Make you data transparent by cataloging it all on the ClearML platform +We believe ClearML is ground-breaking. We wish to establish new standards of true seamless integration between +experiment management,ML-Ops and data management. ## Who We Are -Trains is supported by the same team behind *allegro.ai*, +ClearML is supported by the team behind *allegro.ai*, where we build deep learning pipelines and infrastructure for enterprise companies. -We built Trains to track and control the glorious but messy process of training production-grade deep learning models. -We are committed to vigorously supporting and expanding the capabilities of Trains. +We built ClearML to track and control the glorious but messy process of training production-grade deep learning models. +We are committed to vigorously supporting and expanding the capabilities of ClearML. -## Why Are We Releasing Trains? - -We believe Trains is ground-breaking. We wish to establish new standards of experiment management in -deep-learning and ML. Only the greater community can help us do that. - -We promise to always be backwardly compatible. If you start working with Trains today, -even though this project is currently in the beta stage, your logs and data will always upgrade with you. +We promise to always be backwardly compatible, making sure all your logs, data and pipelines +will always upgrade with you. ## License @@ -145,19 +136,19 @@ Apache License, Version 2.0 (see the [LICENSE](https://www.apache.org/licenses/L ## Documentation, Community & Support -More information in the [official documentation](https://allegro.ai/docs) and [on YouTube](https://www.youtube.com/c/AllegroAI). +More information in the [official documentation](https://allegro.ai//clearml/docs) and [on YouTube](https://www.youtube.com/c/AllegroAI). -For examples and use cases, check the [examples folder](https://github.com/allegroai/trains/tree/master/examples) and [corresponding documentation](https://allegro.ai/docs/examples/examples_overview/). +For examples and use cases, check the [examples folder](https://github.com/allegroai/trains/tree/master/examples) and [corresponding documentation](https://allegro.ai/clearml/docs/examples/examples_overview/). If you have any questions: post on our [Slack Channel](https://join.slack.com/t/allegroai-trains/shared_invite/enQtOTQyMTI1MzQxMzE4LTY5NTUxOTY1NmQ1MzQ5MjRhMGRhZmM4ODE5NTNjMTg2NTBlZGQzZGVkMWU3ZDg1MGE1MjQxNDEzMWU2NmVjZmY), or tag your questions on [stackoverflow](https://stackoverflow.com/questions/tagged/trains) with '**trains**' tag. For feature requests or bug reports, please use [GitHub issues](https://github.com/allegroai/trains/issues). -Additionally, you can always find us at *trains@allegro.ai* +Additionally, you can always find us at *clearml@allegro.ai* ## Contributing -See the Trains [Guidelines for Contributing](https://github.com/allegroai/trains/blob/master/docs/contributing.md). +See the ClearML [Guidelines for Contributing](https://github.com/allegroai/trains/blob/master/docs/contributing.md). _May the force (and the goddess of learning rates) be with you!_ diff --git a/clearml/__init__.py b/clearml/__init__.py index c05221e3..0ad97be4 100644 --- a/clearml/__init__.py +++ b/clearml/__init__.py @@ -1,4 +1,4 @@ -""" TRAINS open SDK """ +""" ClearML open SDK """ from .version import __version__ from .task import Task @@ -6,5 +6,7 @@ from .model import InputModel, OutputModel, Model from .logger import Logger from .storage import StorageManager from .errors import UsageError +from .datasets import Dataset -__all__ = ["__version__", "Task", "InputModel", "OutputModel", "Model", "Logger", "StorageManager", "UsageError"] +__all__ = ["__version__", "Task", "InputModel", "OutputModel", "Model", "Logger", + "StorageManager", "UsageError", "Dataset"] diff --git a/clearml/automation/__init__.py b/clearml/automation/__init__.py index d2ac6d46..71b68351 100644 --- a/clearml/automation/__init__.py +++ b/clearml/automation/__init__.py @@ -1,6 +1,7 @@ from .parameters import UniformParameterRange, DiscreteParameterRange, UniformIntegerParameterRange, ParameterSet from .optimization import GridSearch, RandomSearch, HyperParameterOptimizer, Objective from .job import TrainsJob +from .controller import PipelineController __all__ = ["UniformParameterRange", "DiscreteParameterRange", "UniformIntegerParameterRange", "ParameterSet", - "GridSearch", "RandomSearch", "HyperParameterOptimizer", "Objective", "TrainsJob"] + "GridSearch", "RandomSearch", "HyperParameterOptimizer", "Objective", "TrainsJob", "PipelineController"] diff --git a/clearml/automation/auto_scaler.py b/clearml/automation/auto_scaler.py index b35d0d64..66b51d4a 100644 --- a/clearml/automation/auto_scaler.py +++ b/clearml/automation/auto_scaler.py @@ -102,15 +102,15 @@ class AutoScaler(object): def spin_up_worker(self, resource, worker_id_prefix, queue_name): """ - Creates a new worker for trains (cloud-specific implementation). + Creates a new worker for clearml (cloud-specific implementation). First, create an instance in the cloud and install some required packages. - Then, define trains-agent environment variables and run trains-agent for the specified queue. + Then, define clearml-agent environment variables and run clearml-agent for the specified queue. NOTE: - Will wait until instance is running - This implementation assumes the instance image already has docker installed :param str resource: resource name, as defined in self.resource_configurations and self.queues. :param str worker_id_prefix: worker name prefix - :param str queue_name: trains queue to listen to + :param str queue_name: clearml queue to listen to """ pass @@ -137,17 +137,17 @@ class AutoScaler(object): minutes would be removed. """ - # Worker's id in trains would be composed from prefix, name, instance_type and cloud_id separated by ';' + # Worker's id in clearml would be composed from prefix, name, instance_type and cloud_id separated by ';' workers_pattern = re.compile( r"^(?P[^:]+):(?P[^:]+):(?P[^:]+):(?P[^:]+)" ) - # Set up the environment variables for trains - os.environ["TRAINS_API_HOST"] = self.api_server - os.environ["TRAINS_WEB_HOST"] = self.web_server - os.environ["TRAINS_FILES_HOST"] = self.files_server - os.environ["TRAINS_API_ACCESS_KEY"] = self.access_key - os.environ["TRAINS_API_SECRET_KEY"] = self.secret_key + # Set up the environment variables for clearml + os.environ["CLEARML_API_HOST"] = self.api_server + os.environ["CLEARML_WEB_HOST"] = self.web_server + os.environ["CLEARML_FILES_HOST"] = self.files_server + os.environ["CLEARML_API_ACCESS_KEY"] = self.access_key + os.environ["CLEARML_API_SECRET_KEY"] = self.secret_key api_client = APIClient() # Verify the requested queues exist and create those that doesn't exist @@ -234,7 +234,7 @@ class AutoScaler(object): # skip resource types that might be needed if resources in required_idle_resources: continue - # Remove from both aws and trains all instances that are idle for longer than MAX_IDLE_TIME_MIN + # Remove from both aws and clearml all instances that are idle for longer than MAX_IDLE_TIME_MIN if time() - timestamp > self.max_idle_time_min * 60.0: cloud_id = workers_pattern.match(worker.id)["cloud_id"] self.spin_down_worker(cloud_id) diff --git a/clearml/automation/aws_auto_scaler.py b/clearml/automation/aws_auto_scaler.py index 0c8c4b2d..13c142c8 100644 --- a/clearml/automation/aws_auto_scaler.py +++ b/clearml/automation/aws_auto_scaler.py @@ -31,15 +31,15 @@ class AwsAutoScaler(AutoScaler): def spin_up_worker(self, resource, worker_id_prefix, queue_name): """ - Creates a new worker for trains. + Creates a new worker for clearml. First, create an instance in the cloud and install some required packages. - Then, define trains-agent environment variables and run trains-agent for the specified queue. + Then, define clearml-agent environment variables and run clearml-agent for the specified queue. NOTE: - Will wait until instance is running - This implementation assumes the instance image already has docker installed :param str resource: resource name, as defined in BUDGET and QUEUES. :param str worker_id_prefix: worker name prefix - :param str queue_name: trains queue to listen to + :param str queue_name: clearml queue to listen to """ resource_conf = self.resource_configurations[resource] # Add worker type and AWS instance type to the worker name. @@ -50,7 +50,7 @@ class AwsAutoScaler(AutoScaler): ) # user_data script will automatically run when the instance is started. it will install the required packages - # for trains-agent configure it using environment variables and run trains-agent on the required queue + # for clearml-agent configure it using environment variables and run clearml-agent on the required queue user_data = """#!/bin/bash sudo apt-get update sudo apt-get install -y python3-dev @@ -60,22 +60,22 @@ class AwsAutoScaler(AutoScaler): sudo apt-get install -y build-essential python3 -m pip install -U pip python3 -m pip install virtualenv - python3 -m virtualenv trains_agent_venv - source trains_agent_venv/bin/activate - python -m pip install trains-agent - echo 'agent.git_user=\"{git_user}\"' >> /root/trains.conf - echo 'agent.git_pass=\"{git_pass}\"' >> /root/trains.conf - echo "{trains_conf}" >> /root/trains.conf - export TRAINS_API_HOST={api_server} - export TRAINS_WEB_HOST={web_server} - export TRAINS_FILES_HOST={files_server} + python3 -m virtualenv clearml_agent_venv + source clearml_agent_venv/bin/activate + python -m pip install clearml-agent + echo 'agent.git_user=\"{git_user}\"' >> /root/clearml.conf + echo 'agent.git_pass=\"{git_pass}\"' >> /root/clearml.conf + echo "{clearml_conf}" >> /root/clearml.conf + export CLEARML_API_HOST={api_server} + export CLEARML_WEB_HOST={web_server} + export CLEARML_FILES_HOST={files_server} export DYNAMIC_INSTANCE_ID=`curl http://169.254.169.254/latest/meta-data/instance-id` - export TRAINS_WORKER_ID={worker_id}:$DYNAMIC_INSTANCE_ID - export TRAINS_API_ACCESS_KEY='{access_key}' - export TRAINS_API_SECRET_KEY='{secret_key}' + export CLEARML_WORKER_ID={worker_id}:$DYNAMIC_INSTANCE_ID + export CLEARML_API_ACCESS_KEY='{access_key}' + export CLEARML_API_SECRET_KEY='{secret_key}' {bash_script} source ~/.bashrc - python -m trains_agent --config-file '/root/trains.conf' daemon --queue '{queue}' {docker} + python -m clearml_agent --config-file '/root/clearml.conf' daemon --queue '{queue}' {docker} shutdown """.format( api_server=self.api_server, @@ -87,7 +87,7 @@ class AwsAutoScaler(AutoScaler): queue=queue_name, git_user=self.git_user or "", git_pass=self.git_pass or "", - trains_conf='\\"'.join(self.extra_trains_conf.split('"')), + clearml_conf='\\"'.join(self.extra_trains_conf.split('"')), bash_script=self.extra_vm_bash_script, docker="--docker '{}'".format(self.default_docker_image) if self.default_docker_image diff --git a/clearml/automation/controller.py b/clearml/automation/controller.py index 0625b2b2..365e41ac 100644 --- a/clearml/automation/controller.py +++ b/clearml/automation/controller.py @@ -17,7 +17,7 @@ class PipelineController(object): """ Pipeline controller. Pipeline is a DAG of base tasks, each task will be cloned (arguments changed as required) executed and monitored - The pipeline process (task) itself can be executed manually or by the trains-agent services queue. + The pipeline process (task) itself can be executed manually or by the clearml-agent services queue. Notice: The pipeline controller lives as long as the pipeline itself is being executed. """ _tag = 'pipeline' @@ -601,7 +601,7 @@ class PipelineController(object): print('Parameters:\n{}'.format(self._nodes[name].job.task_parameter_override)) self._running_nodes.append(name) else: - getLogger('trains.automation.controller').error( + getLogger('clearml.automation.controller').error( 'ERROR: Failed launching step \'{}\': {}'.format(name, self._nodes[name])) # update current state (in configuration, so that we could later continue an aborted pipeline) diff --git a/clearml/automation/job.py b/clearml/automation/job.py index cc2d9a92..344b976b 100644 --- a/clearml/automation/job.py +++ b/clearml/automation/job.py @@ -8,7 +8,7 @@ from ..task import Task from ..backend_api.services import tasks as tasks_service -logger = getLogger('trains.automation.job') +logger = getLogger('clearml.automation.job') class TrainsJob(object): diff --git a/clearml/automation/monitor.py b/clearml/automation/monitor.py index 7c751500..dff7820a 100644 --- a/clearml/automation/monitor.py +++ b/clearml/automation/monitor.py @@ -22,7 +22,7 @@ class Monitor(object): self._project_ids = None self._projects = None self._projects_refresh_timestamp = None - self._trains_apiclient = None + self._clearml_apiclient = None def set_projects(self, project_names=None, project_names_re=None, project_ids=None): # type: (Optional[Sequence[str]], Optional[Sequence[str]], Optional[Sequence[str]]) -> () @@ -167,10 +167,10 @@ class Monitor(object): def _get_api_client(self): # type: () -> APIClient """ - Return an APIClient object to directly query the trains-server + Return an APIClient object to directly query the clearml-server :return: APIClient object """ - if not self._trains_apiclient: - self._trains_apiclient = APIClient() - return self._trains_apiclient + if not self._clearml_apiclient: + self._clearml_apiclient = APIClient() + return self._clearml_apiclient diff --git a/clearml/automation/optimization.py b/clearml/automation/optimization.py index ac78c42f..f860642c 100644 --- a/clearml/automation/optimization.py +++ b/clearml/automation/optimization.py @@ -15,7 +15,7 @@ from ..logger import Logger from ..backend_api.services import workers as workers_service, tasks as tasks_services from ..task import Task -logger = getLogger('trains.automation.optimization') +logger = getLogger('clearml.automation.optimization') try: @@ -878,9 +878,9 @@ class HyperParameterOptimizer(object): :linenos: :caption: Example - from trains import Task - from trains.automation import UniformParameterRange, DiscreteParameterRange - from trains.automation import GridSearch, RandomSearch, HyperParameterOptimizer + from clearml import Task + from clearml.automation import UniformParameterRange, DiscreteParameterRange + from clearml.automation import GridSearch, RandomSearch, HyperParameterOptimizer task = Task.init('examples', 'HyperParameterOptimizer example') an_optimizer = HyperParameterOptimizer( diff --git a/clearml/backend_api/api_proxy.py b/clearml/backend_api/api_proxy.py index 164392e0..22281cfd 100644 --- a/clearml/backend_api/api_proxy.py +++ b/clearml/backend_api/api_proxy.py @@ -8,7 +8,7 @@ from ..utilities.check_updates import Version class ApiServiceProxy(object): - _main_services_module = "trains.backend_api.services" + _main_services_module = "clearml.backend_api.services" _available_versions = None def __init__(self, module): diff --git a/clearml/backend_api/config/default/api.conf b/clearml/backend_api/config/default/api.conf index e4d88bee..721f6434 100644 --- a/clearml/backend_api/config/default/api.conf +++ b/clearml/backend_api/config/default/api.conf @@ -1,16 +1,16 @@ { version: 1.5 - # default api_server: https://demoapi.trains.allegro.ai + # default api_server: https://demoapi.clearml.allegro.ai api_server: "" - # default web_server: https://demoapp.trains.allegro.ai + # default web_server: https://demoapp.clearml.allegro.ai web_server: "" - # default files_server: https://demofiles.trains.allegro.ai + # default files_server: https://demofiles.clearml.allegro.ai files_server: "" # verify host ssl certificate, set to False only if you have a very good reason verify_certificate: True - # default demoapi.trains.allegro.ai credentials + # default demoapi.clearml.allegro.ai credentials credentials { access_key: "" secret_key: "" diff --git a/clearml/backend_api/session/client/client.py b/clearml/backend_api/session/client/client.py index 1eefa199..69ce9add 100644 --- a/clearml/backend_api/session/client/client.py +++ b/clearml/backend_api/session/client/client.py @@ -107,15 +107,15 @@ class StrictSession(Session): init() return - original = os.environ.get(LOCAL_CONFIG_FILE_OVERRIDE_VAR, None) + original = LOCAL_CONFIG_FILE_OVERRIDE_VAR.get() or None try: - os.environ[LOCAL_CONFIG_FILE_OVERRIDE_VAR] = str(config_file) + LOCAL_CONFIG_FILE_OVERRIDE_VAR.set(str(config_file)) init() finally: if original is None: - os.environ.pop(LOCAL_CONFIG_FILE_OVERRIDE_VAR, None) + LOCAL_CONFIG_FILE_OVERRIDE_VAR.pop() else: - os.environ[LOCAL_CONFIG_FILE_OVERRIDE_VAR] = original + LOCAL_CONFIG_FILE_OVERRIDE_VAR.set(original) def send(self, request, *args, **kwargs): result = super(StrictSession, self).send(request, *args, **kwargs) @@ -560,4 +560,4 @@ class APIClient(object): for name, module in services.items() }, ) - ) \ No newline at end of file + ) diff --git a/clearml/backend_api/session/defs.py b/clearml/backend_api/session/defs.py index ff78f812..8571ab5d 100644 --- a/clearml/backend_api/session/defs.py +++ b/clearml/backend_api/session/defs.py @@ -2,12 +2,14 @@ from ...backend_config import EnvEntry from ...backend_config.converters import safe_text_to_bool -ENV_HOST = EnvEntry("TRAINS_API_HOST", "ALG_API_HOST") -ENV_WEB_HOST = EnvEntry("TRAINS_WEB_HOST", "ALG_WEB_HOST") -ENV_FILES_HOST = EnvEntry("TRAINS_FILES_HOST", "ALG_FILES_HOST") -ENV_ACCESS_KEY = EnvEntry("TRAINS_API_ACCESS_KEY", "ALG_API_ACCESS_KEY") -ENV_SECRET_KEY = EnvEntry("TRAINS_API_SECRET_KEY", "ALG_API_SECRET_KEY") -ENV_VERBOSE = EnvEntry("TRAINS_API_VERBOSE", "ALG_API_VERBOSE", type=bool, default=False) -ENV_HOST_VERIFY_CERT = EnvEntry("TRAINS_API_HOST_VERIFY_CERT", "ALG_API_HOST_VERIFY_CERT", type=bool, default=True) -ENV_OFFLINE_MODE = EnvEntry("TRAINS_OFFLINE_MODE", "ALG_OFFLINE_MODE", type=bool, converter=safe_text_to_bool) -ENV_TRAINS_NO_DEFAULT_SERVER = EnvEntry("TRAINS_NO_DEFAULT_SERVER", "ALG_NO_DEFAULT_SERVER", type=bool, default=False) +ENV_HOST = EnvEntry("CLEARML_API_HOST", "TRAINS_API_HOST") +ENV_WEB_HOST = EnvEntry("CLEARML_WEB_HOST", "TRAINS_WEB_HOST") +ENV_FILES_HOST = EnvEntry("CLEARML_FILES_HOST", "TRAINS_FILES_HOST") +ENV_ACCESS_KEY = EnvEntry("CLEARML_API_ACCESS_KEY", "TRAINS_API_ACCESS_KEY") +ENV_SECRET_KEY = EnvEntry("CLEARML_API_SECRET_KEY", "TRAINS_API_SECRET_KEY") +ENV_VERBOSE = EnvEntry("CLEARML_API_VERBOSE", "TRAINS_API_VERBOSE", type=bool, default=False) +ENV_HOST_VERIFY_CERT = EnvEntry("CLEARML_API_HOST_VERIFY_CERT", "TRAINS_API_HOST_VERIFY_CERT", + type=bool, default=True) +ENV_OFFLINE_MODE = EnvEntry("CLEARML_OFFLINE_MODE", "TRAINS_OFFLINE_MODE", type=bool, converter=safe_text_to_bool) +ENV_TRAINS_NO_DEFAULT_SERVER = EnvEntry("CLEARML_NO_DEFAULT_SERVER", "TRAINS_NO_DEFAULT_SERVER", + type=bool, default=False) diff --git a/clearml/backend_api/session/session.py b/clearml/backend_api/session/session.py index 34a0efe7..e6da6650 100644 --- a/clearml/backend_api/session/session.py +++ b/clearml/backend_api/session/session.py @@ -36,12 +36,12 @@ class MaxRequestSizeError(Exception): class Session(TokenManager): - """ TRAINS API Session class. """ + """ ClearML API Session class. """ _AUTHORIZATION_HEADER = "Authorization" - _WORKER_HEADER = "X-Trains-Worker" - _ASYNC_HEADER = "X-Trains-Async" - _CLIENT_HEADER = "X-Trains-Client" + _WORKER_HEADER = ("X-ClearML-Worker", "X-Trains-Worker", ) + _ASYNC_HEADER = ("X-ClearML-Async", "X-Trains-Async", ) + _CLIENT_HEADER = ("X-ClearML-Client", "X-Trains-Client", ) _async_status_code = 202 _session_requests = 0 @@ -57,10 +57,10 @@ class Session(TokenManager): _client = [(__package__.partition(".")[0], __version__)] api_version = '2.1' - default_demo_host = "https://demoapi.trains.allegro.ai" + default_demo_host = "https://demoapi.demo.clear.ml" default_host = default_demo_host - default_web = "https://demoapp.trains.allegro.ai" - default_files = "https://demofiles.trains.allegro.ai" + default_web = "https://demoapp.demo.clear.ml" + default_files = "https://demofiles.demo.clear.ml" default_key = "EGRTCO8JMSIGI6S39GTP43NFWXDQOW" default_secret = "x!XTov_G-#vspE*Y(h$Anm&DIc5Ou-F)jsl$PdOyj5wG1&E!Z8" force_max_api_version = None @@ -177,8 +177,8 @@ class Session(TokenManager): if not api_version: api_version = '2.2' if token_dict.get('env', '') == 'prod' else Session.api_version if token_dict.get('server_version'): - if not any(True for c in Session._client if c[0] == 'trains-server'): - Session._client.append(('trains-server', token_dict.get('server_version'), )) + if not any(True for c in Session._client if c[0] == 'clearml-server'): + Session._client.append(('clearml-server', token_dict.get('server_version'), )) Session.api_version = str(api_version) except (jwt.DecodeError, ValueError): @@ -218,10 +218,13 @@ class Session(TokenManager): if self._offline_mode: return None + res = None host = self.host headers = headers.copy() if headers else {} - headers[self._WORKER_HEADER] = self.worker - headers[self._CLIENT_HEADER] = self.client + for h in self._WORKER_HEADER: + headers[h] = self.worker + for h in self._CLIENT_HEADER: + headers[h] = self.client token_refreshed_on_error = False url = ( @@ -308,7 +311,8 @@ class Session(TokenManager): headers.copy() if headers else {} ) if async_enable: - headers[self._ASYNC_HEADER] = "1" + for h in self._ASYNC_HEADER: + headers[h] = "1" return self._send_request( service=service, action=action, @@ -508,7 +512,7 @@ class Session(TokenManager): if parsed.port == 8008: return host.replace(':8008', ':8080', 1) - raise ValueError('Could not detect TRAINS web application server') + raise ValueError('Could not detect ClearML web application server') @classmethod def get_files_server_host(cls, config=None): @@ -624,7 +628,7 @@ class Session(TokenManager): # check if this is a misconfigured api server (getting 200 without the data section) if res and res.status_code == 200: raise ValueError('It seems *api_server* is misconfigured. ' - 'Is this the TRAINS API server {} ?'.format(self.host)) + 'Is this the ClearML API server {} ?'.format(self.host)) else: raise LoginError("Response data mismatch: No 'token' in 'data' value from res, receive : {}, " "exception: {}".format(res, ex)) diff --git a/clearml/backend_api/utils.py b/clearml/backend_api/utils.py index 84d19211..ab35d473 100644 --- a/clearml/backend_api/utils.py +++ b/clearml/backend_api/utils.py @@ -14,7 +14,7 @@ if six.PY3: from functools import lru_cache elif six.PY2: # python 2 support - from backports.functools_lru_cache import lru_cache + from backports.functools_lru_cache import lru_cache # noqa __disable_certificate_verification_warning = 0 @@ -139,7 +139,7 @@ def get_http_session_with_retry( if not session.verify and __disable_certificate_verification_warning < 2: # show warning __disable_certificate_verification_warning += 1 - logging.getLogger('trains').warning( + logging.getLogger('clearml').warning( msg='InsecureRequestWarning: Certificate verification is disabled! Adding ' 'certificate verification is strongly advised. See: ' 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings') diff --git a/clearml/backend_config/config.py b/clearml/backend_config/config.py index 52d344b2..b79cb314 100644 --- a/clearml/backend_config/config.py +++ b/clearml/backend_config/config.py @@ -88,7 +88,7 @@ class Config(object): self._folder_name = config_folder or DEFAULT_CONFIG_FOLDER self._roots = [] self._config = ConfigTree() - self._env = env or os.environ.get("TRAINS_ENV", Environment.default) + self._env = env or os.environ.get("CLEARML_ENV", os.environ.get("TRAINS_ENV", Environment.default)) self.config_paths = set() self.is_server = is_server @@ -139,7 +139,7 @@ class Config(object): else: env_config_paths = [] - env_config_path_override = os.environ.get(ENV_CONFIG_PATH_OVERRIDE_VAR) + env_config_path_override = ENV_CONFIG_PATH_OVERRIDE_VAR.get() if env_config_path_override: env_config_paths = [expanduser(env_config_path_override)] @@ -166,7 +166,7 @@ class Config(object): ) local_config_files = LOCAL_CONFIG_FILES - local_config_override = os.environ.get(LOCAL_CONFIG_FILE_OVERRIDE_VAR) + local_config_override = LOCAL_CONFIG_FILE_OVERRIDE_VAR.get() if local_config_override: local_config_files = [expanduser(local_config_override)] diff --git a/clearml/backend_config/defs.py b/clearml/backend_config/defs.py index f503602c..3d0e145e 100644 --- a/clearml/backend_config/defs.py +++ b/clearml/backend_config/defs.py @@ -1,7 +1,10 @@ from os.path import expanduser from pathlib2 import Path -ENV_VAR = 'TRAINS_ENV' +from .environment import EnvEntry + + +ENV_VAR = 'CLEARML_ENV' """ Name of system environment variable that can be used to specify the config environment name """ @@ -25,15 +28,16 @@ LOCAL_CONFIG_PATHS = [ LOCAL_CONFIG_FILES = [ expanduser('~/trains.conf'), # used for workstation configuration (end-users, workers) + expanduser('~/clearml.conf'), # used for workstation configuration (end-users, workers) ] """ Local config files (not paths) """ -LOCAL_CONFIG_FILE_OVERRIDE_VAR = 'TRAINS_CONFIG_FILE' +LOCAL_CONFIG_FILE_OVERRIDE_VAR = EnvEntry("CLEARML_CONFIG_FILE", "TRAINS_CONFIG_FILE") """ Local config file override environment variable. If this is set, no other local config files will be used. """ -ENV_CONFIG_PATH_OVERRIDE_VAR = 'TRAINS_CONFIG_PATH' +ENV_CONFIG_PATH_OVERRIDE_VAR = EnvEntry("CLEARML_CONFIG_PATH", "TRAINS_CONFIG_PATH") """ Environment-related config path override environment variable. If this is set, no other env config path will be used. """ diff --git a/clearml/backend_config/entry.py b/clearml/backend_config/entry.py index 2ca3251c..709d538f 100644 --- a/clearml/backend_config/entry.py +++ b/clearml/backend_config/entry.py @@ -85,9 +85,10 @@ class Entry(object): return self.get_pair(default=default, converter=converter)[1] def set(self, value): - # type: (Any, Any) -> (Text, Any) - key, _ = self.get_pair(default=None, converter=None) - self._set(key, str(value)) + # type: (Any) -> () + # key, _ = self.get_pair(default=None, converter=None) + for k in self.keys: + self._set(k, str(value)) def _set(self, key, value): # type: (Text, Text) -> None diff --git a/clearml/backend_config/environment.py b/clearml/backend_config/environment.py index 915bceb7..ca389b5d 100644 --- a/clearml/backend_config/environment.py +++ b/clearml/backend_config/environment.py @@ -15,6 +15,10 @@ class EnvEntry(Entry): super(EnvEntry, self).__init__(key, *more_keys, **kwargs) self._ignore_errors = kwargs.pop('ignore_errors', False) + def pop(self): + for k in self.keys: + environ.pop(k, None) + def _get(self, key): value = getenv(key, "").strip() return value or NotSet diff --git a/clearml/backend_config/log.py b/clearml/backend_config/log.py index 6dad47bc..5cd6643f 100644 --- a/clearml/backend_config/log.py +++ b/clearml/backend_config/log.py @@ -5,11 +5,11 @@ from pathlib2 import Path def logger(path=None): - name = "trains" + name = "clearml" if path: p = Path(path) module = (p.parent if p.stem.startswith('_') else p).stem - name = "trains.%s" % module + name = "clearml.%s" % module return logging.getLogger(name) diff --git a/clearml/backend_interface/metrics/events.py b/clearml/backend_interface/metrics/events.py index 1640af88..8b84fb29 100644 --- a/clearml/backend_interface/metrics/events.py +++ b/clearml/backend_interface/metrics/events.py @@ -50,6 +50,7 @@ class MetricsEventAdapter(object): url = attr.attrib(default=None) exception = attr.attrib(default=None) + retries = attr.attrib(default=None) delete_local_file = attr.attrib(default=True) """ Local file path, if exists, delete the file after upload completed """ @@ -198,6 +199,7 @@ class UploadEvent(MetricsEventAdapter): _format = '.' + str(config.get('metrics.images.format', 'JPEG')).upper().lstrip('.') _quality = int(config.get('metrics.images.quality', 87)) _subsampling = int(config.get('metrics.images.subsampling', 0)) + _upload_retries = 3 _metric_counters = {} _metric_counters_lock = Lock() @@ -253,7 +255,7 @@ class UploadEvent(MetricsEventAdapter): self._upload_filename += filename_ext self._override_storage_key_prefix = kwargs.pop('override_storage_key_prefix', None) - + self.retries = self._upload_retries super(UploadEvent, self).__init__(metric, variant, iter=iter, **kwargs) @classmethod @@ -334,6 +336,7 @@ class UploadEvent(MetricsEventAdapter): key_prop='key', upload_uri=self._upload_uri, delete_local_file=local_file if self._delete_after_upload else None, + retries=self.retries, ) def get_target_full_upload_uri(self, storage_uri, storage_key_prefix=None, quote_uri=True): diff --git a/clearml/backend_interface/metrics/interface.py b/clearml/backend_interface/metrics/interface.py index f3022e38..c37927f3 100644 --- a/clearml/backend_interface/metrics/interface.py +++ b/clearml/backend_interface/metrics/interface.py @@ -165,10 +165,11 @@ class Metrics(InterfaceBase): try: storage = self._get_storage(upload_uri) + retries = getattr(e, 'retries', None) or self._file_upload_retries if isinstance(e.stream, Path): - url = storage.upload(e.stream.as_posix(), e.url, retries=self._file_upload_retries) + url = storage.upload(e.stream.as_posix(), e.url, retries=retries) else: - url = storage.upload_from_stream(e.stream, e.url, retries=self._file_upload_retries) + url = storage.upload_from_stream(e.stream, e.url, retries=retries) e.event.update(url=url) except Exception as exp: log.warning("Failed uploading to {} ({})".format( diff --git a/clearml/backend_interface/metrics/reporter.py b/clearml/backend_interface/metrics/reporter.py index 949f6f09..7a4639e8 100644 --- a/clearml/backend_interface/metrics/reporter.py +++ b/clearml/backend_interface/metrics/reporter.py @@ -178,7 +178,7 @@ class Reporter(InterfaceBase, AbstractContextManager, SetupUploadMixin, AsyncMan self._report(ev) def report_matplotlib(self, title, series, figure, iter, force_save_as_image=False, logger=None): - from trains.binding.matplotlib_bind import PatchedMatplotlib + from clearml.binding.matplotlib_bind import PatchedMatplotlib PatchedMatplotlib.report_figure( title=title, series=series, diff --git a/clearml/backend_interface/task/log.py b/clearml/backend_interface/task/log.py index bda1bfb8..06ab451b 100644 --- a/clearml/backend_interface/task/log.py +++ b/clearml/backend_interface/task/log.py @@ -62,7 +62,7 @@ class TaskHandler(BufferingHandler): if self._connect_logger and not TaskHandler.__once: base_logger = getLogger() if len(base_logger.handlers) == 1 and isinstance(base_logger.handlers[0], TaskHandler): - if record.name != 'console' and not record.name.startswith('trains.'): + if record.name != 'console' and not record.name.startswith('clearml.'): base_logger.removeHandler(self) basicConfig() base_logger.addHandler(self) @@ -149,7 +149,7 @@ class TaskHandler(BufferingHandler): self._last_event = None batch_requests = events.AddBatchRequest(requests=[events.AddRequest(e) for e in record_events if e]) except Exception: - self.__log_stderr("WARNING: trains.log - Failed logging task to backend ({:d} lines)".format(len(buffer))) + self.__log_stderr("WARNING: clearml.log - Failed logging task to backend ({:d} lines)".format(len(buffer))) batch_requests = None if batch_requests and batch_requests.requests: @@ -253,7 +253,7 @@ class TaskHandler(BufferingHandler): write = sys.stderr._original_write if hasattr(sys.stderr, '_original_write') else sys.stderr.write write('{asctime} - {name} - {levelname} - {message}\n'.format( asctime=Formatter().formatTime(makeLogRecord({})), - name='trains.log', levelname=getLevelName(level), message=msg)) + name='clearml.log', levelname=getLevelName(level), message=msg)) @classmethod def report_offline_session(cls, task, folder): diff --git a/clearml/backend_interface/task/populate.py b/clearml/backend_interface/task/populate.py new file mode 100644 index 00000000..cd1239fb --- /dev/null +++ b/clearml/backend_interface/task/populate.py @@ -0,0 +1,317 @@ +import json +import os +from functools import reduce +from logging import getLogger +from typing import Optional, Sequence + +from six.moves.urllib.parse import urlparse + +from pathlib2 import Path + +from ...task import Task +from .repo import ScriptInfo + + +class CreateAndPopulate(object): + def __init__( + self, + project_name=None, # Optional[str] + task_name=None, # Optional[str] + task_type=None, # Optional[str] + repo=None, # Optional[str] + branch=None, # Optional[str] + commit=None, # Optional[str] + script=None, # Optional[str] + working_directory=None, # Optional[str] + packages=None, # Optional[Sequence[str]] + requirements_file=None, # Optional[Union[str, Path]] + docker=None, # Optional[str] + base_task_id=None, # Optional[str] + add_task_init_call=True, # bool + raise_on_missing_entries=False, # bool + ): + # type: (...) -> None + """ + Create a new Task from an existing code base. + If the code does not already contain a call to Task.init, pass add_task_init_call=True, + and the code will be patched in remote execution (i.e. when executed by `clearml-agent` + + :param project_name: Set the project name for the task. Required if base_task_id is None. + :param task_name: Set the name of the remote task. Required if base_task_id is None. + :param task_type: Optional, The task type to be created. Supported values: 'training', 'testing', 'inference', + 'data_processing', 'application', 'monitor', 'controller', 'optimizer', 'service', 'qc', 'custom' + :param repo: Remote URL for the repository to use, or path to local copy of the git repository + Example: 'https://github.com/allegroai/clearml.git' or '~/project/repo' + :param branch: Select specific repository branch/tag (implies the latest commit from the branch) + :param commit: Select specific commit id to use (default: latest commit, + or when used with local repository matching the local commit id) + :param script: Specify the entry point script for the remote execution. When used in tandem with + remote git repository the script should be a relative path inside the repository, + for example: './source/train.py' . When used with local repository path it supports a + direct path to a file inside the local repository itself, for example: '~/project/source/train.py' + :param working_directory: Working directory to launch the script from. Default: repository root folder. + Relative to repo root or local folder. + :param packages: Manually specify a list of required packages. Example: ["tqdm>=2.1", "scikit-learn"] + :param requirements_file: Specify requirements.txt file to install when setting the session. + If not provided, the requirements.txt from the repository will be used. + :param docker: Select the docker image to be executed in by the remote session + :param base_task_id: Use a pre-existing task in the system, instead of a local repo/script. + Essentially clones an existing task and overrides arguments/requirements. + :param add_task_init_call: If True, a 'Task.init()' call is added to the script entry point in remote execution. + :param raise_on_missing_entries: If True raise ValueError on missing entries when populating + """ + if len(urlparse(repo).scheme) <= 1: + folder = repo + repo = None + else: + folder = None + + if raise_on_missing_entries and not base_task_id: + if not script: + raise ValueError("Entry point script not provided") + if not repo and not folder and not Path(script).is_file(): + raise ValueError("Repository or script must be provided") + if raise_on_missing_entries and commit and branch: + raise ValueError( + "Specify either a branch/tag or specific commit id, not both (either --commit or --branch)") + if raise_on_missing_entries and not folder and working_directory and working_directory.startswith('/'): + raise ValueError("working directory \'{}\', must be relative to repository root") + + if requirements_file and not Path(requirements_file).is_file(): + raise ValueError("requirements file could not be found \'{}\'") + + self.folder = folder + self.commit = commit + self.branch = branch + self.repo = repo + self.script = script + self.cwd = working_directory + assert not packages or isinstance(packages, (tuple, list)) + self.packages = list(packages) if packages else None + self.requirements_file = Path(requirements_file) if requirements_file else None + self.base_task_id = base_task_id + self.docker = docker + self.add_task_init_call = add_task_init_call + self.project_name = project_name + self.task_name = task_name + self.task_type = task_type + self.task = None + self.raise_on_missing_entries = raise_on_missing_entries + + def create_task(self): + # type: () -> Task + """ + Create the new populated Task + + :return: newly created Task object + """ + local_entry_file = None + repo_info = None + if self.folder or (self.script and Path(self.script).is_file()): + self.folder = os.path.expandvars(os.path.expanduser(self.folder)) if self.folder else None + self.script = os.path.expandvars(os.path.expanduser(self.script)) if self.script else None + self.cwd = os.path.expandvars(os.path.expanduser(self.cwd)) if self.cwd else None + if Path(self.script).is_file(): + entry_point = self.script + else: + entry_point = (Path(self.folder) / self.script).as_posix() + entry_point = os.path.abspath(entry_point) + if not os.path.isfile(entry_point): + raise ValueError("Script entrypoint file \'{}\' could not be found".format(entry_point)) + + local_entry_file = entry_point + repo_info, requirements = ScriptInfo.get( + filepaths=[entry_point], + log=getLogger(), + create_requirements=False, uncommitted_from_remote=True) + + # check if we have no repository and no requirements raise error + if self.raise_on_missing_entries and not self.requirements_file and not self.repo and ( + not repo_info or not repo_info.script or not repo_info.script.get('repository')): + raise ValueError("Standalone script detected \'{}\', but no requirements provided".format(self.script)) + + if self.base_task_id: + print('Cloning task {}'.format(self.base_task_id)) + task = Task.clone(source_task=self.base_task_id, project=Task.get_project_id(self.project_name)) + else: + # noinspection PyProtectedMember + task = Task._create(task_name=self.task_name, project_name=self.project_name, task_type=self.task_type) + # if there is nothing to populate, return + if not any([ + self.folder, self.commit, self.branch, self.repo, self.script, self.cwd, + self.packages, self.requirements_file, self.base_task_id, self.docker + ]): + return task + + task_state = task.export_task() + if 'script' not in task_state: + task_state['script'] = {} + + if repo_info: + task_state['script']['repository'] = repo_info.script['repository'] + task_state['script']['version_num'] = repo_info.script['version_num'] + task_state['script']['branch'] = repo_info.script['branch'] + task_state['script']['diff'] = repo_info.script['diff'] or '' + task_state['script']['working_dir'] = repo_info.script['working_dir'] + task_state['script']['entry_point'] = repo_info.script['entry_point'] + task_state['script']['binary'] = repo_info.script['binary'] + task_state['script']['requirements'] = {} + if self.cwd: + self.cwd = self.cwd + cwd = self.cwd if Path(self.cwd).is_dir() else ( + Path(repo_info.script['repo_root']) / self.cwd).as_posix() + if not Path(cwd).is_dir(): + raise ValueError("Working directory \'{}\' could not be found".format(cwd)) + cwd = Path(cwd).relative_to(repo_info.script['repo_root']).as_posix() + entry_point = \ + Path(repo_info.script['repo_root']) / repo_info.script['working_dir'] / repo_info.script[ + 'entry_point'] + entry_point = entry_point.relative_to(cwd).as_posix() + task_state['script']['entry_point'] = entry_point + task_state['script']['working_dir'] = cwd + elif self.repo: + # normalize backslashes and remove first one + entry_point = '/'.join([p for p in self.script.split('/') if p and p != '.']) + cwd = '/'.join([p for p in (self.cwd or '.').split('/') if p and p != '.']) + if cwd and entry_point.startswith(cwd + '/'): + entry_point = entry_point[len(cwd) + 1:] + task_state['script']['repository'] = self.repo + task_state['script']['version_num'] = self.commit or None + task_state['script']['branch'] = self.branch or None + task_state['script']['diff'] = '' + task_state['script']['working_dir'] = cwd or '.' + task_state['script']['entry_point'] = entry_point + + # update requirements + reqs = [] + if self.requirements_file: + with open(self.requirements_file.as_posix(), 'rt') as f: + reqs = [line.strip() for line in f.readlines()] + if self.packages: + reqs += self.packages + if reqs: + # make sure we have clearml. + clearml_found = False + for line in reqs: + if line.strip().startswith('#'): + continue + package = reduce(lambda a, b: a.split(b)[0], "#;@=~<>", line).strip() + if package == 'clearml': + clearml_found = True + break + if not clearml_found: + reqs.append('clearml') + task_state['script']['requirements'] = {'pip': '\n'.join(reqs)} + elif not self.repo and repo_info: + # we are in local mode, make sure we have "requirements.txt" it is a must + reqs_txt_file = Path(repo_info.script['repo_root']) / "requirements.txt" + if self.raise_on_missing_entries and not reqs_txt_file.is_file(): + raise ValueError( + "requirements.txt not found [{}] " + "Use --requirements or --packages".format(reqs_txt_file.as_posix())) + + if self.add_task_init_call: + script_entry = os.path.abspath('/' + task_state['script']['working_dir'] + + '/' + task_state['script']['entry_point']) + idx_a = 0 + # find the right entry for the patch if we have a local file (basically after __future__ + if local_entry_file: + with open(local_entry_file, 'rt') as f: + lines = f.readlines() + future_found = -1 + for i, line in enumerate(lines): + tokens = [t.strip() for t in line.split(' ') if t.strip()] + if tokens and tokens[0] in ('import', 'from',): + if '__future__' in line: + future_found = i + else: + break + if future_found >= 0: + idx_a = future_found + 1 + + task_init_patch = '' + # if we do not have requirements, add clearml to the requirements.txt + if not reqs: + task_init_patch += \ + "diff --git a/requirements.txt b/requirements.txt\n" \ + "--- a/requirements.txt\n" \ + "+++ b/requirements.txt\n" \ + "@@ -0,0 +1,1 @@\n" \ + "+clearml\n" + + task_init_patch += \ + "diff --git a{script_entry} b{script_entry}\n" \ + "--- a{script_entry}\n" \ + "+++ b{script_entry}\n" \ + "@@ -{idx_a},0 +{idx_b},3 @@\n" \ + "+from clearml import Task\n" \ + "+Task.init()\n" \ + "+\n".format( + script_entry=script_entry, idx_a=idx_a, idx_b=idx_a + 1) + + task_state['script']['diff'] = task_init_patch + task_state['script']['diff'] + + # set base docker image if provided + if self.docker: + task.set_base_docker(self.docker) + + if task_state['script']['repository']: + repo_details = {k: v for k, v in task_state['script'].items() + if v and k not in ('diff', 'requirements', 'binary')} + print('Repository Detected\n{}'.format(json.dumps(repo_details, indent=2))) + else: + print('Standalone script detected\n Script: {}\n: Requirements: {}'.format( + self.script, task_state['script']['requirements'].get('pip', []))) + + if task_state['script'].get('requirements') and task_state['script']['requirements'].get('pip'): + print('Requirements:\n requirements.txt: {}\n Additional Packages:{}'.format( + self.requirements_file.as_posix().name if self.requirements_file else '', self.packages)) + if self.docker: + print('Base docker image: {}'.format(self.docker)) + + # update the Task + task.update_task(task_state) + self.task = task + return task + + def update_task_args(self, args=None): + # type: (Optional[Sequence[str]]) -> () + """ + Update the newly created Task argparse Arguments + If called before Task created, used for argument verification + + :param args: Arguments to pass to the remote execution, list of string pairs (argument, value) or + list of strings '='. Example: ['lr=0.003', (batch_size, 64)] + """ + if not args: + return + + # check args are in format = + args_list = [] + for a in args: + if isinstance(a, (list, tuple)): + assert len(a) == 2 + args_list.append(a) + continue + try: + parts = a.split('=', 1) + assert len(parts) == 2 + args_list.append(parts) + except Exception: + raise ValueError( + "Failed parsing argument \'{}\', arguments must be in \'=\' format") + + if not self.task: + return + + task_params = self.task.get_parameters() + args_list = {'Args/{}'.format(k): v for k, v in args_list} + task_params.update(args_list) + self.task.set_parameters(task_params) + + def get_id(self): + # type: () -> Optional[str] + """ + :return: Return the created Task id (str) + """ + return self.task.id if self.task else None diff --git a/clearml/backend_interface/task/repo/scriptinfo.py b/clearml/backend_interface/task/repo/scriptinfo.py index 977fa426..3f0dd2fc 100644 --- a/clearml/backend_interface/task/repo/scriptinfo.py +++ b/clearml/backend_interface/task/repo/scriptinfo.py @@ -52,21 +52,21 @@ class ScriptRequirements(object): try: # noinspection PyPackageRequirements,PyUnresolvedReferences import boto3 # noqa: F401 - modules.add('boto3', 'trains.storage', 0) + modules.add('boto3', 'clearml.storage', 0) except Exception: pass # noinspection PyBroadException try: # noinspection PyPackageRequirements,PyUnresolvedReferences from google.cloud import storage # noqa: F401 - modules.add('google_cloud_storage', 'trains.storage', 0) + modules.add('google_cloud_storage', 'clearml.storage', 0) except Exception: pass # noinspection PyBroadException try: # noinspection PyPackageRequirements,PyUnresolvedReferences from azure.storage.blob import ContentSettings # noqa: F401 - modules.add('azure_storage_blob', 'trains.storage', 0) + modules.add('azure_storage_blob', 'clearml.storage', 0) except Exception: pass @@ -100,7 +100,7 @@ class ScriptRequirements(object): from ..task import Task # noinspection PyProtectedMember for package, version in Task._force_requirements.items(): - modules.add(package, 'trains', 0) + modules.add(package, 'clearml', 0) except Exception: pass @@ -265,7 +265,7 @@ class _JupyterObserver(object): @classmethod def _daemon(cls, jupyter_notebook_filename): - from trains import Task + from clearml import Task # load jupyter notebook package # noinspection PyBroadException @@ -715,12 +715,12 @@ class ScriptInfo(object): jupyter_filepath=jupyter_filepath, ) - if repo_info.modified: - messages.append( - "======> WARNING! UNCOMMITTED CHANGES IN REPOSITORY {} <======".format( - script_info.get("repository", "") - ) - ) + # if repo_info.modified: + # messages.append( + # "======> WARNING! UNCOMMITTED CHANGES IN REPOSITORY {} <======".format( + # script_info.get("repository", "") + # ) + # ) if not any(script_info.values()): script_info = None diff --git a/clearml/backend_interface/task/task.py b/clearml/backend_interface/task/task.py index 96ad742c..c9944e88 100644 --- a/clearml/backend_interface/task/task.py +++ b/clearml/backend_interface/task/task.py @@ -27,6 +27,7 @@ from six.moves.urllib.parse import quote from ...utilities.locks import RLock as FileRLock from ...utilities.attrs import readonly +from ...utilities.proxy_object import verify_basic_type from ...binding.artifacts import Artifacts from ...backend_interface.task.development.worker import DevWorker from ...backend_api import Session @@ -144,9 +145,9 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): self.__reporter = None self._curr_label_stats = {} self._raise_on_validation_errors = raise_on_validation_errors - self._parameters_allowed_types = ( + self._parameters_allowed_types = tuple(set( six.string_types + six.integer_types + (six.text_type, float, list, tuple, dict, type(None)) - ) + )) self._app_server = None self._files_server = None self._initial_iteration_offset = 0 @@ -216,7 +217,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): ) else: self.get_logger().report_text( - 'TRAINS new version available: upgrade to v{} is recommended!'.format( + 'ClearML new version available: upgrade to v{} is recommended!'.format( latest_version[0]), ) except Exception: @@ -296,8 +297,8 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): if task_type.value not in (self.TaskTypes.training, self.TaskTypes.testing) and \ not Session.check_min_api_version('2.8'): print('WARNING: Changing task type to "{}" : ' - 'trains-server does not support task type "{}", ' - 'please upgrade trains-server.'.format(self.TaskTypes.training, task_type.value)) + 'clearml-server does not support task type "{}", ' + 'please upgrade clearml-server.'.format(self.TaskTypes.training, task_type.value)) task_type = self.TaskTypes.training project_id = None @@ -402,7 +403,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): # type: () -> str """ The Task's status. To keep the Task updated. - Trains reloads the Task status information only, when this value is accessed. + ClearML reloads the Task status information only, when this value is accessed. return str: TaskStatusEnum status """ @@ -445,7 +446,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): def reload(self): # type: () -> () """ - Reload current Task's state from trains-server. + Reload current Task's state from clearml-server. Refresh all task's fields, including artifacts / models / parameters etc. """ return super(Task, self).reload() @@ -628,9 +629,9 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): ): # type: (...) -> str """ - Update the Task's output model weights file. First, Trains uploads the file to the preconfigured output + Update the Task's output model weights file. First, ClearML uploads the file to the preconfigured output destination (see the Task's ``output.destination`` property or call the ``setup_upload`` method), - then Trains updates the model object associated with the Task an API call. The API call uses with the URI + then ClearML updates the model object associated with the Task an API call. The API call uses with the URI of the uploaded file, and other values provided by additional arguments. :param str model_file: The path to the updated model weights file. @@ -684,19 +685,19 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): Set a new input model for the Task. The model must be "ready" (status is ``Published``) to be used as the Task's input model. - :param model_id: The Id of the model on the **Trains Server** (backend). If ``model_name`` is not specified, + :param model_id: The Id of the model on the **ClearML Server** (backend). If ``model_name`` is not specified, then ``model_id`` must be specified. - :param model_name: The model name. The name is used to locate an existing model in the **Trains Server** + :param model_name: The model name. The name is used to locate an existing model in the **ClearML Server** (backend). If ``model_id`` is not specified, then ``model_name`` must be specified. :param update_task_design: Update the Task's design - - ``True`` - Trains copies the Task's model design from the input model. - - ``False`` - Trains does not copy the Task's model design from the input model. + - ``True`` - ClearML copies the Task's model design from the input model. + - ``False`` - ClearML does not copy the Task's model design from the input model. :param update_task_labels: Update the Task's label enumeration - - ``True`` - Trains copies the Task's label enumeration from the input model. - - ``False`` - Trains does not copy the Task's label enumeration from the input model. + - ``True`` - ClearML copies the Task's label enumeration from the input model. + - ``False`` - ClearML does not copy the Task's label enumeration from the input model. """ if model_id is None and not model_name: raise ValueError('Expected one of [model_id, model_name]') @@ -749,7 +750,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): i.e. {'Args/param': 'value'} is the argument "param" from section "Args" :param backwards_compatibility: If True (default) parameters without section name - (API version < 2.9, trains-server < 0.16) will be at dict root level. + (API version < 2.9, clearml-server < 0.16) will be at dict root level. If False, parameters without section name, will be nested under "Args/" key. :return: dict of the task parameters, all flattened to key/value. @@ -838,14 +839,15 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): not_allowed = { k: type(v).__name__ for k, v in new_parameters.items() - if not isinstance(v, self._parameters_allowed_types) + if not verify_basic_type(v, self._parameters_allowed_types) } if not_allowed: - raise ValueError( - "Only builtin types ({}) are allowed for values (got {})".format( - ', '.join(t.__name__ for t in self._parameters_allowed_types), - ', '.join('%s=>%s' % p for p in not_allowed.items())), + self.log.warning( + "Skipping parameter: {}, only builtin types are supported ({})".format( + ', '.join('%s[%s]' % p for p in not_allowed.items()), + ', '.join(t.__name__ for t in self._parameters_allowed_types)) ) + new_parameters = {k: v for k, v in new_parameters.items() if k not in not_allowed} use_hyperparams = Session.check_min_api_version('2.9') @@ -958,7 +960,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): :return: True if the parameter was deleted successfully """ if not Session.check_min_api_version('2.9'): - raise ValueError("Delete hyper parameter is not supported by your trains-server, " + raise ValueError("Delete hyper parameter is not supported by your clearml-server, " "upgrade to the latest version") with self._edit_lock: paramkey = tasks.ParamKey(section=name.split('/', 1)[0], name=name.split('/', 1)[1]) @@ -1011,7 +1013,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): # type: (str) -> () """ Set the base docker image for this experiment - If provided, this value will be used by trains-agent to execute this experiment + If provided, this value will be used by clearml-agent to execute this experiment inside the provided docker image. When running remotely the call is ignored """ @@ -1275,7 +1277,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): # type: () -> str """ Return the Task results & outputs web page address. - For example: https://demoapp.trains.allegro.ai/projects/216431/experiments/60763e04/output/log + For example: https://demoapp.demo.clear.ml/projects/216431/experiments/60763e04/output/log :return: http/s URL link. """ @@ -1428,7 +1430,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): def running_locally(): # type: () -> bool """ - Is the task running locally (i.e., ``trains-agent`` is not executing it) + Is the task running locally (i.e., ``clearml-agent`` is not executing it) :return: True, if the task is running locally. False, if the task is not running locally. @@ -1637,7 +1639,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): mutually_exclusive(config_dict=config_dict, config_text=config_text, _check_none=True) if not Session.check_min_api_version('2.9'): - raise ValueError("Multiple configurations is not supported with the current 'trains-server', " + raise ValueError("Multiple configurations is not supported with the current 'clearml-server', " "please upgrade to the latest version") if description: @@ -1661,7 +1663,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): return None if configuration name is not valid. """ if not Session.check_min_api_version('2.9'): - raise ValueError("Multiple configurations is not supported with the current 'trains-server', " + raise ValueError("Multiple configurations is not supported with the current 'clearml-server', " "please upgrade to the latest version") configuration = self.data.configuration or {} @@ -1725,6 +1727,22 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): """ session = session if session else cls._get_default_session() + use_clone_api = Session.check_min_api_version('2.9') + if use_clone_api: + res = cls._send( + session=session, log=log, + req=tasks.CloneRequest( + task=cloned_task_id, + new_task_name=name, + new_task_tags=tags, + new_task_comment=comment, + new_task_parent=parent, + new_task_project=project, + execution_overrides=execution_overrides, + ) + ) + cloned_task_id = res.response.id + return cloned_task_id res = cls._send(session=session, log=log, req=tasks.GetByIdRequest(task=cloned_task_id)) task = res.response.task @@ -1858,7 +1876,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin): if not PROC_MASTER_ID_ENV_VAR.get() or len(PROC_MASTER_ID_ENV_VAR.get().split(':')) < 2: self.__edit_lock = RLock() elif PROC_MASTER_ID_ENV_VAR.get().split(':')[1] == str(self.id): - filename = os.path.join(gettempdir(), 'trains_{}.lock'.format(self.id)) + filename = os.path.join(gettempdir(), 'clearml_{}.lock'.format(self.id)) # no need to remove previous file lock if we have a dead process, it will automatically release the lock. # # noinspection PyBroadException # try: diff --git a/clearml/binding/artifacts.py b/clearml/binding/artifacts.py index 85f6588c..ffa043f5 100644 --- a/clearml/binding/artifacts.py +++ b/clearml/binding/artifacts.py @@ -187,7 +187,7 @@ class Artifact(object): :raise: Raises error if local copy not found. :return: A local path to a downloaded copy of the artifact. """ - from trains.storage import StorageManager + from clearml.storage import StorageManager local_copy = StorageManager.get_local_copy( remote_url=self.url, extract_archive=extract_archive and self.type == 'archive', @@ -308,7 +308,7 @@ class Artifacts(object): delete_after_upload=False, auto_pickle=True, wait_on_upload=False): # type: (str, Optional[object], Optional[dict], Optional[str], bool, bool, bool) -> bool if not Session.check_min_api_version('2.3'): - LoggerRoot.get_base_logger().warning('Artifacts not supported by your TRAINS-server version, ' + LoggerRoot.get_base_logger().warning('Artifacts not supported by your ClearML-server version, ' 'please upgrade to the latest server version') return False @@ -648,7 +648,7 @@ class Artifacts(object): return self._last_artifacts_upload[name] = current_sha2 - # If old trains-server, upload as debug image + # If old clearml-server, upload as debug image if not Session.check_min_api_version('2.3'): logger.report_image(title='artifacts', series=name, local_path=local_csv.as_posix(), delete_after_upload=True, iteration=self._task.get_last_iteration(), @@ -698,7 +698,7 @@ class Artifacts(object): """ Upload local file and return uri of the uploaded file (uploading in the background) """ - from trains.storage import StorageManager + from clearml.storage import StorageManager upload_uri = self._task.output_uri or self._task.get_logger().get_default_upload_destination() if not isinstance(local_file, Path): @@ -715,7 +715,7 @@ class Artifacts(object): # send for upload # noinspection PyProtectedMember if wait_on_upload: - StorageManager.upload_file(local_file.as_posix(), uri) + StorageManager.upload_file(local_file.as_posix(), uri, wait_for_upload=True, retries=ev.retries) if delete_after_upload: try: os.unlink(local_file.as_posix()) diff --git a/clearml/binding/environ_bind.py b/clearml/binding/environ_bind.py index b2902b7f..af52343c 100644 --- a/clearml/binding/environ_bind.py +++ b/clearml/binding/environ_bind.py @@ -44,7 +44,7 @@ class EnvironmentBind(object): match = match.strip() if match == '*': env_param.update({k: os.environ.get(k) for k in os.environ - if not k.startswith('TRAINS_') and not k.startswith('ALG_')}) + if not k.startswith('TRAINS_') and not k.startswith('CLEARML_')}) elif match.endswith('*'): match = match.strip('*') env_param.update({k: os.environ.get(k) for k in os.environ if k.startswith(match)}) diff --git a/clearml/binding/frameworks/__init__.py b/clearml/binding/frameworks/__init__.py index b658f8b2..2a24ab83 100644 --- a/clearml/binding/frameworks/__init__.py +++ b/clearml/binding/frameworks/__init__.py @@ -114,7 +114,7 @@ class WeightsFileHandler(object): Add a pre-save/load callback for weights files and return its handle. If the callback was already added, return the existing handle. - Use this callback to modify the weights filename registered in the Trains Server. In case Trains is + Use this callback to modify the weights filename registered in the ClearML Server. In case ClearML is configured to upload the weights file, this will affect the uploaded filename as well. Callback returning None will disable the tracking of the current call Model save, it will not disable saving it to disk, just the logging/tracking/uploading. @@ -422,7 +422,7 @@ class WeightsFileHandler(object): # HACK: if pytorch-lightning is used, remove the temp '.part' file extension if sys.modules.get('pytorch_lightning') and target_filename.lower().endswith('.part'): target_filename = target_filename[:-len('.part')] - fd, temp_file = mkstemp(prefix='.trains.upload_model_', suffix='.tmp') + fd, temp_file = mkstemp(prefix='.clearml.upload_model_', suffix='.tmp') os.close(fd) shutil.copy(files[0], temp_file) trains_out_model.update_weights( diff --git a/clearml/binding/frameworks/tensorflow_bind.py b/clearml/binding/frameworks/tensorflow_bind.py index a9b00267..8012636f 100644 --- a/clearml/binding/frameworks/tensorflow_bind.py +++ b/clearml/binding/frameworks/tensorflow_bind.py @@ -192,7 +192,7 @@ class WeightsGradientHistHelper(object): class EventTrainsWriter(object): """ TF SummaryWriter implementation that converts the tensorboard's summary into - Trains events and reports the events (metrics) for an Trains task (logger). + ClearML events and reports the events (metrics) for an ClearML task (logger). """ _add_lock = threading.RLock() _series_name_lookup = {} @@ -298,8 +298,8 @@ class EventTrainsWriter(object): def __init__(self, logger, logdir=None, report_freq=100, image_report_freq=None, histogram_update_freq_multiplier=10, histogram_granularity=50, max_keep_images=None): """ - Create a compatible Trains backend to the TensorFlow SummaryToEventTransformer - Everything will be serialized directly to the Trains backend, instead of to the standard TF FileWriter + Create a compatible ClearML backend to the TensorFlow SummaryToEventTransformer + Everything will be serialized directly to the ClearML backend, instead of to the standard TF FileWriter :param logger: The task.logger to use for sending the metrics (def: task.get_logger()) :param report_freq: How often to update the statistics values @@ -846,7 +846,7 @@ class PatchSummaryToEventTransformer(object): if PatchSummaryToEventTransformer.__original_getattribute is None: PatchSummaryToEventTransformer.__original_getattribute = SummaryToEventTransformer.__getattribute__ SummaryToEventTransformer.__getattribute__ = PatchSummaryToEventTransformer._patched_getattribute - setattr(SummaryToEventTransformer, 'trains', + setattr(SummaryToEventTransformer, 'clearml', property(PatchSummaryToEventTransformer.trains_object)) except Exception as ex: LoggerRoot.get_base_logger(TensorflowBinding).debug(str(ex)) @@ -859,7 +859,7 @@ class PatchSummaryToEventTransformer(object): from torch.utils.tensorboard.writer import FileWriter as FileWriterT # noqa PatchSummaryToEventTransformer._original_add_eventT = FileWriterT.add_event FileWriterT.add_event = PatchSummaryToEventTransformer._patched_add_eventT - setattr(FileWriterT, 'trains', None) + setattr(FileWriterT, 'clearml', None) except ImportError: # this is a new version of TensorflowX pass @@ -875,7 +875,7 @@ class PatchSummaryToEventTransformer(object): PatchSummaryToEventTransformer.__original_getattributeX = \ SummaryToEventTransformerX.__getattribute__ SummaryToEventTransformerX.__getattribute__ = PatchSummaryToEventTransformer._patched_getattributeX - setattr(SummaryToEventTransformerX, 'trains', + setattr(SummaryToEventTransformerX, 'clearml', property(PatchSummaryToEventTransformer.trains_object)) except ImportError: # this is a new version of TensorflowX @@ -890,7 +890,7 @@ class PatchSummaryToEventTransformer(object): from tensorboardX.writer import FileWriter as FileWriterX # noqa PatchSummaryToEventTransformer._original_add_eventX = FileWriterX.add_event FileWriterX.add_event = PatchSummaryToEventTransformer._patched_add_eventX - setattr(FileWriterX, 'trains', None) + setattr(FileWriterX, 'clearml', None) except ImportError: # this is a new version of TensorflowX pass @@ -899,38 +899,38 @@ class PatchSummaryToEventTransformer(object): @staticmethod def _patched_add_eventT(self, *args, **kwargs): - if not hasattr(self, 'trains') or not PatchSummaryToEventTransformer.__main_task: + if not hasattr(self, 'clearml') or not PatchSummaryToEventTransformer.__main_task: return PatchSummaryToEventTransformer._original_add_eventT(self, *args, **kwargs) - if not self.trains: + if not self.clearml: # noqa # noinspection PyBroadException try: logdir = self.get_logdir() except Exception: logdir = None - self.trains = EventTrainsWriter(PatchSummaryToEventTransformer.__main_task.get_logger(), + self.clearml = EventTrainsWriter(PatchSummaryToEventTransformer.__main_task.get_logger(), logdir=logdir, **PatchSummaryToEventTransformer.defaults_dict) # noinspection PyBroadException try: - self.trains.add_event(*args, **kwargs) + self.clearml.add_event(*args, **kwargs) except Exception: pass return PatchSummaryToEventTransformer._original_add_eventT(self, *args, **kwargs) @staticmethod def _patched_add_eventX(self, *args, **kwargs): - if not hasattr(self, 'trains') or not PatchSummaryToEventTransformer.__main_task: + if not hasattr(self, 'clearml') or not PatchSummaryToEventTransformer.__main_task: return PatchSummaryToEventTransformer._original_add_eventX(self, *args, **kwargs) - if not self.trains: + if not self.clearml: # noinspection PyBroadException try: logdir = self.get_logdir() except Exception: logdir = None - self.trains = EventTrainsWriter(PatchSummaryToEventTransformer.__main_task.get_logger(), + self.clearml = EventTrainsWriter(PatchSummaryToEventTransformer.__main_task.get_logger(), logdir=logdir, **PatchSummaryToEventTransformer.defaults_dict) # noinspection PyBroadException try: - self.trains.add_event(*args, **kwargs) + self.clearml.add_event(*args, **kwargs) except Exception: pass return PatchSummaryToEventTransformer._original_add_eventX(self, *args, **kwargs) @@ -947,17 +947,17 @@ class PatchSummaryToEventTransformer(object): @staticmethod def _patched_getattribute_(self, attr, get_base): - # no main task, zero chance we have an Trains event logger + # no main task, zero chance we have an ClearML event logger if PatchSummaryToEventTransformer.__main_task is None: return get_base(self, attr) - # check if we already have an Trains event logger + # check if we already have an ClearML event logger __dict__ = get_base(self, '__dict__') if 'event_writer' not in __dict__ or \ isinstance(__dict__['event_writer'], (ProxyEventsWriter, EventTrainsWriter)): return get_base(self, attr) - # patch the events writer field, and add a double Event Logger (Trains and original) + # patch the events writer field, and add a double Event Logger (ClearML and original) base_eventwriter = __dict__['event_writer'] # noinspection PyBroadException try: @@ -1062,7 +1062,7 @@ class PatchModelCheckPointCallback(object): if PatchModelCheckPointCallback.__original_getattribute is None and callbacks is not None: PatchModelCheckPointCallback.__original_getattribute = callbacks.ModelCheckpoint.__getattribute__ callbacks.ModelCheckpoint.__getattribute__ = PatchModelCheckPointCallback._patched_getattribute - setattr(callbacks.ModelCheckpoint, 'trains', + setattr(callbacks.ModelCheckpoint, 'clearml', property(PatchModelCheckPointCallback.trains_object)) except Exception as ex: @@ -1072,17 +1072,17 @@ class PatchModelCheckPointCallback(object): def _patched_getattribute(self, attr): get_base = PatchModelCheckPointCallback.__original_getattribute - # no main task, zero chance we have an Trains event logger + # no main task, zero chance we have an ClearML event logger if PatchModelCheckPointCallback.__main_task is None: return get_base(self, attr) - # check if we already have an Trains event logger + # check if we already have an ClearML event logger __dict__ = get_base(self, '__dict__') if 'model' not in __dict__ or \ isinstance(__dict__['model'], _ModelAdapter): return get_base(self, attr) - # patch the events writer field, and add a double Event Logger (Trains and original) + # patch the events writer field, and add a double Event Logger (ClearML and original) base_model = __dict__['model'] defaults_dict = __dict__.get('_trains_defaults') or PatchModelCheckPointCallback.defaults_dict output_model = OutputModel( diff --git a/clearml/cli/__init__.py b/clearml/cli/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/clearml/cli/__init__.py @@ -0,0 +1 @@ + diff --git a/clearml/cli/config/__init__.py b/clearml/cli/config/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/clearml/cli/config/__init__.py @@ -0,0 +1 @@ + diff --git a/clearml/config/default/__main__.py b/clearml/cli/config/__main__.py similarity index 87% rename from clearml/config/default/__main__.py rename to clearml/cli/config/__main__.py index 410bacf6..ae4c2abf 100644 --- a/clearml/config/default/__main__.py +++ b/clearml/cli/config/__main__.py @@ -1,4 +1,4 @@ -""" Trains configuration wizard""" +""" ClearML configuration wizard""" from __future__ import print_function import argparse @@ -8,22 +8,23 @@ from pathlib2 import Path from six.moves import input from six.moves.urllib.parse import urlparse -from trains.backend_api.session import Session -from trains.backend_api.session.defs import ENV_HOST -from trains.backend_config.defs import LOCAL_CONFIG_FILES, LOCAL_CONFIG_FILE_OVERRIDE_VAR -from trains.config import config_obj -from trains.utilities.pyhocon import ConfigFactory, ConfigMissingException +from clearml.backend_api.session import Session +from clearml.backend_api.session.defs import ENV_HOST +from clearml.backend_config.defs import LOCAL_CONFIG_FILES, LOCAL_CONFIG_FILE_OVERRIDE_VAR +from clearml.config import config_obj +from clearml.utilities.pyhocon import ConfigFactory, ConfigMissingException description = "\n" \ - "Please create new trains credentials through the profile page in " \ - "your trains web app (e.g. http://localhost:8080/profile)\n" \ + "Please create new clearml credentials through the profile page in " \ + "your clearml web app (e.g. http://localhost:8080/profile) \n"\ + "Or with the free hosted service at https://app.community.clear.ml/profile\n" \ "In the profile page, press \"Create new credentials\", then press \"Copy to clipboard\".\n" \ "\n" \ "Paste copied configuration here:\n" host_description = """ Editing configuration file: {CONFIG_FILE} -Enter the url of the trains-server's Web service, for example: {HOST} +Enter the url of the clearml-server's Web service, for example: {HOST} """ # noinspection PyBroadException @@ -40,7 +41,12 @@ def validate_file(string): def main(): - default_config_file = os.getenv(LOCAL_CONFIG_FILE_OVERRIDE_VAR) or LOCAL_CONFIG_FILES[0] + default_config_file = LOCAL_CONFIG_FILE_OVERRIDE_VAR.get() + if not default_config_file: + for f in LOCAL_CONFIG_FILES: + default_config_file = f + if os.path.exists(os.path.expanduser(os.path.expandvars(f))): + break p = argparse.ArgumentParser(description=__doc__) p.add_argument( @@ -51,16 +57,20 @@ def main(): args = p.parse_args() - print('TRAINS SDK setup process') + print('ClearML SDK setup process') - conf_file = Path(args.file).absolute() + conf_file = Path(os.path.expanduser(args.file)).absolute() if conf_file.exists() and conf_file.is_file() and conf_file.stat().st_size > 0: print('Configuration file already exists: {}'.format(str(conf_file))) print('Leaving setup, feel free to edit the configuration file.') return print(description, end='') sentinel = '' - parse_input = '\n'.join(iter(input, sentinel)) + parse_input = '' + for line in iter(input, sentinel): + parse_input += line+'\n' + if line.rstrip() == '}': + break credentials = None api_server = None web_server = None @@ -104,7 +114,7 @@ def main(): files_host = input_url('File Store Host', files_host) - print('\nTRAINS Hosts configuration:\nWeb App: {}\nAPI: {}\nFile Store: {}\n'.format( + print('\nClearML Hosts configuration:\nWeb App: {}\nAPI: {}\nFile Store: {}\n'.format( web_host, api_host, files_host)) retry = 1 @@ -121,7 +131,7 @@ def main(): # noinspection PyBroadException try: - default_sdk_conf = Path(__file__).parent.absolute() / 'sdk.conf' + default_sdk_conf = Path(__file__).absolute().parents[2] / 'config/default/sdk.conf' with open(str(default_sdk_conf), 'rt') as f: default_sdk = f.read() except Exception: @@ -130,14 +140,14 @@ def main(): # noinspection PyBroadException try: with open(str(conf_file), 'wt') as f: - header = '# TRAINS SDK configuration file\n' \ + header = '# ClearML SDK configuration file\n' \ 'api {\n' \ ' # Notice: \'host\' is the api server (default port 8008), not the web server.\n' \ ' api_server: %s\n' \ ' web_server: %s\n' \ ' files_server: %s\n' \ ' # Credentials are generated using the webapp, %s/profile\n' \ - ' # Override with os environment: TRAINS_API_ACCESS_KEY / TRAINS_API_SECRET_KEY\n' \ + ' # Override with os environment: CLEARML_API_ACCESS_KEY / CLEARML_API_SECRET_KEY\n' \ ' credentials {"access_key": "%s", "secret_key": "%s"}\n' \ '}\n' \ 'sdk ' % (api_host, web_host, files_host, @@ -149,7 +159,7 @@ def main(): return print('\nNew configuration stored in {}'.format(str(conf_file))) - print('TRAINS setup completed successfully.') + print('ClearML setup completed successfully.') def parse_host(parsed_host, allow_input=True): @@ -290,7 +300,7 @@ def verify_url(parse_input): parsed_host = None except Exception: parsed_host = None - print('Could not parse url {}\nEnter your trains-server host: '.format(parse_input), end='') + print('Could not parse url {}\nEnter your clearml-server host: '.format(parse_input), end='') return parsed_host diff --git a/clearml/cli/task/__init__.py b/clearml/cli/task/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/clearml/cli/task/__init__.py @@ -0,0 +1 @@ + diff --git a/clearml/cli/task/__main__.py b/clearml/cli/task/__main__.py new file mode 100644 index 00000000..61a6ec9e --- /dev/null +++ b/clearml/cli/task/__main__.py @@ -0,0 +1,119 @@ +from argparse import ArgumentParser + +from pathlib2 import Path + +from clearml.backend_interface.task.populate import CreateAndPopulate +from clearml import Task + + +def setup_parser(parser): + parser.add_argument('--version', action='store_true', default=None, + help='Display the clearml-task utility version') + parser.add_argument('--project', type=str, default=None, + help='Required: set the project name for the task. ' + 'If --base-task-id is used, this arguments is optional.') + parser.add_argument('--name', type=str, default=None, required=True, + help='Required: select a name for the remote task') + parser.add_argument('--repo', type=str, default=None, + help='remote URL for the repository to use. ' + 'Example: --repo https://github.com/allegroai/clearml.git') + parser.add_argument('--branch', type=str, default=None, + help='Select specific repository branch/tag (implies the latest commit from the branch)') + parser.add_argument('--commit', type=str, default=None, + help='Select specific commit id to use (default: latest commit, ' + 'or when used with local repository matching the local commit id)') + parser.add_argument('--folder', type=str, default=None, + help='Remotely execute the code in the local folder. ' + 'Notice! It assumes a git repository already exists. ' + 'Current state of the repo (commit id and uncommitted changes) is logged ' + 'and will be replicated on the remote machine') + parser.add_argument('--script', type=str, default=None, + help='Specify the entry point script for the remote execution. ' + 'When used in tandem with --repo the script should be a relative path inside ' + 'the repository, for example: --script source/train.py .' + 'When used with --folder it supports a direct path to a file inside the local ' + 'repository itself, for example: --script ~/project/source/train.py') + parser.add_argument('--cwd', type=str, default=None, + help='Working directory to launch the script from. Default: repository root folder. ' + 'Relative to repo root or local folder') + parser.add_argument('--args', default=None, nargs='*', + help='Arguments to pass to the remote execution, list of = strings.' + 'Currently only argparse arguments are supported. ' + 'Example: --args lr=0.003 batch_size=64') + parser.add_argument('--queue', type=str, default=None, + help='Select the queue to launch the task. ' + 'If not provided a Task will be created but it will not be launched.') + parser.add_argument('--requirements', type=str, default=None, + help='Specify requirements.txt file to install when setting the session. ' + 'If not provided, the requirements.txt from the repository will be used.') + parser.add_argument('--packages', default=None, nargs='*', + help='Manually specify a list of required packages. ' + 'Example: --packages "tqdm>=2.1" "scikit-learn"') + parser.add_argument('--docker', type=str, default=None, + help='Select the docker image to use in the remote session') + parser.add_argument('--skip-task-init', action='store_true', default=None, + help='If set, Task.init() call is not added to the entry point, and is assumed ' + 'to be called in within the script. Default: add Task.init() call entry point script') + parser.add_argument('--base-task-id', type=str, default=None, + help='Use a pre-existing task in the system, instead of a local repo/script. ' + 'Essentially clones an existing task and overrides arguments/requirements.') + + +def cli(): + title = 'ClearML launch - launch any codebase on remote machine running clearml-agent' + print(title) + parser = ArgumentParser(description=title) + setup_parser(parser) + + # get the args + args = parser.parse_args() + + if args.version: + from ...version import __version__ + print('Version {}'.format(__version__)) + exit(0) + + create_populate = CreateAndPopulate( + project_name=args.project, + task_name=args.name, + repo=args.repo or args.folder, + branch=args.branch, + commit=args.commit, + script=args.script, + working_directory=args.cwd, + packages=args.packages, + requirements_file=args.requirements, + base_task_id=args.base_task_id, + add_task_init_call=not args.skip_task_init, + raise_on_missing_entries=True, + ) + # verify args + create_populate.update_task_args(args.args) + + print('Creating new task') + create_populate.create_task() + # update Task args + create_populate.update_task_args(args.args) + + print('New task created id={}'.format(create_populate.get_id())) + if not args.queue: + print('Warning: No queue was provided, leaving task in draft-mode.') + exit(0) + + Task.enqueue(create_populate.task, queue_name=args.queue) + print('Task id={} sent for execution on queue {}'.format(create_populate.get_id(), args.queue)) + print('Execution log at: {}'.format(create_populate.task.get_output_log_web_page())) + + +def main(): + try: + cli() + except KeyboardInterrupt: + print('\nUser aborted') + except Exception as ex: + print('\nError: {}'.format(ex)) + exit(1) + + +if __name__ == '__main__': + main() diff --git a/clearml/config/__init__.py b/clearml/config/__init__.py index 02295e06..107f8135 100644 --- a/clearml/config/__init__.py +++ b/clearml/config/__init__.py @@ -135,7 +135,10 @@ def dev_worker_name(): def __set_is_master_node(): # noinspection PyBroadException try: - force_master_node = os.environ.pop('TRAINS_FORCE_MASTER_NODE', None) + # pop both set the first + env_a = os.environ.pop('CLEARML_FORCE_MASTER_NODE', None) + env_b = os.environ.pop('TRAINS_FORCE_MASTER_NODE', None) + force_master_node = env_a or env_b except Exception: force_master_node = None diff --git a/clearml/config/default/logging.conf b/clearml/config/default/logging.conf index 6b3cb071..458695fa 100644 --- a/clearml/config/default/logging.conf +++ b/clearml/config/default/logging.conf @@ -2,7 +2,7 @@ version: 1 disable_existing_loggers: 0 loggers { - trains { + clearml { level: INFO } boto { diff --git a/clearml/config/default/sdk.conf b/clearml/config/default/sdk.conf index 9f481049..20c19a07 100644 --- a/clearml/config/default/sdk.conf +++ b/clearml/config/default/sdk.conf @@ -1,10 +1,10 @@ { - # TRAINS - default SDK configuration + # ClearML - default SDK configuration storage { cache { # Defaults to system temp folder / cache - default_base_dir: "~/.trains/cache" + default_base_dir: "~/.clearml/cache" } direct_access: [ @@ -93,7 +93,7 @@ google.storage { # # Default project and credentials file # # Will be used when no bucket configuration is found - # project: "trains" + # project: "clearml" # credentials_json: "/path/to/credentials.json" # # Specific credentials per bucket and sub directory @@ -101,7 +101,7 @@ # { # bucket: "my-bucket" # subdir: "path/in/bucket" # Not required - # project: "trains" + # project: "clearml" # credentials_json: "/path/to/credentials.json" # }, # ] @@ -109,7 +109,7 @@ azure.storage { # containers: [ # { - # account_name: "trains" + # account_name: "clearml" # account_key: "secret" # # container_name: # } @@ -150,8 +150,8 @@ # do not analyze the entire repository. force_analyze_entire_repo: false - # If set to true, *trains* update message will not be printed to the console - # this value can be overwritten with os environment variable TRAINS_SUPPRESS_UPDATE_MESSAGE=1 + # If set to true, *clearml* update message will not be printed to the console + # this value can be overwritten with os environment variable CLEARML_SUPPRESS_UPDATE_MESSAGE=1 suppress_update_message: false # If this flag is true (default is false), instead of analyzing the code with Pigar, analyze with `pip freeze` @@ -161,7 +161,7 @@ # of the Hyper-Parameters. # multiple selected variables are supported including the suffix '*'. # For example: "AWS_*" will log any OS environment variable starting with 'AWS_'. - # This value can be overwritten with os environment variable TRAINS_LOG_ENVIRONMENT="[AWS_*, CUDA_VERSION]" + # This value can be overwritten with os environment variable CLEARML_LOG_ENVIRONMENT="[AWS_*, CUDA_VERSION]" # Example: log_os_environments: ["AWS_*", "CUDA_VERSION"] log_os_environments: [] diff --git a/clearml/config/defs.py b/clearml/config/defs.py index 87a9cb5e..8fe85ac4 100644 --- a/clearml/config/defs.py +++ b/clearml/config/defs.py @@ -5,28 +5,28 @@ from ..backend_config.converters import base64_to_text, or_ from pathlib2 import Path SESSION_CACHE_FILE = ".session.json" -DEFAULT_CACHE_DIR = str(Path(tempfile.gettempdir()) / "trains_cache") +DEFAULT_CACHE_DIR = str(Path(tempfile.gettempdir()) / "clearml_cache") -TASK_ID_ENV_VAR = EnvEntry("TRAINS_TASK_ID", "ALG_TASK_ID") -DOCKER_IMAGE_ENV_VAR = EnvEntry("TRAINS_DOCKER_IMAGE", "ALG_DOCKER_IMAGE") -LOG_TO_BACKEND_ENV_VAR = EnvEntry("TRAINS_LOG_TASK_TO_BACKEND", "ALG_LOG_TASK_TO_BACKEND", type=bool) -NODE_ID_ENV_VAR = EnvEntry("TRAINS_NODE_ID", "ALG_NODE_ID", type=int) -PROC_MASTER_ID_ENV_VAR = EnvEntry("TRAINS_PROC_MASTER_ID", "ALG_PROC_MASTER_ID", type=str) -LOG_STDERR_REDIRECT_LEVEL = EnvEntry("TRAINS_LOG_STDERR_REDIRECT_LEVEL", "ALG_LOG_STDERR_REDIRECT_LEVEL") -DEV_WORKER_NAME = EnvEntry("TRAINS_WORKER_NAME", "ALG_WORKER_NAME") -DEV_TASK_NO_REUSE = EnvEntry("TRAINS_TASK_NO_REUSE", "ALG_TASK_NO_REUSE", type=bool) -TASK_LOG_ENVIRONMENT = EnvEntry("TRAINS_LOG_ENVIRONMENT", "ALG_LOG_ENVIRONMENT", type=str) -TRAINS_CACHE_DIR = EnvEntry("TRAINS_CACHE_DIR", "ALG_CACHE_DIR") +TASK_ID_ENV_VAR = EnvEntry("CLEARML_TASK_ID", "TRAINS_TASK_ID") +DOCKER_IMAGE_ENV_VAR = EnvEntry("CLEARML_DOCKER_IMAGE", "TRAINS_DOCKER_IMAGE") +LOG_TO_BACKEND_ENV_VAR = EnvEntry("CLEARML_LOG_TASK_TO_BACKEND", "TRAINS_LOG_TASK_TO_BACKEND", type=bool) +NODE_ID_ENV_VAR = EnvEntry("CLEARML_NODE_ID", "TRAINS_NODE_ID", type=int) +PROC_MASTER_ID_ENV_VAR = EnvEntry("CLEARML_PROC_MASTER_ID", "TRAINS_PROC_MASTER_ID", type=str) +LOG_STDERR_REDIRECT_LEVEL = EnvEntry("CLEARML_LOG_STDERR_REDIRECT_LEVEL", "TRAINS_LOG_STDERR_REDIRECT_LEVEL") +DEV_WORKER_NAME = EnvEntry("CLEARML_WORKER_NAME", "TRAINS_WORKER_NAME") +DEV_TASK_NO_REUSE = EnvEntry("CLEARML_TASK_NO_REUSE", "TRAINS_TASK_NO_REUSE", type=bool) +TASK_LOG_ENVIRONMENT = EnvEntry("CLEARML_LOG_ENVIRONMENT", "TRAINS_LOG_ENVIRONMENT", type=str) +TRAINS_CACHE_DIR = EnvEntry("CLEARML_CACHE_DIR", "TRAINS_CACHE_DIR") -LOG_LEVEL_ENV_VAR = EnvEntry("TRAINS_LOG_LEVEL", "ALG_LOG_LEVEL", converter=or_(int, str)) +LOG_LEVEL_ENV_VAR = EnvEntry("CLEARML_LOG_LEVEL", "TRAINS_LOG_LEVEL", converter=or_(int, str)) -SUPPRESS_UPDATE_MESSAGE_ENV_VAR = EnvEntry("TRAINS_SUPPRESS_UPDATE_MESSAGE", "ALG_SUPPRESS_UPDATE_MESSAGE", type=bool) +SUPPRESS_UPDATE_MESSAGE_ENV_VAR = EnvEntry("CLEARML_SUPPRESS_UPDATE_MESSAGE", "TRAINS_SUPPRESS_UPDATE_MESSAGE", type=bool) # Repository detection -VCS_REPO_TYPE = EnvEntry("TRAINS_VCS_REPO_TYPE", "ALG_VCS_REPO_TYPE", default="git") -VCS_REPOSITORY_URL = EnvEntry("TRAINS_VCS_REPO_URL", "ALG_VCS_REPO_URL") -VCS_COMMIT_ID = EnvEntry("TRAINS_VCS_COMMIT_ID", "ALG_VCS_COMMIT_ID") -VCS_BRANCH = EnvEntry("TRAINS_VCS_BRANCH", "ALG_VCS_BRANCH") -VCS_ROOT = EnvEntry("TRAINS_VCS_ROOT", "ALG_VCS_ROOT") -VCS_STATUS = EnvEntry("TRAINS_VCS_STATUS", "ALG_VCS_STATUS", converter=base64_to_text) -VCS_DIFF = EnvEntry("TRAINS_VCS_DIFF", "ALG_VCS_DIFF", converter=base64_to_text) +VCS_REPO_TYPE = EnvEntry("CLEARML_VCS_REPO_TYPE", "TRAINS_VCS_REPO_TYPE", default="git") +VCS_REPOSITORY_URL = EnvEntry("CLEARML_VCS_REPO_URL", "TRAINS_VCS_REPO_URL") +VCS_COMMIT_ID = EnvEntry("CLEARML_VCS_COMMIT_ID", "TRAINS_VCS_COMMIT_ID") +VCS_BRANCH = EnvEntry("CLEARML_VCS_BRANCH", "TRAINS_VCS_BRANCH") +VCS_ROOT = EnvEntry("CLEARML_VCS_ROOT", "TRAINS_VCS_ROOT") +VCS_STATUS = EnvEntry("CLEARML_VCS_STATUS", "TRAINS_VCS_STATUS", converter=base64_to_text) +VCS_DIFF = EnvEntry("CLEARML_VCS_DIFF", "TRAINS_VCS_DIFF", converter=base64_to_text) diff --git a/clearml/datasets/__init__.py b/clearml/datasets/__init__.py new file mode 100644 index 00000000..84f8c2a8 --- /dev/null +++ b/clearml/datasets/__init__.py @@ -0,0 +1,6 @@ +from .dataset import FileEntry, Dataset + +__all__ = [ + "FileEntry", + "Dataset", +] diff --git a/clearml/datasets/dataset.py b/clearml/datasets/dataset.py new file mode 100644 index 00000000..a8de4c00 --- /dev/null +++ b/clearml/datasets/dataset.py @@ -0,0 +1,1244 @@ +import json +import os +import shutil +from copy import deepcopy, copy +from fnmatch import fnmatch +from multiprocessing import cpu_count +from multiprocessing.pool import ThreadPool +from tempfile import mkstemp, mkdtemp +from typing import Union, Optional, Sequence, List, Dict, Any, Mapping +from zipfile import ZipFile, ZIP_DEFLATED + +import humanfriendly +from attr import attrs, attrib +from pathlib2 import Path + +from .. import Task, StorageManager +from ..backend_api.session.client import APIClient +from ..backend_interface.util import mutually_exclusive, exact_match_regex +from ..debugging.log import LoggerRoot +from ..storage.helper import StorageHelper +from ..storage.cache import CacheManager +from ..storage.util import sha256sum, is_windows, md5text + +try: + from pathlib import Path as _Path # noqa +except ImportError: + _Path = None + + +@attrs +class FileEntry: + relative_path = attrib(default=None, type=str) + hash = attrib(default=None, type=str) + parent_dataset_id = attrib(default=None, type=str) + size = attrib(default=None, type=int) + # cleared when file is uploaded. + local_path = attrib(default=None, type=str) + + def as_dict(self): + # type: () -> Dict + state = dict(relative_path=self.relative_path, hash=self.hash, + parent_dataset_id=self.parent_dataset_id, size=self.size, + **dict([('local_path', self.local_path)] if self.local_path else ())) + return state + + +class Dataset(object): + __private_magic = 42 * 1337 + __state_entry_name = 'state' + __data_entry_name = 'data' + __cache_context = 'datasets' + __tag = 'dataset' + __cache_folder_prefix = 'ds_' + __dataset_folder_template = CacheManager.set_context_folder_lookup(__cache_context, "{0}_archive_{1}") + __preview_max_file_entries = 15000 + __preview_max_size = 5 * 1024 * 1024 + + def __init__(self, _private, task=None, dataset_project=None, dataset_name=None): + # type: (int, Optional[Task], Optional[str], Optional[str]) -> () + """ + Do not use directly! Use Dataset.create(...) or Dataset.get(...) instead. + """ + assert _private == self.__private_magic + # key for the dataset file entries are the relative path within the data + self._dataset_file_entries = {} # type: Dict[str, FileEntry] + # this will create a graph of all the dependencies we have, each entry lists it's own direct parents + self._dependency_graph = {} # type: Dict[str, List[str]] + if not task: + task = Task.create( + project_name=dataset_project, task_name=dataset_name, task_type=Task.TaskTypes.data_processing) + task.set_system_tags((task.get_system_tags() or []) + [self.__tag]) + task.mark_started() + # generate the script section + script = \ + 'from clearml import Dataset\n\n' \ + 'ds = Dataset.create(dataset_project=\'{dataset_project}\', dataset_name=\'{dataset_name}\')\n'.format( + dataset_project=dataset_project, dataset_name=dataset_name) + task.data.script.diff = script + task.data.script.working_dir = '.' + task.data.script.entry_point = 'register_dataset.py' + from clearml import __version__ + task.data.script.requirements = {'pip': 'clearml == {}\n'.format(__version__)} + # noinspection PyProtectedMember + task._edit(script=task.data.script) + + # store current dataset Task + self._task = task + # store current dataset id + self._id = task.id + # store the folder where the dataset was downloaded to + self._local_base_folder = None # type: Optional[Path] + # dirty flag, set True by any function call changing the dataset (regardless of weather it did anything) + self._dirty = False + + @property + def id(self): + # type: () -> str + return self._id + + @property + def file_entries(self): + # type: () -> List[FileEntry] + return list(self._dataset_file_entries.values()) + + @property + def file_entries_dict(self): + # type: () -> Mapping[str, FileEntry] + """ + Notice this call returns an internal representation, do not modify! + :return: dict with relative file path as key, and FileEntry as value + """ + return self._dataset_file_entries + + @property + def project(self): + # type: () -> str + return self._task.get_project_name() + + @property + def name(self): + # type: () -> str + return self._task.name + + @property + def tags(self): + # type: () -> List[str] + return self._task.get_tags() or [] + + @tags.setter + def tags(self, values): + # type: (List[str]) -> () + self._task.set_tags(values or []) + + def add_files(self, + path, # type: Union[str, Path, _Path] + wildcard=None, # type: Optional[Union[str, Sequence[str]]] + local_base_folder=None, # type: Optional[str] + dataset_path=None, # type: Optional[str] + recursive=True, # type: bool + verbose=False # type: bool + ): + # type: (...) -> () + """ + Add a folder into the current dataset. calculate file hash, + and compare against parent, mark files to be uploaded + + :param path: Add a folder/file to the dataset + :param wildcard: add only specific set of files. + Wildcard matching, can be a single string or a list of wildcards) + :param local_base_folder: files will be located based on their relative path from local_base_folder + :param dataset_path: where in the dataset the folder/files should be located + :param recursive: If True match all wildcard files recursively + :param verbose: If True print to console files added/modified + :return: number of files added + """ + self._dirty = True + self._task.get_logger().report_text( + 'Adding files to dataset: {}'.format( + dict(path=path, wildcard=wildcard, local_base_folder=local_base_folder, + dataset_path=dataset_path, recursive=recursive, verbose=verbose)), + print_console=False) + + num_added = self._add_files( + path=path, wildcard=wildcard, local_base_folder=local_base_folder, + dataset_path=dataset_path, recursive=recursive, verbose=verbose) + + # update the task script + self._add_script_call( + 'add_files', path=path, wildcard=wildcard, local_base_folder=local_base_folder, + dataset_path=dataset_path, recursive=recursive) + + self._serialize() + + return num_added + + def remove_files(self, dataset_path=None, recursive=True, verbose=False): + # type: (Optional[str], bool, bool) -> int + """ + Add a folder into the current dataset. calculate file hash, + and compare against parent, mark files to be uploaded + + :param dataset_path: Remove files from the dataset. + The path is always relative to the dataset (e.g 'folder/file.bin') + :param recursive: If True match all wildcard files recursively + :param verbose: If True print to console files removed + :return: Number of files removed + """ + self._dirty = True + self._task.get_logger().report_text( + 'Removing files from dataset: {}'.format( + dict(dataset_path=dataset_path, recursive=recursive, verbose=verbose)), + print_console=False) + + if dataset_path and dataset_path.startswith('/'): + dataset_path = dataset_path[1:] + + num_files = len(self._dataset_file_entries) + org_files = list(self._dataset_file_entries.keys()) if verbose else None + + if not recursive: + self._dataset_file_entries = { + k: v for k, v in self._dataset_file_entries.items() + if not fnmatch(k + '/', dataset_path + '/')} + else: + wildcard = dataset_path.split('/')[-1] + path = dataset_path[:-len(dataset_path)] + '*' + + self._dataset_file_entries = { + k: v for k, v in self._dataset_file_entries.items() + if not (fnmatch(k, path) and fnmatch(k, '*/' + wildcard))} + + if verbose and org_files: + for f in org_files: + if f not in self._dataset_file_entries: + self._task.get_logger().report_text('Remove {}'.format(f)) + + # update the task script + self._add_script_call( + 'remove_files', dataset_path=dataset_path, recursive=recursive) + + self._serialize() + + return num_files - len(self._dataset_file_entries) + + def sync_folder(self, local_path, dataset_path=None, verbose=False): + # type: (Union[Path, _Path, str], Union[Path, _Path, str], bool) -> (int, int) + """ + Synchronize the dataset with a local folder. The dataset is synchronized from the + relative_base_folder (default: dataset root) and deeper with the specified local path. + + :param local_path: Local folder to sync (assumes all files and recursive) + :param dataset_path: Target dataset path to sync with (default the root of the dataset) + :param verbose: If true print to console files added/modified/removed + :return: number of files removed, number of files modified/added + """ + def filter_f(f): + keep = (not f.relative_path.startswith(relative_prefix) or + (local_path / f.relative_path[len(relative_prefix):]).is_file()) + if not keep and verbose: + self._task.get_logger().report_text('Remove {}'.format(f.relative_path)) + return keep + + self._task.get_logger().report_text( + 'Syncing local copy with dataset: {}'.format( + dict(local_path=local_path, dataset_path=dataset_path, verbose=verbose)), + print_console=False) + + self._dirty = True + local_path = Path(local_path) + + # Path().as_posix() will never end with / + relative_prefix = (Path(dataset_path).as_posix() + '/') if dataset_path else '' + + # remove files + num_files = len(self._dataset_file_entries) + self._dataset_file_entries = { + k: f for k, f in self._dataset_file_entries.items() if filter_f(f)} + removed_files = num_files - len(self._dataset_file_entries) + + # add remaining files + added_files = self._add_files(path=local_path, dataset_path=dataset_path, recursive=True, verbose=verbose) + + if verbose: + self._task.get_logger().report_text( + 'Syncing folder {} : {} files removed, {} added / modified'.format( + local_path.as_posix(), removed_files, added_files)) + + # update the task script + self._add_script_call( + 'sync_folder', local_path=local_path, dataset_path=dataset_path) + + self._serialize() + return removed_files, added_files + + def upload(self, show_progress=True, verbose=False, output_url=None, compression=None): + # type: (bool, bool, Optional[str], Optional[str]) -> () + """ + Start file uploading, the function returns when all files are uploaded. + + :param show_progress: If True show upload progress bar + :param verbose: If True print verbose progress report + :param output_url: Target storage for the compressed dataset (default: file server) + Examples: `s3://bucket/data`, `gs://bucket/data` , `azure://bucket/data` , `/mnt/share/data` + :param compression: Compression algorithm for the Zipped dataset file (default: ZIP_DEFLATED) + """ + # set output_url + if output_url: + self._task.output_uri = output_url + + self._task.get_logger().report_text( + 'Uploading dataset files: {}'.format( + dict(show_progress=show_progress, verbose=verbose, output_url=output_url, compression=compression)), + print_console=False) + + fd, zip_file = mkstemp( + prefix='dataset.{}.'.format(self._id), suffix='.zip' + ) + archive_preview = '' + count = 0 + try: + with ZipFile(zip_file, 'w', allowZip64=True, compression=compression or ZIP_DEFLATED) as zf: + for file_entry in self._dataset_file_entries.values(): + if not file_entry.local_path: + # file is located in a different version + continue + filename = Path(file_entry.local_path) + if not filename.is_file(): + LoggerRoot.get_base_logger().warning( + "Could not store dataset file {}. File skipped".format(file_entry.local_path)) + # mark for removal + file_entry.relative_path = None + continue + if verbose: + self._task.get_logger().report_text('Compressing {}'.format(filename.as_posix())) + + relative_file_name = file_entry.relative_path + zf.write(filename.as_posix(), arcname=relative_file_name) + archive_preview += '{} - {}\n'.format( + relative_file_name, humanfriendly.format_size(filename.stat().st_size)) + file_entry.local_path = None + count += 1 + except Exception as e: + # failed uploading folder: + LoggerRoot.get_base_logger().warning( + 'Exception {}\nFailed zipping dataset.'.format(e)) + return False + finally: + os.close(fd) + + zip_file = Path(zip_file) + + if not count: + zip_file.unlink() + LoggerRoot.get_base_logger().warning('No pending files, uploaded aborted') + return False + + archive_preview = 'Dataset archive content [{} files]:\n'.format(count) + archive_preview + + # noinspection PyBroadException + try: + # let's try to rename it + new_zip_file = zip_file.parent / 'dataset.{}.zip'.format(self._id) + zip_file.rename(new_zip_file) + zip_file = new_zip_file + except Exception: + pass + # remove files that could not be zipped, containing Null relative Path + self._dataset_file_entries = {k: v for k, v in self._dataset_file_entries.items() + if v.relative_path is not None} + # start upload + zip_file_size = humanfriendly.format_size(Path(zip_file).stat().st_size) + self._task.get_logger().report_text( + 'Uploading compressed dataset changes ({} files, total {})'.format(count, zip_file_size)) + self._task.upload_artifact( + name=self.__data_entry_name, artifact_object=Path(zip_file), preview=archive_preview, + delete_after_upload=True, wait_on_upload=True) + self._task.get_logger().report_text('Upload completed ({})'.format(zip_file_size)) + + self._add_script_call( + 'upload', show_progress=show_progress, verbose=verbose, output_url=output_url, compression=compression) + + self._dirty = False + self._serialize() + + def finalize(self, verbose=False, raise_on_error=True): + # type: (bool, bool) -> bool + """ + Finalize the dataset (if upload was not called, it will be called automatically) publish dataset Task. + If files need to be uploaded, throw exception (or return False) + + :param verbose: If True print verbose progress report + :param raise_on_error: If True raise exception if dataset finalizing failed + """ + # check we do not have files waiting for upload. + if self._dirty: + if raise_on_error: + raise ValueError("Cannot finalize dataset, pending uploads. Call Dataset.upload(...)") + return False + + self._task.get_logger().report_text('Finalizing dataset', print_console=False) + + # make sure we have no redundant parent versions + self._serialize() + self._add_script_call('finalize') + if verbose: + print('Updating statistics and genealogy') + self._report_dataset_genealogy() + hashed_nodes = [self._get_dataset_id_hash(k) for k in self._dependency_graph.keys()] + self._task.comment = 'Dependencies: {}\n'.format(hashed_nodes) + self._task.close() + self._task.completed() + return True + + def is_final(self): + # type: () -> bool + """ + Return True if the dataset was finalized and cannot be changed any more. + + :return: True if dataset if final + """ + return self._task.get_status() not in ( + Task.TaskStatusEnum.in_progress, Task.TaskStatusEnum.created, Task.TaskStatusEnum.failed) + + def get_local_copy(self, use_soft_links=None, raise_on_error=True): + # type: (bool, bool) -> str + """ + return a base folder with a read-only (immutable) local copy of the entire dataset + download and copy / soft-link, files from all the parent dataset versions + + :param use_soft_links: If True use soft links, default False on windows True on Posix systems + :param raise_on_error: If True raise exception if dataset merging failed on any file + :return: A base folder for the entire dataset + """ + assert self._id + if not self._task: + self._task = Task.get_task(task_id=self._id) + + # now let's merge the parents + target_folder = self._merge_datasets(use_soft_links=use_soft_links, raise_on_error=raise_on_error) + return target_folder + + def get_mutable_local_copy(self, target_folder, overwrite=False, raise_on_error=True): + # type: (Union[Path, _Path, str], bool, bool) -> Optional[str] + """ + return a base folder with a writable (mutable) local copy of the entire dataset + download and copy / soft-link, files from all the parent dataset versions + + :param target_folder: Target folder for the writable copy + :param overwrite: If True, recursively delete the target folder before creating a copy. + If False (default) and target folder contains files, raise exception or return None + :param raise_on_error: If True raise exception if dataset merging failed on any file + :return: A the target folder containing the entire dataset + """ + assert self._id + target_folder = Path(target_folder) + target_folder.mkdir(parents=True, exist_ok=True) + # noinspection PyBroadException + try: + target_folder.rmdir() + except Exception: + if not overwrite: + if raise_on_error: + raise ValueError("Target folder {} already contains files".format(target_folder.as_posix())) + else: + return None + shutil.rmtree(target_folder.as_posix()) + + ro_folder = self.get_local_copy(raise_on_error=raise_on_error) + shutil.copytree(ro_folder, target_folder.as_posix()) + return target_folder.as_posix() + + def list_files(self, dataset_path=None, recursive=True, dataset_id=None): + # type: (Optional[str], bool, Optional[str]) -> List[str] + """ + returns a list of files in the current dataset + If dataset_id is give, return a list of files that remained unchanged since the specified dataset_version + + :param dataset_path: Only match files matching the dataset_path (including wildcards). + Example: folder/sub/*.json + :param recursive: If True (default) matching dataset_path recursively + :param dataset_id: Filter list based on the dataset id containing the latest version of the file. + Default: None, do not filter files based on parent dataset. + :return: List of files with relative path + (files might not be available locally until get_local_copy() is called) + """ + files = self._dataset_file_entries.keys() if not dataset_id else \ + [k for k, v in self._dataset_file_entries.items() if v.parent_dataset_id == dataset_id] + + if not dataset_path: + return sorted(files) + + if dataset_path.startswith('/'): + dataset_path = dataset_path[1:] + + if not recursive: + return sorted([k for k in files if fnmatch(k + '/', dataset_path + '/')]) + + wildcard = dataset_path.split('/')[-1] + path = dataset_path[:-len(wildcard)] + '*' + return sorted([k for k in files if fnmatch(k, path) and fnmatch(k, '*/' + wildcard)]) + + def list_removed_files(self, dataset_id=None): + # type: (str) -> List[str] + """ + return a list of files removed when comparing to a specific dataset_version + + :param dataset_id: dataset id (str) to compare against, if None is given compare against the parents datasets + :return: List of files with relative path + (files might not be available locally until get_local_copy() is called) + """ + datasets = self._dependency_graph[self._id] if not dataset_id else [dataset_id] + unified_list = set() + for ds_id in datasets: + dataset = self.get(dataset_id=ds_id) + unified_list |= set(dataset._dataset_file_entries.keys()) + + removed_list = [f for f in unified_list if f not in self._dataset_file_entries] + return sorted(removed_list) + + def list_modified_files(self, dataset_id=None): + # type: (str) -> List[str] + """ + return a list of files removed when comparing to a specific dataset_version + + :param dataset_id: dataset id (str) to compare against, if None is given compare against the parents datasets + :return: List of files with relative path + (files might not be available locally until get_local_copy() is called) + """ + datasets = self._dependency_graph[self._id] if not dataset_id else [dataset_id] + unified_list = dict() + for ds_id in datasets: + dataset = self.get(dataset_id=ds_id) + unified_list.update(dict((k, v.hash) for k, v in dataset._dataset_file_entries.items())) + + modified_list = [k for k, v in self._dataset_file_entries.items() + if k in unified_list and v.hash != unified_list[k]] + return sorted(modified_list) + + def list_added_files(self, dataset_id=None): + # type: (str) -> List[str] + """ + return a list of files removed when comparing to a specific dataset_version + + :param dataset_id: dataset id (str) to compare against, if None is given compare against the parents datasets + :return: List of files with relative path + (files might not be available locally until get_local_copy() is called) + """ + datasets = self._dependency_graph[self._id] if not dataset_id else [dataset_id] + unified_list = set() + for ds_id in datasets: + dataset = self.get(dataset_id=ds_id) + unified_list |= set(dataset._dataset_file_entries.keys()) + + added_list = [f for f in self._dataset_file_entries.keys() if f not in unified_list] + return sorted(added_list) + + def get_dependency_graph(self): + """ + return the DAG of the dataset dependencies (all previous dataset version and their parents/ + Example: + { + 'current_dataset_id': ['parent_1_id', 'parent_2_id'], + 'parent_2_id': ['parent_1_id'], + 'parent_1_id': [], + } + + :return: dict representing the genealogy dag graph of the current dataset + """ + return deepcopy(self._dependency_graph) + + def verify_dataset_hash(self, local_copy_path=None, skip_hash=False, verbose=False): + # type: (Optional[str], bool, bool) -> List[str] + """ + Verify the current copy of the dataset against the stored hash + + :param local_copy_path: Specify local path containing a copy of the dataset, + If not provide use the cached folder + :param skip_hash: If True, skip hash checks and verify file size only + :param verbose: If True print errors while testing dataset files hash + :return: List of files with unmatched hashes + """ + local_path = local_copy_path or self.get_local_copy() + + def compare(file_entry): + file_entry_copy = copy(file_entry) + file_entry_copy.local_path = (Path(local_path) / file_entry.relative_path).as_posix() + if skip_hash: + file_entry_copy.size = Path(file_entry_copy.local_path).stat().st_size + if file_entry_copy.size != file_entry.size: + if verbose: + print('Error: file size mismatch {} expected size {} current {}'.format( + file_entry.relative_path, file_entry.size, file_entry_copy.size)) + return file_entry + else: + self._calc_file_hash(file_entry_copy) + if file_entry_copy.hash != file_entry.hash: + if verbose: + print('Error: hash mismatch {} expected size/hash {}/{} recalculated {}/{}'.format( + file_entry.relative_path, + file_entry.size, file_entry.hash, + file_entry_copy.size, file_entry_copy.hash)) + return file_entry + + return None + + pool = ThreadPool(cpu_count() * 2) + matching_errors = pool.map(compare, self._dataset_file_entries.values()) + pool.close() + return [f.relative_path for f in matching_errors if f is not None] + + @classmethod + def create(cls, dataset_project, dataset_name, parent_datasets=None): + # type: (str, str, Optional[Sequence[Union[str, Dataset]]]) -> Dataset + """ + Create a new dataset. Multiple dataset parents are supported. + Merging of parent datasets is done based on the order, + where each one can override overlapping files in the previous parent + + :param dataset_project: Project containing the dataset + :param dataset_name: Naming the new dataset + :param parent_datasets: Expand a parent dataset by adding/removing files + :return: Newly created Dataset object + """ + parent_datasets = [cls.get(dataset_id=p) if isinstance(p, str) else p for p in (parent_datasets or [])] + if any(not p.is_final() for p in parent_datasets): + raise ValueError("Cannot inherit from a parent that was not finalized/closed") + + # merge datasets according to order + dataset_file_entries = {} + dependency_graph = {} + for p in parent_datasets: + dataset_file_entries.update(deepcopy(p._dataset_file_entries)) + dependency_graph.update(deepcopy(p._dependency_graph)) + instance = cls(_private=cls.__private_magic, dataset_project=dataset_project, dataset_name=dataset_name) + instance._task.get_logger().report_text('Dataset created', print_console=False) + instance._dataset_file_entries = dataset_file_entries + instance._dependency_graph = dependency_graph + instance._dependency_graph[instance._id] = [p._id for p in parent_datasets] + instance._serialize() + instance._task.flush(wait_for_uploads=True) + return instance + + @classmethod + def delete(cls, dataset_id=None, dataset_project=None, dataset_name=None, force=False): + # type: (Optional[str], Optional[str], Optional[str], bool) -> () + """ + Delete a dataset, raise exception if dataset is used by other dataset versions. + Use force=True to forcefully delete the dataset + + :param dataset_id: Dataset id to delete + :param dataset_project: Project containing the dataset + :param dataset_name: Naming the new dataset + :param force: If True delete even if other datasets depend on the specified dataset version + """ + mutually_exclusive(dataset_id=dataset_id, dataset_project=dataset_project) + mutually_exclusive(dataset_id=dataset_id, dataset_name=dataset_name) + if not dataset_id: + tasks = Task.get_tasks( + project_name=dataset_project, + task_name=exact_match_regex(dataset_name) if dataset_name else None, + task_filter=dict( + system_tags=[cls.__tag], + type=[str(Task.TaskTypes.data_processing)], + page_size=2, page=0,) + ) + if not tasks: + raise ValueError("Dataset project={} name={} could not be found".format(dataset_project, dataset_name)) + if len(tasks) > 1: + raise ValueError("Too many datasets matching project={} name={}".format(dataset_project, dataset_name)) + dataset_id = tasks[0].id + + # check if someone is using the datasets + if not force: + # noinspection PyProtectedMember + dependencies = Task._query_tasks( + system_tags=[cls.__tag], + type=[str(Task.TaskTypes.data_processing)], + only_fields=['created', 'id', 'name'], + search_text='{}'.format(cls._get_dataset_id_hash(dataset_id)) + ) + # filter us out + if dependencies: + dependencies = [d for d in dependencies if d.id != dataset_id] + if dependencies: + raise ValueError("Dataset id={} is used by datasets: {}".format( + dataset_id, [d.id for d in dependencies])) + + client = APIClient() + # notice the force here is a must, since the state is never draft + # noinspection PyBroadException + try: + t = client.tasks.get_by_id(dataset_id) + except Exception: + t = None + if not t: + raise ValueError("Dataset id={} could not be found".format(dataset_id)) + if str(t.type) != str(Task.TaskTypes.data_processing) or cls.__tag not in t.system_tags: + raise ValueError("Dataset id={} is not of type Dataset".format(dataset_id)) + + task = Task.get_task(task_id=dataset_id) + # first delete all the artifacts from the dataset + for artifact in task.artifacts.values(): + h = StorageHelper.get(artifact.url) + # noinspection PyBroadException + try: + h.delete(artifact.url) + except Exception as ex: + LoggerRoot.get_base_logger().warning('Failed deleting remote file \'{}\': {}'.format( + artifact.url, ex)) + + # now delete the actual task + client.tasks.delete(task=dataset_id, force=True) + + @classmethod + def get(cls, dataset_id=None, dataset_project=None, dataset_name=None, only_completed=False, only_published=False): + # type: (Optional[str], Optional[str], Optional[str], bool , bool) -> Dataset + """ + Get a specific Dataset. If only dataset_project is given, return the last Dataset in the Dataset project + + :param dataset_id: Requested Dataset ID + :param dataset_project: Requested Dataset project name + :param dataset_name: Requested Dataset name + :param only_completed: Return only if the requested dataset is completed or published + :param only_published: Return only if the requested dataset is published + :return: Dataset object + """ + mutually_exclusive(dataset_id=dataset_id, dataset_project=dataset_project) + mutually_exclusive(dataset_id=dataset_id, dataset_name=dataset_name) + tasks = Task.get_tasks( + task_ids=[dataset_id] if dataset_id else None, + project_name=dataset_project, + task_name=exact_match_regex(dataset_name) if dataset_name else None, + task_filter=dict( + system_tags=[cls.__tag, '-archived'], order_by=['-created'], + type=[str(Task.TaskTypes.data_processing)], + page_size=1, page=0, + status=['publish'] if only_published else + ['publish', 'stopped', 'completed', 'closed'] if only_completed else None) + ) + if not tasks: + raise ValueError('Could not find Dataset {} {}'.format( + 'id' if dataset_id else 'project/name', + dataset_id if dataset_id else (dataset_project, dataset_name))) + task = tasks[0] + if task.status == 'created': + raise ValueError('Dataset id={} is in draft mode, delete and recreate it'.format(task.id)) + force_download = False if task.status in ('stopped', 'published', 'closed', 'completed') else True + local_state_file = StorageManager.get_local_copy( + remote_url=task.artifacts[cls.__state_entry_name].url, cache_context=cls.__cache_context, + extract_archive=False, name=task.id, force_download=force_download) + if not local_state_file: + raise ValueError('Could not load Dataset id={} state'.format(task.id)) + + instance = cls._deserialize(local_state_file, task) + # remove the artifact, just in case + if force_download: + os.unlink(local_state_file) + + return instance + + @classmethod + def squash(cls, dataset_name, dataset_ids=None, dataset_project_name_pairs=None, output_url=None): + # type: (str, Optional[Sequence[Union[str, Dataset]]],Optional[Sequence[(str, str)]], Optional[str]) -> Dataset + """ + Generate a new dataset from the squashed set of dataset versions. + If a single version is given it will squash to the root (i.e. create single standalone version) + If a set of versions are given it will squash the versions diff into a single version + + :param dataset_name: Target name for the newly generated squashed dataset + :param dataset_ids: List of dataset Ids (or objects) to squash. Notice order does matter. + The versions are merged from first to last. + :param dataset_project_name_pairs: List of pairs (project_name, dataset_name) to squash. + Notice order does matter. The versions are merged from first to last. + :param output_url: Target storage for the compressed dataset (default: file server) + Examples: `s3://bucket/data`, `gs://bucket/data` , `azure://bucket/data` , `/mnt/share/data` + :return: Newly created dataset object. + """ + mutually_exclusive(dataset_ids=dataset_ids, dataset_project_name_pairs=dataset_project_name_pairs) + datasets = [cls.get(dataset_id=d) for d in dataset_ids] if dataset_ids else \ + [cls.get(dataset_project=pair[0], dataset_name=pair[1]) for pair in dataset_project_name_pairs] + # single dataset to squash, squash it all. + if len(datasets) == 1: + temp_folder = datasets[0].get_local_copy() + parents = set() + else: + parents = None + temp_folder = Path(mkdtemp(prefix='squash-datasets.')) + pool = ThreadPool() + for ds in datasets: + base_folder = Path(ds._extract_dataset_archive()) + files = [f.relative_path for f in ds.file_entries if f.parent_dataset_id == ds.id] + pool.map( + lambda x: + (temp_folder / x).parent.mkdir(parents=True, exist_ok=True) or + shutil.copy((base_folder / x).as_posix(), (temp_folder / x).as_posix(), follow_symlinks=True), + files) + parents = set(ds._get_parents()) if parents is None else (parents & set(ds._get_parents())) + pool.close() + + squashed_ds = cls.create( + dataset_project=datasets[0].project, dataset_name=dataset_name, parent_datasets=list(parents)) + squashed_ds._task.get_logger().report_text('Squashing dataset', print_console=False) + squashed_ds.add_files(temp_folder) + squashed_ds.upload(output_url=output_url) + squashed_ds.finalize() + return squashed_ds + + @classmethod + def list_datasets(cls, dataset_project=None, partial_name=None, tags=None, ids=None, only_completed=True): + # type: (Optional[str], Optional[str], Optional[Sequence[str]], Optional[Sequence[str]], bool) -> List[dict] + """ + Query list of dataset in the system + + :param dataset_project: Specify dataset project name + :param partial_name: Specify partial match to a dataset name + :param tags: Specify user tags + :param ids: List specific dataset based on IDs list + :param only_completed: If False return dataset that are still in progress (uploading/edited etc.) + :return: List of dictionaries with dataset information + Example: [{'name': name, 'project': project name, 'id': dataset_id, 'created': date_created},] + """ + # noinspection PyProtectedMember + datasets = Task._query_tasks( + task_ids=ids or None, project_name=dataset_project or None, + task_name=partial_name, + system_tags=[cls.__tag], + type=[str(Task.TaskTypes.data_processing)], + tags=tags or None, + status=['stopped', 'published', 'completed', 'closed'] if only_completed else None, + only_fields=['created', 'id', 'name', 'project'] + ) + project_ids = {d.project for d in datasets} + # noinspection PyProtectedMember + project_id_lookup = {d: Task._get_project_name(d) for d in project_ids} + return [ + {'name': d.name, 'created': d.created, 'project': project_id_lookup[d.project], 'id': d.id} + for d in datasets + ] + + def _add_files(self, + path, # type: Union[str, Path, _Path] + wildcard=None, # type: Optional[Union[str, Sequence[str]]] + local_base_folder=None, # type: Optional[str] + dataset_path=None, # type: Optional[str] + recursive=True, # type: bool + verbose=False # type: bool + ): + # type: (...) -> int + """ + Add a folder into the current dataset. calculate file hash, + and compare against parent, mark files to be uploaded + + :param path: Add a folder/file to the dataset + :param wildcard: add only specific set of files. + Wildcard matching, can be a single string or a list of wildcards) + :param local_base_folder: files will be located based on their relative path from local_base_folder + :param dataset_path: where in the dataset the folder/files should be located + :param recursive: If True match all wildcard files recursively + :param verbose: If True print to console added files + """ + if dataset_path and dataset_path.startswith('/'): + dataset_path = dataset_path[1:] + path = Path(path) + local_base_folder = Path(local_base_folder or path) + wildcard = wildcard or '*' + # single file, no need for threading + if path.is_file(): + file_entry = self._calc_file_hash( + FileEntry(local_path=path.absolute().as_posix(), + relative_path=Path(dataset_path or '.') / path.relative_to(local_base_folder), + parent_dataset_id=self._id)) + file_entries = [file_entry] + else: + # if not a folder raise exception + if not path.is_dir(): + raise ValueError("Could not find file/folder \'{}\'", path.as_posix()) + + # prepare a list of files + files = list(path.rglob(wildcard)) if recursive else list(path.glob(wildcard)) + file_entries = [ + FileEntry( + parent_dataset_id=self._id, + local_path=f.absolute().as_posix(), + relative_path=(Path(dataset_path or '.') / f.relative_to(local_base_folder)).as_posix()) + for f in files if f.is_file()] + self._task.get_logger().report_text('Generating SHA2 hash for {} files'.format(len(file_entries))) + pool = ThreadPool(cpu_count() * 2) + pool.map(self._calc_file_hash, file_entries) + pool.close() + self._task.get_logger().report_text('Hash generation completed') + + # merge back into the dataset + count = 0 + for f in file_entries: + ds_cur_f = self._dataset_file_entries.get(f.relative_path) + if not ds_cur_f: + if verbose: + self._task.get_logger().report_text('Add {}'.format(f.relative_path)) + self._dataset_file_entries[f.relative_path] = f + count += 1 + elif ds_cur_f.hash != f.hash: + if verbose: + self._task.get_logger().report_text('Modified {}'.format(f.relative_path)) + self._dataset_file_entries[f.relative_path] = f + count += 1 + elif f.parent_dataset_id == self._id and ds_cur_f.parent_dataset_id == self._id: + if verbose: + self._task.get_logger().report_text('Re-Added {}'.format(f.relative_path)) + self._dataset_file_entries[f.relative_path] = f + count += 1 + else: + if verbose: + self._task.get_logger().report_text('Unchanged {}'.format(f.relative_path)) + + return count + + def _update_dependency_graph(self): + """ + Update the dependency graph based on the current self._dataset_file_entries state + :return: + """ + # collect all dataset versions + used_dataset_versions = set(f.parent_dataset_id for f in self._dataset_file_entries.values()) + used_dataset_versions.add(self._id) + current_parents = self._dependency_graph.get(self._id) + # remove parent versions we no longer need from the main version list + # per version, remove unnecessary parent versions, if we do not need them + self._dependency_graph = {k: [p for p in parents if p in used_dataset_versions] + for k, parents in self._dependency_graph.items() if k in used_dataset_versions} + # make sure we do not remove our parents, for geology sake + self._dependency_graph[self._id] = current_parents + + def _serialize(self): + """ + store current state of the Dataset for later use + :return: object to be used for later deserialization + """ + self._update_dependency_graph() + + state = dict( + dataset_file_entries=[f.as_dict() for f in self._dataset_file_entries.values()], + dependency_graph=self._dependency_graph, + id=self._id, + dirty=self._dirty, + ) + modified_files = [f['size'] for f in state['dataset_file_entries'] if f.get('parent_dataset_id') == self._id] + preview = \ + 'Dataset state\n' \ + 'Files added/modified: {0} - total size {1}\n' \ + 'Current dependency graph: {2}\n'.format( + len(modified_files), humanfriendly.format_size(sum(modified_files)), + json.dumps(self._dependency_graph, indent=2, sort_keys=True)) + # store as artifact of the Task. + self._task.upload_artifact( + name=self.__state_entry_name, artifact_object=state, preview=preview, wait_on_upload=True) + + def _download_dataset_archive(self): + """ + Download the dataset archive, return a link to locally stored zip file + :return: Path to locally stored zip file + """ + pass # TODO: implement + + def _extract_dataset_archive(self): + """ + Download the dataset archive, and extract the zip content to a cached folder. + Notice no merging is done. + + :return: Path to a local storage extracted archive + """ + if not self._task: + self._task = Task.get_task(task_id=self._id) + local_zip = StorageManager.get_local_copy( + remote_url=self._task.artifacts[self.__data_entry_name].url, cache_context=self.__cache_context, + extract_archive=False, name=self._id) + if not local_zip: + raise ValueError("Could not download dataset id={}".format(self._id)) + local_folder = (Path(local_zip).parent / self._get_cache_folder_name()).as_posix() + # if we got here, we need to clear the target folder + shutil.rmtree(local_folder, ignore_errors=True) + # noinspection PyProtectedMember + local_folder = StorageManager._extract_to_cache( + cached_file=local_zip, name=self._id, + cache_context=self.__cache_context, target_folder=local_folder) + return local_folder + + def _merge_datasets(self, use_soft_links=None, raise_on_error=True): + # type: (bool, bool) -> str + """ + download and copy / soft-link, files from all the parent dataset versions + :param use_soft_links: If True use soft links, default False on windows True on Posix systems + :param raise_on_error: If True raise exception if dataset merging failed on any file + :return: the target folder + """ + if use_soft_links is None: + use_soft_links = False if is_windows() else True + + # check if we already have everything + target_base_folder, target_base_size = CacheManager.get_cache_manager( + cache_context=self.__cache_context).get_cache_file(local_filename=self._get_cache_folder_name()) + if target_base_folder and target_base_size is not None: + target_base_folder = Path(target_base_folder) + # check dataset file size, if we have a full match no need for parent dataset download / merge + verified = True + # noinspection PyBroadException + try: + for f in self._dataset_file_entries.values(): + if (target_base_folder / f.relative_path).stat().st_size != f.size: + verified = False + break + except Exception: + verified = False + + if verified: + return target_base_folder.as_posix() + else: + LoggerRoot.get_base_logger().info('Dataset needs refreshing, fetching all parent datasets') + + # first get our dataset + target_base_folder = Path(self._extract_dataset_archive()) + target_base_folder.touch() + + # create thread pool + pool = ThreadPool(cpu_count() * 2) + for dataset_version_id in self._get_dependencies_by_order(): + # make sure we skip over empty dependencies + if dataset_version_id not in self._dependency_graph: + continue + + ds = Dataset.get(dataset_id=dataset_version_id) + ds_base_folder = Path(ds._extract_dataset_archive()) + ds_base_folder.touch() + + def copy_file(file_entry): + if file_entry.parent_dataset_id != dataset_version_id: + return + source = (ds_base_folder / file_entry.relative_path).as_posix() + target = (target_base_folder / file_entry.relative_path).as_posix() + try: + # make sure we have can overwrite the target file + # noinspection PyBroadException + try: + os.unlink(target) + except Exception: + Path(target).parent.mkdir(parents=True, exist_ok=True) + + # copy / link + if use_soft_links: + if not os.path.isfile(source): + raise ValueError("Extracted file missing {}".format(source)) + os.symlink(source, target) + else: + shutil.copy2(source, target, follow_symlinks=True) + except Exception as ex: + LoggerRoot.get_base_logger().warning('{}\nFailed {} file {} to {}'.format( + ex, 'linking' if use_soft_links else 'copying', source, target)) + return ex + + return None + + errors = pool.map(copy_file, self._dataset_file_entries.values()) + if raise_on_error and any(errors): + raise ValueError("Dataset merging failed: {}".format([e for e in errors if e is not None])) + + pool.close() + return target_base_folder.as_posix() + + def _get_dependencies_by_order(self, include_unused=False): + # type: (bool) -> List[str] + """ + Return the dataset dependencies by order of application (from the last to the current) + :param bool include_unused: If True include unused datasets in the dependencies + :return: list of str representing the datasets id + """ + roots = [self._id] + dependencies = [] + # noinspection DuplicatedCode + while roots: + r = roots.pop(0) + dependencies.append(r) + # add the parents of the current node, only if the parents are in the general graph node list + if include_unused and r not in self._dependency_graph: + roots.extend(list(reversed( + [p for p in self.get(dataset_id=r)._get_parents() if p not in roots]))) + else: + roots.extend(list(reversed( + [p for p in self._dependency_graph.get(r, []) + if p not in roots and (include_unused or (p in self._dependency_graph))]))) + + # make sure we cover leftovers + leftovers = set(self._dependency_graph.keys()) - set(dependencies) + if leftovers: + roots = list(leftovers) + # noinspection DuplicatedCode + while roots: + r = roots.pop(0) + dependencies.append(r) + # add the parents of the current node, only if the parents are in the general graph node list + if include_unused and r not in self._dependency_graph: + roots.extend(list(reversed( + [p for p in self.get(dataset_id=r)._get_parents() if p not in roots]))) + else: + roots.extend(list(reversed( + [p for p in self._dependency_graph.get(r, []) + if p not in roots and (include_unused or (p in self._dependency_graph))]))) + + # skip our id + return list(reversed(dependencies[1:])) + + def _get_parents(self): + # type: () -> Sequence[str] + """ + Return a list of direct parent datasets (str) + :return: list of dataset ids + """ + return self._dependency_graph[self.id] + + @classmethod + def _deserialize(cls, stored_state, task): + # type: (Union[dict, str, Path, _Path], Task) -> Dataset + """ + reload a dataset state from the stored_state object + :param task: Task object associated with the dataset + :return: A Dataset object + """ + assert isinstance(stored_state, (dict, str, Path, _Path)) + + if isinstance(stored_state, (str, Path, _Path)): + stored_state_file = Path(stored_state).as_posix() + with open(stored_state_file, 'rt') as f: + stored_state = json.load(f) + + instance = cls(_private=cls.__private_magic, task=task) + # assert instance._id == stored_state['id'] # They should match + instance._dependency_graph = stored_state['dependency_graph'] + instance._dirty = stored_state.get('dirty', False) + instance._dataset_file_entries = { + s['relative_path']: FileEntry(**s) for s in stored_state['dataset_file_entries']} + return instance + + @staticmethod + def _calc_file_hash(file_entry): + # calculate hash + file_entry.hash, _ = sha256sum(file_entry.local_path) + file_entry.size = Path(file_entry.local_path).stat().st_size + return file_entry + + @classmethod + def _get_dataset_id_hash(cls, dataset_id): + # type: (str) -> str + """ + Return hash used to search for the dataset id in text fields. + This is not a strong hash and used for defining dependencies. + :param dataset_id: + :return: + """ + return 'dsh{}'.format(md5text(dataset_id)) + + def _get_cache_folder_name(self): + return '{}{}'.format(self.__cache_folder_prefix, self._id) + + def _add_script_call(self, func_name, **kwargs): + # type: (str, **Any) -> () + args = ', '.join('\n {}={}'.format(k, '\''+str(v)+'\'' if isinstance(v, (str, Path, _Path)) else v) + for k, v in kwargs.items()) + if args: + args += '\n' + line = 'ds.{}({})\n'.format(func_name, args) + self._task.data.script.diff += line + # noinspection PyProtectedMember + self._task._edit(script=self._task.data.script) + + def _report_dataset_genealogy(self): + sankey_node = dict( + label=[], + color=[], + customdata=[], + hovertemplate='%{customdata}', + hoverlabel={"align": "left"}, + ) + sankey_link = dict( + source=[], + target=[], + value=[], + hovertemplate='', + ) + # get DAG nodes + nodes = self._get_dependencies_by_order(include_unused=True) + [self.id] + # dataset name lookup + # noinspection PyProtectedMember + node_names = {t.id: t.name for t in Task._query_tasks(task_ids=nodes, only_fields=['id', 'name'])} + node_details = {} + # Generate table and details + table_values = [["Dataset id", "name", "removed", "modified", "added", "size"]] + for node in nodes: + count = 0 + size = 0 + for f in self._dataset_file_entries.values(): + if f.parent_dataset_id == node: + count += 1 + size += f.size + removed = len(self.list_removed_files(node)) + modified = len(self.list_modified_files(node)) + table_values += [[node, node_names.get(node, ''), + removed, modified, count-modified, humanfriendly.format_size(size)]] + node_details[node] = [removed, modified, count-modified, humanfriendly.format_size(size)] + + # create DAG + visited = [] + for idx, node in enumerate(nodes): + visited.append(node) + if node in self._dependency_graph: + parents = [visited.index(p) for p in self._dependency_graph[node] or [] if p in visited] + else: + parents = [visited.index(p) for p in self.get(dataset_id=node)._get_parents() or [] if p in visited] + + sankey_node['color'].append("mediumpurple" if node == self.id else "lightblue") + sankey_node['label'].append('{}'.format(node)) + sankey_node['customdata'].append( + "name {}
removed {}
modified {}
added {}
size {}".format( + node_names.get(node, ''), *node_details[node])) + + for p in parents: + sankey_link['source'].append(p) + sankey_link['target'].append(idx) + sankey_link['value'].append(max(1, node_details[visited[p]][-2])) + + # create the sankey graph + dag_flow = dict( + link=sankey_link, + node=sankey_node, + textfont=dict(color='rgba(0,0,0,255)', size=10), + type='sankey', + orientation='h' + ) + fig = dict(data=[dag_flow], layout={'xaxis': {'visible': False}, 'yaxis': {'visible': False}}) + + if len(nodes) > 1: + self._task.get_logger().report_plotly( + title='Dataset Genealogy', series='', iteration=0, figure=fig) + + # report detailed table + self._task.get_logger().report_table( + title='Dataset Summary', series='Details', iteration=0, table_plot=table_values, + extra_layout={"title": "Files by parent dataset id"}) + + # report the detailed content of the dataset as configuration, + # this allows for easy version comparison in the UI + dataset_details = None + if len(self._dataset_file_entries) < self.__preview_max_file_entries: + file_entries = sorted(self._dataset_file_entries.values(), key=lambda x: x.relative_path) + dataset_details = \ + 'File Name - File Size - Hash (SHA2)\n' +\ + '\n'.join('{} - {} - {}'.format(f.relative_path, f.size, f.hash) for f in file_entries) + # too large to store + if not dataset_details or len(dataset_details) > self.__preview_max_size: + dataset_details = 'Dataset content is too large to preview' + + # noinspection PyProtectedMember + self._task._set_configuration( + name='Dataset Content', description='Dataset content preview', + config_type='read-only', + config_text=dataset_details + ) diff --git a/clearml/debugging/log.py b/clearml/debugging/log.py index 3fbb8d6a..366735a3 100644 --- a/clearml/debugging/log.py +++ b/clearml/debugging/log.py @@ -56,7 +56,7 @@ class LoggerRoot(object): # avoid nested imports from ..config import get_log_redirect_level - LoggerRoot.__base_logger = logging.getLogger('trains') + LoggerRoot.__base_logger = logging.getLogger('clearml') level = level if level is not None else default_level LoggerRoot.__base_logger.setLevel(level) diff --git a/clearml/debugging/trace.py b/clearml/debugging/trace.py index e060a54c..5ca1be0b 100644 --- a/clearml/debugging/trace.py +++ b/clearml/debugging/trace.py @@ -145,11 +145,11 @@ def _patch_module(module, prefix='', basepath=None, basemodule=None, exclude_pre prefix += module.__name__.split('.')[-1] + '.' # Do not patch low level network layer - if prefix.startswith('trains.backend_api.session.') and prefix != 'trains.backend_api.session.': + if prefix.startswith('clearml.backend_api.session.') and prefix != 'clearml.backend_api.session.': if not prefix.endswith('.Session.') and '.token_manager.' not in prefix: # print('SKIPPING: {}'.format(prefix)) return - if prefix.startswith('trains.backend_api.services.'): + if prefix.startswith('clearml.backend_api.services.'): return for skip in exclude_prefixes: @@ -208,7 +208,7 @@ def _patch_module(module, prefix='', basepath=None, basemodule=None, exclude_pre def trace_trains(stream=None, level=1, exclude_prefixes=[], only_prefix=[]): """ - DEBUG ONLY - Add full Trains package code trace + DEBUG ONLY - Add full ClearML package code trace Output trace to filename or stream, default is sys.stderr Trace level -2: Trace function and arguments and returned call @@ -244,7 +244,7 @@ def trace_trains(stream=None, level=1, exclude_prefixes=[], only_prefix=[]): __stream_flush = None from ..version import __version__ - msg = 'Trains v{} - Starting Trace\n\n'.format(__version__) + msg = 'ClearML v{} - Starting Trace\n\n'.format(__version__) # print to actual stderr stderr_write(msg) # store to stream @@ -252,7 +252,7 @@ def trace_trains(stream=None, level=1, exclude_prefixes=[], only_prefix=[]): __stream_write('{:9}:{:5}:{:8}: {:14}\n'.format('seconds', 'pid', 'tid', 'self')) __stream_write('{:9}:{:5}:{:8}:{:15}\n'.format('-' * 9, '-' * 5, '-' * 8, '-' * 15)) __trace_start = time.time() - _patch_module('trains', exclude_prefixes=exclude_prefixes or [], only_prefix=only_prefix or []) + _patch_module('clearml', exclude_prefixes=exclude_prefixes or [], only_prefix=only_prefix or []) def trace_level(level=1): @@ -343,7 +343,7 @@ def end_of_program(): if __name__ == '__main__': - # from trains import Task + # from clearml import Task # task = Task.init(project_name="examples", task_name="trace test") # trace_trains('_trace.txt', level=2) print_traced_files('_trace_*.txt', lines_per_tid=10) diff --git a/clearml/errors.py b/clearml/errors.py index f3ef762d..8f1ce8c3 100644 --- a/clearml/errors.py +++ b/clearml/errors.py @@ -1,3 +1,3 @@ class UsageError(RuntimeError): - """ An exception raised for illegal usage of trains objects""" + """ An exception raised for illegal usage of clearml objects""" pass diff --git a/clearml/external/kerastuner.py b/clearml/external/kerastuner.py index ffbb30fe..60e1bf3b 100644 --- a/clearml/external/kerastuner.py +++ b/clearml/external/kerastuner.py @@ -14,7 +14,7 @@ try: except ImportError: pd = None from logging import getLogger - getLogger('trains.external.kerastuner').warning( + getLogger('clearml.external.kerastuner').warning( 'Pandas is not installed, summary table reporting will be skipped.') @@ -26,7 +26,7 @@ class TrainsTunerLogger(Logger): super(TrainsTunerLogger, self).__init__() self.task = task or Task.current_task() if not self.task: - raise ValueError("Trains Task could not be found, pass in TrainsTunerLogger or " + raise ValueError("ClearML Task could not be found, pass in TrainsTunerLogger or " "call Task.init before initializing TrainsTunerLogger") self._summary = pd.DataFrame() if pd else None diff --git a/clearml/logger.py b/clearml/logger.py index 69a8604b..11e447c6 100644 --- a/clearml/logger.py +++ b/clearml/logger.py @@ -36,14 +36,14 @@ if TYPE_CHECKING: class Logger(object): """ - The ``Logger`` class is the Trains console log and metric statistics interface, and contains methods for explicit + The ``Logger`` class is the ClearML console log and metric statistics interface, and contains methods for explicit reporting. - Explicit reporting extends Trains automagical capturing of inputs and output. Explicit reporting + Explicit reporting extends ClearML automagical capturing of inputs and output. Explicit reporting methods include scalar plots, line plots, histograms, confusion matrices, 2D and 3D scatter diagrams, text logging, tables, and image uploading and reporting. - In the **Trains Web-App (UI)**, ``Logger`` output appears in the **RESULTS** tab, **LOG**, **SCALARS**, + In the **ClearML Web-App (UI)**, ``Logger`` output appears in the **RESULTS** tab, **LOG**, **SCALARS**, **PLOTS**, and **DEBUG SAMPLES** sub-tabs. When you compare experiments, ``Logger`` output appears in the comparisons. @@ -90,7 +90,7 @@ class Logger(object): if self._connect_logging: StdStreamPatch.patch_logging_formatter(self) elif not self._connect_std_streams: - # make sure that at least the main trains logger is connect + # make sure that at least the main clearml logger is connect base_logger = LoggerRoot.get_base_logger() if base_logger and base_logger.handlers: StdStreamPatch.patch_logging_formatter(self, base_logger.handlers[0]) @@ -126,7 +126,7 @@ class Logger(object): logger.report_text('log some text', level=logging.DEBUG, print_console=False) - You can view the reported text in the **Trains Web-App (UI)**, **RESULTS** tab, **LOG** sub-tab. + You can view the reported text in the **ClearML Web-App (UI)**, **RESULTS** tab, **LOG** sub-tab. :param str msg: The text to log. :param int level: The log level from the Python ``logging`` package. The default value is ``logging.INFO``. @@ -151,7 +151,7 @@ class Logger(object): scalar_series = [random.randint(0,10) for i in range(10)] logger.report_scalar(title='scalar metrics','series', value=scalar_series[iteration], iteration=0) - You can view the scalar plots in the **Trains Web-App (UI)**, **RESULTS** tab, **SCALARS** sub-tab. + You can view the scalar plots in the **ClearML Web-App (UI)**, **RESULTS** tab, **SCALARS** sub-tab. :param str title: The title (metric) of the plot. Plot more than one scalar series on the same plot by using the same ``title`` for each call to this method. @@ -190,7 +190,7 @@ class Logger(object): logger.report_vector(title='vector example', series='vector series', values=vector_series, iteration=0, labels=['A','B'], xaxis='X axis label', yaxis='Y axis label') - You can view the vectors plots in the **Trains Web-App (UI)**, **RESULTS** tab, **PLOTS** sub-tab. + You can view the vectors plots in the **ClearML Web-App (UI)**, **RESULTS** tab, **PLOTS** sub-tab. :param str title: The title (metric) of the plot. :param str series: The series name (variant) of the reported histogram. @@ -237,7 +237,7 @@ class Logger(object): logger.report_histogram(title='histogram example', series='histogram series', values=vector_series, iteration=0, labels=['A','B'], xaxis='X axis label', yaxis='Y axis label') - You can view the reported histograms in the **Trains Web-App (UI)**, **RESULTS** tab, **PLOTS** sub-tab. + You can view the reported histograms in the **ClearML Web-App (UI)**, **RESULTS** tab, **PLOTS** sub-tab. :param str title: The title (metric) of the plot. :param str series: The series name (variant) of the reported histogram. @@ -305,7 +305,7 @@ class Logger(object): logger.report_table(title='table example',series='pandas DataFrame',iteration=0,table_plot=df) - You can view the reported tables in the **Trains Web-App (UI)**, **RESULTS** tab, **PLOTS** sub-tab. + You can view the reported tables in the **ClearML Web-App (UI)**, **RESULTS** tab, **PLOTS** sub-tab. :param str title: The title (metric) of the table. :param str series: The series name (variant) of the reported table. @@ -1022,8 +1022,8 @@ class Logger(object): The images are uploaded separately. A link to each image is reported. .. note:: - Credentials for the destination storage are specified in the Trains configuration file, - ``~/trains.conf``. + Credentials for the destination storage are specified in the ClearML configuration file, + ``~/clearml.conf``. :param str uri: example: 's3://bucket/directory/' or 'file:///tmp/debug/' @@ -1150,7 +1150,7 @@ class Logger(object): The values are: - ``True`` - Scalars without specific titles are grouped together in the "Scalars" plot, preserving - backward compatibility with Trains automagical behavior. + backward compatibility with ClearML automagical behavior. - ``False`` - TensorBoard scalars without titles get a title/series with the same tag. (default) :type group_scalars: bool """ @@ -1214,7 +1214,7 @@ class Logger(object): try: # make sure we are writing to the original stdout StdStreamPatch.stderr_original_write( - 'trains.Logger failed sending log [level {}]: "{}"\n'.format(level, msg)) + 'clearml.Logger failed sending log [level {}]: "{}"\n'.format(level, msg)) except Exception: pass else: diff --git a/clearml/model.py b/clearml/model.py index f13064d4..667ed0d9 100644 --- a/clearml/model.py +++ b/clearml/model.py @@ -472,9 +472,9 @@ class InputModel(Model): framework, and indicate whether to immediately set the model's status to ``Published``. The model is read-only. - The **Trains Server** (backend) may already store the model's URL. If the input model's URL is not - stored, meaning the model is new, then it is imported and Trains stores its metadata. - If the URL is already stored, the import process stops, Trains issues a warning message, and Trains + The **ClearML Server** (backend) may already store the model's URL. If the input model's URL is not + stored, meaning the model is new, then it is imported and ClearML stores its metadata. + If the URL is already stored, the import process stops, ClearML issues a warning message, and ClearML reuses the model. In your Python experiment script, after importing the model, you can connect it to the main execution @@ -482,12 +482,12 @@ class InputModel(Model): network. .. note:: - Using the **Trains Web-App** (user interface), you can reuse imported models and switch models in + Using the **ClearML Web-App** (user interface), you can reuse imported models and switch models in experiments. - :param str weights_url: A valid URL for the initial weights file. If the **Trains Web-App** (backend) + :param str weights_url: A valid URL for the initial weights file. If the **ClearML Web-App** (backend) already stores the metadata of a model with the same URL, that existing model is returned - and Trains ignores all other parameters. + and ClearML ignores all other parameters. For example: @@ -715,7 +715,7 @@ class InputModel(Model): def __init__(self, model_id): # type: (str) -> None """ - :param str model_id: The Trains Id (system UUID) of the input model whose metadata the **Trains Server** + :param str model_id: The ClearML Id (system UUID) of the input model whose metadata the **ClearML Server** (backend) stores. """ super(InputModel, self).__init__(model_id) @@ -731,16 +731,16 @@ class InputModel(Model): Connect the current model to a Task object, if the model is preexisting. Preexisting models include: - Imported models (InputModel objects created using the :meth:`Logger.import_model` method). - - Models whose metadata is already in the Trains platform, meaning the InputModel object is instantiated - from the ``InputModel`` class specifying the the model's Trains Id as an argument. - - Models whose origin is not Trains that are used to create an InputModel object. For example, + - Models whose metadata is already in the ClearML platform, meaning the InputModel object is instantiated + from the ``InputModel`` class specifying the the model's ClearML Id as an argument. + - Models whose origin is not ClearML that are used to create an InputModel object. For example, models created using TensorFlow models. When the experiment is executed remotely in a worker, the input model already specified in the experiment is used. .. note:: - The **Trains Web-App** allows you to switch one input model for another and then enqueue the experiment + The **ClearML Web-App** allows you to switch one input model for another and then enqueue the experiment to execute in a worker. :param object task: A Task object. @@ -789,7 +789,7 @@ class OutputModel(BaseModel): .. note:: When executing a Task (experiment) remotely in a worker, you can modify the model configuration and / or model's - label enumeration using the **Trains Web-App**. + label enumeration using the **ClearML Web-App**. """ @property @@ -990,7 +990,7 @@ class OutputModel(BaseModel): Connect the current model to a Task object, if the model is a preexisting model. Preexisting models include: - Imported models. - - Models whose metadata the **Trains Server** (backend) is already storing. + - Models whose metadata the **ClearML Server** (backend) is already storing. - Models from another source, such as frameworks like TensorFlow. :param object task: A Task object. @@ -1044,8 +1044,8 @@ class OutputModel(BaseModel): Using this method, files uploads are separate and then a link to each is stored in the model object. .. note:: - For storage requiring credentials, the credentials are stored in the Trains configuration file, - ``~/trains.conf``. + For storage requiring credentials, the credentials are stored in the ClearML configuration file, + ``~/clearml.conf``. :param str uri: The URI of the upload storage destination. diff --git a/clearml/storage/cache.py b/clearml/storage/cache.py index 3e1af1e1..3a80dc8f 100644 --- a/clearml/storage/cache.py +++ b/clearml/storage/cache.py @@ -58,10 +58,10 @@ class CacheManager(object): return cached_file @staticmethod - def upload_file(local_file, remote_url, wait_for_upload=True): + def upload_file(local_file, remote_url, wait_for_upload=True, retries=1): helper = StorageHelper.get(remote_url) result = helper.upload( - local_file, remote_url, async_enable=not wait_for_upload + local_file, remote_url, async_enable=not wait_for_upload, retries=retries, ) CacheManager._add_remote_url(remote_url, local_file) return result diff --git a/clearml/storage/helper.py b/clearml/storage/helper.py index f8804284..efaa9487 100644 --- a/clearml/storage/helper.py +++ b/clearml/storage/helper.py @@ -681,6 +681,7 @@ class StorageHelper(object): # try to get file size try: if isinstance(self._driver, _HttpDriver) and obj: + obj = self._driver._get_download_object(obj) total_size_mb = float(obj.headers.get('Content-Length', 0)) / (1024 * 1024) elif hasattr(obj, 'size'): size = obj.size @@ -785,12 +786,12 @@ class StorageHelper(object): def check_write_permissions(self, dest_path=None): # create a temporary file, then de;ete it base_url = dest_path or self._base_url - dest_path = base_url + '/.trains.test' + dest_path = base_url + '/.clearml.test' # do not check http/s connection permissions if dest_path.startswith('http'): return True try: - self.upload_from_stream(stream=six.BytesIO(b'trains'), dest_path=dest_path) + self.upload_from_stream(stream=six.BytesIO(b'clearml'), dest_path=dest_path) self.delete(path=dest_path) except Exception: raise ValueError('Insufficient permissions for {}'.format(base_url)) @@ -1024,6 +1025,11 @@ class _HttpDriver(_Driver): return self._default_backend_session.add_auth_headers({}) return None + class _HttpSessionHandle(object): + def __init__(self, url, is_stream, container_name, object_name): + self.url, self.is_stream, self.container_name, self.object_name = \ + url, is_stream, container_name, object_name + def __init__(self, retries=5): self._retries = retries self._containers = {} @@ -1055,24 +1061,39 @@ class _HttpDriver(_Driver): def list_container_objects(self, *args, **kwargs): raise NotImplementedError('List is not implemented for http protocol') - def delete_object(self, *args, **kwargs): - raise NotImplementedError('Delete is not implemented for http protocol') + def delete_object(self, obj, *args, **kwargs): + assert isinstance(obj, self._HttpSessionHandle) + container = self._containers[obj.container_name] + res = container.session.delete(obj.url, headers=container.get_headers(obj.url)) + if res.status_code != requests.codes.ok: + raise ValueError('Failed deleting object %s (%d): %s' % (obj.object_name, res.status_code, res.text)) + return res def get_object(self, container_name, object_name, *args, **kwargs): - container = self._containers[container_name] - # set stream flag before get request - container.session.stream = kwargs.get('stream', True) + is_stream = kwargs.get('stream', True) url = ''.join((container_name, object_name.lstrip('/'))) - res = container.session.get(url, timeout=self.timeout, headers=container.get_headers(url)) + return self._HttpSessionHandle(url, is_stream, container_name, object_name) + + def _get_download_object(self, obj): + # bypass for session result + if not isinstance(obj, self._HttpSessionHandle): + return obj + + container = self._containers[obj.container_name] + # set stream flag before we send the request + container.session.stream = obj.is_stream + res = container.session.get(obj.url, timeout=self.timeout, headers=container.get_headers(obj.url)) if res.status_code != requests.codes.ok: - raise ValueError('Failed getting object %s (%d): %s' % (object_name, res.status_code, res.text)) + raise ValueError('Failed getting object %s (%d): %s' % (obj.object_name, res.status_code, res.text)) return res def download_object_as_stream(self, obj, chunk_size=64 * 1024, **_): # return iterable object + obj = self._get_download_object(obj) return obj.iter_content(chunk_size=chunk_size) def download_object(self, obj, local_path, overwrite_existing=True, delete_on_failure=True, callback=None, **_): + obj = self._get_download_object(obj) p = Path(local_path) if not overwrite_existing and p.is_file(): log.warning('failed saving after download: overwrite=False and file exists (%s)' % str(p)) diff --git a/clearml/storage/manager.py b/clearml/storage/manager.py index 13d13f8f..c3426b30 100644 --- a/clearml/storage/manager.py +++ b/clearml/storage/manager.py @@ -48,8 +48,8 @@ class StorageManager(object): @classmethod def upload_file( - cls, local_file, remote_url, wait_for_upload=True - ): # type: (str, str, bool) -> str + cls, local_file, remote_url, wait_for_upload=True, retries=1 + ): # type: (str, str, bool, int) -> str """ Upload a local file to a remote location. remote url is the finale destination of the uploaded file. @@ -64,12 +64,14 @@ class StorageManager(object): :param str local_file: Full path of a local file to be uploaded :param str remote_url: Full path or remote url to upload to (including file name) :param bool wait_for_upload: If False, return immediately and upload in the background. Default True. + :param int retries: Number of retries before failing to upload file, default 1. :return: Newly uploaded remote URL. """ return CacheManager.get_cache_manager().upload_file( local_file=local_file, remote_url=remote_url, wait_for_upload=wait_for_upload, + retries=retries, ) @classmethod diff --git a/clearml/storage/util.py b/clearml/storage/util.py index ce53889b..9875e0d2 100644 --- a/clearml/storage/util.py +++ b/clearml/storage/util.py @@ -1,6 +1,6 @@ import hashlib import sys -from typing import Optional +from typing import Optional, Union from six.moves.urllib.parse import quote, urlparse, urlunparse import six @@ -72,8 +72,23 @@ def sha256sum(filename, skip_header=0, block_size=65536): return h.hexdigest(), file_hash.hexdigest() if skip_header else None +def md5text(text, seed=1337): + # type: (str, Union[int, str]) -> str + """ + Return md5 hash of a string + Do not use this hash for security, if needed use something stronger like SHA2 + + :param text: string to hash + :param seed: use prefix seed for hashing + :return: md5 string + """ + h = hashlib.md5() + h.update((str(seed) + str(text)).encode('utf-8')) + return h.hexdigest() + + def is_windows(): """ :return: True if currently running on windows OS """ - return sys.platform == 'win32' \ No newline at end of file + return sys.platform == 'win32' diff --git a/clearml/task.py b/clearml/task.py index ee70255b..12b3a9ef 100644 --- a/clearml/task.py +++ b/clearml/task.py @@ -77,8 +77,8 @@ class Task(_Task): configuration, label enumeration, models, and other artifacts. The term "main execution Task" refers to the Task context for current running experiment. Python experiment scripts - can create one, and only one, main execution Task. It is a traceable, and after a script runs and Trains stores - the Task in the **Trains Server** (backend), it is modifiable, reproducible, executable by a worker, and you + can create one, and only one, main execution Task. It is a traceable, and after a script runs and ClearML stores + the Task in the **ClearML Server** (backend), it is modifiable, reproducible, executable by a worker, and you can duplicate it for further experimentation. The ``Task`` class and its methods allow you to create and manage experiments, as well as perform @@ -93,7 +93,7 @@ class Task(_Task): - Create a new reproducible Task - :meth:`Task.init` .. important:: - In some cases, ``Task.init`` may return a Task object which is already stored in **Trains Server** (already + In some cases, ``Task.init`` may return a Task object which is already stored in **ClearML Server** (already initialized), instead of creating a new Task. For a detailed explanation of those cases, see the ``Task.init`` method. @@ -102,17 +102,17 @@ class Task(_Task): - Get another (different) Task - :meth:`Task.get_task` .. note:: - The **Trains** documentation often refers to a Task as, "Task (experiment)". + The **ClearML** documentation often refers to a Task as, "Task (experiment)". - "Task" refers to the class in the Trains Python Client Package, the object in your Python experiment script, - and the entity with which **Trains Server** and **Trains Agent** work. + "Task" refers to the class in the ClearML Python Client Package, the object in your Python experiment script, + and the entity with which **ClearML Server** and **ClearML Agent** work. "Experiment" refers to your deep learning solution, including its connected components, inputs, and outputs, - and is the experiment you can view, analyze, compare, modify, duplicate, and manage using the Trains + and is the experiment you can view, analyze, compare, modify, duplicate, and manage using the ClearML **Web-App** (UI). Therefore, a "Task" is effectively an "experiment", and "Task (experiment)" encompasses its usage throughout - the Trains. + the ClearML. The exception to this Task behavior is sub-tasks (non-reproducible Tasks), which do not use the main execution Task. Creating a sub-task always creates a new Task with a new Task ID. @@ -197,7 +197,7 @@ class Task(_Task): Creates a new Task (experiment) if: - The Task never ran before. No Task with the same ``task_name`` and ``project_name`` is stored in - **Trains Server**. + **ClearML Server**. - The Task has run before (the same ``task_name`` and ``project_name``), and (a) it stored models and / or artifacts, or (b) its status is Published , or (c) it is Archived. - A new Task is forced by calling ``Task.init`` with ``reuse_last_task_id=False``. @@ -215,7 +215,7 @@ class Task(_Task): .. code-block:: py - from trains import Task + from clearml import Task task = Task.init('myProject', 'myTask') If this code runs again, it will not create a new Task. It does not store a model or artifact, @@ -285,7 +285,7 @@ class Task(_Task): This is equivalent to `continue_last_task=True` and `reuse_last_task_id=a_task_id_string`. :param str output_uri: The default location for output models and other artifacts. In the default location, - Trains creates a subfolder for the output. The subfolder structure is the following: + ClearML creates a subfolder for the output. The subfolder structure is the following: / / .< Task ID> @@ -297,9 +297,9 @@ class Task(_Task): - Azure Storage: ``azure://company.blob.core.windows.net/folder/`` .. important:: - For cloud storage, you must install the **Trains** package for your cloud storage type, + For cloud storage, you must install the **ClearML** package for your cloud storage type, and then configure your storage credentials. For detailed information, see - `Trains Python Client Extras <./references/trains_extras_storage/>`_ in the "Trains Python Client + `ClearML Python Client Extras <./references/clearml_extras_storage/>`_ in the "ClearML Python Client Reference" section. :param auto_connect_arg_parser: Automatically connect an argparse object to the Task @@ -324,7 +324,7 @@ class Task(_Task): :param auto_connect_frameworks: Automatically connect frameworks This includes patching MatplotLib, XGBoost, scikit-learn, Keras callbacks, and TensorBoard/X to serialize plots, graphs, and the model location to - the **Trains Server** (backend), in addition to original output destination. + the **ClearML Server** (backend), in addition to original output destination. The values are: @@ -342,7 +342,7 @@ class Task(_Task): 'xgboost': True, 'scikit': True, 'fastai': True, 'lightgbm': True, 'hydra': True} :param bool auto_resource_monitoring: Automatically create machine resource monitoring plots - These plots appear in in the **Trains Web-App (UI)**, **RESULTS** tab, **SCALARS** sub-tab, + These plots appear in in the **ClearML Web-App (UI)**, **RESULTS** tab, **SCALARS** sub-tab, with a title of **:resource monitor:**. The values are: @@ -409,6 +409,7 @@ class Task(_Task): # create a new logger (to catch stdout/err) cls.__main_task._logger = None cls.__main_task.__reporter = None + # noinspection PyProtectedMember cls.__main_task._get_logger(auto_connect_streams=auto_connect_streams) cls.__main_task._artifacts_manager = Artifacts(cls.__main_task) # unregister signal hooks, they cause subprocess to hang @@ -569,10 +570,10 @@ class Task(_Task): # show the debug metrics page in the log, it is very convenient if not is_sub_process_task_id: if cls._offline_mode: - logger.report_text('TRAINS running in offline mode, session stored in {}'.format( + logger.report_text('ClearML running in offline mode, session stored in {}'.format( task.get_offline_mode_folder())) else: - logger.report_text('TRAINS results page: {}'.format(task.get_output_log_web_page())) + logger.report_text('ClearML results page: {}'.format(task.get_output_log_web_page())) # Make sure we start the dev worker if required, otherwise it will only be started when we write # something to the log. task._dev_mode_task_start() @@ -580,55 +581,76 @@ class Task(_Task): return task @classmethod - def create(cls, project_name=None, task_name=None, task_type=TaskTypes.training): - # type: (Optional[str], Optional[str], Task.TaskTypes) -> Task + def create( + cls, + project_name=None, # Optional[str] + task_name=None, # Optional[str] + task_type=None, # Optional[str] + repo=None, # Optional[str] + branch=None, # Optional[str] + commit=None, # Optional[str] + script=None, # Optional[str] + working_directory=None, # Optional[str] + packages=None, # Optional[Sequence[str]] + requirements_file=None, # Optional[Union[str, Path]] + docker=None, # Optional[str] + base_task_id=None, # Optional[str] + add_task_init_call=True, # bool + ): + # type: (...) -> Task """ - Create a new, non-reproducible Task (experiment). This is called a sub-task. + Manually create and populate a new Task (experiment) in the system. + If the code does not already contain a call to ``Task.init``, pass add_task_init_call=True, + and the code will be patched in remote execution (i.e. when executed by `clearml-agent` .. note:: - This method always creates a new, non-reproducible Task. To create a reproducible Task, call the - :meth:`Task.init` method. To reference another Task, call the :meth:`Task.get_task` method . + This method **always** creates a new Task. + Use :meth:`Task.init` method to automatically create and populate task for the running process. + To reference an existing Task, call the :meth:`Task.get_task` method . - :param str project_name: The name of the project in which the experiment will be created. - If ``project_name`` is ``None``, and the main execution Task is initialized (see :meth:`Task.init`), - then the main execution Task's project is used. Otherwise, if the project does - not exist, it is created. (Optional) - :param str task_name: The name of Task (experiment). - :param TaskTypes task_type: The task type. + :param project_name: Set the project name for the task. Required if base_task_id is None. + :param task_name: Set the name of the remote task. Required if base_task_id is None. + :param task_type: Optional, The task type to be created. Supported values: 'training', 'testing', 'inference', + 'data_processing', 'application', 'monitor', 'controller', 'optimizer', 'service', 'qc', 'custom' + :param repo: Remote URL for the repository to use, or path to local copy of the git repository + Example: 'https://github.com/allegroai/clearml.git' or '~/project/repo' + :param branch: Select specific repository branch/tag (implies the latest commit from the branch) + :param commit: Select specific commit id to use (default: latest commit, + or when used with local repository matching the local commit id) + :param script: Specify the entry point script for the remote execution. When used in tandem with + remote git repository the script should be a relative path inside the repository, + for example: './source/train.py' . When used with local repository path it supports a + direct path to a file inside the local repository itself, for example: '~/project/source/train.py' + :param working_directory: Working directory to launch the script from. Default: repository root folder. + Relative to repo root or local folder. + :param packages: Manually specify a list of required packages. Example: ["tqdm>=2.1", "scikit-learn"] + :param requirements_file: Specify requirements.txt file to install when setting the session. + If not provided, the requirements.txt from the repository will be used. + :param docker: Select the docker image to be executed in by the remote session + :param base_task_id: Use a pre-existing task in the system, instead of a local repo/script. + Essentially clones an existing task and overrides arguments/requirements. + :param add_task_init_call: If True, a 'Task.init()' call is added to the script entry point in remote execution. - Valid task types: - - - ``TaskTypes.training`` (default) - - ``TaskTypes.testing`` - - ``TaskTypes.inference`` - - ``TaskTypes.data_processing`` - - ``TaskTypes.application`` - - ``TaskTypes.monitor`` - - ``TaskTypes.controller`` - - ``TaskTypes.optimizer`` - - ``TaskTypes.service`` - - ``TaskTypes.qc`` - - ``TaskTypes.custom`` - - :return: A new experiment. + :return: The newly created Task (experiment) """ - if not project_name: + if not project_name and not base_task_id: if not cls.__main_task: raise ValueError("Please provide project_name, no global task context found " "(Task.current_task hasn't been called)") project_name = cls.__main_task.get_project_name() + from .backend_interface.task.populate import CreateAndPopulate + manual_populate = CreateAndPopulate( + project_name=project_name, task_name=task_name, task_type=task_type, + repo=repo, branch=branch, commit=commit, + script=script, working_directory=working_directory, + packages=packages, requirements_file=requirements_file, + docker=docker, + base_task_id=base_task_id, + add_task_init_call=add_task_init_call, + raise_on_missing_entries=False, + ) + task = manual_populate.create_task() - try: - task = cls( - private=cls.__create_protection, - project_name=project_name, - task_name=task_name, - task_type=task_type, - log_to_backend=False, - force_create=True, - ) - except Exception: - raise return task @classmethod @@ -721,7 +743,7 @@ class Task(_Task): helper = StorageHelper.get(value) if not helper: raise ValueError("Could not get access credentials for '{}' " - ", check configuration file ~/trains.conf".format(value)) + ", check configuration file ~/clearml.conf".format(value)) helper.check_write_permissions(value) self.storage_uri = value @@ -758,7 +780,7 @@ class Task(_Task): """ Get a Logger object for reporting, for this task context. You can view all Logger report output associated with the Task for which this method is called, including metrics, plots, text, tables, and images, in the - **Trains Web-App (UI)**. + **ClearML Web-App (UI)**. :return: The Logger object for the current Task (experiment). """ @@ -796,8 +818,8 @@ class Task(_Task): """ assert isinstance(source_task, (six.string_types, Task)) if not Session.check_min_api_version('2.4'): - raise ValueError("Trains-server does not support DevOps features, " - "upgrade trains-server to 0.12.0 or above") + raise ValueError("ClearML-server does not support DevOps features, " + "upgrade clearml-server to 0.12.0 or above") task_id = source_task if isinstance(source_task, six.string_types) else source_task.id if not parent: @@ -820,7 +842,7 @@ class Task(_Task): .. note:: A worker daemon must be listening at the queue for the worker to fetch the Task and execute it, - see `Use Case Examples <../trains_agent_ref/#use-case-examples>`_ on the "Trains Agent + see `Use Case Examples <../clearml_agent_ref/#use-case-examples>`_ on the "ClearML Agent Reference page. :param Task/str task: The Task to enqueue. Specify a Task object or Task ID. @@ -859,8 +881,8 @@ class Task(_Task): """ assert isinstance(task, (six.string_types, Task)) if not Session.check_min_api_version('2.4'): - raise ValueError("Trains-server does not support DevOps features, " - "upgrade trains-server to 0.12.0 or above") + raise ValueError("ClearML-server does not support DevOps features, " + "upgrade clearml-server to 0.12.0 or above") # make sure we have wither name ot id mutually_exclusive(queue_name=queue_name, queue_id=queue_id) @@ -923,8 +945,8 @@ class Task(_Task): """ assert isinstance(task, (six.string_types, Task)) if not Session.check_min_api_version('2.4'): - raise ValueError("Trains-server does not support DevOps features, " - "upgrade trains-server to 0.12.0 or above") + raise ValueError("ClearML-server does not support DevOps features, " + "upgrade clearml-server to 0.12.0 or above") task_id = task if isinstance(task, six.string_types) else task.id session = cls._get_default_session() @@ -990,7 +1012,7 @@ class Task(_Task): name = self._default_configuration_section_name if not multi_config_support and name and name != self._default_configuration_section_name: - raise ValueError("Multiple configurations is not supported with the current 'trains-server', " + raise ValueError("Multiple configurations is not supported with the current 'clearml-server', " "please upgrade to the latest version") for mutable_type, method in dispatch: @@ -1024,11 +1046,11 @@ class Task(_Task): :param configuration: The configuration. This is usually the configuration used in the model training process. Specify one of the following: - - A dictionary - A dictionary containing the configuration. Trains stores the configuration in - the **Trains Server** (backend), in a HOCON format (JSON-like format) which is editable. - - A ``pathlib2.Path`` string - A path to the configuration file. Trains stores the content of the file. + - A dictionary - A dictionary containing the configuration. ClearML stores the configuration in + the **ClearML Server** (backend), in a HOCON format (JSON-like format) which is editable. + - A ``pathlib2.Path`` string - A path to the configuration file. ClearML stores the content of the file. A local path must be relative path. When executing a Task remotely in a worker, the contents brought - from the **Trains Server** (backend) overwrites the contents of the file. + from the **ClearML Server** (backend) overwrites the contents of the file. :param str name: Configuration section name. default: 'General' Allowing users to store multiple configuration dicts/files @@ -1038,10 +1060,10 @@ class Task(_Task): :return: If a dictionary is specified, then a dictionary is returned. If pathlib2.Path / string is specified, then a path to a local configuration file is returned. Configuration object. """ - pathlib_Path = None + pathlib_Path = None # noqa if not isinstance(configuration, (dict, Path, six.string_types)): try: - from pathlib import Path as pathlib_Path + from pathlib import Path as pathlib_Path # noqa except ImportError: pass if not pathlib_Path or not isinstance(configuration, pathlib_Path): @@ -1053,7 +1075,7 @@ class Task(_Task): name = self._default_configuration_section_name if not multi_config_support and name and name != self._default_configuration_section_name: - raise ValueError("Multiple configurations is not supported with the current 'trains-server', " + raise ValueError("Multiple configurations is not supported with the current 'clearml-server', " "please upgrade to the latest version") # parameter dictionary @@ -1141,7 +1163,7 @@ class Task(_Task): return configuration configuration_path = Path(configuration) - fd, local_filename = mkstemp(prefix='trains_task_config_', + fd, local_filename = mkstemp(prefix='clearml_task_config_', suffix=configuration_path.suffixes[-1] if configuration_path.suffixes else '.txt') os.write(fd, configuration_text.encode('utf-8')) @@ -1187,7 +1209,7 @@ class Task(_Task): """ Get a Logger object for reporting, for this task context. You can view all Logger report output associated with the Task for which this method is called, including metrics, plots, text, tables, and images, in the - **Trains Web-App (UI)**. + **ClearML Web-App (UI)**. :return: The Logger for the Task (experiment). """ @@ -1247,7 +1269,7 @@ class Task(_Task): def reset(self, set_started_on_success=False, force=False): # type: (bool, bool) -> None """ - Reset a Task. Trains reloads a Task after a successful reset. + Reset a Task. ClearML reloads a Task after a successful reset. When a worker executes a Task remotely, the Task does not reset unless the ``force`` parameter is set to ``True`` (this avoids accidentally clearing logs and metrics). @@ -1290,16 +1312,16 @@ class Task(_Task): # type: (str, pandas.DataFrame, Dict, Union[bool, Sequence[str]]) -> None """ Register (add) an artifact for the current Task. Registered artifacts are dynamically sychronized with the - **Trains Server** (backend). If a registered artifact is updated, the update is stored in the - **Trains Server** (backend). Registered artifacts are primarily used for Data Audition. + **ClearML Server** (backend). If a registered artifact is updated, the update is stored in the + **ClearML Server** (backend). Registered artifacts are primarily used for Data Audition. The currently supported registered artifact object type is a pandas.DataFrame. See also :meth:`Task.unregister_artifact` and :meth:`Task.get_registered_artifacts`. .. note:: - Trains also supports uploaded artifacts which are one-time uploads of static artifacts that are not - dynamically sychronized with the **Trains Server** (backend). These static artifacts include + ClearML also supports uploaded artifacts which are one-time uploads of static artifacts that are not + dynamically sychronized with the **ClearML Server** (backend). These static artifacts include additional object types. For more information, see :meth:`Task.upload_artifact`. :param str name: The name of the artifact. @@ -1308,7 +1330,7 @@ class Task(_Task): If an artifact with the same name was previously registered, it is overwritten. :param object artifact: The artifact object. :param dict metadata: A dictionary of key-value pairs for any metadata. This dictionary appears with the - experiment in the **Trains Web-App (UI)**, **ARTIFACTS** tab. + experiment in the **ClearML Web-App (UI)**, **ARTIFACTS** tab. :param uniqueness_columns: A Sequence of columns for artifact uniqueness comparison criteria, or the default value of ``True``. If ``True``, the artifact uniqueness comparison criteria is all the columns, which is the same as ``artifact.columns``. @@ -1323,13 +1345,13 @@ class Task(_Task): def unregister_artifact(self, name): # type: (str) -> None """ - Unregister (remove) a registered artifact. This removes the artifact from the watch list that Trains uses - to synchronize artifacts with the **Trains Server** (backend). + Unregister (remove) a registered artifact. This removes the artifact from the watch list that ClearML uses + to synchronize artifacts with the **ClearML Server** (backend). .. important:: - - Calling this method does not remove the artifact from a Task. It only stops Trains from + - Calling this method does not remove the artifact from a Task. It only stops ClearML from monitoring the artifact. - - When this method is called, Trains immediately takes the last snapshot of the artifact. + - When this method is called, ClearML immediately takes the last snapshot of the artifact. """ self._artifacts_manager.unregister_artifact(name=name) @@ -1361,12 +1383,12 @@ class Task(_Task): The currently supported upload (static) artifact types include: - - string / pathlib2.Path - A path to artifact file. If a wildcard or a folder is specified, then Trains + - string / pathlib2.Path - A path to artifact file. If a wildcard or a folder is specified, then ClearML creates and uploads a ZIP file. - - dict - Trains stores a dictionary as ``.json`` file and uploads it. - - pandas.DataFrame - Trains stores a pandas.DataFrame as ``.csv.gz`` (compressed CSV) file and uploads it. - - numpy.ndarray - Trains stores a numpy.ndarray as ``.npz`` file and uploads it. - - PIL.Image - Trains stores a PIL.Image as ``.png`` file and uploads it. + - dict - ClearML stores a dictionary as ``.json`` file and uploads it. + - pandas.DataFrame - ClearML stores a pandas.DataFrame as ``.csv.gz`` (compressed CSV) file and uploads it. + - numpy.ndarray - ClearML stores a numpy.ndarray as ``.npz`` file and uploads it. + - PIL.Image - ClearML stores a PIL.Image as ``.png`` file and uploads it. - Any - If called with auto_pickle=True, the object will be pickled and uploaded. :param str name: The artifact name. @@ -1376,7 +1398,7 @@ class Task(_Task): :param object artifact_object: The artifact object. :param dict metadata: A dictionary of key-value pairs for any metadata. This dictionary appears with the - experiment in the **Trains Web-App (UI)**, **ARTIFACTS** tab. + experiment in the **ClearML Web-App (UI)**, **ARTIFACTS** tab. :param bool delete_after_upload: After the upload, delete the local copy of the artifact - ``True`` - Delete the local copy of the artifact. @@ -1416,7 +1438,7 @@ class Task(_Task): .. code-block:: py - {'input': [trains.Model()], 'output': [trains.Model()]} + {'input': [clearml.Model()], 'output': [clearml.Model()]} """ task_models = {'input': self._get_models(model_type='input'), @@ -1510,7 +1532,7 @@ class Task(_Task): .. note:: The maximum reported iteration is not in the local cache. This method - sends a request to the **Trains Server** (backend). + sends a request to the **ClearML Server** (backend). :return: The last reported iteration number. """ @@ -1704,7 +1726,7 @@ class Task(_Task): # type: (str) -> () """ Set the base docker image for this experiment - If provided, this value will be used by trains-agent to execute this experiment + If provided, this value will be used by clearml-agent to execute this experiment inside the provided docker image. """ if not self.running_locally() and self.is_main_task(): @@ -1732,12 +1754,12 @@ class Task(_Task): def execute_remotely(self, queue_name=None, clone=False, exit_process=True): # type: (Optional[str], bool, bool) -> Optional[Task] """ - If task is running locally (i.e., not by ``trains-agent``), then clone the Task and enqueue it for remote + If task is running locally (i.e., not by ``clearml-agent``), then clone the Task and enqueue it for remote execution; or, stop the execution of the current Task, reset its state, and enqueue it. If ``exit==True``, *exit* this process. .. note:: - If the task is running remotely (i.e., ``trains-agent`` is executing it), this call is a no-op + If the task is running remotely (i.e., ``clearml-agent`` is executing it), this call is a no-op (i.e., does nothing). :param queue_name: The queue name used for enqueueing the task. If ``None``, this call exits the process @@ -2006,12 +2028,12 @@ class Task(_Task): :param session_folder_zip: Path to a folder containing the session, or zip-file of the session folder. :return: Newly created task ID (str) """ - print('TRAINS: Importing offline session from {}'.format(session_folder_zip)) + print('ClearML: Importing offline session from {}'.format(session_folder_zip)) temp_folder = None if Path(session_folder_zip).is_file(): # unzip the file: - temp_folder = mkdtemp(prefix='trains-offline-') + temp_folder = mkdtemp(prefix='clearml-offline-') ZipFile(session_folder_zip).extractall(path=temp_folder) session_folder_zip = temp_folder @@ -2053,7 +2075,7 @@ class Task(_Task): # metrics Metrics.report_offline_session(task, session_folder) # print imported results page - print('TRAINS results page: {}'.format(task.get_output_log_web_page())) + print('ClearML results page: {}'.format(task.get_output_log_web_page())) task.completed() # close task task.close() @@ -2072,10 +2094,10 @@ class Task(_Task): def set_credentials(cls, api_host=None, web_host=None, files_host=None, key=None, secret=None, host=None): # type: (Optional[str], Optional[str], Optional[str], Optional[str], Optional[str], Optional[str]) -> () """ - Set new default **Trains Server** (backend) host and credentials. + Set new default **ClearML Server** (backend) host and credentials. - These credentials will be overridden by either OS environment variables, or the Trains configuration - file, ``trains.conf``. + These credentials will be overridden by either OS environment variables, or the ClearML configuration + file, ``clearml.conf``. .. warning:: Credentials must be set before initializing a Task object. @@ -2114,6 +2136,40 @@ class Task(_Task): Session.default_web = web_host or '' Session.default_files = files_host or '' + @classmethod + def _create(cls, project_name=None, task_name=None, task_type=TaskTypes.training): + # type: (Optional[str], Optional[str], Task.TaskTypes) -> Task + """ + Create a new unpopulated Task (experiment). + + :param str project_name: The name of the project in which the experiment will be created. + If ``project_name`` is ``None``, and the main execution Task is initialized (see :meth:`Task.init`), + then the main execution Task's project is used. Otherwise, if the project does + not exist, it is created. (Optional) + :param str task_name: The name of Task (experiment). + :param TaskTypes task_type: The task type. + + :return: The newly created task created. + """ + if not project_name: + if not cls.__main_task: + raise ValueError("Please provide project_name, no global task context found " + "(Task.current_task hasn't been called)") + project_name = cls.__main_task.get_project_name() + + try: + task = cls( + private=cls.__create_protection, + project_name=project_name, + task_name=task_name, + task_type=task_type, + log_to_backend=False, + force_create=True, + ) + except Exception: + raise + return task + def _set_model_config(self, config_text=None, config_dict=None): # type: (Optional[str], Optional[Mapping]) -> None """ @@ -2285,15 +2341,15 @@ class Task(_Task): # force update of base logger to this current task (this is the main logger task) logger = task._get_logger(auto_connect_streams=auto_connect_streams) if closed_old_task: - logger.report_text('TRAINS Task: Closing old development task id={}'.format(default_task.get('id'))) + logger.report_text('ClearML Task: Closing old development task id={}'.format(default_task.get('id'))) # print warning, reusing/creating a task if default_task_id and not continue_last_task: - logger.report_text('TRAINS Task: overwriting (reusing) task id=%s' % task.id) + logger.report_text('ClearML Task: overwriting (reusing) task id=%s' % task.id) elif default_task_id and continue_last_task: - logger.report_text('TRAINS Task: continuing previous task id=%s ' + logger.report_text('ClearML Task: continuing previous task id=%s ' 'Notice this run will not be reproducible!' % task.id) else: - logger.report_text('TRAINS Task: created new task id=%s' % task.id) + logger.report_text('ClearML Task: created new task id=%s' % task.id) # update current repository and put warning into logs if detect_repo: @@ -2567,8 +2623,7 @@ class Task(_Task): self._kill_all_child_processes(send_kill=False) time.sleep(2.0) self._kill_all_child_processes(send_kill=True) - # noinspection PyProtectedMember - os._exit(1) + os._exit(1) # noqa @staticmethod def _kill_all_child_processes(send_kill=False): @@ -2800,7 +2855,7 @@ class Task(_Task): if filename.is_file(): relative_file_name = filename.relative_to(offline_folder).as_posix() zf.write(filename.as_posix(), arcname=relative_file_name) - print('TRAINS Task: Offline session stored in {}'.format(zip_file)) + print('ClearML Task: Offline session stored in {}'.format(zip_file)) except Exception: pass @@ -3179,8 +3234,8 @@ class Task(_Task): task_data.get('type') not in (cls.TaskTypes.training, cls.TaskTypes.testing) and \ not Session.check_min_api_version(2.8): print('WARNING: Changing task type to "{}" : ' - 'trains-server does not support task type "{}", ' - 'please upgrade trains-server.'.format(cls.TaskTypes.training, task_data['type'].value)) + 'clearml-server does not support task type "{}", ' + 'please upgrade clearml-server.'.format(cls.TaskTypes.training, task_data['type'].value)) task_data['type'] = cls.TaskTypes.training compares = ( diff --git a/clearml/utilities/args.py b/clearml/utilities/args.py index 7900d1b9..0d5fa853 100644 --- a/clearml/utilities/args.py +++ b/clearml/utilities/args.py @@ -46,7 +46,7 @@ class PatchArgumentParser: from ..config import running_remotely, get_remote_task_id if running_remotely(): # this will cause the current_task() to set PatchArgumentParser._current_task - from trains import Task + from clearml import Task # noinspection PyBroadException try: current_task = Task.get_task(task_id=get_remote_task_id()) diff --git a/clearml/utilities/check_updates.py b/clearml/utilities/check_updates.py index 8bec7c46..23916c6b 100644 --- a/clearml/utilities/check_updates.py +++ b/clearml/utilities/check_updates.py @@ -27,10 +27,10 @@ class CheckPackageUpdates(object): cls._package_version_checked = True client, version = Session._client[0] version = Version(version) - is_demo = 'https://demoapi.trains.allegro.ai/'.startswith(Session.get_api_server_host()) + is_demo = 'https://demoapi.demo.clear.ml/'.startswith(Session.get_api_server_host()) update_server_releases = requests.get( - 'https://updates.trains.allegro.ai/updates', + 'https://updates.clear.ml/updates', json={"demo": is_demo, "versions": {c: str(v) for c, v in Session._client}, "CI": str(os.environ.get('CI', ''))}, @@ -62,13 +62,13 @@ class CheckPackageUpdates(object): @staticmethod def get_version_from_updates_server(cur_version): """ - Get the latest version for trains from updates server - :param cur_version: The current running version of trains + Get the latest version for clearml from updates server + :param cur_version: The current running version of clearml :type cur_version: Version """ try: - _ = requests.get('https://updates.trains.allegro.ai/updates', - data=json.dumps({"versions": {"trains": str(cur_version)}}), + _ = requests.get('https://updates.clear.ml/updates', + data=json.dumps({"versions": {"clearml": str(cur_version)}}), timeout=1.0) return except Exception: diff --git a/clearml/utilities/proxy_object.py b/clearml/utilities/proxy_object.py index 837f80e1..14ce49cf 100644 --- a/clearml/utilities/proxy_object.py +++ b/clearml/utilities/proxy_object.py @@ -77,6 +77,19 @@ class ProxyDictPreWrite(dict): return self._set_callback((prefix + '.' + key_value[0], key_value[1],)) +def verify_basic_type(a_dict_list, basic_types=None): + basic_types = (float, int, bool, six.string_types, ) if not basic_types else \ + tuple(b for b in basic_types if b not in (list, tuple, dict)) + + if isinstance(a_dict_list, basic_types): + return True + if isinstance(a_dict_list, (list, tuple)): + return all(verify_basic_type(v) for v in a_dict_list) + elif isinstance(a_dict_list, dict): + return all(verify_basic_type(k) for k in a_dict_list.keys()) and \ + all(verify_basic_type(v) for v in a_dict_list.values()) + + def flatten_dictionary(a_dict, prefix=''): flat_dict = {} sep = '/' @@ -88,7 +101,11 @@ def flatten_dictionary(a_dict, prefix=''): elif isinstance(v, (list, tuple)) and all([isinstance(i, basic_types) for i in v]): flat_dict[prefix + k] = v elif isinstance(v, dict): - flat_dict.update(flatten_dictionary(v, prefix=prefix + k + sep)) + nested_flat_dict = flatten_dictionary(v, prefix=prefix + k + sep) + if nested_flat_dict: + flat_dict.update(nested_flat_dict) + else: + flat_dict[k] = {} else: # this is a mixture of list and dict, or any other object, # leave it as is, we have nothing to do with it. diff --git a/clearml/utilities/resource_monitor.py b/clearml/utilities/resource_monitor.py index 15f4d9b2..f64c2710 100644 --- a/clearml/utilities/resource_monitor.py +++ b/clearml/utilities/resource_monitor.py @@ -41,7 +41,7 @@ class ResourceMonitor(object): self._last_process_pool = {} self._last_process_id_list = [] if not self._gpustat: - self._task.get_logger().report_text('TRAINS Monitor: GPU monitoring is not available') + self._task.get_logger().report_text('ClearML Monitor: GPU monitoring is not available') else: # if running_remotely(): try: active_gpus = os.environ.get('NVIDIA_VISIBLE_DEVICES', '') or \ @@ -105,13 +105,13 @@ class ResourceMonitor(object): if IsTensorboardInit.tensorboard_used(): fallback_to_sec_as_iterations = False elif seconds_since_started >= self.wait_for_first_iteration: - self._task.get_logger().report_text('TRAINS Monitor: Could not detect iteration reporting, ' + self._task.get_logger().report_text('ClearML Monitor: Could not detect iteration reporting, ' 'falling back to iterations as seconds-from-start') fallback_to_sec_as_iterations = True elif fallback_to_sec_as_iterations is True and seconds_since_started <= self.max_check_first_iteration: if self._check_logger_reported(): fallback_to_sec_as_iterations = False - self._task.get_logger().report_text('TRAINS Monitor: Reporting detected, ' + self._task.get_logger().report_text('ClearML Monitor: Reporting detected, ' 'reverting back to iteration based reporting') clear_readouts = True @@ -231,7 +231,7 @@ class ResourceMonitor(object): # something happened and we can't use gpu stats, self._gpustat_fail += 1 if self._gpustat_fail >= 3: - self._task.get_logger().report_text('TRAINS Monitor: GPU monitoring failed getting GPU reading, ' + self._task.get_logger().report_text('ClearML Monitor: GPU monitoring failed getting GPU reading, ' 'switching off GPU monitoring') self._gpustat = None diff --git a/clearml/utilities/seed.py b/clearml/utilities/seed.py index ca67e8e5..aa71007c 100644 --- a/clearml/utilities/seed.py +++ b/clearml/utilities/seed.py @@ -12,7 +12,7 @@ def make_deterministic(seed=1337, cudnn_deterministic=False): Ensure deterministic behavior across PyTorch using the provided random seed. This function makes sure that torch, numpy and random use the same random seed. - When using trains's task, call this function using the task's random seed like so: + When using clearml's task, call this function using the task's random seed like so: make_deterministic(task.get_random_seed()) :param int seed: Seed number diff --git a/clearml/version.py b/clearml/version.py index 538eb5d8..610aac28 100644 --- a/clearml/version.py +++ b/clearml/version.py @@ -1 +1 @@ -__version__ = '0.16.4' +__version__ = '0.17.0rc0' diff --git a/docs/clearml-task.md b/docs/clearml-task.md new file mode 100644 index 00000000..9bbe41d8 --- /dev/null +++ b/docs/clearml-task.md @@ -0,0 +1,136 @@ +# `clearml-task` - Execute ANY python code on a remote machine + +If you are already familiar with `clearml`, then you can think of `clearml-task` as a way to create a Task/experiment +from any script without the need to add even a single line of code to the original codebase. + +`clearml-task` allows a user to **take any python code/repository and launch it on a remote machine**. + +The remote execution is fully monitored, all outputs - including console / tensorboard / matplotlib +are logged in real-time into the ClearML UI + +## What does it do? + +`clearml-task` creates a new experiment on your `clearml-server`; it populates the experiment's environment with: + +* repository/commit/branch, as specified by the command-line invocation. +* optional: the base docker image to be used as underlying environment +* optional: alternative python requirements, in case `requirements.txt` is not found inside the repository. + +Once the new experiment is created and populated, it will enqueue the experiment to the selected execution queue. + +When the experiment is executed on the remote machine (performed by an available `clearml-agent`), all the console outputs +will be logged in real-time, alongside your TensorBoard and matplotlib. + +### Use-cases for `clearml-task` remote execution + +- You have an off-the-shelf code, and you want to launch it on a remote machine with a specific resource (i.e., GPU) +- You want to run the [hyper-parameter optimization]() on a codebase that is still not connected with `clearml` +- You want to create a [pipeline]() from an assortment of scripts, and you need to create Tasks for those scripts +- Sometimes, you just want to run some code on a remote machine, either using an on-prem cluster or on the cloud... + +### Prerequisites + +- A single python script, or an up-to-date repository containing the codebase. +- `clearml-agent` running on at least one machine (to execute the experiment) + +## Tutorial + +### Launching a job from a repository + +We will be launching this [script](https://github.com/allegroai/trains/blob/master/examples/frameworks/scikit-learn/sklearn_matplotlib_example.py) on a remote machine. The following are the command-line options we will be using: +- First, we have to give the experiment a name and select a project (`--project examples --name remote_test`) +- Then, we select the repository with our code. If we do not specify branch / commit, it will take the latest commit + from the master branch (`--repo https://github.com/allegroai/clearml.git`) +- Lastly, we need to specify which script in the repository needs to be run (`--script examples/frameworks/scikit-learn/sklearn_matplotlib_example.py`) +Notice that by default, the execution working directory will be the root of the repository. If we need to change it, add `--cwd ` + +If we additionally need to pass an argument to our scripts, use the `--args` switch. + The names of the arguments should match the argparse arguments, removing the '--' prefix + (e.g. instead of --key=value -> use `--args key=value` ) + +``` bash +clearml-task --project examples --name remote_test --repo https://github.com/allegroai/clearml.git +--script examples/frameworks/scikit-learn/sklearn_matplotlib_example.py +--queue single_gpu +``` + +### Launching a job from a local script + +We will be launching a single local script file (no git repo needed) on a remote machine. + +- First, we have to give the experiment a name and select a project (`--project examples --name remote_test`) +- Then, we select the script file on our machine, `--script /path/to/my/script.py` +- If we need specific packages, we can specify them manually with `--packages "tqdm>=4" "torch>1.0"` + or we can pass a requirements file `--requirements /path/to/my/requirements.txt` +- Same as in the repo case, if we need to pass arguments to `argparse` we can add `--args key=value` +- If we have a docker container with an entire environment we want our script to run inside, + add e.g., `--docker nvcr.io/nvidia/pytorch:20.11-py3` + +Note: In this example, the exact version of PyTorch to install will be resolved by the `clearml-agent` depending on the CUDA environment available at runtime. + +``` bash +clearml-task --project examples --name remote_test --script /path/to/my/script.py +--packages "tqdm>=4" "torch>1.0" --args verbose=true +--queue dual_gpu +``` + +### CLI options + +``` bash +clearml-task --help +``` + +``` console +ClearML launch - launch any codebase on remote machines running clearml-agent + +optional arguments: + -h, --help show this help message and exit + --version Display the Allegro.ai utility version + --project PROJECT Required: set the project name for the task. If + --base-task-id is used, this arguments is optional. + --name NAME Required: select a name for the remote task + --repo REPO remote URL for the repository to use. Example: --repo + https://github.com/allegroai/clearml.git + --branch BRANCH Select specific repository branch/tag (implies the + latest commit from the branch) + --commit COMMIT Select specific commit id to use (default: latest + commit, or when used with local repository matching + the local commit id) + --folder FOLDER Remotely execute the code in the local folder. Notice! + It assumes a git repository already exists. Current + state of the repo (commit id and uncommitted changes) + is logged and will be replicated on the remote machine + --script SCRIPT Specify the entry point script for the remote + execution. When used in tandem with --repo the script + should be a relative path inside the repository, for + example: --script source/train.py .When used with + --folder it supports a direct path to a file inside + the local repository itself, for example: --script + ~/project/source/train.py + --cwd CWD Working directory to launch the script from. Default: + repository root folder. Relative to repo root or local + folder + --args [ARGS [ARGS ...]] + Arguments to pass to the remote execution, list of + = strings.Currently only argparse + arguments are supported. Example: --args lr=0.003 + batch_size=64 + --queue QUEUE Select the queue to launch the task. If not provided a + Task will be created but it will not be launched. + --requirements REQUIREMENTS + Specify requirements.txt file to install when setting + the session. If not provided, the requirements.txt + from the repository will be used. + --packages [PACKAGES [PACKAGES ...]] + Manually specify a list of required packages. Example: + --packages "tqdm>=2.1" "scikit-learn" + --docker DOCKER Select the docker image to use in the remote session + --skip-task-init If set, Task.init() call is not added to the entry + point, and is assumed to be called in within the + script. Default: add Task.init() call entry point + script + --base-task-id BASE_TASK_ID + Use a pre-existing task in the system, instead of a local repo/script. + Essentially clones an existing task and overrides arguments/requirements. + +``` diff --git a/docs/clearml.conf b/docs/clearml.conf new file mode 100644 index 00000000..cda232ad --- /dev/null +++ b/docs/clearml.conf @@ -0,0 +1,196 @@ +# ClearML SDK configuration file +api { + # web_server on port 8080 + web_server: "http://localhost:8080" + + # Notice: 'api_server' is the api server (default port 8008), not the web server. + api_server: "http://localhost:8008" + + # file server on port 8081 + files_server: "http://localhost:8081" + + # Credentials are generated using the webapp, http://localhost:8080/profile + credentials {"access_key": "EGRTCO8JMSIGI6S39GTP43NFWXDQOW", "secret_key": "x!XTov_G-#vspE*Y(h$Anm&DIc5Ou-F)jsl$PdOyj5wG1&E!Z8"} + + # verify host ssl certificate, set to False only if you have a very good reason + verify_certificate: True +} +sdk { + # ClearML - default SDK configuration + + storage { + cache { + # Defaults to system temp folder / cache + default_base_dir: "~/.clearml/cache" + } + } + + metrics { + # History size for debug files per metric/variant. For each metric/variant combination with an attached file + # (e.g. debug image event), file names for the uploaded files will be recycled in such a way that no more than + # X files are stored in the upload destination for each metric/variant combination. + file_history_size: 100 + + # Max history size for matplotlib imshow files per plot title. + # File names for the uploaded images will be recycled in such a way that no more than + # X images are stored in the upload destination for each matplotlib plot title. + matplotlib_untitled_history_size: 100 + + # Limit the number of digits after the dot in plot reporting (reducing plot report size) + # plot_max_num_digits: 5 + + # Settings for generated debug images + images { + format: JPEG + quality: 87 + subsampling: 0 + } + + # Support plot-per-graph fully matching Tensorboard behavior (i.e. if this is set to true, each series should have its own graph) + tensorboard_single_series_per_graph: false + } + + network { + metrics { + # Number of threads allocated to uploading files (typically debug images) when transmitting metrics for + # a specific iteration + file_upload_threads: 4 + + # Warn about upload starvation if no uploads were made in specified period while file-bearing events keep + # being sent for upload + file_upload_starvation_warning_sec: 120 + } + + iteration { + # Max number of retries when getting frames if the server returned an error (http code 500) + max_retries_on_server_error: 5 + # Backoff factory for consecutive retry attempts. + # SDK will wait for {backoff factor} * (2 ^ ({number of total retries} - 1)) between retries. + retry_backoff_factor_sec: 10 + } + } + aws { + s3 { + # S3 credentials, used for read/write access by various SDK elements + + # default, used for any bucket not specified below + key: "" + secret: "" + region: "" + + credentials: [ + # specifies key/secret credentials to use when handling s3 urls (read or write) + # { + # bucket: "my-bucket-name" + # key: "my-access-key" + # secret: "my-secret-key" + # }, + # { + # # This will apply to all buckets in this host (unless key/value is specifically provided for a given bucket) + # host: "my-minio-host:9000" + # key: "12345678" + # secret: "12345678" + # multipart: false + # secure: false + # } + ] + } + boto3 { + pool_connections: 512 + max_multipart_concurrency: 16 + } + } + google.storage { + # # Default project and credentials file + # # Will be used when no bucket configuration is found + # project: "clearml" + # credentials_json: "/path/to/credentials.json" + + # # Specific credentials per bucket and sub directory + # credentials = [ + # { + # bucket: "my-bucket" + # subdir: "path/in/bucket" # Not required + # project: "clearml" + # credentials_json: "/path/to/credentials.json" + # }, + # ] + } + azure.storage { + # containers: [ + # { + # account_name: "clearml" + # account_key: "secret" + # # container_name: + # } + # ] + } + + log { + # debugging feature: set this to true to make null log propagate messages to root logger (so they appear in stdout) + null_log_propagate: false + task_log_buffer_capacity: 66 + + # disable urllib info and lower levels + disable_urllib3_info: true + } + + development { + # Development-mode options + + # dev task reuse window + task_reuse_time_window_in_hours: 72.0 + + # Run VCS repository detection asynchronously + vcs_repo_detect_async: true + + # Store uncommitted git/hg source code diff in experiment manifest when training in development mode + # This stores "git diff" or "hg diff" into the experiment's "script.requirements.diff" section + store_uncommitted_code_diff: true + store_code_diff_from_remote: false + + # Support stopping an experiment in case it was externally stopped, status was changed or task was reset + support_stopping: true + + # Default Task output_uri. if output_uri is not provided to Task.init, default_output_uri will be used instead. + default_output_uri: "" + + # Default auto generated requirements optimize for smaller requirements + # If True, analyze the entire repository regardless of the entry point. + # If False, first analyze the entry point script, if it does not contain other to local files, + # do not analyze the entire repository. + force_analyze_entire_repo: false + + # If set to true, *clearml* update message will not be printed to the console + # this value can be overwritten with os environment variable CLEARML_SUPPRESS_UPDATE_MESSAGE=1 + suppress_update_message: false + + # If this flag is true (default is false), instead of analyzing the code with Pigar, analyze with `pip freeze` + detect_with_pip_freeze: false + detect_with_conda_freeze: false + + # Log specific environment variables. OS environments are enlisted in the "Environment" section + # of the Hyper-Parameters. + # multiple selected variables are supported including the suffix '*'. + # For example: "AWS_*" will log any OS environment variable starting with 'AWS_'. + # This value can be overwritten with os environment variable CLEARML_LOG_ENVIRONMENT="[AWS_*, CUDA_VERSION]" + # Example: log_os_environments: ["AWS_*", "CUDA_VERSION"] + log_os_environments: [] + + # Development mode worker + worker { + # Status report period in seconds + report_period_sec: 2 + + # ping to the server - check connectivity + ping_period_sec: 30 + + # Log all stdout & stderr + log_stdout: true + + # compatibility feature, report memory usage for the entire machine + # default (false), report only on the running process and its sub-processes + report_global_mem_used: false + } + } +} diff --git a/docs/contributing.md b/docs/contributing.md index ff3efbae..5365b6a5 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -2,39 +2,40 @@ Firstly, we thank you for taking the time to contribute! -The following is a set of guidelines for contributing to TRAINS. +Contribution comes in many forms: +* Reporting [issues](https://github.com/allegroai/clearml/issues) you've come upon +* Participating in issue discussions in the [issue tracker](https://github.com/allegroai/clearml/issues) and the [ClearML community slack space](https://join.slack.com/t/allegroai-trains/shared_invite/enQtOTQyMTI1MzQxMzE4LTY5NTUxOTY1NmQ1MzQ5MjRhMGRhZmM4ODE5NTNjMTg2NTBlZGQzZGVkMWU3ZDg1MGE1MjQxNDEzMWU2NmVjZmY) +* Suggesting new features or enhancements +* Implementing new features or fixing outstanding issues + +The following is a set of guidelines for contributing to ClearML. These are primarily guidelines, not rules. Use your best judgment and feel free to propose changes to this document in a pull request. -## Reporting Bugs +## Reporting Issues -This section guides you through submitting a bug report for TRAINS. -By following these guidelines, you -help maintainers and the community understand your report, reproduce the behavior, and find related reports. +By following these guidelines, you help maintainers and the community understand your report, reproduce the behavior, and find related reports. -Before creating bug reports, please check whether the bug you want to report already appears [here](link to issues). -You may discover that you do not need to create a bug report. -When you are creating a bug report, please include as much detail as possible. +Before reporting an issue, please check whether it already appears [here](https://github.com/allegroai/clearml/issues). +If it does, join the on-going discussion instead. **Note**: If you find a **Closed** issue that may be the same issue which you are currently experiencing, then open a **New** issue and include a link to the original (Closed) issue in the body of your new one. -Explain the problem and include additional details to help maintainers reproduce the problem: +When reporting an issue, please include as much detail as possible: explain the problem and include additional details to help maintainers reproduce the problem: * **Use a clear and descriptive title** for the issue to identify the problem. * **Describe the exact steps necessary to reproduce the problem** in as much detail as possible. Please do not just summarize what you did. Make sure to explain how you did it. * **Provide the specific environment setup.** Include the `pip freeze` output, specific environment variables, Python version, and other relevant information. * **Provide specific examples to demonstrate the steps.** Include links to files or GitHub projects, or copy/paste snippets which you use in those examples. -* **If you are reporting any TRAINS crash,** include a crash report with a stack trace from the operating system. Make sure to add the crash report in the issue and place it in a [code block](https://help.github.com/en/articles/getting-started-with-writing-and-formatting-on-github#multiple-lines), +* **If you are reporting any ClearML crash,** include a crash report with a stack trace from the operating system. Make sure to add the crash report in the issue and place it in a [code block](https://help.github.com/en/articles/getting-started-with-writing-and-formatting-on-github#multiple-lines), a [file attachment](https://help.github.com/articles/file-attachments-on-issues-and-pull-requests/), or just put it in a [gist](https://gist.github.com/) (and provide link to that gist). * **Describe the behavior you observed after following the steps** and the exact problem with that behavior. * **Explain which behavior you expected to see and why.** * **For Web-App issues, please include screenshots and animated GIFs** which recreate the described steps and clearly demonstrate the problem. You can use [LICEcap](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [silentcast](https://github.com/colinkeenan/silentcast) or [byzanz](https://github.com/threedaymonk/byzanz) on Linux. -## Suggesting Enhancements +## Suggesting New Features and Enhancements -This section guides you through submitting an enhancement suggestion for TRAINS, including -completely new features and minor improvements to existing functionality. By following these guidelines, you help maintainers and the community understand your suggestion and find related suggestions. Enhancement suggestions are tracked as GitHub issues. After you determine which repository your enhancement suggestion is related to, create an issue on that repository and provide the following: @@ -43,12 +44,18 @@ Enhancement suggestions are tracked as GitHub issues. After you determine which * **A step-by-step description of the suggested enhancement** in as much detail as possible. * **Specific examples to demonstrate the steps.** Include copy/pasteable snippets which you use in those examples as [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). * **Describe the current behavior and explain which behavior you expected to see instead and why.** -* **Include screenshots or animated GIFs** which help you demonstrate the steps or point out the part of TRAINS which the suggestion is related to. You can use [LICEcap](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [silentcast](https://github.com/colinkeenan/silentcast) or [byzanz](https://github.com/threedaymonk/byzanz) on Linux. - - - +* **Include screenshots or animated GIFs** which help you demonstrate the steps or point out the part of ClearML which the suggestion is related to. You can use [LICEcap](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [silentcast](https://github.com/colinkeenan/silentcast) or [byzanz](https://github.com/threedaymonk/byzanz) on Linux. +## Pull Requests +Before you submit a new PR: +* Verify the work you plan to merge addresses an existing [issue](https://github.com/allegroai/clearml/issues) (If not, open a new one) +* Check related discussions in the [ClearML slack community](https://join.slack.com/t/allegroai-trains/shared_invite/enQtOTQyMTI1MzQxMzE4LTY5NTUxOTY1NmQ1MzQ5MjRhMGRhZmM4ODE5NTNjMTg2NTBlZGQzZGVkMWU3ZDg1MGE1MjQxNDEzMWU2NmVjZmY) (Or start your own discussion on the `#clearml-dev` channel) +* Make sure your code conforms to the ClearML coding standards by running: + `flake8 --max-line-length=120 --statistics --show-source --extend-ignore=E501 ./trains*` +In your PR include: +* A reference to the issue it addresses +* A brief description of the approach you've taken for implementing diff --git a/docs/dataset_screenshots.gif b/docs/dataset_screenshots.gif new file mode 100644 index 0000000000000000000000000000000000000000..9049c2d1ebe5104df9d3c13d7c5f37075efb1cd5 GIT binary patch literal 458123 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 d0*{bJHUU>hePUn7?D6mMwcy<-Q#032|X*?f@Q z?{p+G>w*W7&obkYzFO4nXKqTDct zp-$wgUZ~+}2cRWM5ficYjd&AGjhcfzemQ^iT805A&^^F*9GlI@!^qe-D@CkyLv01e zyi+niw;wAY-0Iewm+|V(zK%E|*utJ3bQuJW?^;SOR1HhH)roS6&?BfMYLsKG7KOlu zO&xWYen3h;GvyneJ_D5%AZB%X%4ETafY#>2eAqfHsR#>-jX#k5)g5-NH8db@n#R{2 zGpy_#;iuBbt@fV=|s-pS`;hxUHpa648(kn)jj}83=br6B*-hy&PEP9#Bia|=fpT-AB=kPFT*ogGoaZ;z?QBx4~ zCO8Olrey_sFp=FI)b@FG1e7&qCMHZu*0!NTFHVtx8(u`z7#V>W^a0XEMmSLF=U;y_ zno%H`s#V&Pt9AcouF}l`z?2vHx=u`j#87lTlFb7Lzi&3B5eN|<4fVW*wzi-Q7$#4N zn_kbyrn{ojehS)#N1HY1h7X3qA^v-U9k}FhrOr$nx|txEXsnuz22ALbUx9}auZhzf z6Z}xfL*Ybrb|#w(9gpEStYEp+IQt`+~y)P8nL2}srYc=%X3 z)elBnm07G3DxrMv_cN)Fdo@UI+{?G~nhhWIVyK3fXMRmkj7QB6UY;|cQ~zBd-FZ7` z^wZ69Ha}&9dil1us1nI|ZqQH>f*&6={^B7}JG@t0U9e&%L7<;R&{1u3KnEpLn$B$p z-db@9=b>kbI&-{YAhsBKF#vRiScd?hSm^$<0SPz&w9yr|=+FP<r5&jpBA%L9P_A!K01o0u zh0)qr%}_c|`QRwV`>+gU>gG(mpqo_FAeQuz_hv0}4t#~6OLq?nwE;@r-aN^JFAAu_ z5k)}gqCf+ELgMfVRBf}53IE1X#V}280F|%|IM-Ma1`+um;f?1EB*oF46fJ)u7kycJ zXi!KGl%)@HXkoF6z}R-ZRwtUf8OK$Mfq9!5UIyi`)5c5&6i39g`7rfOWr++7oL*Hi zr}u^S{B1ezGF30#++@p7Ux?V8VQw%p$j7pK&4G~uStI}sMX>Unljuig7#93EF2*|z|DDLNF| zEx)!{^(fK{G6Se415!;;=)uRMEnxXqBADnHf&$ifh;rxw{%wZx_;p@*5dM^x>uox( z9uZKbBvjPu$E`T2m50xn9Y$z%4;+CR`r!)qc#;SkT>K&e!>8;cB}s(f-g77pXpNo& z65K39&T<_P!^;;DiWIoed+b+GpGBAfE-Q@sFsx<)z2aM1#UJ--*PQPtAke95a}3BR zRMPPS#lbYelWrBDn50uQtX=RFQIK&7W3WFcJY{AaV{Wo*E=VBa#$o%jYsO6K4Il7{ zI*1BE*4aZ$G!{4$U_#k9GBHFolDv;=fF#l*{ALg^x5&}GDs+i>4n^k#7~I8!HX#^D zpTMEMQkPCHy*q@Ht(^5F7BBe;&d~L?d{XyU_&7Y}W6b6A&E>}j1?JwJenJ(frrxk& z1kF=3zhVYnPDoEt3o--i4MJ2nh%|J?d&Fi|K3Qqb^){#&Gw5goLmu2ZFjYj~uOPoS z9lRpOg0_xX)Ma`g2~yWU|l$UiO@G1E+0# z^+_7mR?3=uJ7p80#0UYrFurt~1bW^(rM zSJiW7!dlLK)FQ6;vxz(7Zkux<}^z=+Yi2kX=k&1 zj80XWX~6hK0bYQNN`Pr@0f%B%-cwatq2|VIpLlubGDD1brA?~w=G^2FMGlCnEO?&N z3?m0heOl#>^^!UW1L*P!007P2EP707?p*~AmcsXmJt;(J@KfGMNyq{IyxOgB+H6$e z+p#bJsz}kSzOcsuO@BGjc~zkxb?vZQ>zW!7l2AUmd7;p)aoRIDJu|4zXBiPZp{iwm zKa77}2+&z=gNLl3kl^NfGA9@meq>!h??UfYxy*WNpff^SaE?Aqc!JnZ~ zFrchjUNU%kpQ<}Yo#L6egDMzLbcxxJ1)ftiFAtviMLzt*Y-1v=EFbf&5E*iyoFtNX zNF&E%0KC>m4}Dx~30QuWS{&d8a8rJ#ltG7t**|?QVyN7`-=v*DopP7})(3EsAa02a z<)*7n4Pvzhl#Ikw=z~Y~AV)qiWQBaMA`0Y)b^4Bjzox&U`M2db==08$3Vr*Y8h6en zcPI@HZL0e$I~9QA&isTs?Fd)3YZ$JID}-H`EB;{7QoU zIu-&Q+tApqQnjNZ?>Ti0e3MXVHxmku&Xv;6CbBrk%y4YmJGCFvj<^0<9FTCNzm^li zjlo3PK-pv=lg;J#2K@Kh1eP49OZsH_YT5-O=X@C6f2Y?n5{uU)9dK`5C-23G*h(_+%j(4m~ibC}o(H zdEVS^mVa`7qG_^G<>%M!jO!JPcxVG4M;}mOKL^=eTB^jh^7*0b7B+g+y`HJZh*CA# zTmNp-Ixi~RP1Q8erS8VUjmHKxXy@2q7$`gCw?0gVeK7L`luZpb%R^+5%Z^`u!*eg# zPz0uxtkt>cxoLono@QKQXtv&7;DX`>uoC zu0YortY+$coajw}`+(?iC|o?qM@=2_r&P^gVb8L1gv*fX{f^`8W(LU$qQlcx8A$Z) zWr?pXCLf~w40R+tqlSDoc{zY*(jG!fjTceE@{acCqAcctA z`;j1+F0@ygBQfDmeZaRpT|D4=sn(k(%pQVki)gAiMo-8y%2+3Y?C02y zlJr`>YBS3lunkWU9SwN)=fb?XfNY`G(cSc-n2f6KjQE$XQKOl{V?T%Zcn&}~Fu`3M zhVb9XSdPj4yqlZV_zX9o<87YLwU-Zz%?~#(5Z)6GjyXf;!;K5^N}2II#X0|oDRJK` z@!LzP$d(n@%a7kH^D{398Yujctg=^%OAsniGP~q5cp+%7YB09?MXXoF7#`lEt_95( zHkTbADB#k+u4_iq9gr0mEa%nqX7F(Xj2Hx1Cj)_x#WtMWZ#ZknFU&7PyqP(C%9sdE@ap(~d*bO$L>xKi* z49#v|V<0%XxPlK}3?_`d=p#V-_#zB+Licg-1bI>l7my_@U{LXWXpBE`Lj2!EUg5JT z10DLlEP-V#qxU#pn5s@7-}!Fvs)~E^!oTUL#CKc{o#qJ-q#oTkdvMq*J6oUlzV)&2 z{oOp7zxgKshSzqNI%~)`mOlQ$1_5Xdm9D_jxes z%L~?*!6#hfht+dQ-##a;v?i@TVts>M+v56fi~riTaQ|2FYde2gpH=!d{v`d#GTAx% zjy)#)_nUfcH|xLMqW``|ANy|D-`ysFPwvt2h#&HM)Tt8t z@JHgm5hEt+!+-PdPHuGkr*k=B1_sw5&pZ%(AuxE{EQL!{je862YmvdP)wK;}fLRxDqDO^J%@gUfq-fu|}o&rjcrD&kotCqepK7@h7;f93xg9g5_%Rx4jBev-6U-6rIi;Iy3s6b zoc&$DXKItI2S>ymDcOh+shP*+N0aHImb%v@6Axv9vk#;HlT1q3i+HAs?W-}II#}ow zR9SVuyU$mdM~Ctlp&4*Nk9-DFA|YQEB3vh}YuU7UhEo<)^iAbFFKV4B59XVirQnP( z!vano1;av~37DrMy2_okz{uazwWA*OEa1ewE&d4$LC@j|ONo^67jm$isG~^#2v9&xa=!SDt?|D@+0@_6 z;;DU>oia`a8QNPblu(&5R3-~YmrT2bJr;cDaphmrlo!mLBQyS|Xz7e^+GB;x3S|Du z^}z4VY`l)qHKp%EZa)@s*GQZf>MBas7Mk-rze$w{TB*fgic(?;iK zvNvm*^R84Uj!=t`F~Up`;T1Ve=1Fy2h_UbegHQFtN1x+GqdCx5H=A!s=nHjNqvaZI zTZ3Y+VuhCVg?3#U&D$8nW+=L2vD(n&4*N=aL{o~Sp_wnSG{itpWSu661t9Qr+Y>1# z6FP!dGugMOMH%Efwbd%W8{UV=@H>}#C4Twk)(F|R8*#lhJ};Udq!&R;58s&~)v>M} zreQ8-S={jj*pTXMxs_7NF*1mT)Y0$h&cr%^4!M>N&_uvJ6s-LE&FcmnWy4bXxpqS} zUHW3)rO`=3l|LsZ_yI5@r0G+Mi@|xaY%#`~QF2qMg`CegQkPsbfC#MJG$!}^MoK?i zz3S5;?kp(}z1%ZWDT}thRl!BnF!(z07sux5yipL83%j0{1QQBAVRe1;!jr$X0o!N` zZ1}4HNYIuF00I`1%_9|jP-|1Z^}oXi~e^j?JD>Cqk=>2`a0!xwn(+z_; zgIV#US270huu_0CCe0X!d~QFZ5F+w1Z;*h1D)9-oY^Vh6Y`k)RcgsVI$=~x+is7 zC7n8wXH_wFC*AyDN+Kx+o0!*-FEpV8cPs5f1|rMLQ4dZ!j+6CeKjOT@XNd;5NNikY zW0`!dP01?G(#eOzBOx;)Amz9{S)J)y$j z2o(&u_D==Gw-w}Ez6aw@_G9QK`{bs&ovB@qN<|_&*aJgV!?4Ujy-#cULfK34109l% zi=EuxctCcsP&Q%ImLyUY-y($uO`vgAAV7p26QZViE4}ME zMbt`>&WWQ#J;umvFpvzre%=!~g~K|HLiBCXU_jzS*@yX05v1Btflo_qZA~Lbog`HJkbi`x6~103FcyjO>+Q#E}erPh&oqpVX$Ct zpS>V5LSvklOU4zzw``-K)(i~Bj+&1I`A%U0yRua_`JF{Ulk#R2Goqms7UZk31`BdP z;8;R2FRLS%kylVY2^X1Ye)oKZBk+Xo@jgFJ7)|+wq?vYLD6K^G9$edId=}y&bUTE9 z$iP<=^YbDYl4v+&L}vo0sy`!FKq?f;bK*C4Ni?zX=Ap$XPwCWKvFZ3x)bq$7iE>yE z{fnxm8W0TeF6G@!H=l=s3*2_MQ82w^J$eV!fxZmaQM6K3k&t+M=Rv+mB3 z^S$b2n@8FuV-7ALazQg$%Loke)TPTgMsk=oWmKFu1VZB`as^B0UY>#R7XD}-ZFBB2 z$*w!`L1=2rfg)Y9Cw#w&GJ3a_xjZvQ#-> z3)OIsgF#VaJu3<8#OXs#iHqIu#1^fJ{f@9MJqzeJ$4v zdI&7?hE@CBI%a$nJV`vo_2;ZvLvBPOn1Vn9Kpv8w)dhv~!)P#4GT3-r zoM`PzyC*TF1|SG<>6k~H5HyW1dFG)q$4o>8#_Ul*03c^1p^Lc0&8lIsX73gprmz>v+TUFmR&o*d2P3gQdD>)un%B`dAykS zmT&~L^xl^0WSmdhdSx8D-g7Jcyf>IETGkVl>#01gTorpnlvQPzwR;Qs^DQp1kpkv7GRwdgJcSQ0s5Ue`dR}2Otw_+%i-Oa z0+S5!^+nX7q0Uy3%`*HCnzm(;W9&@iqcg;Jx1gNie(*(6O9jm5+vqSF%X#8(Q#!6k z!^kZmZB4O5kOkH4WQ#n`u?v2r@4v3s?^&&Oq7ASakhQ%ON(7rOj`0l{*sq8WS3b#H_pEQifus+&gbnb+syw> ztpP~OEDhv-Gv?;24kPhW&_{vY+Z$if(O;R{0~1_~T265LF5$Zf116ifw&6c!t-JqiI{bH0BRbhOu&0s<5t3V z_n!+JMkWVBex-McJpLqd#CO)2GDVsc-}0gF2Fp0}`31i02Ts=XE*86;xD02sR+}E` zxE9v)B>sG59hDkLKnMHLG9~wK)huLOJ5ZoL2?C+s=xJ#^VQ=Vs0n1s5N=T)0GV|~! zgb8f`=NAUiN-~MTVe5lZK9rih;RyCYU8b>%Z%FKamPXy;$S3k0YA7}6a?NDeWjo1N z;VXfy;rmgjogc!b-z1)Zn6cWY6bB2dVnvUTdex=c^lYG15t6DJ-5tsu#ip$Abd-67-XwBcyF8*XOEpKE9`K{1|g3Cld=fuA@ zANau+C^sXBm{u2p!9(vti!~RZ(vtV+@0esxhm4tN#^ki0P=hJ#;!~!<_KqXw!X1_X zlf4!0;BEWp=PWyYR)dT1pH-0}6C2Q2`QY#n$_ZEGu}$RH4=mCt;t@S(2B65Hq(b$t zc@FQ=BZ$ZVzMw#}Uzy`gfXCBJ9MtLGg*+?z*6Xj$vfl7VL1ui2~wKgXNJO%|7kVN)m zB2YfX<+>*5T#LvKyyC^UmERVfSR%Xk-|uen#5&3&a0a+s392xEO^`l?$<_0N&mfW;<;DfYYJNZ`DV#y0(ApY7yESJ!E>; ztS-V!N0FG;4wsgwB1fACgvM7|yj=^t_* zkn{MqD1VTOtdYY$Jad_y$dLS^>867!Ju1JRj(=}`k?kQX@`iAnvAOkM_Dej0fPk>f zLXk}1P2NINShs*_#~+!YGWD=v4ijOB8^DnSb`wR?qDX1cyEdmt`VUr5ltXRh z8$w?AX+p`NEw%kgcU(D(({6}l){`;~V-n9NYa+i&R>#P9%@A+RWc7<=4~mSm%vkAB zk)a|vf!?wz^t9oboR1>8%jM3aB(qa6&lQ$P-VajV9})ZYa)(`!e3)xKTSaDGPRf7f z`TVX0!W9KkZF`yBC&gR~6)FlLs|Ar&W|^?dgGg8riNDWfc`w zdq=^&l9!a@-)1UWXDi!XwVGy4N9#+L1JXsI8UwD?BNf#zW~*O|*1U18c~?>MVYcR@ ztF%0`W=&LjefIiy(HqZPum7mH@ptydf1)&)8|}O6bx&^^?|TijTdiug>fKt>#PsTV z_8P@nyWCnc_G$}ylpct+4Z5}2yJ}d>wkF24y>Yw!&Mm*yjhJm9{aox$N{s5v`#ayo z+J{B-R(mZRyDgvN+hOhLoFZR9UShR!d0DC_oUh6Jek@e+9%UJRxgj6y^7!RRjx%b|xI=p}rP=8y_;5nbHB>s|4 zDv6gZO_7ti+xy}}-)r|H4~E-Le~|5d^yqQChX*0ccr9-H!;|mg{Vq%Q`^Co_l>h<%^*_((nUi$Yx8kW81jK@{WJ(c&hpgi1JbbW8Cr(%Zgr8()_;T<+y zztu{dYRob9g-$Gyjzu%v=MIlOC)+vv*f_qaqG?qyc+C3DU_zA{)alFu1jzE zln~88A4d1~%+oMZf|B&o&)}D_AJP)BMEx@y&alJyzHYA3QbgS$vzsQTTAm=yHdY~b z-_zse*(Fa;wyU-S&y@#|V=V3XTM;3YAi2T=)0k>&F|2J!7hcvwE|4Rx!Ac@^8#cmt zxbywabk~p+&g8RCz?hZ9CZ<6^Q|)+A&|h8 zTw*kSVA3hR<7#EFYt8(-ukGIbita*bu{9p(4{3A%vK$nUPJzF&`QSqVf+b^%oGiIa z+B{ul>B_suu5aoY3W#wfv+=Xg0s#&{Lh0qTHws5MiWXW=JtMQdJzae9^rYPe7QK!A z%;ar2QM$AZbz_RN`~xQ%aS%dnSyJ=s2-N(^P$D(Z#OaNm5b67 z6S8Au`wi&@S90B*`?bOA)syFIatXa;AUogrE~l4rm=O+HCte6%cPsX;CnwO&~sKq z%ew<9^EmC!cMuo0Am}0($5h_JboiBBSnH^4VMu-kWm7JP0Q$rZE*|2uJ2F zNq2)Zs0hfKVz-+w{S1UVEgU~^4M~KA*#9T#`>6K?JL6>EXjbwm%;Q`f;K78iA4eqC;E3=)vrj%avsLDaPPkyQZHX1ifIh&7hvn-u%c?9ECjdyQr!**GJw*y z<8^BRbVeFl#-`f3vu-#`L^EV=w6lIB4`-fppA;9QdOU;f5;!KE`ydfm5|g~ zC*LDZjtRlpe`dp^u0%*;vGh#WRPhxiT<;Sq8+Kx=X^Oyhi$S~MwY8ZPyFTmh86%*$ zqkEIMIEdswda>GY=acK0n(iYsU>9Wic~vn+@x|qw@GD4cC7V1#DOMq*ArPE@F*m<; zthfA3|C4`zcYi!eH#P77@2~tu{p;h<0j-nTQlv{~jQ`C2cn2KM-g?7nYXKd`2)Vu^ zo2oFOX@G^lW}Ys$y7#klkbA@|y``C`5eQPyZcyKaI5eUu>G-a~G%zlaZhFM#bBD#NZCnjY zyL1S)WN8~0{}6`UrNzEFwy70GgnUPgrx|zwX2BKPaxLq1**cr+_4$^{8x6(IAdNF>zgVjr*wKMZJ1QAJvC&;?y6G9opRb%yJQ z?z^|CMUQ4!nI`6I-nqw~-h8xw>))-N=c-*;CMYDhK1tj0XE~fSUYIiXxU%OsNCvvJ zV)A^Boo@miL7lcYIO=!n$lUQi zyD}-usF166oDVJ7tWCTK;LdtO*~R^hrdxORH`|U@vO|zJX+;*NBcT(nCq<`PI(w0S zi+J2heuX$Bw~agT-07=3Pe+}3>S+iZ6TL~8ysSt8cskd_9lOX?Vs`9TynTSuj#Hcwk!-?f1~w*UG+S9w zb{_#oy=)?KMfk9(WcYD%kSq#G(xOlS3YXI8u!J(55>Bs0cE^IaE&1Exu|#0Ad4TiM zb{V#q8Xbon58K>#kfPREWBp>jtuP=Vuhk{>nFYZasO4BNJfn@-(S zc6s*Px%bi)GY|o}gopbZ%Q_)5SS6T!f*_T>T>+}-+s^l!v*nX**@G6rUwj~d;PwVU zQp&Gf-~65?rt^K3_bLxJ3KbpJyp#k$+;wt?M6tO$cbBb}ot$HC9Sr4@twkC7 z;~MgF+WZwx&OUb&3NRz3G}`E3+&cphso-&FwpFnh_U2Up4Q}yW&4BMh4u`z-3+CQ^ zt=%aAnLr7-h5vAin~qGj%R1v=mti}zb9c0cU0j<$btAxF+nOQ+0;RUeBtLj@#Zv@# zWCsMx?zx>UA*e!_5|;4AdgJJ-bJF7P6=}xLcuquXfmAnk)n1O_X){r0w$CA;M(N^3 zHYCV#L;Fh9@{w@JlTTtNM(ZCN%R(nC2S*jXKJ2*>M>)YOn})9JHZl%lBy2y#`UqjZ`Jpi5Bha|Rn1mBGAi2zI+{KC{t1#XLis*ua>*7t3@2ZUd3 zr5YO98=0`*j_)(XTOKTWpo-~vT+3NlBN<<{QuDaWlnlQE>5d=jR@XCju1F+56^Pvi zQgy*&0D5`xRS(zcOT3W1gEeCR$f@foZNyLJ!9D7|ueY?`<=t@j@GGCK|BUUg7WaRf zq}RP0%C;7_<11FUG<#02PNw-EJk$_ocE8(p_`N2uwP+A7%Hs=4Mf^7+YqzdH{wIl7 zk$IS5O;0{r*C7Gbljb<)1CiC*vgv65x1FEY_etSQY<9%sopN3dXtXjbn{Q6`$CcRw zd{5?&?)L0sVkQ}Hr0(ulDteEgV@sfFsQvdJSiiepKmHc|I=+&gq(=Du_@w3VgQ5>3 z-}G-iN+cvqI`uNy1V%;VRB%@p-T&L4dHv+~!`J`5#UER2Y>(gdq&>HHmI+PM+c$po z-@o6F{`;}1Kz|xd! z=yZn`3z#)Jk?RfA+Kzm04aClnC3nd<5ei<9B8MSkx=#<9QUxrACOPUD8XtOiKGUqOm`c z%JNA|m`O|8O#?;JNzrjpx6+~&($mY+GrQBXXVO2MmC~Xo{IO40)l88&p7CQby|O!_ zdM4xgZpKmawSw}5sIoL#OlDJgW=nTwZg6^}FmQV$llxDqRwp?yI7=lx>uytKZ+8~& zdZvLeY(Ou2h?M;_CVR9z`+0gcp+oA$ZuYoH&SZJ^E4`daMaXn{&in41K~m1#ZVpo< zcS$jKK`(c8CWk*Fce6Y9%S`UK-P|paydAx~pL%&KBv#&TdES0^-gHdf!EPQPnh({_ z|EVXnVV%v|&E`0f&pmr6Hifc@=5TG~Ki4bRXV3n-mL=9xfSoOn+@pwyUX;==lyxnX zk1bpfF5D+)r~%1}dxZqiA`Sf_r(1=$6p|~fiwt^-jAn~WHf(gxI~>z5ws0-Bj4jUR zD_%-1J~dlxyH{+dSy3Uq(?Ui^p7nGzIDT|f{#+C+Gl%}U& z^FJRKvR4`*T6U=?#XUBmkRA7)A1+8JOPDQ7+ADK+E*rTe_5O`;&qNkjQJ&dTp6zPz zAGyf?S)qB8ag=G8+jx0-MMY&#Me&kUEPJXctJ#>F06EMd>^-e$s;F$~sU%33s|_0b zv<#)VK+~U9K8UUAepY#>M?+2>u%|`G|B3p8MnDv}xOemvimIOXRF5@RvV1aXUHRyu z)dNcW33Qa%GB5c}_1tWY7$$3BqxgDH)h8D|jjlL^-9=5R{-3RDIEc!k=#AlsTf)Qkh0kR>7>1$wACI5{>2+Ak%#Rd zHBvqjQbgeR7SA(LjJ!X_-QRcy!p33~PLO&|H40#$OjBsL6Yl-Z zg%LmPh@f^m4*59W2QjAuI5FBxB_VsmB$0Xz`;_imjv6g#H-n>ZG;1tht=H-0>!{;0 zFM_9!D<}_PxVYggN?8g{L7nXcHCLsUY^7ssj_

q?Q9_mhye$mZcc_Is^qhy7hUTE*!$!#NMS|a)l`CzV%HMv)IR@2!zCql zOwZjqBRyee9NON-7rD*4kbCQrp!8LCbi((}b^+&Fucy8t@9Kux1Uh0OC6#4&lreyv z*6|;8u7T+XkO~idKD~XkU=|;QWWzZw{ReHM;$m|46N2i`#s#pSFc;%>5WD4LRZn)t z`J%3DiN2o@eiI4%2)MNQKsV)%OgKRO;A{&{)@vX_wSy~y20V_0W{g|WB7t+4pi}|N z97r3^=O#Ov{ihv*7)2lr$HG(m4c~H$(<~%3xpuciI)AWxdK*9V=E*R)9Z?nEUZ`Xk ziDskSZl?fdweG4Nfyo468+(paA@*n_S8qU2%maS8xX@xIXJ{&r7#PR_obK4-ye1S( z;o>Tx2Yaxr!`uXQQVMuZLy>Ndr~#s*`INCwD})!UDDRe56pl^+?~%-o!R%m6 zx*jkjutlj8Dc~xt#YLm7D##qawzzU=sD1pP)|`TY_sy&b7dGOB*+3Lb;GqR~9E+U^ zbp1ecM<^4e1uWE!EeXJTgPz3Fz-9+Q7Y5su=AF|RA-`I;$CrdU#-U*hAscC-NcGgm z4B@0mfUGVuQrq`pQ6%4#N2&wbJ3i1Cs7{j>W3v|%2gUwrOWrZ%?5vfviWiss8_@>2 zpVSGIj*C5&KEmc>`;rD3!vI;{JQt%y;pQeLnu=D2QAmcRsGZfK=_m^1NW-GuL(ZK^ zmvSh-u_BHU{!mrEg_5A*%zof71JZ&}gp3^~jZ+@GBt6^6qw2tW!CW0i!!L~E#VWN0 zlL5nN$MhD%*ISSZd0C4~vep#H$w}EWP`tw=%F_;rEmDJZz})y*>?S+>esu%Fwd`-l zVLcu4#z5C*fv6He!Fc?{FAIgWanw(cErnD4GxM4P@%8b8apy9nDk$dUDfUsQa)&oW zcl%^DAxh8%cKLzfDQOi?hM-GC&+xaXS{nq{;+(9G_cu6?}fk8`FHJ`i79F#y;wk()X)LHOc zoF+=jZfYXUUh;?P$sEW?v0NUDzeOC3W?AT9&Y_qMw1 zryE0++Zd3`hUsw)PUB5Yw(|AT`FYRMEQ;Tt%FOi(qEKeV;}AMm{E$8qHa|18X}TL5_UhF|hAr%*m&N@j9M^NvBj(Tg_|0qUp6>p71QjhlAn+-Hm@ zs!^{6k1tc3(D&YS`5^jVLcjALTf5}VR*PTCKX!EB7;D+K()`HKe1x4b=K_=GH<1U& zT&Oa&B}JLM)-ZLef3x)iXU6mT*BjGYI22Ccut@DKKNYX&cqB*X$tRU}$}4;uQRc^6 z&5zK{KR_%V8)IM*O*M;vX{ALs210#5R%!~cE?IbyhH8U{9ZfEU<{4QAXi3WFTTT|D z<(QTcTAw~b*bK1-@fL_QIy0%5u!6Hrz6aFv_-8nxwuwABQ>gp~5o;XGdJAUoKfc~G zs)?v=7oLOwAwcN87<%t5NHO#dp?9SB-kTbF?;uT-UPO>y1QAdWkt#(*K$>) z=Q(GcbN;;FUMrbv?b-KCW+yAj%v@zg%P$imFX}RXs>Rv|&Teu38_zn*vS-Gl--rUB zfHj2%e`B`O{dt=HcY6olX%lLWYTQP@cR{ zlds2@He8NF8^Nr;@%pQ+bp~W?po*O#Lx{MJ9t$wjF!2}QR&rCbY^xO$uP zr#*vXQl(^#nT!kh-H?XWY$oF!i8z#ry41Vi)NR!=_Ks82Zfl>*7E|y{r`m|A%uKy~ zh##>}c~_(v%~a#KdgqVOYPyQ(=kr7lkD(9N?*07l7NdIU`#^5EQJ+>|Q`HAr%_3g9Xen>u{@6Mlxxp zWi|(z=*{oGcerw%?xy{y@uLKb*1zYI^y8tJoUi3i;^jk{o~G8YQq**-P`C`gWMHcl zxL)F{fL@`T5rF*DjdQAoa?> z9#I7#pq8JlsW*jqA&R!Q@b^V9_eeshJFQ8N)whH!b+R1phJw&zb06}9Di6TnrJV#R z$ZVogX4+Z`9z7ZXB^N`1lnxJM=N7#|Ag${kLL3@gm~!9C#m>ZB}r0?grMYmmV_x%tAUv& z!9N04n;ZYlk&HVUPi<}kcY56VXix6~&rFHz*!Na!euw^;eAb@sD-jI<5)_h%6}Od? zv(?qz#HO~tQ;3ozjtC9EMeQNTvTye zDg{T8oNbyM2Jw7J&XP#?65?#hPh)g=n6_HQT!syVt8j8)AO0K2h0f=4e^F(LlNiTd zW$`mESUCYNXG*daMmdhH?@0KTM zUJ^)qw@<6f`E-7E?K|!~_!Z*)>ecIIpT3h(IltFGccPrzV(`tE1_*ij{oj&l$e&gJ z`yu(GhdN0<@B>d>f8a+yrzxT^|#M% zb+1Fe3b>hVuKdg_`$qqeP%(TXiDv*CzLh2O5WHO|vWCBt61H};_pEN<*TJ_o#i--% z-GQi+H-z`1&))OAiN2WDxcB# z1_h=S#r%`72h;SR2&89XK3M)#9he-5qA|Rd>X_)pFV! z@G{!9J6?$$$5#H=LYH-s0r(0ORF>kEoCjEHn~-oxzir=5QX4^8^&j zD$(a{lGtb>)hG#!VtrK^zUfB*8v0*JIx*%8A|E}SJipG&aInXW+03y$d~oZQ?^$_`!NB+`;pp)wB;rQ;myQ_m!j zqH`9JqBhly9| zcDk;3x(nd9FAV&_M?z*s6kg;&RO_8|yp#aT6iSR@JSTuOoMncWr$vs@;t8UX<>Omp zcIO9~14su!&a>(F(%&+jmn)Ojvy&BYyHKD5)N74Uu&A*uI-6H9(tAU;Iq)+hNt`kIjz99P;ccAyQtr~+o@;jkhykncv8h%P(Jr(`}yE@mkR5OXzDu#+5FLzSM`mFE+M_0pX(whuZ@?2ER z;HuRh{WX<@k6Hj!HjZa%pP&wi5_@O zXe30Z*;^bMad*0&q=^6LDDTJv4N5^%GNij8SA0sVFNZS5WRA-97DDayaagYNnC!3{}C_BP>OE+Fb~46#V^C=YQqzCApY@$hp0(x{`0-3&NofF}JHJH-H}g7vL_rj? zu0$wh3sE31+XU(Xx^COh^Q1%!jS0A&Ukl)}@6Yw{>LF+r1$R>ceik?(`9pHbJ9Yt% ziaqQQZef%g6&lZT*Gv;{9Z%3IJ64;V9XR+l#6?N5^_oSQS<3=sTcn_t+zVhjpzU3O z_KBo39bo@nG9>hKJH+F(w{4Rgi2(}i@mty}$4j~UBBK6zP>MiM252ze^9ER&6i$>Y;${A1NIu@tD*$M!(0 z1XSAzU>{42ASa9*j0M~q@$E6R$b?{W!l;&pN+jXlUE&uQ=v|W6HASS5dQdQ$F6368 zmOLRo53d}T4UkOewHFH}mrBAU^SuDS*uyye78$UJ58DIT+z@*1#ROsSs&0tLTN7E) zgBjWQ=JH9QY{^3osbx(cc$GXb)H--^oi5GMB>NY&BgW z(uV}(OSQYPT;(yHRk;8P00Xfk+Y(5Nm^)|;2o;|i&zH!lFc-x`ZmHI__dI+I5@<1@ zo1DZ~&X*6P=R@-O#Wg@m9z|E-t6PXC(1SZipK2fb>S}8o21Ob|au6sl<2=Ibe;*tCZ z>lVCEdHOm%=m~(jnY1cy zvXgsStIPEdNdQ`2onQSpZ{3eS{!E>&h}*WrokIxuH4Q*Z?>){wJlc^%Bq1km0jT0saMsNz$rMbwX`cXMCE#)jTHr!g)i zgl8v?{8lCL7j{LHAOJ9nD4~QJ3G0o5Yk7iwUWR2dp~LS9IXwmd8gGigK-pEmKJGw0Hz8tJO-{~Fkhf@DQ`Y=!{6Yt7EfDsBrh5)x zjP4LJ99wPcYNIASh&C0KnC2@th1-uM+XMKehD*!hudD?wCbWbDv?t@yyD2mDpLj&( z`9nrXJKxUW?9-w#EnPk2A!qe6mXMI_B-g#f#j%(W`((z~P@kUkO5TsGUk%}_&9czm z0uH1t-b>wv^kCVS06iq_loyYFxchVdy6-POxe>O3?(_jKvYw&&uubGX!HSF@*d*F@YFMb_+t9;KJ@n3`2c_ zM%CaxuU5k+137v?r#ulCiuqXrLdEj-_+5Q1V8qxt3kD!zGhi?R|LE=ze)h`f;fJ86 zaw1agQ2Z7pbkgSV%ycO zu9MS!KB-L{$+akGf_?IU^=i&KEd3@mlfE|~oF~uvRrnB5*?P)@4g*s)7|0@(nl_n6 z5t@f4NQBy?kXyJ75;#E8B5^LN2;#h@jX*A@xg3^no#GFc*1AMV5ZRy+B*}XW$%pLJ z_vEAH}%|z&_ zGv3#X`S6_Kr4EruI0K7GD6dLu^~(NwgtWU;>TVpZc*Mr)novF+3XI=FmP`O9Lhq%G z?xp({#QHu?RR63*1W6MwjJbUt$mf!wzMpUA(QnCMW>xZth&M(nK6>y~p51=w=>C(P zk^+!Bi#RpoSW$9#%)3+iGUROA#Dn_8vKm_EhOUFg(SxrQ2hXPt zny(LD?mTJYW^ds>Y?D634pSVqn;mw#9(G!mDE@L4@;vOVJ$&`Fq@(MwfAR1&mZ5)d ze`(`zkoIUun4v$rJdyqAo!QaIHNt?AXEgC>?D3H=0hQ@^g|+O?hsC4Gu0zojubK!1 z0l0jo>*?&%J9FH}f0T~rU5^(-k3T0KFFii~QhQ7g81uW~cm@7+Ve$BQ<9Ln0w-D=d znS3Z)ALbQ4E97M1$&5JcuMsC$6CZ`)((|wSePH5ap2J#Qko6rsLcxshmD?&(Zk zg(DmNkn(@97Aco2h)+%cL6N{$S*<6Nc+mL^?0V43=_4UPuAXoN|84hS zlPlKqI_SvbXK)RAeN4Qx5+qW3JyiZyLZ@BIIzy()pzei4i4%-GsF{sBR&k5GNH4}3 zA<2A0kmsUARa8AKV5C*mF*gHMd<)iZlvK4KOMAhKwn#M1fSc0LqSzRVq*FE{u56tg}np4nIuyXzU^hm03QL_QsP5cq@1+ z*X?T3J?y`Zg`9{fpfWs|uANzoX}9lY}P)m-~8 z4l6I$J#&UClfrljya3Rf4yYUAXBb6B)1jLtUb6T8atx8Z=wPP*$HiH%E;bZ4)o}lS zXpVf4vK=1;C~OV7;r@`Bz?+NI44$?SgXlH23H=y)b5vg~c)hO~9C~s$?EGl|f@h{& zIf-&|f0Or9wRWMn&vL#xNu7Qgc%e?D-t@T@=?`A>6T3c6p~In}-aOC@2s0W&kFi&4 zzKe%3L9{p((gBZ4gm^{cz+iCODK)))OJZ--Pfx7X>8uKdd0QXB>tD}EU>oM&h8e~y zqyynmyX21?X@clzLf1=F903yiq!+dphYqNWAXD#ms-h?})^_WlwaU<;Pp{?p0$rR< zPd-ro)gFWA!d+GO25&P%Y z&x@0jfA=tQxI1s;;62q89stNTh82>>qDTwrDFCj<8+9T;b$1O3vVTW z?-Y$=XBNTQGV{V;@#mYgj^7n%(&{Y4T}EAy0R$GJv6v^0KToAl6dLp$u^ecW7%me+ zcX_C_XOIG*SWcEOP_PgjHwT1f*fWvWD*=N_y|xsX9PsHGi8HeUVhzcey@)DC$U!x_aWWQ<*@++5@Qi1aQV^QOv`mYt%i59%U zF3glZc!F%Fvkm}6vpzOOuE;%`P38BjmVLfF61daY($Wd&9`;Lr-Ms?omwbO5Gy>pF z^u3j7T5f^U0xM^bWFlxwCpHwi?D~5SyH`|~ zEJ=?M_K=!kl@43IsLk$HlE%!1sWXMVGbD_^b6KcV!Xml^!s}5?V4v?708UB?!%ave znQNk(Cgt#Hnz|2uQ8ix@Rc78Ro;S*pNv)B6`V!PZDOhu_$tCiRd*yfnSTH&c9~_ks zjU&ze>9XwIG0DjTV&5^L?u-V+0*H0-g0B;R83w|5q^wKeh&$;=gCN`MO#XXMBH$Ex zUu+N#$zSwzRo}vf>+94G#vrojBBDrL2fx(Yak*;$O#9WhcZ@8O9D53=zNOchj{asN zkK=vEM%kLIF3(Omod7Xgk*ya!&R8~MKixa&Pe81Jbd>`J`>W- zHwa`Clo$wx5Q@>`u~SSJC@QLoZCXPQprHqqa<|X zk5QR$f??qn@ue0ZuK%!TKlZ)_d)g1Jgl_ z!aEz>@19UYQR^}A+;@1K{U(Ha_5?x)vl_v&X{>Sz+~_#|`3lO;dUXZQEL9GO1v$no zhPOmNUmXdum?V5qZUrpyN`g9|xMmTlzT5w>|13gq&x2H%Nz3AxOL# zHH9NIV7B6Pm!y7*`3Wjb)&zLV_%sf_G;40tzXd_teldt?+@xvm84-Rcmj1haUi;>S zuly_{8zl-*8N_)?_>;$TLe!+5e^kcDl*~gR7_yu(RkSVz2ylp(3Uya$aR-6DPZ70~ zV~t|ibA7bwICm4_SNEZ!9(YG6P^{p@Jt=pKuDW z!G$Io^zGMD1*&Dt0L4R_bnkvf>}Dv6I}Az$j@JCjKO6)fZQrh?D=!)735pdSHYx82H7b zt_)ZOpC5qyrCt&+NE_Dj7e%#cP@FH_CsPv2i9)`GkTWDGjFv)zeQU`M?Gv?=Nuklz z^o!R6G6NS)Cl7XYp^A8^r2GM+s^y&o;3RyubZ*J2*4Z?+Q#?VqFofU<4SOQeDV01h zr5=Bf+|?$5jG#PLd(e@lU_HL`w#gB8C@>ru!i7cPV-8Xz-?DR6yuX*f0nhp)BK~#D zuYWdSHOl?7)>>s!>}ouqs{4*X3w>*VwV`rCsRWmse&oNe?@^qk%tBp!GPzqpGI4X# zNx%>vUS>!#KyFWQR!^u~kH8co{&N3mmRfUJrM^a#M=GBEj%Eh%7=W15d)Y${o?=-M zNGFU`J-%v~5L}r2d!7%|pkU7+jzp`XtMHuUU%BwF*}Q?v+ItTku2BB+!mIJV9#8q6 zk{dXmH}FM{uM208msqKB1#FP_nU zCBx@Q^>-#-2aE21Q+l`NPj8RDR1#0e~XlGP+Q!;wp~|1DPc%ZY^t#$ zszYFiI-9(0H%f_sy5NGM9M+5=?kXo9e|Gq~oCN-U7PLz8>;1$?Tyz;L1a6K$HvSM% z{t$|Z(49SG$T(Xqrxa$RlCGdqbcm`(Pz$qxfp64y6$Y2(#uLlN02})CAQ^fv7BWbJ zh=Dk;G1gWvHnTBxRWJ>(F^?9}hOz~KOoLZdq)2Aiw%=DR!Z22(PyN+ANL0BFC*_dWY9@LzI<6oV!X~m_tIE zgPqoi>~58$K8KW9m6RQa^cs_-vb}U@mCQp9WMUOEbE|B<@A~-{IxjMU8~i7IW^d#bgLaOy2q z>#=X@if;%nfA!bGK2sjW(Z*}ga4tjI8bektBUY~S9+Z)Ejj z$tw)Rp36udFtp+_Ppq-XzbRkCfT)~&D>sHwO)5CTo*UIrnr3;Ykk&S2S!|tZ?++uwSHJ` ze}X!HS_;o`Z5`=pf9|?KVV)rA-LoUt3uYdpC$$&Ix)3{_P}jOpu$qJx53eszcw$|6 zW}T089xv9DJEFEOvY999v2$2#byG)O^c2s7#X80FT3`0M2S0coUDrL*c6umHMTrlx z|5F#k${WkQmx|9T!9oF=P=3uhK7lR)pg5IuA#G;LRpz$cB3WMfDG#Yk*KO z_;!eE7er>;d%yT+j_K4nW(@^)e6frkO&#xZ#Xa(NH14#hwDiB#e4^p*$X8O^Q1Yqv zu{v24z-lnKA8j#SRKjw$zg)7@5c+igk!Hoy1E9%;Gy4F5XXMBoIlk=G<>qf+U540K9;Y(*r_5EUVa__WR#HZ%8Jx*DDOJH{RO3L@m$pbL;#bg6i?{;!g`o*d(xH(O&up*+SRc;>)#&l0JHfJ*=l=4V z_k4;x-LD(J(;#U}Su_H)U}VebD6woTQ=Uzu9u?ynKC5w3oFMiVl_Qe(?LBJ0(jl>( zpYc#dZyf>R^kJ=Ph$4f^ zY(RCESazKJ1gO{fg+wr3cdth47x-S&VW`Dg<@#G@)#1DJjXh>fl$0p;Q-jRyB^W)} zEP`KP!0r_*#6)Uk8vQkh6!kfsL%CouPX9x7$TxlZ4-L(0czo7FtOAE@Y+aSCRXxXo z&U1)_w_K#p#sRf)-9~-t(KYzDfdTs9spof_-#6{3ejj+xHlq?aLnoa4E#ip*2!WCx zih*s%vJ?@O*g)>%zNmSv>g*p6^EN8Y8?&6ogz=(amvi_XfQ)9*Q(aIUgT_|^gk8i3 z@b)0i78Z7-Y>9{k3^Qx;M>Nnwfs!gX!An79lB~BnVg_$@Y&eVpc!jNarxGln=8Xwm z8j3r}w|tiu(BjKw)%0h49fma25BC9MO5&NdxO%|DYye=Q`HvF%p+PyuANqk}49GWK zKo2wd6f>x0Sl#%sZ=b-SPxzla+0@=b@PhhVD0884;kP)4z(d^CZ?7iGJLNB)d#FT_ zdOiH2G80G;^;$)&=L3KMV`NoUidaos>#g?|KMK8*X;4*lE>ycAJ$}(5^X_d!uu7CA zTkJyo4Ex~t;ycpDczD+5q_r}Wd0ykn-BRHf`Zm5%!QPIoy_9bqP{N~l^1b; zqsReU=%8(~RyB0+J_*KtWe6xz^Nm(hSULhP5db!VAck!059Sm%O`Iq;*MmNdSRNo= z9~N;2K<@|$zo>(PVNk=-zn7lq6>#-R+^hNkqGf>t!alF+ms zsHt8?`V6$6dl0@ic9%Q*j4@?UT!nx$HSdoPp4D)^s+9(0_^!S7MzmH@dJ2mm3Q_-7 zb7Hup<3lMf=BA@ejs*ROhAJmHahUT%CEqwZN(-;n|M7bJ8N0|IX5wO#!F%Q);PeaO zpW@Q|<$6Ko8~JD3`Xlrzc@IcXb$_)7w$V^pEU0~^kcv00wa7q2^<#&L&fR2{E>X;% z7oR(mKmKMT7-EFPfZ&AmlTJ?gfM~}DXQClGiskL zjuspq!#P*m=-v&1y~p^G6{)BnWxju+@`2vV98C-6jlFkyE<$+yN6HX!6pxoY*=JWE z;Wo=(P0Ew3PWJ_1k$SQ~4_dszESA&EMQ7YellW3UY`HKwoWWs(e4+e12cRD0ZpvJP zQgwIG_9Z87P&YuBA$TjTzi~f|#+lzQ^62r~bKNI&e5qzgPctZ|^{4d$ zbHMii_Rh~Qsv#rehQ9iV#o-ggM!&v zC%38%6687IS{*FWyOM*= z8E>i4aN!5pr0FWfPp=|X3t=^A`3`cp(5S+@8Ip{B(%E4BqfYgkkYZR@`ZGKB7XXM0 z$heAMt}aLrz4|m}nnR(_pp{`!L&|0o%1~j**p!oCk&)Y|Oq>o)UzwFrq-*F&u{@$d z5K$^mWNJH9L`7#92Y$G~NR`GN(hkmuLNSIaFJWHwdnQYwWCFwg2x&rDFja*TKUh!PjI zR63v{Yoeh;%{&h@T2Ox@S^9T`!4BfzUq{I@3q?Y_Wyj(qq7$_pP`(`|db3iL6DWpd zYW;ocnQi60qc3v22kCEq53pg#O~4=|5OWjH=FF_xvoOEyXJ$FJjFsEqZO6yV0@(%D zWed~|{7cOJ6y)6iZ~t;+v5c}cg}klrNc`ei!TpMlCl7X5U{t``Fl_^Jy^R zDerf?UrI$`ku8J5H;h4gA9R21E3G(Sdc8wK@NhZbMbYNr8RiiiZB2*9(+lg&_3xr; zRH9?b9vs_0JT`xXKlrHkS-VOiLN7p$Ua0E#yEwI_cvB093GgG?AwGZlO}C}QeIQg- z|BoGHUV6BXRG{AtJ21KQ<_bcLOwQU65hrAj_((&?z%U=4oU3F5jqj3viOFx^U+_;R zgQD(mt_)8?$5W~_@0&}>$KQEP`FgM&b$`&M=Zjo_3cHX7>**_emUm^nsHX`8&oTy| z;g=wFheEJilE+#mYB>xOKA+SsEw$+1pOFE4{cnZ-POGTRUv$G8Re`yT`&ak>m8K(= z`{Z5_nO8H_VY(zy5OQR;J@DWcjN7Cqn=Mx9;9xb6H-|A1z$X`-rw5cqV;Knjsp-!h zW56IyO6r!Gs=>!Z=EBYh(OOIq-+f9527`(Lz54NF1!+>w9$^Xtj0kx!80xA|t3j^p zgT_%tLrX|E9@Mjt31O0G?Uzs6DO6``P5U1ESav^Kx>w|p6V5UwB zR+(IM`@ocIPLO{na)Phc;oF-SCOa`$WjiOtGQThO{4onifU_p+RGL&gP^v#frU)1p!=-X?j$1tLGoh30_BrO_sxDD5Vf#2mpoUJ-RWt2 z&U)}<*q7C>=K|gj#P8KUJ)ct1Qn+5B0u*oC8puGZi|so-Sak45d^$&q*%3O2bi+{w zj~9lcui&2Aya|DqA93N1*&rf@huIs|jGo1AtZs_X^+c<43j{`~e?z%~#rT~U#==U(BW>PulQJ9W##6HUFXpD?&L)fv67I(8v@0?g<<(+QKLzK} zeM>gHvr=?EsnfBJ%H;q7b;S;N1fp=MCz&)(T^j??kIlujaCRDz1b*sxL*vmhyI}6n z+1eZhf4;D2eM00ti#jjnoj}b;)Ww0EdkM4fOhVG2#9udt0b3@ua>LkKy~Sm()=9Ik zKE20_U;Q?=RcKH{LZ5B=ymNJOWNF<&baL7XGG7emtO{dk2U@GFB2H2lzCHTeL=3a? z6S`sL#W0m;YeuIigYsco>{Ybo^_llQMW!saGGu=&ZDlFJWsw2KG+(y!2tC;pNemyG zyPQvWSqfu3ns3#IHl=hy>9jD@oo6v{tG$X8;pM%m9Q~57pm4Ka*yVJ6{xAD6-p$Ld z4?+GLgfK@>5D|jEJnW$LgYeg*_E~-FUww+39*QNJZ8hiIw?B#4jR)ZSQYWv! z!EH{5h(uOS-%=RZoQ;Tt7W{a%wPT(gg54=)O}TWnxtNqaS-F^2BD1}mH4N=k8}q8& zxJ-KuFXedos2=6{$>Zhf_1A!D+n=iu8uCBr^)<>yGu=*BZ?~6mo`>jQMd+{{N zcO&W1+ONabX}jOYy(eqGO&iGmjo^7N|NMP1YjFSX)fc~Sf4fGqzTrPBdiV|d`)vCD zzrVL9&-5_@r^wsMWbU1dZy<^y6uxkF4C%z$n`#+UpKNw4O~*PGU#v)pbl4zv`0F~M z61_4-W_CQ+iZP*~1|C&&c7jmw2C)OZO6-y*hPRr6lpmqO@*_J*;c|nl*G**%l#{F` zxk-^z^lp%-)mPiZ^z6w^J+FRFs;R2uiYF4a?vs-yxVcF;M6Zrxm!`W&ZZXW#tBcg; zWcUPcF>TOm$WG;ChIDMPoE2#({K(0A;LMT6y{@4I&&^Jd+-9RF))Z|v#5s6wbFeXJ zY3b+Y7IbWLi4|+<`R3-O{3#=+W0w}l%+0Tn{LW{{K*z2AL%SjPyMP0Oj-^pfiX_^W z)q{4+VyHar!cpOfFVW&G|JS<@euMF&Y<7<=4KB;?wmiF)sU&UzgP9p&Z3%QUNchSC67m-nTTV5iV%Z z^I1t3{AEmsEO>6(d0=|MxnSd1&}e&gV2)q4U>;NO!bR%Pa)I59Zr#7qJ><}O1GY%_ zfVyEb{m}NT#JqA`uSx9F;e8O(QbD9-bga~o0|mAZeakQ(mlAU1#CE9P@bFSCr}M}~ z%v!Hukw(4v>c~y0@#BELXh)6Iu}2mC?CdX^&ZdxKuMi~1!eU0dV2O~2L#g%Z53@Ml zbpG^sS+g~GVb6%dx&fcH<(6<^@1)*0Poh1Wef`2$6V@(1wx+hnzJ-0A)-HiA3$|yO zh5ZAKUwv9rzMeN1zCPw+3ijKvyPYZ=K;hAcH>!X6^`r33-&J}*!3uQst8frsy5;%$ z$7MW`q9M|!#<6mT_Cy9n!!vO-54kKHNd1c5hR3u7$}u}qWQFsdsrXT8J#nPTTY9&o zwx8<2>;!v1Jp!b~qz624!h2L?diVM)Yxg5|iw0CYrbhcRyUx>@OQg4Vqp|f~F|!Nb zu5>gH>t=rIlkcBWPd?BsoEHu;Tb?;AeRPn%CM;x8v}fm6i@5fQk=5>v@YE^9e*HwSrK6+F)B_mn-SWfYur7hVNmjkLoKjItZYAVSmt@j z^<~}92oH2t$$akWi>Eqeo~BX8jqA2ojSdQWhVM%jJAZtC;Zx>iTSxi1@A~Rx-IA9* zS?LmrIeU{Al)tV!#=ook|;B|GXP@s-+E0w1(vxPdL8vCg`H-D zG%S2K^RIu3!5<%rx|%N^F;xY`bg6}H)lMQa5n$4NIQ^ixZuSb?X9B>faVDNWex%SsW zYcrkO08_r@&tIQ6+JalM%8tN8?2|oDx7%Kp9h;=teg4WC)>fy`5ZL|u^Tm_(z7v*1 z$KBuG0)B)Il3~9yxp8e!{0marH6NVO{j-I4|ND*7({r(xvs2&ABPJVdPD_9G56S(D zm_7V$8ccV)XZY{5N?Yox$uE4*_D+;9cFz55V!P)kK*X=a;o+0sp9+0G-oMuVJ-ylL z3OJUqiT*ylcJMLmVaJKh-mbx$rItGEm6nghwgKz!)o)TjLs|4m*0aT*-xV}JJj0rP z>wb0+_UL)jzlXPTve=96dnJdD9{qhJ`|tP9H~ECTf9#I_L0hJNy#y#u-@`>g4Cqm4 z<63Alh>Lt;d-u;LAFx>V2U<})S@c`!7Cfbyp=h07$}JFd@=yW|KC;ftcRqi=)E_|@;4^L}^ z?VrNQKEluZ$^L1R-JX(d9ZZ3F;or&0NzdA~$p{k+j^V8oVjsy^#3*}Vlw7Tp4g5r6 z6h8z5sPGyqd0~}|B0yR;m6jMen>&SVd^@xi$0m9iN*1`spJo+6`z@8y77}GQnQ)esF zn-r$kV$4k`PkTgRBWKJkFy`3+mMjnG+ccI9!*Ux44NF~Dt^n&9MY#nRwE+3d0qMfI z7~+_ZhD{eiYV>se3_%l^k7aFXr9Ef+*Z?*lW9Q2)U&(+7h;z6c6S?^gN}hA%>=PIg zu3i#z>WLS3WwU-i;LGYIO3}jU%G+yn4F*1iVI{w)tf(^b({-iOp*)*3OeZsemEDj zP^*ZdoO+hqtd`C328Bv6G3e-cf)K&mBiWKhW#Q*FL* z6_I!;TSFCW7j(CY$~j&G@POV`I=cH>B0&E+bKj}lhdKY}?eeqjHd7L~b3p6Gc7=@# zt2GJ5{R{LjF&V>V#VcbEE0Wjoe)m9<9+(TRG9eVHi93nk4Ln$BgIhi(Rf#SCyRw8b z-{qTd-2{F~6**VFVm%cF6Q`XE6}5a3?JPNS4^>0SU2aJ=OX?wYof#`h^_Zz(q{Ka! zOLgL!%Z{KKPb!TEl8t7U8VQ$r%E6i$9f;IR%>qfSf_Y63=yA_Wtr}`IXrAlMSr~he zcBdq=C|Ji28$3}tuQMX~A~slevg7`bW9{2>-7k_Ni_g``o@;y!)<4{=4GkXKlQh_8 zm-{;_aCK>5>da|MsDDO{CJhmKo{pBgKr<9P8}Be=>(pVpLUDx{;dK}Zh1?U9GCmA4 zmX%WUcp*T1Wh~T*^vg2g2$6_@o9dXF7Ur2=&Fg=sHX|*F?3q%X%rOIn+%YsX)G##< zyE2Sf&{e=CqqkdRgxt-MvMddY@2||g-_8yH6kFK1gq)FtG zoy#t54X;%?r<={LH69&&u%mVTJBjZ`tI>MpiYMU~(k0@dLlV`crg!ZeXXfto-I2J} zT}@KoK-+=0b<#R^McNOXv*XH-vjECp&e39Ru)a3b2s39qxiPz!? zt-05XujfxfUoD^2S)+ z+7~NtE8`~=7V1Og@AH$bk@8hwVW_3rN#swtV%`9J>F^5EWZK#A*Aj9g1`#zE`f^4N zWk18^!Xg{YgG)b0X3c%b4h`)5DIM@L>dWl4jahUZ%`sBQdteAp-U=t_p^w);`z*&`5=5kDML+KM4XGEg96(gI=_kn}7!F<}Aj?dGv! z60t%>v|`9O>wq}f9%_eH(_bcbG?#HKRDl>mLgoqzb~Z}J3Zihp#%DhM?6apGhJe6< zvc(~()q$zYAxT0BW>)Cq5$@KcPROmq6ds-uwv@!dmZ;N{j6dfYh@pL0l+sGil#bni zh8v_B6sg+{st03e+ip@@m*~rvzV|PQsEN}w_z;MKk{K!}nr~9mD(KlOh&VyXb3GG_ zOUWJtxK3hkBEph#B4>Mo)N-Oodo>6Hle-epa5(U$T=;~1gZjoIL!emL zt2Q;lA`gGBi?uf?56D+x5cYB<5AUJ>bu(=b$&9cdvgj@N(&kDYlO%zohgKJ|S?2Ls z7Ve7Q(8eS^s2Gj6WD*ChrZb4l>KC;R(TT5{))yE3MV5TaEsUVgaI(++?i%Ti$P7cm z%8N_0id`WashvuBBVRJCRmsP~lLC5+7J9urT+<&E(Vo&5eby$VA4}Kl}goaXte8vUmWf?0WZqI~@xF zpgRcw=)d?o1Ume8M|ikru&XNooYw&WsU-kV%>V$*8aH#eiNm%3tOu$-2}hvfNDU zNM?2xHUUO1c6x4Ub}m77A#rX2X>M^OpOhTGl&rXv{9S2TDIsAER(5R}q?xRgfdGe> z1gDwGT@NkUaC3zq4H0S zf{2KU3W{O*zTG{$`>=E7d0uADoVj=I{rxo!q_wRDv^@Crp9q>hlQFt~OYO0imcEXm zg`t_Pxs{`>osEs5PJp%UQx6O4d#-klZhEHP4lZ6+?oVAk{Ji~wd;>#+9)&;g^>T8u zHQGM8*geP8!jwVCla&7UJuM<48QbOy~{7aJE zM_$@Y=XuZ81s~P>eJFLJSB#^-lPheQq~M*3^ld`itF?Dex$B+a;F+cOB**kos<&s# z)3B&V_tS26lv_V)^m$UDZ69Ogac$&tZRvS!^YGdx?Aqwbb-?{=+wdXjC&TgHDQSwjH#RXTJvseVR!(l# zi?rrsY)VNwuKHChg-}>iXvTmX7w0 zp6<$;shrG(`t-4?+WC%#4?T6?8nMgc*>lS^bL$-oGY#i6?N_@sFY_l~ydFs}m`ko+ zjqX`btAEqgH(1%cUe&c;*Rt4Nl z+`@X|_}^D^KWbJk+BW~x&wi=@aNYHZ(EF2+b@Xp?YG!0~d}ecca%OpMeS3OsZE^W)Ugw;zjtw|7ogcRx*h`ZxLO zdj0Zx`RM1~{=vtON2g!Ee)@QL{qGCm^5egw>l4EDr(c&pew<$uzJDiN-yE0cf4?1{ z&VO3&o^2;30O(0sb#X<5QKWQ&4imWI;r|c6TaCw%x;620S52UH^kYa^MT_|NnCi%A z?C-*xbQwtUxuaBsF=>$+Me54yBbTYb#b^>cl~G+Ocf(?K`E{vH(@HQgXWHc6annbm zI&{AY`(>PK`!cV{}A_Q$bY1|Bev z)OO$3J{CNR--es~1n8Nna=ug~x~j0G&1ThSCdaWec)M)QqqE#KEI4Xui+8-1nPC#0 z`7B)Dasq1?t!&am49e?T{Do%4+bf{#{`;$MdiFm?@s$$B?NW-KJiry&-l5iWK+Jt+ z>o}Q;?HZeG;?N;~O-a*qa19{g-$4^GcQ+*O>O9Hyonb)_b ziM}Zn*N?=!fFk1712(uZ+XhGFy!0j%0S`++77WogAV&$rcovjY-Yo}2pHT6Nv`!ut zCJ z&*#&gvoWEsz0#N9G7vxi*;{C&*Kjg#iv&(f;uWw?Ou{0%$&g-uvUvvX&b#+U0_RX< znL@r>1q3JHo|+Aj3*jOYvK;{o`f}Aft`VSW#Dv7gjLQhaT=4K~I?k)68R>>wIq|~0 z)UBfun_ip@#N>Xv)6&`hq=JKuxnbH8YjDakQZe79L>g$7lkI{uDaDUBjy1?c83Lde zkJ#MK7~Q3wX#1R{JWxg}cSX-iT=Ds`sH=rg9!Ld`#?5fT zG$q%^;o8KI7j;g&ifq*v+Bn;7O837d>qJtWl>L|LEbMu&p!9on^xbDM$l#f~@EsA% zvI!?C6Hu)6VIo_>O{}^tu^1MoJHpBQkjvI)?3dm8z_jxa^>lWOX=f3cUMMF^Z9HBt z+LBVB49}a=xgc(Zp%8a5ysh6AOTvJS=cge?ui`hvuTm3R{2LRxC&uV9Lou(Om&OMugc`%mJfu`LO{Gno(56Qe5xZrB>0&JajQY0|>>c)> zIpFs=<4n?hoj{QSx3Xn;Qz6Vwq{?gAM9i(?>;+!KWd7S_{I#9&AGFZ?{8vOXiL2zo zDOl_yhgf0ZBG!UnSK6m0oSw#uY!m)m^!ex^A{BtFlg}b>!fkXTyd-j`&n)-BiMDi} zlY-u?3w)X&9P`qtcvRjPlm#axj}YD^HxhIrFC5flr>fT1rX_k%t?y1d6q#&mh_DF^ z=0Rx{CE2Q*CR#ojIoKY%w-%~iL$zvTUA|{Q$Aodun}-;wpi8$dDrG*eB%0=_ zgKzh8sJ9iHP|VK-7A}ma2%L@i!p`#^`)mac4apn8UdT?&j4A!I(Rpq`k<)TEB9WP> zMSA{{ABUX!dC@f*Hgv-LNBE8Y%c}av3qKnmxX+Gp*^ETzmOx0Svt}@Hq&e=RdYDn2 z3*)rS6UUnJ*iw8=XcSu0uauN5Kp$dfl96sf9f*_Dkd6&t;Vq)jVK_4zzfvPUxDanx z;wDVVq|N6#Sq=hOafUP>r8eGit82fEK_?2E=Q+Irkx`?dj9I497&$cg_D=F|hM&OM z3eAet*Vsp5uajrB(7---SJ_y^(kEmQ(0_)6zPo7h>*KnvR3axk%VjhJ|F@i>{p_do zPM{166mj@LwtSjNCb`mT-=^0oDy!CMB4ON36mcM6M6%P$iI>n@kCX`=9`ik6xV0u1 znU|=Zab=bQoiukL9@-jn;jsaBbdi0_=AJsek#TJn&7x=mas{_zY1gXM#HFz@lz&%; zPrjtMt5PHxD%>{l;2Pa%UT`w)m%CHA!7;C?tqW(48P$D?`m|LfJURdrv6yHFsR3y0?z{NuzF!Gq;0%F(Vp~OWR9lV-9 zbwrv(O5rt3W${1cW?YA8Sg()Uoh*;qD*jqlN^7q%P=WG z_CWBHWFmRlz?B;wakWeIKqrq>;5D7;STp*Yau?BNbZD^32^~o`DtcYSc=lJv>23|H z@MOFe!bRMVN2=6C-7~qfqsjLZzH9m|*6bJmZ#T@uImgxuhdc!aSyafd$1zRE(+BiJ zmKNwxx8wI|h}ffqntw;KT~iEs$wVY|+zGP9ixDqCp`<5yLe+U7@E<}b@$&gTVkX?n z#Q`(kNck@Ja>Y^p%kg3^;hgbXmIQ(3IPt{}oFEs|ZSqiP`9J!uCs}QRjmt68Nm4Hs zb#c@G++6vw_8>P#*As*MW9ihb07`LUA4ubV&Ul~0c+%}5A^aUNPBzJXNaW#kG=L=Z z3o|`jH@d~BoX4^llS*#&1x0+OHBrSAzdS;mA^D`yIqWYL9&j%;Sgl0RN|Xv1RTw;_CaaC1Pq1(9!%1Wy-!N3xgifL2$Q{>3Eor;N-Ya-&Nn@ zg@>l#aL796!wPM3K#-i;jcNRZ(!y|q7nTYq78(^_+aa%ofl}t7)O0t97hw1>;x!Qv z7|+e~n5_S?n3_xIA0AneDC8SZgnJ;%pLAwsCbY@A(ZHdv`LfLW@_yE{`-+Y_ve-)WGxuO zomTSD@AfTceij*!Q7PiXVji2SXGpL;98dfaN&W=Mu|KG7xAbBx6Vg@m(85B0;6Ud! zisY|2@Q-xLEUBM&I%GTEVxWwtHo%l$>Sb?xXkpwF0ia-Tt1**_Q9Bbh7ti5d!qeyS zZ~`k+GS7E6O2D&-@&}(@eE>N*DFNHLo?PrAmqjP&#%L>%lO!uZK4|JZ^wYiymGast zWeZ6xHc0&06lO;&%gQDE=8?SCWV-Z%iW@$CN?a<0U;i2fJxk}ZO>^ud5^5fzTiYQD z+_8k60kLO-X*g`r5LX_SLTd+@QbbvYBP$DJNN}R6Kl7WS@zj#!@NNql1jgGZz@$gH znrwtGfP%8ctRk+@tDT_byXY-RdG=QTPfNH&ITa31R`wm6dpl?ot0K^xc%$#ubuksU zKb<(EoLkM zH@y%;mc^4tCnd@y%p>I?SVa2ZXP%c9Fn-m@4omSCM~ORQ_Bbpjz74|eh?z_lQ#w5l zq${->Eg%T*aFx>(TI^Gr!2E`^iq0{TDUY9h;X)x~gnXr~Nz`sVGcRy&x001F_)+~l z)>Xo-Bi=BPE=Hf@&QAGDPXL=nLW)dYvqEiaB2C*Rb*BOiDgNn`REiP?8ma*3HC7D# z4L|_`l~~tKC5Gj6)^RS>b*9CDXf!7i>7&zL%VogkU(;+Q#?cH42Yi=rI;I&{hY9>C zH~O9s`5pH3QLdjeENG>k(zKz{hCfOgwsKs5{JNgjwD>>267)w~93k;!dQ=xI^fYEjv`{ryi%Wn8nmeXDj@t8OlnkTXtitJU~# zs|ib+nPQv87Q>2Jn@w(;T~C|CR@>dbZDE<#PKxbr_U(x@ty%Hy9zE@T(+w_L?ec@I z0g4^L_8pJIIzs<8`Y1jXYOS}oWlI#O7=(zf7< zTRzyZj#u^wSzMQF5jbzFOJb+1P_etrzPloBt9}dk0x(@IR6U z5v)U;N<-^r{oE%!Ype7tQ|hWDmP9SjM;*3Dfo8*Zds}Q~h87gZ zu4_kWfn&}mEk3r2d&glwR8;R& z-O2Fb)|7h^I`;*-R%g<<34D!!8W&T@p7mB?!IW4~B^EO4J2m}RqxeOycmQ-<5vl~3 zN_rtWVm~(K(5osny;9ddg(VyIC7Z(aR$amBfYS#Kv$ES`7fG`wxr~)qP)|5`3JIk^ z&UE)qJVim1wx?&O$;EfzPfW-@f#$mNKotR$l}^)}XwjiMiisHjzY}!2h(a7iMu06) zV#!u;6s5@NOccp53%CkLk%NFL%>z{M&uy+7DvsLgs%le+|}<}rkE$&z`xjlt?oF`0HRkM|83#fwudNh?kl(g zu_^)U%Q=~(z(Q1U;GZ+o^91`|i(!pIhqXV#YozN7kCH)wZ!nZQ)S_2!hJ_ZqA}Dzr zdtdxpI8dG|tXrlC09WQuQksl?PhOoW0x#6QJYGF&q3#l(%m5}{|H(9GY=vu03jy$~IHMF0=7yzrP4B6k7S^{X*}%DKtnaVEf1R+(<115d78{ z1C>DahCA{q25eFkK>+oXh$1jeK4W-2Sf+n^F&tcqeLpfyCd$4^DhCZc0jm)2sf(gj z&vq+C-fK628TR)1cK}lWFclWEiK8e8gXWl!WfVak2~P#HP3b95kMt~d{o8>#Lw6V+ z()Wq76dXS7KO}_TMd&&18xO9vo_v_XgS$@-#Mt-8d}n&+S4p$yKa9Vpz>P8$T51ly?AMQb4PSjo7=r)97*WB1+{Q@OUyvMQbxy zWPNFNCOdhV=M;ec0zee4pHgn*6um!tN2>zZ+U)r-M+ zbKfI;M=UI&L|69z){U6o_VEr%(r{7NpF7w`BYL_HN6eb3~0Br&;p9qh?8h}*<>=wNL z({TMqO?*_sZ!8l>F%tf#^FeR*%gYp+Ke+3^_&Y=W4?4T;%FKkxOzlz zznU)`pZI#UeDB}tososYf37z(uJ8Z7yZ-mA@!#I_5ph7%&U3<1A%RSZa8fwTQAarA zxK;;_y%D?4StVRF4pHI%{d#|WGl>c)M(v;?i7DANvrTr@V=38GqM1zhG!w~gIgDhR z?rW#8DL*5+Wp<#O#$!|fPXK9Y{a^g9|GSYK^F!kTYZ)@zGTW)(*H zDlyEKf@T?(^>;^KTYk1m7OZ?mY>=vE)9n7HKXRBOV0~R)q-QD?{~oI82w)fPpUpn=0TnkL`k1kdL@)m-c@p9 zF7_g+rmktIW`68dUgg|TK$$AN66YGCIOE^7cke&^E~FX_Ok@%d-VS}H@hA9rrT*S{ zf#VIo`?l}FOM>H7==TqA3Uvyf^`@L1za5C1Qx5-o@v~`(@1<(bv%mj-|An0OpB5~= z9QaH@fgJnNMP$%S^hF;u>2f8&$tG(uq`nK@&XGFRODXbeo~o;&(32Mu zTMRT18z7Q26d&hqF_fIslr)lFb89h@eIG4pEPq%=Xfam&I&wog{6GAzi3YWnl#Vc+ zd+UM>BQe}erz0a{UY{>>Y1}~kL#z26Rr+Nh2`i!vL&A!b{(t!0h&Btm2kx0bhma3# z*7u$h%h))_@vK@pCTYpoTE4VwxAhE)kg>D!&-}^h-Dt#M=~rGZW98dH%xL2=%+uiz zgjxBu_OQwEx5NM9cm3NOpT@Mw+B&LHN?4lp^!;{3gLylhqKcLOqwg9^-;3qAE9V%` z=dtdbC{_`&6MgHV=$*ZY6{Blv^1sf5)H|p22kyC+U3SmRx!c_{{;ThP&Ajl)5Bb>T zS@@jrzxdswbXBbFA#3K%;+N9@^1DVWp~qh7?f-}04fCyQWMg@M%k<1S!@PC!BiuCH zCSeYDSkZIp8`Q4&wQG8{=RxGQqd4e|9Vxv$0Gi`Jt$nwhFejgq_pyl+;8mbR6e|iMZM%z#S*@Ja*9YL;M-d z*N~Q>yY-?>gKsB=G4-@74G1~4FWwLQ##o$ZGP3HaNrXK4gDpwKNRSC1PA&Rb20QKI zkx$A^B2Wi11NY%4xCFwre<0z6g^ovxDmKL~3!XSr4{2<1_;(_=JH7h5#j4op%HQ9l%T+QCyKW3^+c{C1_ z5w>KzD zW9U+#|B8c&m({miMCb7xhv;w*R%HZVLd2|FYc2 zNrGu73Y<~wCvI^ zF(Jl#pz1^(yS}L=HVe*rlhDsKRT~5VtQAFFIx#|raGJ8*y-mk|wr17yC;Bu;`sM>o zNZ`OO(e3`vYy&jPcFr!*ES?k0f%x!sW@;laafr0ar`Fs&b2HYzjjl{i-IgcUYLYj- zS_(A?7S1J`DVb{YjsUsbaj zugMIQZVx=gmOo_qXk+F*NGnCECKfgR-i<1$%_=k7-GJtvwKF4#g0$BDB|S;k(5gii zJ#k!Il9Q>DvxPJ9sgo*>n9x%p*Z9>C=i}Vw$hMSNGw|nI= zdW68+mLim|Au zr^dw&d;uV4t^&Yb{6p*CFdv4!E9;p%INYluS|)@Qu}U@&YPJIrD0|wr0mrbT(UCV) z8$Q~@3i=C6#!s;MHj)V#BBxr{XRs)tom_5jcg96|kOz^8oz*5;axTGfMem2<2M{;A zFAP#WK*4n|Pg&UBBTwliPyp{DAW1V=7$?yWp->KD6P$ljD1n zzVvsCj+=)+H>76z66Wx7n(SRMS=)IP&N>gRg`%bblJK$tfl%&66nerwA}3l6QzEyajB(4Ol!u z**arfJ7az4qsj5TS~ii6HYB!qF`9W|{&iyaGgNPJkNbM;b36bdH|VDu!|a8IlMXu0 zli1pT#C1vh=cC;~YBUb9HlZNa-dHQNnt@~{+=hq`(4=)X=yNjyRafV`Kx<8qJf9%M zTJj4r>_*xY0W9U!{7uxT zbPSeGL!Pz4g9WGx04d{$3~)e;oHFM4@|r(@K-w6+B4BeVH^U_wX(MXpJ<<@V8A?km zkloa!-U!a6pFa&iY!Qp#lTDFMuYV z#{d9AIW;#=)sS3>n4u#X=Ns%tgbW>;Ri?Y^p&(Qhvfm~3W{rzO8Nf`w_x{Zo!dHnK zg)@{JIW5-u-K6D^2k^Jmi8JqWXkmlRYr_zHtxqFulro2V(54t}S3({j%6FV308=ql zc^)X}q{NHJ)=cdgbvTdWLE-e|blfzNW}%VfOh5zS${?1}XMQ6F%OEq0KECyKHKhs- zO-=C~B7=Cbc{5E@RODS3w4S=2#*1E^nOYbu$`B{6$2wxn-vGgj@A#ml=0|v7qaH!% z_bwf$--Qg;k(D5EB|x2X9XHK-6x6kb>`azOa%9m}yqCE_89hj|GiC$Nd@!O7Dbg8h zp6CgzssB-KCf+F;-f4)RuCD?5){V40jcm*)PYjn+uF|%1LBIDAUxDi7w@#QIMY{^u z#w|A)F6-4B@{-_dy5Lc3kt0YZVpIN@A{U@%9@=zalpyy<%U3hA0p7m!hatWe=@4GK zv2n8mn0`}9H1w&q#iecv8Q2&>tgF4@s-#W*NnX z@!=E2+R8@XI*ht1iDva0`WkAPD=M0vi3wzjO>-N6%-}&x2%otOT$auKS-u62=U|5s ze}WOS#TP1uWu{>zuY&RCO+b(2uqu1u@M7NiP6eUc@ZA7?g>cg3kiU zPNc6*40-mDWi|koN6eG~=IjH&O`-+k325aSL8bK8n=y*5oQQ~tX^JfoW9|??l3pGi zL*`VgRRpq}G`+d#p{|+AUbc!&%q`TAAX6PZlPtYlEWeYQqe(3PJkX=;wQ^z%GXN+$ zAIllDXo&`tFNzKh@$N~X7IWI1JpeSsOA`i;G-7nrdf4P}psa8zPtC zp>0VB<@yt#5yimPXK5u^T@Ne$wqd4eS^0AsU4{fj1Gx%5llnUn?TwoXE(SmYH;GhN zCHib2EWT%5pT5m)P(OY}Cwvqq0iwo@Jxn!vlNWv84}H^ew#RhR!+DLWfPv;KmJ2J} zGc|XZ=^3)E8MdR?O+8qldNipzjj3Q?r(+jJd>Bj1x>-)?y z+b&jhnYK#tBF^15A#c}jq0v2x5`ATI6i$KxBQwEd)DSN5D5?s z;!Y}8mnts$@moxcbSBUK*4+;_@4?ba+0kZN^pzr8we_nHMdrqgFiZ%2`xwBtDS5L9 z3=@;^VoPSj2@}Ej`y@V)!%oWFE)3A!X3vaNYPDR){(ZGuTho)rWnDLtw&GxRyRUuG zuA`*qZd-qPxwIM3e%&2YPb9uCm5Dm%u_$L==<6d#Zjj)k?w7uKTfdU$y6u;aft;=G zmx(@964h7FJQ}Ju?n56)_fEFVU1Yw${FyVVSKB%T{*9^rTTTS1AHW8nfjlN)wuI-1 zdB2G$mI)w;d)^!e6=qJ5-%3=lCvi84g^tbd73Zr}Mc&g~YI8+vRYgLIN~N?iHLE}g zwm>FF9(t1n%nC6dOoR3jfWao#JP0kiqYgV*BC!Fw#V@cDAfJs$SO;(b!jiU|Ll6G{0jClQXR1UWkrFqKBJ`feGER$i4%o0W$ z;Pf=GXx}{XtM4lbNow27{dvO`ttI<$LYw#CM7&{c_Bl;OHCCrJYg*4Ru&TQQ?t>33 zGrxS7qTh*LV&ZVygm^Lje()GH>|Vv>%go*QqXQ|d#7w_hsvKL024{q;LNI{K~LE?O9o zSizQ=_FW}hw6P6nh`(o_R;IHxGga|0Vc5_i%hfNI+kEow(O+(eoQ=a>ZTOLe&d2Ec zV;{W;eZvvUhG367u7DpAEB$XOOTy$<>u$gJSaHvCeca4k2|;X3`hhmU$2Zb5d~eL+ zlN@{k;|i__fqvqexOv?WyKKEBUpF+T@tIHKxk_^@sBxn~XrVmx=LO4YZS3^V*Wp!e z&o%Fv*VRw~KBDZD3y$qS4{r+hZ`=zWO`6wnwFjYaK$7`=`Z{MbVPJAwCSlj;tvS5C zrbci4ujg8>UKbrbyh!Cw%niTmpQr}ZKbq4B0{kl@a{Tii8$ZZ`G6B`cn!`|7rj}*r z+yj+UX$>+ETwuT{SEVP-w%W-LxAU1@%Gw!YiraC=nZqn1U2hTDcv-0YVU+*ZMlv7y zd>$PPbfwVcf%6J-8*jP;kg0zm&?A8dnk0hv0c`yM8eI~z^hRzX%)iH7T02Y1>U;bu z4cu@u(Gxc0D&V2S1JS-%_jwZkP7;8*hHvN2*I9K6uo}0F(%=4gk>#&$q5JD!bjWf) zX7W_@7-mX_M&?WQ&Y$a<&J$7W=vd~cl=*8uPSSK7bi_`-rLZAjT4}9p&Fs(0+-j_B zm{=W+WIW=AC7T+0AQ#$BX}IS!K-CFp^KZ3=IH9E2QNtrqEO~GJNKJ>r_PYdY5x^)1 z!ohKCbWAcbX)BUnuDkj!eb^Trk0$FHCAVUkqXkzbm=kcfHJTl@`d{$~&aw%q<@r70(G z|6^sY`Mn@z&)()oyoV1dvKtr2>@tG7kcdEYQ^2!edGnW#lIo((4+A$wE6gH=o#9}O zVEOZ(jz7QG`g|S9v=Y&eRkJ#*w^hh8zpt;}8f}^_&rK+_UtI>V-2<5kpWDW^MmeIJ zmNLKW1=A=xm?cc<9}x-c1oxF?J$(5)NRi&;tDhG`mmw)=tiDY24kPB~bk9r;7h(p3 zhV?_tqCe~Z3e~hGTl(AAZ~|bcb8E{gx8&B_JUPKG(fex#e^Y2H%@=i{z2FzSbMJk3 zY=d)i#uJC}CpP2zJmWvvE5A8P8y`s8nQLf{FX@;sjETwmdA|PA2>FY9z`zm8VtG4^ zBbz=Qh52BW&jcfDSKZ0f&#wt(B_&DV)5oM-0A80!+5*3Q9*ZTlE94`TI?EuD$IH>tIf(nHcolPwCGstHCt1AN38G8mtk?2a7CxR^g_$FD18a*6uq# zz04qg`aR!u7Nex|Zf$z%1i^!g?kx-~$>+{JZqY9Xqw_bp5x1V;|31m$~w+@oVOnZ)> zi}Z+|>M?2orck)SsJfi!GoWovMwMBJb1e10{D>##2t8$Q46NG`A}nll#m=Gy4k|9Y zW%s8on3fc>fPQ7ope$vtfpX_uHlC3WnJ1<|I=v@;?Tn%cxn)>6#6FilLQ5iKxR(az z3`kRRDJTxe1rOQ=r#TX~C#{%_dcI+Zw2FCt5)o}D$V76WWKec$4R2S_3^~CcZ)s8Z z-PSi07Kn`uh7_EuB@juk0!YgeHnxJ-DSyGz>ANp^^Bzvg^W{I0PpCjej!zW;y6KfpSydbhjjDJph)=58 zaB@wc67Y(Tq|OW#JQgV5eC^G?aqv*6vCpLj)sVIBqbD=;=c#x8lv8P)#2Y~kKE~@# zDRs_TCB%@pg>IWJy-1+_JY@T|g^AVl^7%Y;0&a>WP13~F)4{8YW`gWS)PcRkIk*`Z z{LyWZc0FXAA)!}5m@@#pYrL>0ZhX=n5AT-VQI{~_=GxT##Qcp;?F;WNntTHB%?a!< z!l{|O_wQEV^pOy(o&Ynj8pIh@5+ZEB+Ujwuoiv_?BYb?xHnYjWWW$o`C(Akl%4r7$ z6(67({I9pME3~E=L+sK=B<-F8t++T!emU-;w|w3gZ0rwdGC-Sr$vm`bp@3)YULKCY zX4{lr|5z6|Do7?C!9cp$*mY^1NYwik8{5M>CA{n;Z*CKJN5fNAex!x`Ot$*=f{Z_s z{nix`q3s8Ex|c>86~){~$N7D#hDG5XSsS(L7G>a)krm0aAw!9?()*n^3AXrdHdQ-^ zaYdqY@CVmunfDmt4YmiGL+HX=jsBmLlGZ+IW464#MA`moeE#?w*mKYr@I7$0oD~__ zRfHf$q6YU~?8sH1V?C>Yc3`E>SFA`X;veabZw2X!+IhZmo0gc6X*zTAdsk{>r_qF1 zZh-b z$!>%*ZcyYH^}7uY>{J;yJzyxoY2PK;!i4Pj_AZcnbFcikLcaOp%&TI7@}l(uEyYPt z^MZc@{AJ~t)H7>N%jz{h5v`sy3T#dv55UAuZDFKS3F<^;rQ3`CI%>*Ve{ATnu z?(svA`WrL7bufW?9ZH-B%jCBcm~m#WHQ&IwSA+uu;S`d#vqK~@t>5b8y?2>)QEE(C zrZJpsrOazeQ4&6p^**e(i8okpwU=O#S~Ei=0_%gs3fOqtWjue&1ga+kMMF1p!Y4Dl z#<}+aKzFq-Z{N8_+DRWteXhnLuejcxw^JV~?L>n+G6b98NR99=oSz&#g?#|vP!i$N zAASy0;Q)}xRcY!*D?|JFWP_{bt{qS$o}3^aJr!JBN|Js=K3+oBS9Y5qM)sMq>kLW8 zT&1n(dW>S?6_27K*#&Z$2%5WMZ>#8XtEsJ%8;W8zTfInY1@KYV844@#89cW$8f0Fr z-XM|}<3^u@a<`a|niV$Y7QC4^Q#guCyP{}Vhilndpfb&ec8C%23k-tax)OT*Q&w>QHQ-qSUs?GSN&cCvusT9qdh$tAq0)=ee&6A?5qp-?pIMVsChDww3X=I*Vm&w zV9n1IX0WJz1Q8L!2}xY^*$sZ+1bW~s@u`(d3^B4p{6;yF<2Q~7hPHZhUjK!txX4*~ zyPR0fsexUB#j@gcKxF#70W=bTxul66t+}KOPFThWCGd8`m<(d}edTm%$%r!UHWgSO z576J)tM!Wk1U!LQRztJJJ(4jw-wv5aWB@hA1d{ipB$RdpIf;mJ8XjDfh@al6$NHFx zOmlkui96Vb`pFqk_Zb$VY;$ZwDHkK`Ep6x?DVW`t$Ww*Yn|YZ2*G%~g&gW88%mOoD z*}LzaZ@5tBZc}PoQADTls)^DFT?}ROVuU{~ru4ND%?A~ZrZ0Na(qB2>B6y8zzG$ZK zFB%HCtf3s>cacCtEr=y+H~N@yk&eRq%%+{y(EC$>WNnNy$F#mgD;W?Htj2QeW@ALj z8Sm~^TFN<3JR~9U&^DTpI3inap!N)1SWreJ)we3{*4BT|kZqLuNQ zvhl+y&If`F$d7+U-t34q5Oz*whY`TK+~1{8@g*t_j4|eKqVI`kIG&R2_wY;5yo%m+ zhL_lYVnWRwTTHx$%O{9n4936P==AP7tP#O3Oc+GaBV33{d?e*{w3Jdpd}*!|FHTAU z_UQ28iv3nFumu6TWft^|6tvdIez0kM6w0xl@bB68U;X!9{cfqA@>41Cj0|AsX1h&n z*5LLyv32J(t12A&4gH(PtKgejxANLoFk9zZ{`vR={aifp#b?NoHYLiJlz@BG``q!L zyJt@Xxx-L%(OhE1`!|0QG@o6*?wx;2hb7e&Ub!_nPn1w_8FTmT;OKtzd)gh0m&HAh zXguTyc>3t=8of4C89O|iW0w#^beC9H2fy-)iGwKRUAi#Sw`6oC|N9eftB@-q2b)on z$3>^NHz?bS7~(a_YS<~V?tOY|iQUDJ8fyk6g9LPk=z&ap*vK7RT(q0+uj>DVTZ78S z&Ez#{pj2LU+5#CPOD8~Go1v;Fs9nc>*?XzRn`D(E?QE z6s7+n7kn^9Xvo+?e!^FlO-b~!^lp$n*GtI{#_OWvMJFt#cMRQM;PnC)EOCas%DTLi z^IOZhF-k-}%bS}H#A^Jg6Xa6VdZtF10ZpEZlGUVuzLxyZ>^m$MYO&O@OON+U@8&+uUUb!TZL-Wh1=_6cGtpH?4OYHc#PKhbQ}FWIoP@?u$DML4N;jrJurfn zD^3x}6wJ!?3V4*K%G6&RgamLq6mV%QYRPLK{3>$S0+lIrbKCTDTMw0*eRN&X{qXw5 zf%fC_?eh<)p#xQgWSeIPW?7{sGGtC>9(h6-N^d*A*FzuAw)BY<*%uJ#8E z{|G)0wj|~rC9{q1HY#l*HE)P!X$;71$jAkw6J=0b;t?ozr!9$Wb#^3Omw2MZ*s_xG zviIY|kR$G{7apiT-1<)s6wP?l0)WChSqCE(c^3y>$7E@KhT%`$8l62XXD6S;(uPxc z6rc0?_a~sIJd3v7E$zy%L|*w!RRy@Ry9!?D&6Mbr!)Pn7D0cqmK3?IE4~z2n;t9vr zM*$VjTozqUCpR^Z&<*@a?f;YCtt#CHJh0NG*hW2|GN%ZL6vzfuBT*FR{Cr4vAq=1$ zSjoN)mGA(|=7GdA?b&ZWoz(e)H(ejgBvME0D-u|TG(T#*=62w`v3-y7(Iyfm@D@jp z0<_8U1V6ubS#JM6ZqQq!`C~I#Ri3ezVA`iR34IsP$4Fz^!ZCqjhMHn_!4lq@{8O?_ z4`?dGC+Pz-_IWSp_D$JvSlHRK^uAyvG@bilb?(j#&%ero)}+b7)#eX}`6%nRw<=2d z1?&3B{)`CLuhx`CYZdt{7HtYP{;Fvt2;!#rt5tj|Y3ZP>-t93{1OZ{!CYjn61s~k$ zB&>^HLA$o?u24JsR)dFc)S`FcJF* zE8#JZy0M16(ff7d-FvuabrTI<6IQt+R-Yy-{3?09`cvwr`-NvDj>4I9jiCDDQ(n^_ zy=P8^=YG}A^_NVM)X!7Zm(Cu{Jv(Xmc(QO`IObjT8$l8OcPERpyvqciN!qPtpF=?? zZ%3@~!ZVTe*!uMpk&UeSjS69Ke*I>HNM(h{R=>#hn14klL1bakzk0oXJFWimK;-?e z`u7C?zK#-bmr8a~_={piu~@xJKcBg;n8ep;tZZm3=hN^Lz)<$i!;SFF})PO^{VMsp*VA86LX_DOUI4V zBhEVB#5yO=w${YLa&awkFD2z)wa6DrDpa;8G)gLVNXl@a6~|kY<|LKZT9n^Q zsvNece3exF-J%*51h{HJQA?>YN=b77lvvJXxmwkK2dT>j%d57^7zE33NoiqVwBuTv<9q45hi!MiO5gk4cJEr+ z3DWLFE#u7C?#vH&w&B^$$wfn!9xqsMx|LaY3to^~YOaP=KfLit; zW5+`d*+9OIKrz`M*^VGp*bJ@_ij?kB~PhNFA zDU^L$+3~bdHmsu~Y(O@Ayd!*0He#(6aDZnj!tiYmiG->nUH~a5P!ZH}7{*Qvhg>Af zPtXgD$abWNl3er;S<&qwMk!R}J-JwdXJ_n#n_K&X3MCh>(;5F275Az$p-?WdvNH^V z2N9{q4_rj6UPSM!BZSe3@8wbsJ5#>Od6J`5A!tbGP?Cn6sMG~^E0Ql5@KQ`ZUA8M- zRo;;rMV_sOIRDL?F-Q&rsEDDXIJ)>uK+OC@sj{7E8eKVs@~9CKY)5w$`wV|Ow6IUoS|dVSaK9Cr7{fe5{_vUL>mYzyFo40Zn`Gh#!HOgcb1TSFl)Ou+*4vf~HIQ6wGeoa9PTwGbc;8E2MTcXSI(rjX+UX4@qYlKKwZD~$|u4tU_dpK0L|M1B~U;$cRD3> zd^;P!pTBq|pu9C>fv3NC!WTEUdpkt)`2~D)7jy#?gg^*v0W_=vzI(F(us{v;yCYBm zIYT`;C&ImN^B}mw)~Ein#fyDIZvZp!`#7%v4uJeMlYlcgK?tCL)ki=)4?q~$ygYNe z1(5R!$bj9?GYKGr%V+Zm&{Ph@fL7VP0GL1wBtA7GKo{&oKFGs6yhAyh{X9RyK3D+& zoPaazL*vIh>$m=32SBGofu(PNBE+~YR07ZsKq7d8)30+1jJc-cI?|6h4A^$C2f(-o zG`9~yHq*O4L%s7;a~8+~^Gm-!6oEA-{IGNNHN$h;*E#ZoGoRA{=C`^v4+1T$JvI-* zEJ#4~b96Nay8whe0ep1$KQz6Ezc!Ei(myoZ%RN8<5IB%vL4hV@5HMH}3o;@H3mR)w-2ySFc~eh7~)OY+18s(WX_qmTg(s0p)qD>gI*z#myU=~kHs(Kw`i*e(|w=!tt;+V3nF?TU%PP@U; z6oFl?5#9jF^M*dq%(03LAWJq-%cztjoMo94sEU@AV|DTbv{1>^RWq`43u{?=k#p$N;3jp_NoOVwZoyEK zlPU~k8E#r3(X?gMX~hEnI`rndfmYlPg8>qe7W_UN_x$lR%$p+9ZkL);IwyAIVlT&=s+e&`x@a;9V!BFAs2PF(d4<7 zR!9h?&IIBjv>!=bksJO5l213nNN{E*5{_8~!GTCvW(cfIxS>Jr^r>Y=*6tB!h*ET70>O z9%VJF*WP>a%~#)j`R&)=e*q3y;DHI&cY{PesQ@H`van^7PY)nLkx6b13ysPiqvT7A zOt=MO#&AKS;F0ALAQAHfc*LApk=a!dS(p$ZkZX3$Vx3iJh@d15uz-dN0&twA1{D^W zrGh+Hxxh350q8;-BpTpinOU1rg@zT5se*tkkck3?EuJwGB?W2t^)p=ygNBIkgr498 zM_{3$g`yRHL~D~_sX>HAVv%5gM`Y1^5m+n`z!6LVz+#ywLI^|6m$18FJCgnuf5Gut zB;df2q(y*Rf&d1A)Bm&SvR@Tm`q5uosJON8oac)5utrIlCCz#Z>sMOFN&BA^n(hBuvNUPkmP<8 z49{>O7KA~dDJqZ%TLItzvIJyABKJVhkjO%_ut1)YAQ3Kj=OEBff&dy}g#ajS2o%Xx z5ol8ch@9XU8kijwNV1J)Hg7dxVu5x>@`wouByb+J zJk%9M8d8L78ibj&)L;OhWDU;+RzK$>z=PJukags8&i{-eGV%?%u5OoY>Fbm!}0Wx+`g#=8p0wzEknsmiXi72iJH;Dq>4B~=aJRt^W zc*f6Ovec1q0gL-^D;ZhSj(qH69y3YAJZeFM6gVRvP2fU4YPdUnG~p5YSRx0S*aQGD z#R>`7fHSIy1$NXG09>#~4HL1CC7!?;^H6LfK^t1pj+V5gHSK9pn_7TvKoOO=PfTVq0Q4f@ zaE7Zw)7-({kS1ZBR1wHEw ztTzRdy@S2!V44fRH`M|hKr&~_gb;+_10f*5ywiI) zf~WuuyYNOCucHN2jzq%Hoe(t%*#0zPa=b!WdyaFzgMc)6;u(^>Mh!fGf)9M)0Q(d` z$w8oiii2R}A=vca(m}5QETR>XLnr{yn+WLvfWOSOH%uow1^v2$1|vrS2x6!bQK1A2 z&Pc)mlEScOcn2bPz6q|kQGRV6p18`Orxya~9fbPP%1BHge60%!s zQGo#jV;`>YK@WPsg9~6Q$O1V4Q(j?fC#I|^0pM&Eb1ke4^12AnXQC6)9e(kTpZw)F z|M}5R7dhafn*$kvgSm5y{w2gvE4RP}Wo`il_=}Gq5~~ck(=TASz#DYMWQgG(PC{{r zz#}-r3IyQJGARqx1S<4kF96CPjzuOU;wF^LZWN;CEbkyDp#sE70z5(h9tb zAV{gQGAd1yK;Qr>e0G90vLPob#1E`#$N)eKmLLHFpzKCM1(Rx_R?Q;@!N+KWL_mXh ze2g{F1_mu)11gXtw1K761_jAZ$gqha!e$^80G_Ua68s@DZo&yr(5j?K&JYBd7EZzd zN}vF08H#|-Wa!Cg2_@93C0>x>bYT@1VHFet0__kB!UiM^z@;qddZepVq7dwIDhvez z0cI*%Y-*;!tOWA@;7jDp_s(Pm2CXFmU;wdU2u!9GmVq!7a3?HL0vB*15McIXf|_QD zAmm`|_zcrDqF3loAP4~;w2xuzVIJxM{0d800>A{Gpt9^iSZ0SDh(Oh}r5UOSnKUZ` zP9Tb!K(czRvhHCVEWrD=rHTUZ9MLfy)o~r!u^rzC3vdAnW($vQ0orIJ4sKyi#6l0s z%@$nCDoCIoZ2=9A&>iCfO`c(#?q`-#CU8Qa5435f7O$yJf(tN^q}pzHZen#rKoLwr z00w~@kRS&X;ZicFRwkeY-lG6$Lls_tXb@*1IG~_(;>|#@@W7*1^a^gCV{?9F5xjv3 zJRl7I!2| z7$#%`76E34QW<_p;|>quSR^ZRD9FiacVxkH{paeGOj%Xw^ zbwa3|!M(CT8{+U0f>H#C(kR_>DEIPtc*OG_H#8 z2-d3691XHUE%ZV$G($CXLk;3!JV755r?o!iBeXyfDB+gAVlm9E{SrhDD&q?{v@YcE z@Q#c|{$M^@VKpF7pa$S&DgZt7qZMqxr8J>HW??ugL=mO~6BGfINc zU>Q#0NzEZAMr=^ZKp7&#Lb9P8gtS%q?Hz<%+UBtmju4su6poy|1MjiHHAvR(qc4FD6VLD+%KY}61jRK4UEK=b98p9K$RVTCn zWE%qpDE2K1aw4pvV~tE~TtXvI$ShnIE5J)BR<>rzVqpx7Ab9pAX7()pbarxrb`D7d zXyt@B&y*`f&j$JyEL5~Hg0N?44j&x@Mkm)_d{vF^$Cntl zLKXL3VmEbZw{~s!c5yd%H?%Ko0c6R|V>W?f(P9DqZ?`<*cab-FaRFp;;TA?fccC|W zrFVL%w|cGjda<{S24DruAP{zI6Mld}*5V5U(%gcpF?Jw()p!1V*|&Y&_kH0ves#BM z(*n3`!TyT(d;>v#`L}=l_kRI6fCYGfFLVKp*Z%PLd>`W$Fphv7_<ghhCSN!Wcm;9@qoF#_RvOSpwy_=RCOhGlq$&oKaYV1vmm zeQ9`ydANst_=kZwi1}p!#(>-sX$%-Zh?RJWnYf9a_=%lZ0CHdq#*N%OArQtO1wI#w zxwwnH_=~|fjKz42$+(Qo_>9pwjn#OK*|?3}_>JK>j^%ic>9~&V_>S>7kM($u`M8h$ z_>TcOkOg^=3AvCB`H&GgkrjE78M%=i`H>+xk|lYPDgL>VE%}l$Ig>SclR3GQJ^7PC zIg~|tlu5aiP5G2jIh9p;m07u!UHO$^IhJL4mT9?`ZTXgQIhS>LmwCCDefgJxIhchR zEl{nPjro|7IhmDtnVGqno%xxadDNhJnyI;(t@)ald9JW|oA=>cxcQsA8Jxv=oXNSF zy}6vxIi1ycoz0n@-T9s2IiBTtp6R)s?fIVZIiK};pZWQi?V+CmI-mu5pb6To9<-pR zd5aL*ofUea9r~dmI-(_dqA9wfE&8G{I-@muqdB^xJ^G_3`kX;}q)ED@P5Pu!I;B;5 zrCGYAUHYYAI;LfMrfIsSZThBhI;VAdr+K=k{(btVfjX##dZ>xIsEzulkvgfBda0SZ zsh#?%p*pIida9|qs;&B}u{x`@daJp*tG)WG!8)wPdaTL1tj+qY(K@Zwdac>It=;;q z;X1D6damiZuI>7+@j9>ddawDqul@S30Xwh-d$0++unqgL5j(LJd$Ae2u^s!dAv>}q zd$K9JvMu|vF*~z0d$T#avpxH>K|8cXd$dWrv`zc8tGc0|S+!BSwO#wQVLP^Ed$v=0 z9U7q!2qCw1d$)PJw|)D!fjhW=yAT>-9ccTwkvqASd$~<|9x&ky*nzpfdL0fyxUKuT zu{*nS`w)y46o>AP$b)tyr72%Q?xX`L`p19r)oMg5kn>`w;Fy7=9ZP z?%Tun!4Y~J#nC*?)qKq#TcKy%UG!NMzCglV;R}eb&fR4mn7qN;dmd7u491|}#wfv^ z+Y1t*9TYkrFoC`GS<%5D$HD%A62t%usO83Ue3@xsz0m*~-YOKvfYRlq4&*z&6@kjd z0TjwW5!_180bLQ$dmp}`48XvL!eI=|;1>L04ibUDV_eQv{hGf896~`6c>S0o-3!cs zT9DZl#^4Nc;mCzu5uO~r<=e=M575yd7`&MtLZJ+-eIIB+5*nP-Y3LHbpxe5e7AOG> z&;Z7vxwi`;687O7Ab}eAVavIEyW0WGdppCOp%6N}!*~0`A3@-Ao6QkE;T3-2>6#zB z;TMcMi;5ke;rkH^-Cb0{3xc80%|H*%y|XaE3)ubR)tkLD{tS-j)XEzS^x)H#eVi$L znJrx$<^T*lfeyUD5&q_(4$OeZleyNB;h)1n$g>T{;ocLne(Pi13_4-xtJ$}s zp&kq&x2NG8;$0f_;U3KV5bR+c?m-`%fg0?g9?X0i+~LTd!4NVW%nw1>w4C${-18#= z(a!-92x0g6A;&|Uw;8_pjsN(OU#s(h7UJ6s)&U;k0Ur2)%HuiK6M-CR{tWz~4rYDo zd%hoL{1LqW{u$yS;~#+@=0FSp0Ss`wm{&d!Hen2)9-LYI@YjJKSl#H2dmKQ)=;;8* z0U}(PMEq!tQIrpp8BSx)INLXmRT(dVp6zqxCD_F=js%{$H;&F3cKr51R7jE*9WZF1 z?W0%6%&%YP^uaVEEuoo*8^_=@=*7z!e{;la0uyLmzL#{yczI+}B}Zc2R0Z{-D4Zu=WzMuSsR}1PlNY}@+P4af z#=yIHK_i=(*+xh7uyq|b$4tA#8eMVRH!f5eGr8^&K8>1?>eYwXonvjNwL3`E_BA@B zFI}VlX#37ZVuy~N%?22+_S~h$6LH=cwH|*^Z*=bF_Lj>ha{u zn?H{}z54a++q-`cKfe6=^y}Ndk3YZu{rvm;{|{h*0uD%Efd(FkV1f!R$Y6sGJ_uoi z3Wju7g{yo%V^IDd zYT~q(8J>`_(<**inTU;;`SnsvODZ-`lAf$orRpT6Bhb*|SRM71`T*-i)>=Mf z&?9J)eLAe?aWj!`|iI_m|YVK#r1;qV00x+7iwe>7!T1yjC;`H z3p;^G04WpMyZ7&CD_dw$s^gbtZ`nVa9kGeh7_- zUZ9MnIx>eokcCdEQ^aY)AtHCssY?f$QH5rByL>Uv5UQC5I;;gA=i!E3_Iku2nq!D@ z5u!EQX~*-ZgNRVJD|?}=&b@}W5Ab{seynVzD_;rASjuviw5+8qZ;8wQ%xr!yY!I40 zgOQ=ZWmPP33NxIDF}c8rNzKrevrH1YWGd!92~kWrn6!@mRRx0^Od^V3su>L)?n59o zib+oFl0Y!%f*eol8w~4cl75(D7G-$R#kh#0awMr4XaW-)>CugDh-5P++7$uA*(*Ty zp&dRn!!jm9F;~nb9s6{JVT5%Kv%MoTgnJbkRVNO|SacENe3d`wP@{PeqZjr-;pGbV z7YyRUXXfnVrr6=cXmI8tb^OLBpdm+dx)CFeINTY|Q4VgHgN^3NS0TFf4BG4iIn%hu zbBGhXr`m=&`Y0FnjDwteID_pJuH)hWf2#EN%3{BD_H=m?%kQ#o7nj zD#%4>niE(gJ>8%}xR00(5GsjL1aL9r5!(6>w4N2Ch+>+j)hfmyl47kQ@L?)Ky+svc zcjSPC~~XfCNf`;Ac;GI;XOo1 zgCADimYC#8Xi$VZ;^&3SA;~AK_1gsH!dS#0rLxfcAfxhjx;~^W z5IG@J-c;C-I#-1bUl6lCn(PHW2#PnZil8{c%vf-+)(p3Zsc7c%7ni=#qbBj9Tol2z z&6Pp1!6=DVPF+8#sM)xbkjpK&)}@t*xzwK~bb9g?9`6Br*w9iQv4u_SWXrY3%x<=` zpAGG3OMBX~R4FcOf$eN-`xe@^g)i)3_XH}>}+ql+usiNxVN1jQYQ>JZqX{#(A^e!rw`2dfseokp2C11yu%}uvY>#W z55GXgL@*@x$nWQ@WkwfqCyzhNq_a5_+$K2_BrzSCefs0-AVi&*I1umAa{O50eU*8Z^ zP#&>l{o%zlzVE*GzYqTKi+}v&2hiP1e+yyI{mq1_2kPe|4qV7z{ekiwe^>=m80DQ*x z3%&4sz0iDT*bDy4*9%hkAa)T(En*?hL}q6Yb7XcQv3Cp$r-gm!hkpo&fhdS!w}8Rt zgI}0!rSWu1xE}pre~(yykcbOM_#i;BC4_VrMuSKPCKNHaDi#t(gD8rlNQ$Lsil^vT zM(A{SR}bXze)5qI-Ee#!ID)^R47B)x%fNn!mn0Jd2EO185Cw15)QM~Mi3QaC(6D6}l8te94%uLj z4ss6I5dM+;Xpt9*kr}Cxdvz%DGcgXtdA?AQ4U!KNxsfM{k}0W@E7?kb4xsRoccFg=k`Rdi5AQGwbD#({ zNgj+7LFj=Qjt~#>zzu$uAo<`8U6CI?i5??4AeM2IYsr>v>6UNlANckSRCE_;u!rK9 zHe4c(lwbxL0Ux3A2+;#bei=uE;R;!K9+<%lY!nhanI20)Z~e${>0y@U(GR~MhV!O@ zt1}N}*bC55glH%XYu69$Xc6+z3o$4UWeA$(VUlnOo3SaIvq_tp(~B^9HJoS$V`37$ z{1=XM}NQZN`4z zASHddI*fB!TtpA4P(i*16Nhn_rm$*?P&1|`2D?B9glQg?Ssvo>netYe!eAN@xDNH8 zfyN~a{eYV62Y8pc4ufG_z0fk3$%30%9%@;e6>6auilO_+iHg@cx%r8qm=Iq;K)mT5 z3E@YE=@+MiL|aBu7r`kd#=3uoH)JR5I!p>&ZA>W)I>(2Zu2ahyo4oU|Nnz9{5?9`%n-5`x#wM z2Mxr)H7dn5^dJoF01m>iI@{29ZVFAkU=BdV59rV;{jhH2!4I#Qp@nLwhl;3Lh=)P( z1&YB`O(vd%0jc)c9@BXmuAmwDkPgwa3O2+KuV6dy;9-msir(dyaq$qU@FD_{Atu@- zW`Jwo;0aLUf1PR%hbbrdPz_3f2`@r*G{v5rawuRT5L^@zlscy60S@ONGQHpn8~6-N z#irmu6>J(^zpxI}x;olQ82RuE>^G;E`4_~Hndvd8zL2Qts;=wGt^yd8W;+wKYCf@fnDK%a!X@)cswBD!WOJ}4coIS+L+v0Ab#VR$c*me?fd;s+ zZb)(%2Wun4Sr8x@5&>8qWJ(y@u!b|Sj{X@>ELEEKFb|`tIc(~u+X@X#1*fS-3|+yd z{ICrV0S>+3p96Oe=-RGBOSDC6v{V?JYc`x`QU*l$sk{ZM;6)b&dm39A52D(wy&4s@ zXA-VZBd>rZr-3Aj01y3Ow)X&;;D8DuQ9ojdo>d7GBz2e@3nsLH23OOVlvy765D)c$ z4xbqh@nC{IyN*g>t^CjnJku)O(0Bbn47uu=pQ#VpS`YH@ZRMd46neCq%ekHFx!z}~ zCc&yMS~J5*7GC=oYe8vDs*J88rqxNEC6yu52}7Y6e|3Q+LH^bXE@2aM5DfId3-uEY zV^C#vz@C{iC&XF?8FH+8TOK8$pGOFR=KwQys#53RxHCJa_)reLu!}G8xCH89D|?yL zYYvx79+nZApUb}O>%Q+Rb|zZ3tstbPF*CVP4xLpaAJe4CsR-s!4OY{w(K&Cb0B?x$ z4D!GVS>r=P+N)|&Pw60|W`e2E01q>BUvg0H$Antm7fF zs8O2PSeiB>55f=+!oZp(LAb);4nLL;{eZ*!u(JZU59GQJm+7o-*c;Rfze%jbOU%Tr zw5Y!#j>;JnVStYG!GA1)z86tJiogniASY%4dDVv${=7g3&cIXzJRVwWSxAv`;Q$JF zW+P~GYX7+vn6*01i4;J!o-RtaWMOLj<-5*n9`kSx-|HZn+r){i$cxO#2(zKdXpA38 zqWH0Ie8@%)7q5a^ri9UN>$@IErVpnBvdL;Nh}_7hjLNC3%1-%-K@o}vsd!wQV~2vI zG4A22B&;w1-1#Qp`lMV^3&hi(=~0=H;vOdt?9e zKMmADE!0Cz)J1L7M~&1;t<+1+)J^TwPYu;kE!7--&{b{KSB=$Kt<_u2)m`n?Uk%n_ zE!JaA)@5zhXN}frt=4PJ)@|+9Zw=RRE!T5R*L7{zca7J1t=D_a*M05Re+}4yE!cxi z*oAG_hmF{Yt=Nmr*p2Pjj}6(8E!mSz*_CbCmyOw(t=XH+*`4j#pAFifE!v|^+NEvU zr;XaFt=g;2+O6%{uMOL=ZO`}+Jxu-u4!`iTvaQ>@&D+tn4ON$Iy--0xji{l?xBlFSa$-?;SOI~L&Zv)|@X-~i*v13n-MJ|LLf z-Z8@q*f!tB^?}#`-0F?r{ZbEh&;}je25ztpcEAW^!4D$d4#nW%9ex=6U<{AY28@td zz~BZpf(~rp48V}$9o`7&00-8?55NEiZSV;7gW{J142+<#Vd)K~@ClwUv+>jlpYRFa z+O>d#SZVPMo1o=d-VEXJQ~qUv3Z1YCyYQx=kPC#-3Z0haTfPgs2t%LHGOe)XTdoUU z-YVkI3Z38y-rKdFz!MRX77r5T&Fl(W{t4b24q`s%p0EzI!00M8=Yj4Dp1^0D(+Qnm z3tS`TbG`|F^9`o337+5!Nsb_);Wvf;=d6I`oSqd+-sDg2AmES+dOqr_L3bf9B^iU0#uIn@e=M2Q@xxnD5*9xHU38N6L6d3HHZh{f<>x~uY&+XdTt8kx*)Fb30j`(T;o&o-4A&#>h7>PoZjicz6qaD>kI;(TJGdz@$KNg z4r{LE*g8&~&?@K2{_I{6=ALlur!f!SKni*e4Gd~0^)5!x-puom3Y*{(g}w>K{$@VK zbpo&D%q|Y7@CmtY$feB>@n;KFyk_LxZTFqw5>n!fa1J?t4)$OSY#Xqz&tr`2X62T=MbPhZl)qG48kxBZ7?P%4&o+pDj(-opxob1}c}nefz?7`s6I)JXX2x zMdY}T)+SHuF0!(f&D^X{$?~-twX9pggB@kgq*>EuO;?_lne!IPQ@d}QVn!SXN}xBR z?c{OW7AluXcL^6F&1LWARjgSNZt~U5TBl(8^0B&=t(!S>_kt$l>F}PoPS7IKOO-$(waM1TeMP|z{`P5;#hlQXhPnmx(@=z+*q(Jajp@tj)BJ^|lYj-mVy;~2AkQZl}$dW3Ztr^_< zMT9CM%BhQ9+(#cEX$0q&B%cE@ELS+;BrF#nLXjv?bg^os(R@r3u`V0qElqtA>V!ok zfs`hqFD<*1!ZoYJ%tsJ&v5p>Ipuy;{efa4zA`(s6<;{!+Y>|~+KuKn#s`%kC9xOR* z)W>~hiPO+RbD|NiX7br5%>gIfCr}?zq@|N*c+}KTB1enS8SCZ=QJ)1jWRylqZAs5J zUm(Kkmrwp|aFikUab=WG+jaL{c#Y#HKAQN+XI_1* z8!TRa`}Oxh;B-h{eaciJ;*pBg7)6D;QaCEU{aD=xIg6 z16jd^oVZ$~FruEv8gAAXi?o@?mYuU2YTig(haYl6*<~Ys!sW=DkP5sP;gz25gjj8v zu5K`2Bf<-pbM7fxPAs*)jGm10d~D|vmppM3YoB|vVuWoq+OlOji55w`cIkUCS2-fl zGR$(07}b?NStd-+41~zy)Vs_l?~cOhwiRb*&8QuGz;SRyPoRN^-JICrC!VFHS<`Bn zoq~vKy+PsIp01rk5mw|Qg~&v@5`>F4x^h7fZJIvn#hsRExy2v;JB= zkxSKe@ad=caWAuO(Nuc3cVGYpP=Es@U;zzyKm;aGfeU2dX{6Hz2)2P@5dlUUs1qsg zMDSzmv5`!G0f!{9hc_1+jCkrJpzD0hJJP_;Iz09(mkC8Cu=7=s+(D8Xs%aBD+(c!{ zjl9*60Q=o!Tw_s1c zm9O}LB$`a%=lEUmF=!=V)$-N+R=N)MOx07Wlc#6z%bB}X9nlk5hWCgg!=hfo4k zC_wVe7paOgMS(^us`3q7a6^9DI%4k(7rIOCkZB#dO zx};}6{rOLT1{5^~dxSgE(YJ`qrwt8@hewux#6=w>Ne`Do zf{)H&O_$DuVlIu!j-tGjpU+9;*cLRlSw2IYz5dYD7n!tAEDIY9dA54Asj+(A1D2;Q@lLj*w^KD35s3cr27I~4kN)AcmifK7$8a?J% zCm-@y+A|*48>h8{aLzKN`W_P2Qj$d--k6(AC~FW@6=@m$sA=M!5uc_ib$RLIh+7>3 z*X1N6iJ)l4qtx*ZvZgIA@OTGV+R-!qdGB`nkcaN%G81}Oqg(nwZe!%~q;Q0U6~PeX zV4s0k#sG3FG6gS3@&OLfq)VXdWp8`w$&XM32RPJ>2rXbxf;2cHmhRpHWyj?y8*ZpcO`N(GEk$ zgqS~tPVi)6p?xJ4R!pQ+nC+-u=IE+gJd&e@WF@6%bT=`_nk9`c+cd$5ic|N%(GkxE zKVyvo6tVt9itqSo@mh#p;J^j`je-ndXh&Px>&nM3e-S*I!joQ7B{xn0~=OCYVf^m)yQfEHd5e6I>Q8JUxr#|%<#v6oj4m-Tz zPYMoD8${e`on)gGov=|+j#3I+yc3Q1V19CQCQ5+=YHAN{ z(z|Y;0<{(&$kLumsm6LkM`2xhI*L~mVcfDRG4fWnqQsTJ51uXNaBSwX0rfGPTm9>2 zKUS)(8(idK8Nc|&AUpDk7L*_bLMVY2lH7g(3_t-~pn{1YHfV!&@HeYKw|3B&Hedt) zpbmW~1~~9HW*Crj7zQ`sFge<&4HFsl7zQ|KgGX=}H?S7*csS<}m1-b`POt_0Yoj;% zg>dt<2GOAlDgLd*Xe7fJq$vx9Jz0k9Q5@?!tUt1de4s5r+d)v^ig)6=Y=Mjaa}E*_ ztep9lh&VA|F}hJZ5F-RMrJ)E|aw?7h2UFMtPUrna9xh;{x3L&(P*d$W;1f4j% z3DGWa92HxTbNLwNV(X2o8gl@sDu2>XwqZ7o?zwUTBA18H#bRoX6>| zAhW^m{yQRQXpD5)golv9O&G%gY)5y5wt0y!_*=t#K!-XI0uji87D#~<5P>Z?ly?kB zfgDJJEJ%YqNQAr!JWNQ2Y)FTENPjUFTfhbQgN9k$hkmFAT)2dM%*PziKNGkhh#X0h zEJ>3*Nt8@Um0U@dY)O|Sj(PZnTL^~VfWKX!Kbf3JI)H(WOac7Tg@t@cp&Ux0EJ~w1 zN~BCmrCds;#EO3S1zZRQJ;ViyyakH1guqyiCl@OwHU(&g@Lnh@O53CeIvA(kxBWJWbS0P1RgY)@)7J zd`;MlP1&4H+N@36yiMH9P2Jp0-t0}^{7v8tPT?F*;w(<%JWk|HPUT!q=4?*qd`{?$ zPU)OZ>a0%dyiV-QPVL-I?(9zQ{7&!;Pw^a2@+?pDJWupYPxV|+_H0l0d{6j{Px+ir z`m9g;yifehPyO6a{_Icx{7(Q4PyroK0xeJjJx~NqPz7C325nFWeNYIEPzjw-3LVS{ zx=;+wPz~Ks4((76{ZJ4M(GRUq5-m{^J<;D3Q59WL7Hv@%OTAP~&D1-U&~)fhPyJL- z4OP{ep&lgoscDFz6tUC7Em_p_R*nvG+l&w{9 zn1e)kyD~U~^zc|;zy_Li2XMd!YnX#GSO#qHBypevFHi)=7z2t~g^%qBR{(=Wc)Kxh z1b+=qlTBHvo!V1f*+rn1idu+c>xfjBVI6Kn$-2F(S7T)>7_Slp)tPUmf337%m8T-k#)gN%y^hV9-9 z`doZi+tjTuF9-%&CMo5Hg01#eq%U}V>zBUJb9N2~_jo^sb1_7{R zLM~)OK4e5rWJO+NMs8$Beq>0FWJ#W6O0Hx}zGO_!WG^-VKaNsB-Ul7fWKkYvQZ8jv zK4nx+WmR5fR&Hfieq~sW#?VlL((Hh@}w z4P#zrW^QI@er9NnW@(;gYOZE$#^PjljcfkiW^V3gZ~kU*4rg&5XL7FQY;KKmPG@yq zXLfF9cYbGhj%Rp2XV#Esd%kCU&S!nzXMXNyVJ3hhzU46nXd)KqF{bC$@MncyXohZR zhkj^?j_4~EfDPyXi@s=#&S;I!=mjw7B_@E1-e{55=#HLZgjNlSPHB~1X_jtjmwstu z7J!kS>5TS(jP__GmT8)vX`8laJ%-|wP7RnIYN9S`qdsb+PU<#ZfSqn?j%H#47yzf< z=>?GDphgX)&T6gRYOd~TuU_e?9%&KS=q3*9owjOER_3o>YqoA{w|;B5erB_t>aw2e zkw$BCRqMFkYrgJlzy52$Zsf2Q0sbMFX(0&dy0&Ywj^e96jlh0v$c}8uo@~mFVzUnE zvu0w&7HPa@4K?^|&<<_U9&OStZPPw&)J|>HUTxNHZP$Kn*p6-4o^9H$?N6?3+|F&? z-fiB_>YmleUT)@YZs&e(=#FmIzU|(wZtK2o?9Og@2JV?o z>=WSb4mfVrkZ$rWZ}UEH^iFT}rf%(SZ})z0_>S*jo@x{jf)Q|Pf>z?DE`v=N>)+mJ zoL=JBP;UY+a05SZ1V?Z7mTv}ca0h>I2#4gIPJuB%0}BU(9BAsq-slj>0WYuxFW7_} zAnxD>YS&0`6i;y#UvU-({_O>ia2Stq8J}?)_hOpP0W>HB3)gWp*n!Mm;+e*UU+9Hi z5ON~V@DhLG0dH|8Z*nJpa@*GH8lQ41uW~D=@tGC@9ruC|@Bk0k0Sku#n%;1YCh{G~ z0W?oUFSu*QK5;02b2yLlIDhdguX8)Ub3D)Oncjgi7=w%kb3gBH;TCBkFZ4nm1EyYV z6K@SUZ*)h0bOfjKJfCz*uXIc2>X}B^9Qf}Lu<$V-^o=%jL-+9{cj6_7bW~4uRcCHV zzjRlBby$yehMwsP-*k)?0#Bdm059U128JOQby5fLHfQuzFLq-;cGYfmSzmT$Z+2%7 z=b6TFFZgd92ZK-k2lA2bgaKX-IbcVM3BPG{XN?*JS} zgBf8(BSVpBMU z1b~5Ru!jDhzWbx!c`Cm9A+CmshkC_de8zWWjTZTf_5iQ+fDMTEF(CW0S7MzOX{|4V zKJW8xANeLeb+vEqHCThvPkqs5`=37rbI=EQCWM}cahZk7l5I}`5J%u3-fSY%CB7Okme}|bL;!b!6eBcJAAL19_2MnEeJk)<2$Gwy%Y7 zfm=r(t&(YxIKDa3$0k<%0yt}zT*n3_0V~9(1p~XkY~PfC(hM>M&FaD=#;UJB*Ly4( zE;&(W^VWU1E?nyS8|Tk)3{rQcryIS$R+zoID>Ks?^t0>nU^8T{{qD|uU@WB>V@Fu= z>FZye=mosxUxDlO5egpNethT*>Bzlhl{`6*FZCbx*1nWVynT0m(zNld+Wf`!*HPi? zVUJx1^Sv!Rj4zH`*`k^7NOO*3_q=mv4}NOnXL+JH+egSaJ~sYs2dqM@=2O_fuDtjr z2;ew3>YDPY^G$)CVX>BCWkq)Y#tPlJHEkp=P}h^`tuQT+@!*Tag4GCY2ZumP5Uru` zV49T#h_+e2yD?@jYjK_oql1zlI+%COFzA&NQXBvaLo)+U>^zWwyb(LnR48vo-i&{3ICy8KZ}dre*C9%uOXOpQAd6>hDIM)IF3luYICs=KRA5lCj$@^|;m z{N_CPxu&^Bp<49cJCZavxSjOYsNJpK7PWpq2M7j2=Lx*@uZogR@5vMJ%=Fa+>N}Y) z`x?pf?Y{~o{!>Loo@}&k)nvO-ZY_D!SlJI|@<5=I=+BzH}>vt&MQ-i$$d+1B+ zhY3i2Di~j<^AZHNN=sj;>#3SxHs;T>XPF&=CYxVNKFVfBN!x5&_Hq2UxuOMB7NFkT$eE`}cQpptl7I%_m_wgxRz3B$ zvnx{~=L!W?vF!k@IPEnMhuTtp0yw5v*>MlC6 zNi9}m07#wjPqBKO1|h&@Yq`I2WFvmGL{#O~tzmz6rQ#p6)mf&#dLc61 z#SzmuC+ad~T~+Ty=Q^(O^DFggM$3Lfg-f+RMv^Qaq&{|XM{9oviL2^Ec*#60x}~xD zD(V$w$?gQCVO4u{L3T=}z!>kgM2%#UXepth)_0p`1U+x-ecTKc8Q zN2eu8wIP-v$~YJEeSw;j5qo|g(<1du3A8$yYAx^QGbVDKfZUVwl+SK2@DhlLIeX_u5<=E=_8>3l`+-YpVB{Z zU+s!wI$#WJif5OQ#tmWbc31QqHGlb$Rd`B|)_s;cDU-PaQ}eD4@vvb|ua+LX8)2!8sU z*0z>Xz;B2nEpw!x@m{T?F*R~DGriD+@3`H`!|WZ}du^rPZhKK0e-k@pVYIB|@vJ-MAaB%lrfpB%F8c8Swpy{weAEU}+Ms@K z^6yD1?AgYfq}>#^hDC-yxC(=BCYyCHnK?50X3!K=RR5e`S3P`X824``$q@R&zkF%t zmC$mMckT5W#?qr^0s8T_2&oyCl55$ws%Mb#TC+=hY99sz|J-5!F%og@eS3WIhD=qv zrF+pjZvbsQm)|=@EZxLw)$asll^1-brq*RT7n1jYj$o{m5UT|P#(M+8k<}@uGaZac z`4Mc5z27rUmeL?PZjH$}5n|n{YT~2J@D;R=xk}%)=l)Fnp}6z1<=dk_FT&2&G=FM* zz5i$bIppdFB`2=^LXfvwx@;qi6Zc=D7S~nsEsKy&%lJEoL^1VdfiQx40}r|Q* zqr;Cj^mho#C5qN1wd75cWGAyg-?3svH8J~;AguGy!NkzRGfRKJ4@=z_Gt+&vz>qcAc%j=fQG~zfU~k9Uw)?yKY-|BOMGcXIpyHBBq&z~m$;obw(OQ2 z<;9KRxEo1Sbq16@4`!z8*-3s;I3IV;?_>K3^g-7><;Il9~~tJW+_&$pWwd6zER@|Rs-H?Bzn-4{0m z?Gj?Ng!O1qK+s)Ka!F9p{ln$}1nw?uyd?a_fLGQ`$lYDkZ%H)NT?{;daQ8@s>XS!r!K4KEK}X`P^<9J zBhH)2?FSUKU)d7J^CFDcP`!URIi`R$yLB z<5g?ROOU5mfVc>~9(mO!)XO%?tJKNME_Kx|XZ4!*D(gcp`?^*8##PGvRfjGw#{m(W zhaL_;R-Kl-oCW(G_q<$At8SE5In%DW!oA(vyIlmm-6ciMD68Ex*F5yRJuSQ4Exo<$ z*C49Zo_=fIp=%z_Yd&$_zN!Y^L5U(z&Jhu$29FJf1Fy3J{h9@WwqP6su}OGBN;$@V zfUfL=rLA?BNSJr9W|c48C&WhdmS5tnRE&nvuM zC?DB9sEn}fz?WR3=#5UX!lNxXDFOv2b?U2aI!rV2;!M>s5<~DC0qZg!*6$gQJU$2H z5`3(i)2zr@vF`e55>p&!M8bVqpZM0w5Ix_7J&{oF#L%Q}Eyol_BQ`62pFYRL@YZhn zDN8FTQrm9SqL3=yJ|S{XEGt4Rs&vDm!RH>?+*Y5(7Al^=lWbMkb;pJRv|VG_A#OWc z8{?dAV+V0i!31#OfZ7yHVb_BS8xeKi{PxNO_ge+2B8iq1)J*Y4d3tvhZM2Dy6fcS- zE`8Vn!SonV!$Th&AvF#lI`oODAe@M)x!QpbtW83j2;)R#srX)@*4Ee0i_d$r0juX! zlV*Fi3xNegw8PSx0|<$8I20bK(!hz@(AVfA=mf`W7N&s0;*f>l&j5~|7;mxCNzSC{*+K$po0usx^bDMcWlFTX)V-B;sam6{g^j`n z;?f-!03^n)AyjB1_M4A|YkM?^-a# zctf)K;VbRnIzvFJuh34{GyxT+r?GN*YXB`3=!UhuR18iAxpDxwuFAd5;?ZOgyZBEz zdfMaEjD2VcYl14`CMK^dLol=0p5SM2>qZtx`v4sqYG`&qFv}vUmi+qIs{hu$3*(JL&2>|TsD+}U!3OJ1L zaj=LMDb|P9%>#d?_s2Wu{HLz}SQryv`803uW&Xfx1HW5yKYm+;ZdzMIB%t_aPahTR zOF((+X=5P4&N2lGD0Q1B(`I_#G&khH=~(-NvxqP}q2EYP4aX9$h~cXx^e5ncCm2ek z&^0IFUmVHk1SiukAi?Ks(2zGMU=l2hm+%w==rb`3fKE!Egg%wGlMxWXnM}Wl$0L_Q z;~!basqo-a#Q~F!K1eXZpDd1;V;s zE)gD>=72bM!xQQ)argx?E`TiNcN6lvBF+zUJKYh^S%%ZrAGC;=)(V4I_QU8Mh;-ZN zZ(n}%Nv+JC?(%>4oHyteilvvt#l0?w3zF|{?IG0nKyacIMM(hu zgw$Dii)nzHklvt(Z!GiT;XXO!%kAM$z}rk?I-QZxlqjN3NiB`bUbc;b2_BwQW(tr9 zj~<#@+J%Y~(+`xGwA7}(R}Z$d>$2iSJ{FV#UcW?D>e1%PLEr76tf_@M-~RJ0pjA_R znj<0dGeahS!{G!b|M#s$nOuJWgqB08okM?6S$;+~@lMo`IBcl3&IiLIGwwH}g~vni zdw&G!X&v;{w8eDFkTzL*o{J%AcKSNC`)ap`yO1smZ`m4w|&I9u@a$HfGzv*s$no6ObZnUyx^aNxB&@NfCL{i<` z+qFFNm|KG&&@HC4WJT+R5DR4B-8h_tsZ@nc0^}0Jp^by^@LC!*E*jG*&||a%GEuIf zu-oX&rz!L#J?$`bUr)TYG)%1z!mO2IMItQN=tpo+7_A&8>EI-c60{51Qa;huu7zs{ z8}X@69)W$t*%AOArhm{eO)9KLEm}LQ0A$@|QnIzL%%rA`g}m6yeY$zOf#@2`*^T_2 zofHy>lTwSQ>sblvJJ?CV9fH;Ikc|*bR;MQfsWy~M_H9*jNPtx8xf2=cO_s7^}n z?$@?jBv84NOtkT6X9D^KA5Oc^+sE7-bW`t?{-7u{AddJo+Mej7tIF&`A&I>u9zr$# z=c^WZgW&DZ+-!%ozjuW?ugiuT3RzXTJF~?tL?ME+qp$Y^`T%=6Xk4XQPpz`FP#c6f z6QYcSMjS%Y4=t=o1+g~t3n9)zSg^3UbIm2G1FN#Kfv=aeTG$O%3eOwA}_Ah%p{$!JMhabAzikcO|QvCaDnC& z6Ok|*5tEu`A{zaERGI?GH-4Nx3h$OrJmpE0aY#t4NKbp*e6t&P^R>}3H#CeJDpBH1 zVAYpvq4r{s0FltJ4QUZpCZ-%}hpQ}>()+m@nc(gCGwmViZoKk~EB(%Q{>;i2enbl~ zY{C-sjTYklg(zTogamcNexqand8X+QFP=9T%z=R@vj72S7GakU!J$08dqK%$g`jX_ z?aB9jNE#|E{_2x1fq!(G{uJWUTG5Viax@{I9S%TcZ&)%ltI3y2HcL?|6-#Sy z%1cS0Hu`>oGTSRP6cxVHHeqB5ZPa}3n*2^!I1?yLwuC&uh?CPnVT1=`FxdF9CGmBJ z$4BiwbzXW6nG%fx+Yg)#=*;Jxiq;U`!dPV-M73Fu6AD&kiZA-x#!j!{9(Gb7lvEI- z!66M+J-*P$ioB#eN)B~$YSWh8N6EUzD>`=N?+|9cU+5$dc*Y5QIFd{ws4&tv#<2X=I(aqZFYp1r zm~*n{{6EY{rtS0@7KinRr)u!!Q5S$lQz z3PiyOk9TF-Z-Dj-LCMu_;4bg07? zq?QdtkPNcldgAga!5uhqWSjM$guLs_>CBmR-noLh$w}`Ja<13Fb%f}VPN@{C4u6v< zF&c1(-#v@nhw>x1vs$Tig#R7@BsPWq5=ekLFNkXW2IQ;YG%_7b1bUU(ECS=zb0#7a zh9{c{H`8YBX1(E<-F?L=nz@I=t0cRJ?e7QXUY_vT>|VZb9v?=`QMp&T+!t3L{u@Jf z$pwl$i$2e9>x8WJ1eXkb%U6_C@F?Q8T~zFqtLjwXx5vAR8iuUdt@McU_GcR@|9!WY z{lHPdV^B6%*<(nc*VSMc(^bAqe=nHcCjbDimqRv4RQy4~g6aH?o_JAvXTemr zV!xDZD1RVtsv+OC%k(1W-oW7%z}VR((h^i6afgo-+i1RUodyt1l-+Kii$rH zE<_ErUh1SO<}BPY;EQy27=l|zEY=j|P@lf6X0Pis$39*_HVD$0^B#KR9!9J>2oIkN$Lc>j-}*GW^kFJ zN*s}_taEXIopZ8{nyE3VM%Xx{=S3XH*5oENJ0MEe{bx(h{(St$cTVc&e}29DG00!IXkxU1GXlS%+v85BcR_3jf?ooaHFvVZJGt)VxY$ys02ikiwKA z43ceh4Y}{CU-9UuRX`!glmE^w3;5SsB2&vQI=?M}d(+NPYo0kXa(tQZWXe$YC_Cjv z6u<5eG5rRvlhb%h;HsVir95;AX9FL7{Ap46ynE5YeZT^|s7xsrkz*d)o=v?R4C6SZ zp?4;MIat4C+#V{A5626WC8s_sMl8}vbuh~umiGxn#&VtqcS{cA8SQIFv!#X%rPdY_ zm5|GMv3YCCFD1-`z`L2#eGP~L0)S}#I4G;86Aui0>8G!5=IWtB;%91`dw?@Y=SHm6Ie%bZg z+ccH3y}otzmBpRBuZoXRwPs+nf)jHJpKOCMMI{xl_6K7*aXo(K*W>7!X7Ri)i_9k^ z7QG8$YaTb_{O1RH?)l0L4>sbBI+?1Z)Z3(P=-cEALoEfb-@IwOxIyN=?26K3`fa{{ zDkw4vd~Scs!C_|p%KHx!zk?!Y9Db7TmNxLpIJ0aey4%w*4B&grUMkms;kTIQ`V3U% z-7G~!Al%a*d!IDCa@z1_=Uzt&sA5q`O0z9yFj%-jI66F4VHNgA_muow=a zz?FA@6HKU%pIxy6Q6!6KKce(qYl#OzS@JSC)4$fi=}{jQGKxcn`W^}}ulQDn+;*$I zKCo$^Hj(=b$5~~fZpnOApSAd?yjrP2ur^t*UT3XyhzC7tPA)S`xXKY}qP((X!D_Q# zgz<8-e$4SDq+q|~Qu3wslk;n2HFGhV%}nRB&AY3#%~fPaUo^W#N|en(1?QZvp)S{G zcEJH3%;}bi3)k3_yZbLi=WdzDaE+H=Ijp^Qb;u)*v zJLE=8e3(3Z6Z!0g&66$tIqT;zKZ=H;!X@654c>u{{&M#1mC0`fN6jyt0{vaMfsd0% ztseq6TyiC+hE-jFS?}`DjWX4)KUkIVl)!tRx#xEa{&vL71m6G2{Zs$qsJ80@v+GqY zvSx4(+uDL*Q1OyJusQDHoDWXcEg3y2I3`Lwtb35=r;i}xY*dUF&7OMIhksZ^X^<%L z0M=y0EdGWF)-5$C3?k6}^r?2ndt&HD9nUI>?M_>4rXQ9LShZ{2P<2kF7Aa#PrBF%K zQvuQEWn4SBUVlmE&=eQmUpK#>PJZ}Po*Kiu?biFP8?7Rk!2(d8lSEaKEVy^82EYlv zADl!8jl%={Pyi`HV$L>R7!o&iK>p{yhkH;$PjQa#hmpP=gbpPxgHvLE!0z0@4<{gw zNd^#L1c%!PD?71YY+Q4R8uM`2erbF0v7b?rnRnf5zCKB!vX&P@TBfqQxT(Vm09gH6 z_~1=yl>WB@IRwR;&GFV&tp~I%D#f4x>y_Ig~H?njzJsL zU4QhlXkU%czGb4@t%bhNqWdm=5l!62#etRt^ok%((bf9{o!&ZnR0kRK^8x};1Yc{X zLmLDz7vm2@0B{`0p8#SczeVWb_=6CDcf%$Y#M%lI=fTmR5OmuF`7c#@O9IatN8obI zEJ_wEDwT9v-&h`R(cQ1Sk>bYfE~2Mh<2Xt3IdWUq0ozwnY#0lKRyKq?iwOj~aw~e1 z{gzXn)U1AqQ1>ilg;(&8`nD$OOpjRM1nO^ z_2-~v|V9ycYZv1u1EGQJpPqr}R85NX+3n^I&`J)B38hIrY4OK0L z4ReG|M!BxSMaV78!XZRqhfxt1xM-)Gh)*Mn?Vf=5z)V~V#zt; zX`|wp-(tC==W%=D#iJ6>;gZXy5;cm4g`?3+xA~KTE{uY>Cw=)HMfHObR4;O*2S=sN zb0o(am+JST`F8Z9fFH)5$8bU5lOh@kob`dJ22gryjrv<~1`l@{_#bJyF?rbj#JHt` zNQTVt`iW^JRr{#^d5+jN9LL36-j^Yy?(Rg2F17`xFaQ?wUfO{F&QaQIN75BIs z|NJ6vhp(Q&zVhE(-LocwH4C!ku}c5CLZqN3{{mnNA|0bh%6f1?!QVWhvUdpZy~{K{ z9uW;t9#?SQ=~3DY<;QlS1TFO7NU6$T?kfu*Nm8KdI7ri4O-ETk*iDY~M=%H`x^W4P z&A#Oc@JCZBPf$o-c_KjOu4Gl9!KTTO%rFF*s^qt4=; zX_{lsTcK!B8P~QRZ=9&_X)Jqv3U`30W^SJei#z3tfLdLiNx%Dw}n(2&E^hYHO#?E=bKA$G&i9T004xuXF(9V$&w< zGFwU+Z`@RnvFKi>W~sQzDg><ZWn3Mr?Dv~El!T!40Kak^TtELhYTRpp z6}YsYFO~C?I(_{rxSN-#1}@)NITdR>+*`os3mf1@y7o#Ow$&{_yyQZ#xv|)|{qw!a zeKb;}674M}F~10cB2hbx{0G6H5i_dsauMfC{)q@mkHw3;A}e-RP)QpsoP=R&sgZT+ zx&Bd5XH7^=*3GOXU(V`CXeid}r2HssftM9Rc>oeW4wiqofG%E=r~ospRy+>!aC>3n zS9A9(&!pcpy?dt^H02#aHrB}kbw3E_v{HTsAX(eW+4L8$y+;S1j)-F2mR+$ynz1f) zaSnS`if*lJ3i^Q2Vu(?!mWPmyey6WyxhHN3I4|IcR)QUa?V~g7eU+^LE(O+7>arz= z)Y{xpdvXW8;-~whtFiUbW%@~*qZflUFuivljzejE4|id|+X4ym`P-s@?`5<2`(TB; z_nzEyd2%=AeQm(|XYLD#XS5W-@9*W>Mm|w{h5Js9e0442sclrvlc<{Ck#C=HKW&bB z|K$FE_a+cIC z0HFetVhsxu(k$c5r(#-+W9bCNIgaIg-s#r~goU9KS_mXkxv*YgqDf)${V5T1yEv<3 z3^hV)a1nmos5!6XZnF#;0P!7k>Vybw4q(o7WclruiD87Nttv+{d<8rR{ zPS$!VwU-eN(k=XbrePKy#?)()4RMdAB=wXyg0+;)NY=i)ar;NMwj%dTW;E$wR?qxfyPoEZ_ zz&WRJydN;u8HhgD#J4T+{sim(ydz&hFF2SjV?D1Wo-v%@!cuYhhsTG<^Y^%$pcW|d z7|oU!Q34gLefTF3oIVIZ|598VKP-0fzWwZJ8C?;i`~$A)DTcK8+u(W_c5!V5#lJFc zbMn;kf6Y0 zw*;#)qQWnG(XCKL3-ZNHNYWS8rk$QK6~(YcVb%`aX^EL^f=d4RqMsm?@AGAylKGjs z;M99*`cVq4ZV?f<>s|{8TB1X%MlOvzzcT`*v*vV$f^W1z`jn$0;`r%bJeO%Qz0>9T z_{ZCSMZdD5V)E@V0j*+nv0CptWx;?P9IVvhvyyOR`Ljpk*iEv?of3@5D?ZY{LkQqQ zfa=^tj|_anRRpfbX3@k|wX90f06HsZ9dFH0OCi7H2HDw zskA{HJK4`6RE`hmqF*wWbc&U9seS7lWAB=I86nXr+u&9p#Y05%K;^Wfl^jdqjzlZR z?zb7l&hJE9o*s{LWe1-7E{;97d3pzPdftBTxii}vQzCxvJn}wIU)pS6j9p*slfKN7 z{$d`XT*rQiDfCKT|Et*nUid%^`v>+ie)XM!&pbn83WK-a<0XWLzVZye3>orykH7CK zJ;w88d6xD&nJ0|y{2sN{mwm^tgv>9x@A0p4J^wn6P+e^}oAsk}1n-uNus{38`(*^? zG;ozT%>8Us%4v~r&W)~vHK})0Yi{fn!x;D7!DWFF-MMk|s|skRo7u$!7IPCW55}z@ zObGE#`p-?iFq?#h_uqc@{r-b5p>x=KbKjGnP5on;%C(+KbDDng?0p9B^sQ&pFPwg? z4oyRpr)zj;nm$Ipa#DHgH1nBvcJ9&4f4n~kbF*KaVtOAaDDgyEL8p&VFtmPGzbH4B zXKrWi`^1B}!Dr|nPM8G7?%Tm2n6sAAEH7BZ|Jm+a3{H${eV&ny89T}Q4 zj@PLa<~}~;uC~OV{|T$RUBPy8+b4P<$Fjg!M83o zzf_ac@G6#-5%F8Fl55Qfc=JNF@6;TP5PLW-Bb$jyuL8ng`aQB##JCsel58#H!y>v+$ z13f>8bRy+jzEnb|7Le-12!J3K7vD?K# zZXd`s)Dr@C^PEFqIpQ}Tz# z)xq4Ex`|6a;QH4xbQ+&od-LX4t<@{%;r4LsP=m){so8(6zuy&&g{rQ$zu)&n1*?mX#H(wUQl(or+(U$V#Fx{X@{K0b)Yod4GqjI3mNON;iLYeo zS9>kn#W{6xXPK&QuH<43Bv!33Hn&#uZ}LhMxaLc9^2piUP+TqaEV#Ay)R!@dyjm2% z_|nVnT7_Z>KuPV&fCew*ua!n0ZLUAZy%}FCONcubwYz^q&|G`A&y`8!(q;=&ljCRx zBzN&1ms~E=7}l_M!~)K^mt{GusvagxBbQezlqn2|yBh1#(YTI4hzq&dj+BebXq6p& zE&wP-#G9+V@c;8+quRl( ze7p6(pXDx_Drjv+007Z`T@s21s!8ry615z7q*@*Tz~}|~KEkM(z`B~$2#5{~9p1c-4na1R{s?H3WQ>~v+<&XW zpbI#VB5^E`8dN_7c_;ts*Co8cP^KmHk4<2B7%8gi3H|xd2$OTZod*-+jyf@OST_uU zmxzQiWzxeIJp2jA3yH%p%4?R_jX>M+tv~3tA+e}h5-p&E;PiY{Lb)3n0zN-)KpH75 z+#%Ee=S*MMNC#t?!@%sV*RZH7b26XO;-hxQ>)-!5{nfyK_i(#;tRUR>{srQVN<3tw z3UdK0;B^q`fy$gUeGQLAuBKeA(=NM0kL3H}(EgPOEHItZokst7iaIAU!6lD_Jw9oV z4kC3Ld9&Z0y$7q4aOZnpWsp)6NeP+9yn*+XfkLt(zuE}Wj@op=+^-i;X}NaS zaWf61?44y&(j{m>htwfc;@JCMz}4|dB9(?Y+}i{oY?^Yuy0{u;hvxq{C8Lf z1;9##P=T2645>a$e0JGsZA0WL*?ZGs@~3-GT$nH29ihy^6$5*m2h65(w9ki-~GvTCX|d+pc%V|p@Uqp6e`V2HPT z^ol-BI7}kZ$aZjM{KOT`eQG%9 zO5&gs74u(-pr#j>0SQ`Bevqpfij9L&|WAvj87=zvOGi?Mqx7|ItVub zc{!bt`#C183AYQx1J&S$PQSo7s@Y2`m*i3wzy1{0)YzLOwV_4A-M@s>lRs9Pov#8% zt8(Oy1=PrzU1{6~A)xYA3bDn`Y@h?3DUYoH?STf1o^kMrAG@io8RQuAs0-&5a?pQC zVxLPAZqBd={yi*f0F2_e<$gC5ydPTSi9H@%XAZFf1Mv?>x>?U>d$yoBShU4hFynOc z3vgCDhxE8Wb!`Di@Sa0_?bGDr2$YDLq3^Cm9Dl+mFQfW*?SS>){wu$f0P?Jq+P#y} z!Y|Fq_@P^yDbo_Og`PThMcqK39tQ&%`(I|+0X{p$Ke1(elMEGrh>lI6z2@_1-uZNu`4nH zlgsF@ZO{y){^v@69Q(v7<)967pcJo^ocT~V1Rg9z+rfKNp51-u_eBHzrZh%`(ncgcAfANvsSzkNW)a1zd{rAZV zkJdXj49!okJ|G{s)kkmIem$Mcr8#U6Gud!5Kl?F5)_?c)s-1Vt+58##FXiY*l2|k6 z0{6e;zMtEqCoydEV*gG?GRYx@<`3%BT~4RIemb(Sda&j4Pg5?!P*?u*#a{8hjX59k z-=9mmPp#wY)HY*(U@d7spFE|%sq>lq_xbdJT+D^#w}%QA45#@l^9AsnE~&hp82TyP zlhqgk6%NS^j}IF{&q8 zA6qerN5hXYJ|GeR*`@`1Q6rRFzWG$uy^}w7q_LS zu^fQO;7ISPHOVTxpEJec>ceDtAmbmVba5w?lG(mln8tlft(oY{3rZFPC1;H?6R}|c zB4$}xml2_xYem};OFMs8VHS%U+_){3XZpGs1|D~@R41n&7iLmer@yHsU^37IfJi{P7*I(v6V)j2Y>G@Pm0ZBixd_iIStl>k(pg5B_ki4h!T-K zoX;jBpE;^N8-H3bHT`V4SDD>qAv*h-VsO4mM=Zr`%o=nvbPF5T039(-78 z;=?$5?fL14=Y?L+8Q7n{w7{HeltJ4C$o;`UDwn*gp{iRf1G9a#bs1cEj6oHP^V2(SU-b3i1R#A2#WdmI6MW$XM8uoFOq%*ui(Ow0@9sDv()= zdqO^v-nh+*5hw94yu!DrIw8B_S!;z{Ho%_;P>w*vZ1O3wv^XN9$(NxT(4a#&*mwfI zQ_Nn;ijui7Z6+XJNdaRehrlU+@@4=d0C_~XhNn7Zut#2<9C1&6dJLwo3b$!zP()Pt zD;e=CrGT(0R9MF1J)pe0x>560RA+U`TD9yq$POM0e1OrELEO=_4VH{@2#l%+jY^8T zK(^-NI|_15asn1KQzN$pcdrgwt5IgtnjR=>3)^2Y^8E`1Y<@sMN|?rO6nRbhGYfP$ zPfbSu6^ZNZH8=7r*Q8f6sK-Lt>CY~Q08g3L4C?q(SYb=5h*DEx;up~2Ev z-lCm`vZwYy%qM7Sm;goK@fnlnfmKE)C9t{x0V7~KkHE3}vB%Y< z_#g6s*8OMz-mVG%SOlmeR4e2!tu|RSt0JmZVg*dW0@(o97@C)m^yCNguWH8{R~inw z^!jm^!&VKVs|QaAO{F{r#H6FE7BhR12~N*q(+a3qW+{*iJVA zq$UJ+b4OOL)-q*`{ZD&Zp9Qi%&9;0(#+H;be?FM`yypM8EAg{# z`Dd~Np3;#E;Bf>;>^rfcbhE|&9}ScV!>xjb=I@p&ZbQ^={Axy;3vo3-qAf8%sru1 zIXeB_zUMu`LvTOo9=noPQdfE-N_tNedL6@w?iIZ_p1z5}UWe68I-F8mNneC%U!r5L zv>PFnr$2b84;|i>6WuRp+OOx;UpU*(R^Kn#-CwFbKu=|GH~HPz?L{rcRuiM zaDZiXpuus_Uuv*vyRWrl&?J3Os%o%BG3^+-*W8S3Z4ui_YlVj;Z0{pFhqmc}6xM?gZeixzdzczU7k6;InFb{!2k zsH{7vW6X0d>gsP~j=J`gl{%jrEixLuJ~Z@gOOAuvDk}8pV#I`j`fX5F$NR&!ge`A% zWUwHr=eE;iic^%&95QDkm!Rj4|*+*3KlCMFD|hhhZ7_y{EY*nDZKht69`Zm5c-O zxo{=;;Kyq-*sxpia&-6)Od9ZNEX}#}+__WWxS3Y(F)*-j36P!yTxs`4%xsI4c17Up z0W@19uoGPTPjJ#;Sm-SehT0LD*9+);d|?-)(&&KE1`0U?-e|Sld+=TNUbOK=@YDtG z^0mJ|o6v*z%QLx?)}^a!w^p|WSMABGvqP&1ORKKVYolUo9vQ3NpVm4bt;JNW1@NtxZLS6C zt%W{ZZ#7&Ga9@v@U$3uO_wQPNsIyT)wUJ7(o>01x?z>?txRFZUNa)?LS=z{Q-dvE_ z%uC!T__R5by!kX}rG#(m@y4dU-e$$atwMvXpo-1f`K`}2TYBzWZ*+cfQT{6J-fAxW z6%+JJQSetg`PZxNUmr7m;hndiift<_{p$I&ot3!#7PCFX_xtLf?IiH;(TBfj41Wt$ zY){Sqj;Q)Q!MHWA^QV{b4|CV=mC`>RUgSUPLBF@if4F=8Fva~LIqx7vc3^rtN1t}Y z5_jfT|D5xYYFBs2G;YOnVNouPkop+KLb$9KcyE|YK>+{_xuU&zpU9Nw- zx4U;Y1$GfGdsaew!b`iNpZ8o7_uQ)Yr1|%6tnRI$_7r3GaeDi!Zu{y#_p596ODXqt zbPr$@2PnBe`p*vnybkPy4vhaDI1vxNcJ5#bvOphsWghtcJYuXmdJj4Z(*4T`{>$id6!!e@L-)Te0)M0a{iW{u+Zz8D=W_g3 z?AXlkIO+2-HtzV**Q0d)6U*h}cjU#tIWZ@HP$vy;Cxt&xewLs7D?cvPJ(UKZrih(Z zK0j^qInD1psrz?2)_V#|IBjq_yCQhj1UqT{d}bbZmREDu!GCVMbC$h$+7)v?Yj~dJ zcHZ~%{6+csp!wMs-3t=vqD<^!{Q1SA+eJX^#gBg%sO}4crHcg@@^=C9GVFZqGnqDy z{IZ6;&Hs;LiR{yPz8CY)0`)k)y6Skg~r zlW`^%S}Yr6@Lqig<+QvkI*FK->OZwyH7<~G`jo(FwPsqR5;#wMYPEj7^zt+VT2`Aq(@EsILEf^i(`PnjE4uN^=8e~@#lMDpq;@!Z_=960-*ulImzs(IVJ zlMqNKk(SVf(0lKQB=ioU_ui#SQB+DoR{`l=qzb4YAWiALOK(b*Dx%Us#c=XG@B5wi zd~2QmnYEIAt(m#A_nssx*>nH)H8mP;1y(2SAD`cjB)MsQ>N#C5Z=vzr`s~hpim0me zO`CI{PmR871J7+P{8l+^u1Q#JFAt+1Jz~==wEY#hGyWVEUz2|sygyex8va-6_q`u0 z?U4{R`>W8Sh4B}fFFG9WRcx(v#2_625vcOjEw|&MfJkMU$ z>xy=QCH2IKN9*+@jXqCTiZ8gn)0bU~nJJgtEt7mJ_4J9P;q8m9cZTBMz*3l&A6z4b zs+8(dM(UFA1|!XUj^JW--tq=xUD53yM*6aI%5Yv~uU8VX+JcZENAjU?ME+^MRl zne}>YN1J=6x_L)o;&tZ$`F_nHPwN3+w?@85-MD+JZ?l`;tslzoB3k`gf7W39+RLq( z{X4Ho6g%1>_h0?&q9nL;?m|6m`Fj!Zih;vk-fe-UtS=OU#$_!Q11D&E3WBCId7rw15;{USX8Wp{rqp0@)Z`V@O@8@ie85fQp| z+oI#a*9!l?4@OHXlpcMTZ0-m=XojG|x?26O9vw|+zVJO}ltqPKti5;`-t#%WGvZHV zR%F2MpSzur=_hNS@mI2FkPZd*A*~}2(b5%h6XQqf>Imiz6@d)EqGmK9TX?&-dC!MWlbeY(QJPF z5UL^5bXU=Wo{xN+Tu2!1hZPf?qZtLx(;8Aa|YF38YWo1b>NxForoEdSeVoEG?&bsHl>%Y zey{K7Ol$jT%U#an>$pG8q+nNyTmH41L2%Q%^!+lrTPyO0T0JIK$7LQ$5U&Z>4U-qw zvz(~NZ9^ud%K6RQZ_B2H{(z@ax+T2*AUNi8=-ky!I&v( z)|7+WOUKaD*r3?7TyzepE4yu+GcOe-F$dT8{a}IzeK|E!*!IHw+%>UgG^x}K;WT0< zHZ7Ae3)4ZsO`a>v9VjC#HOlXpmwK9^was2TaI;!`+cK-o3c2rGPHQ#(!F-`O#LCjm z+tz4rUb4!p=Kczc-MFho+qrb$Lt$EnzY2@JzP%jbT&-uDWISGNQ+wOp`kdXJWmi=0>*wuZ zLqBZZ+_}x*Z?k2yPPc&VX{Yx~YPB6_mwo@r#V^=n*Orpn;={rmeaJ0WyMucdgrq6e z{q|e-fjA4t5pMs7a~}32k1g7NhSNRz{M7yuKc9W)_>4OId#gkFMzhoJZGS9o#{u7B z(FJiw;4WMo!Lo9uWb>5KHx-?9l`owEF9YIa-JQ;~EPL5x;PEq?PE^^Jh8!A{kM-M} zWsBupC*AHQYVJ6nR9X(mp3@|~b#Y<2u+&j#y74Sr(UlYUz>R??Fs9j$Xb&`fo?;Yh!wXpZ9v!EGbc}m&S@o8u6uWXZ9SKaTowQl}+Uum;?F;CWBN8}%N@ksu6^3(Rew-28K!u+~;LVLcs z9KM3uZct{E_EvofNU&(*rg=fuFWhlA!?D2sYA1Av{_9bNr|lN+0@W}%Brv1dR$M?- ze$-Csq^B!v8(Q(;qomhKd5-Na>OOP=#T8UUA1{j7epV*el? z(k>`!_-oRm^`!8A*jF>rhr{U+XX8rk-y9+j7Cj=)-@g63>)-h&drRr84HBUjMw!1( z&&JcckbIOmL9^BD@oVB|=&l=OxS{MdYId;0zs!Jn1iRQnN^@~DSDp00ggqfGrZ z7uojxTg2ZT&B(-6)U{{R^~Gsqv8wY4un-W!@5@iE|Mo5_&jDp7~(ZcEIe3TJ- zCALt<~};s1Ld2`C?tgv8w))LScx;3o=Z=K{R+jie4BfWo-a{_ zmjx|QaGRftL1;`xP!TO+ds`T+x_r_DVd%FDdra0T%x!J2U)`|l6y{GL{)@xOf>Z?=jQ#<&e?%MY{s82KTgH}dgd1;@H&My~xSLH!oXEtVPm%_jZyZ`5Cw_S>4a z*lnpto%B1LHao&K!tk5}&Kb=vY8v-U1_<9V_h5~H=mF2!Ca*G$JMRX(gPVM2HC#6b z{NPRgU`>14!MhEOfl`{5s)NC%jUld@#zBMk-*nitDL;s532hkE?HvqDYzW^PR6iMv z6l%c2hfthDQDc(AQh=BPS>U9~O-HS;O`z~H2{2(O^cL24vL~Ei4rn>_^h$XlNmgm9W$H*F3idp&TAOX@6#?R9xm7#E<7E6p~qJQA1USHo@ zNGZNE9c>C84Q}R=Z;BaxUpD&TRQi3xXxr>)d!Izx)@UbqtSdvb6F$}>HP-7Y)T1`m z?>aUh#or%1Hk2_oe84?aHa6NfHYUX}Iy?69bZjDw^&@zEifep23^}7VK5IIDMLj+j zJiZV!9{OZ_scigHFvsV<@#U>rEC9g%3k)6t5VqIk+N!F?nkt&&V&W3l005}S$Hg}Y zOfXCI^$QLpG$1XltdWo{Le>%ipa<{)gq&Q00+cZrJwo(!vDP1f9Uj| zs$s5fK`w+mI+D-gz|?0m$;dwCg`Q>>usx z6GAw+f6G6oNa5yZW%YyyUKrv zXZklDLx^%FM0o*R2oY)ke}FH*>EC$3KW_q|525_e;0C!%O8i>|q)-6>h*z(#Pq+a9 z2!Ubvn{s{qr}+B%ZwUZEvieHc=WGC= zIi6sexfI|O==AT7hzQRhcXt5bxB>uxSpfjFlK=pj4PoR614k(Tv;#^P002|MVCjtm z0J(Vp0FMXZ#clt?i9-ni|9jy6pMCy&0RQ>K>TBw1V@y@W2t`CrMOz;X{%5}c4i=Cs zfJ{P6LQGg(LRdnA1*8bLAttUMC8Z!OBmA!b2%!OF0A2_T91myUU}WKDX5)u52*8=- z1(-QlIRu%wIpExi?A#&(e4HG@68yr_+=4PZ5_0^~xA-JvC8TfPl9rbi5!IHJGnbb( z6yo%esAVb@a{Db&U0lt&GiVt*k99^)>y?wJhvi ztnFM)ES$8B-0hq_O+6ksxq7>M`Q7mea=&xe_wN1Rdtss89wBb#Iub_7W>T+w<)1sr z#=2{zhngn^7`=L+|Ky?P6FZ}x`(lj=rg@J&GLu7Jr}~y8x(=q8f2>yCpk#J+|@4GPsxN>5&}jnfx#;D&+p-fZ!}^uL_%cAIw53 zeePGQ+r-*D>d|+<*1vOYdH34t;kB{8&#r=MzB?9w z_aDQHj9f>@K8Z_6%+8N{nw0h=HY+JTJ3TWmJGUS+DYY&sCAlP{t|}`j>s5CC%cSg< z)bzI%Ij@@XEAvY$lFMt0OJA0jS5>{Lc~xCs{jRyO`NR7U?e7|z-&ejG$;%kbPMm(5 zK2i5(=fkV@S9#Ne*%Py`CKg+!Mr;1geK;Dd$FG+^dp`Umw=cc$V@&H}%A3jdj_!um zo{D#iZ{AHmNxy!bbe;VE=bPrUH!p@KYQN{tEI%Fm+}1nrc6#aQ!0+sjXO;7R-cB91 z?BeV9uQR`1_4E#mj(!{%93ER59T}gVSX>^PpP!zY`}BEbVPR=;a_HBmzTK&D{Pxh* z{`~dD((c~U+S=hA~ z-_BtcA!adRiyk$Ud_=kJQ+mzV0N1bWc>%9KxJ z&U}Yrmr|ETYV`O#k?#I6<1bvsL_Qyx>{)Q(FU?*Gw={9FruwIiV!C?|-XYraI%-?H zf6f}Y3$g_lMXznZX3_K=m!;$0)a=+H=~~M`)j)Vl#T165tGNsE#I}w_Z|b(#BoWvz z7U_1z_=Qp^Q&EmhOGr*O?IE=}eCCM-d)l}lze**BzQ;Cw9Hj^M07?2$gI$z8xn0>+ z!FM+ENG^p5NEh)E@8?vge(t9%V-9z=Y{xjSf*e=(^CgMOfF`|MpQf)n`BheNpR%ju zCu8ki1A@k>4H?nf$|CY9Wy+kMjTPweuNumF3%2VvcIB5P`ob(3eQ9QqOkBn2e1Wb0 zVl(42Vo7~y*>-3K89cL!oB<@DiqB;|{YqVTW3~#d?)9|`W5n$Rw>D>tp))~G!4GO6 z;l(f-r&Ny-?#w+dw>KWrrsh^qp%mA<Aq>MKXlVkQPRGCGjvr8*6^nRBc^MPN5^KbNRJ);4I*P?xd`ReBd z6;dbFCANJ_W}w5i;v|w5mVGNoK@NIZQG7%Bs{tWu^OunKmM5JS!Yz{Jo?lS5@j<@Ze#{F1l!n$RV ze1=4gpl)Ko1RMU%r1tkKfa>$m;_$7LF3_C#?U$C%?vo>N9Czw~;Gv&nRGuFZtdpS4 zU(pdt%dzJ%7a2hNQY`2$@M|9@;+t2Bkx(0kJY<(?bb+qfcC>0ho<_w`5TgAPs z1WrzU5f;wt2j9_Dg(fO97#uGXC5NIqE)Qc@7QsLLwE9Hv1RxWN`k6DSr7jc!!Xk-V zyDFM}%x>#MYO`@DPj;fU2XCeGkz5V}YFwm6U~(zKDn?xu=_2S}ww)o8?_nO;ktOwX zQlD+XqP-WGJ5;jo*6rwRPAG@!u*s7w94Au0I@h6tP=2E)$e>)>zkEOtrDrlMOm9F< zYPjbPy1n?C(FcPvkvgx7d>-Sd53o?;k|uii_Y0L2_6>1g8MBFHkxoi_65pbh0{JDr zhlc~#{R>+o^IWdbJ6M+OQFl+>_tOIei}C(>+1-tLGUl1CX=6d!@`AE7RB#BXNaO7fF<&eKgeN@C!*6 z+lW;7QXeg$91qI`96Z<>R=Y1qg({_M2BC4?_!4A|nr}H-be?VSUMb*NeY}j1z5wxQ z5KNcPh1n+2M@B+9rh*}h*=I$EU3f8S4p*b-6^o^pse>2>aPp^0LmY}T43=$)TK5CU zbv_t9H2`xmPs`_fsos}Tdz^zzmW(aSD4^iE&mn7((Dm!8+qr|`{6kuaDZY+wvcMuS zC+Ks6h>6FyMJudUJtOk-qlH(kKC90{6EWk1{a<`;6*q^b*pJF0LMoc0g)%!LHc|j{oU*0Zu{Z{C2#@X$lfV4 z+Yvnlc?HbysJr?~IXTZ}c6ER3%?{Sqytks&Qz_Me^|2CXo^ZN@#^;Ld{q`aXyp9Td z_+B=Ja@LaDJSWuePN5se|<~{j$0c0jD+2pc} ztBcq+vzh@_9ewWlpvzV>zu{SMYOX54mB*=b=hPYezdz% zdEZV!SYeAEEc`Qdh2b`9VavS?^QTC}7WopiHS_IcfuilE^1?dyb8F4r%u$gaOJK#2)P@Zymn;Eq!BEYlKwDPKHmM+?Tm9J`8?~o$hhD$-!m}yd!m6hef13Umi^y zw-P+oXd)Du*xUcsmkDdGiKi@0$>Ltsv@x!7R^ z7c%v!-T)){m*8?xxP3?dU$A*(_(x!&)&cO5vMCZrRAvv-RtcwF2dqLAJ|Bh`oddF> zSvM*I8zFZ{E1-*$U|ys%SJyp0C+75KB-8y{pu2#d7W&;d;^nl5(Q!17>cd~Zd!#RR z^UM9PKj~n;P_UI|lqkfB-wBu%6TwFvLV{G`vc&x@_ERAE)Lk;5&ZxCRW9W`3htYl> z$BbQFF{YNWzV$KYm(+HLlrKF5NG7p6a2D+%was_Im&Nu?0IeEz^1Tc=E7*Lolr$3q zCOTp!DS_420v+TS5NK{47h+?HTQE!3KdGViT`;_*7$5r{aE6aDPN`vtbYg7Unl-d75BKp<1qWF zzqmifMXR2krJ_<#V*m(Cc_bz$5#eOmSPVRfN<=uq#g)n9(d6!WHl0bkwP+F7cwD9Equlkk%KJur3h-E;+kTSy>E~4lp zHHkJ&xenDwAGw4{dnaj5UX=ca!+*exN~Bnd>r!+Fovr~%O>G8DGy%{jEHEvn%poAv z9sn)NwXp$cTLiCPK3lkPINGffH z8%W3UV|dsR9I|fo^&*wH3J{(aoA--aBh>imyIdY=lNTF|+a!4}ALJ=C8drV=C1XTv z=-u&07K}w+W9AH6>`o0S6y{hOP+wp%hk5lc?X?X6C{zq`nMYkK=%E}wT%MIh8>n6f zdRzpv6r(bBA&%yWpv4~olT&B`lKNhn*!XFH=%%}{qw+Wx%KR`2h7o4>gwH~-<#Q~b zx+pSK3h|DG1S`C)VVDs%_sf|TnFMa#GpyCv+9;P|;u44P^6s8uMi*-)Ou~HW?{X_k zT>^9If*nm>-pB9&VYPy!n2ep!!k3!ZeL1S>T-f6rjSp7b^RyHeNKhhxTwfk|^q{Ek zSFy(wfys;t6=Ohdu~`$YD?*+}AD8ZHM)O;QEB7+992&lMQC~r4={;88N7%-z6>!dC zV%hW8p}=P;B`^l}sv$6jF$?5mX^s?Wf5$t)>-m~DdLN>q;01)d<9%cqgc$%d-Y*;| zmjbye<4Z2c#Hg4j7wCD>ZU?-q@9sYwkgaIhfFWa&hdjzj=Dleg zHPl`{xdGsKfhhKdq&|#?ISl~RdI2C$f!Bj&w@j#_il5+dAUdwh%Oi<7&AW7_DG}DL z@=!RFBfud5#?~KCUPRKaC0fZ3e?A-o{bXXf$FL;8{i4b*pPFVxq56wL&6bWVPd#k0 zks>VZPDmr9poj(FLjDNJKW@&jT&1-|Bc*kuQ+7&OGD#ZofQo2K!Pq$`v7WRI<70Tl z{QVPT#L4wd5ou2fxIT!Zrp4tE5=Ejd4xZxJL0}@vVNH%CC+g%h9=DsiNZ&G`PXzER z@O9#{bucvAF}DG7<278ynY<>!E%8uY<~0k^sT63({RPL{52ZApLZKtG#fTz}B>;IT z7N(MG@TT7-yoi*5u0|XRfR30yb=hWPwB8#fJqauftt6+=w8#%2`DvXWao2yq4Fb=z z?T%RPcAyawBKxrB6QLL4E(E>!0x1fv6a@j93}c>{r{d1jNpM4Lmg zPTYhfD-D2|W&}1Vi2S)rR#8*~c}rRN9B22n#DOlQMa%=|nF{=OnNH+P*&P=G$V!W9w(h%@is?SW&ofJB=~H3o zDRK;0TS*zXTK|}|Ru@0|DDY6@TfNC3S&gMeS&ZG2sHl4nz4bCn=Dl8&kB}9J)g`-F zsFi>OkYzFN)3b==Mdq1usane##mOr~+DmWLrns{>YSB@l{x(3uidc3Z*yW{A?1}rs zXlfzsDhpkxF7n_&0w^`d#SyJGioWcED#^COzKQ4aW5JT1bv!*rZW!hJa zedbV#JI9RIDSd`=)Ln;^`FDBLSo#V4TZt38dqY0#$dJ4NVJZeJc?mNGJX5z~pv0On zrf3bgKU{tQ`!th5R+rdfo~hJ;%H>j%YU*E@>~|z(X)2->Nnyq}B8ivYu}#9&6RC2* zskiZH;>Rhp$~NRC*hJkqQ1UvLewVdlVj^5@D0%eO^su6%5UcPcd6q4eFjn({5YWvm zyqf#YgEzx#M%kDXI97q|Cnj_~n}!hp{2UB>T3}0g2vwD1-Km4=)FL-J7MAT_VzuypiG5Hf5r zjFWiyNiFk7>zjX0MwIKA3^<6_L$x;>w1qBwOgYqrwDF8w0h1w#0HNBcJX7VxThg=v zfM@ICSq%nk;H)?fV)}Nz7^a5Y1D|$B`Uw|h(dWukwTWvi^7PdyBmtliN84*|-5JTj z@9FyV(|Pyy&72?bWd*B!P9atK1VGYI;8S3)y1<@Bw`QzDl_(~DcJrx*#n;8ls@7bkhK>kymsFLQs_NjBD*oi-FBm{h~^R_L}gBDUN> zTUvz-d>H!MeV@`lZ7>%a=q6LM9jbgnzDFJS61lRb)o$;)YZx4FQ{U}1wBN3LAfoca zSI53aRDIo(b=PclCtZ1$z`upA(nf#T#6Pg#El{BzS=lwS+!E;DO;Fv7D)fCE5p%C& z@6!l%z>mE&rLV};wTy_bKFMG6I=&JX)qc6OSID|wqO@OTzrXz3xX5q+Rmc9D)%_a$ zel6>_`UqoHrEg6U-<-*d@Iyf;vIFw$`_wz@lH&(z&v z(lGGVTtyD>Lu|b8`=^fY%d6k@#kZymw%+^g?Zpx8Bois7{7~p3+Fkwe1OMZY_2;qD z&r|!K=Mg_I3xEEu`6-Dc5?KEZU^@h%4#C%(Zwg~JR`(SIxD`Gf-nc%byarIAj^GYQ zw4z6lhjdXT1>AR!D()PybqW$(_P8AI$1p-}Cy_`1{eyVzSmgRxjP0aM>40k*F4eit z^WsFI^F(p&MCtkjjUu`hIa$^?)rdURdU5*r?#bfF@e`**6N*z~)S0QnnfcEX2>|FV z{vhNB0gO9yWIK0yaY*^`)I9Xe^Tqj{&U2+_M70Lz_>Hr?8yC(F7xy}sgt(a-BQDZD zo=03?V1Hf!mJdGbTu}a43wv?-BvRHL#bmH{ndox)RJ0H0@GC3w*Dcg#dgm`u(O(7E zztTi5f>cjZQ1pfVemO6Gzv}$0@Eafv=&PXoU61!2W6%DS;3rH5uTQ&_u4Wznnq33>C$6T}u9nyS=6C!JrDa;! z|C{0ecPA2m>&0IhCz`D_ye1|7hv?pok7wbu*Ulwdhn@J{PQX|ZD8hjTATE$V6h#bU zRm;I_sKmi;a`e@q{{`TZRYJPH{Qm&BykNrI<^K(Uqk)}*nN0UE{{nDKGu?yb+W!J@ z`=)99RpxHc#3iCAsHv@_Iu%25{0+SLOp}lC606(Ibxd8?h6I9y9Ub6!$5EvP`kvA(25OkszC|Brve|2F`~PnYqOY7xas9D60$80^#2O>(^v zTI9S$@IEw}3rV?Lr*MoqdU7ZKuz4-2@jH#}p=ew{{4BM|rYmNqK8~94mds580C&9o z4*+NX_u={XmDkO`?IS+Ajbf{j39!L>qZ`=o)Z3z_mkHyYj8q@KeIUBIUP=SW*>GYs zVzC4we2l%ufxcg?H!|F^N)O@gS-Hh&J{n<;xA1tK+O*roL5?J*Ia6v#NDN@7_k)zS zw;=nz%@3T?{;gOf!dH6%0D^-*r!aWq(EQF9SqK%Rob{CFoQ?07| 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

#x8DE9|hu7He!*?H#M^ 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 z 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 ibAd&CM3mIzQ_g){I?dmzOz+(Z6N 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�L$% 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

!*X_>=^b@}G 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

C~!OFLC#D8(8*2=SP3h79nHoKX+ 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 --name +``` +- Add local files to the dataset +``` bashtrue +clearml-data add --id --files ~/datasets/best_dataset/ +``` +- Upload files (Optional: specify storage `--storage` `s3://bucket` or `gs://` or `azure://` or `/mnt/shared/`) +``` bash +clearml-data upload --id +``` +- Close dataset +``` bash +clearml-data close --id +``` + + +#### Integrating datasets into your code: +``` python +from argparse import ArgumentParser +from clearml import Dataset + +# adding command line interface, so it is easy to use +parser = ArgumentParser() +parser.add_argument('--dataset', default='aayyzz', type=str, help='Dataset ID to train on') +args = parser.parse_args() + +# creating a task, so that later we could override the argparse from UI +task = Task.init(project_name='examples', task_name='dataset demo') + +# getting a local copy of the dataset +dataset_folder = Datset.get(dataset_id=args.dataset).get_local_copy() + +# go over the files in `dataset_folder` and train your model +``` + + +#### Modifying a dataset with CLI: + +- Create a new dataset (specify the parent dataset id) +``` bash +clearml-data create --name --parents +``` +- Get a mutable copy of the current dataset +``` bash +clearml-data get --id --copy ~/datasets/working_dataset +``` +- Change / add / remove files from the dataset folder +``` bash +vim ~/datasets/working_dataset/everything.csv +``` +- Sync local changes +``` bash +clearml-data sync --id --folder ~/datasets/working_dataset +``` +- Upload files (Optional: specify storage `--storage` `s3://bucket` or `gs://` or `azure://` or `/mnt/shared/`) +``` bash +clearml-data upload --id +``` +- Close dataset +``` bash +clearml-data close --id +``` + + +#### Command Line Interface Summary: + +- **`search`** Search a dataset based on project / name / description / tag etc. +- **`list`** List the file directory content of a dataset (no need to download a copy pf the dataset) +- **`verify`** Verify a local copy of a dataset (verify the dataset files SHA2 hash) +- **`create`** Create a new dataset (support extending/inheriting multiple parents) +- **`delete`** Delete a dataset +- **`add`** Add local files to a dataset +- **`sync`** Sync dataset with a local folder (source-of-truth being the local folder) +- **`remove`** Remove files from dataset (no need to download a copy of the dataset) +- **`get`** Get a local copy of the dataset (either readonly --link, or writable --copy) +- **`upload`** Upload the dataset (use --storage to specify storage target such as S3/GS/Azure/Folder, default: file server) + + +#### Under the hood (how it all works): + +Each dataset instance stores the collection of files added/modified from the previous version (parent). + +When requesting a copy of the dataset all parent datasets on the graph are downloaded and a new folder +is merged with all changes introduced in the dataset DAG. + +Implementation details: + +Dataset differential snapshot is stored in a single zip file for efficiency in storage and network +bandwidth. Local cache is built into the process making sure datasets are downloaded only once. +Dataset contains SHA2 hash of all the files in the dataset. +In order to increase dataset fetching speed, only file size is verified automatically, +the SHA2 hash is verified only on user's request. + +The design supports multiple parents per dataset, essentially merging all parents based on order. +To improve deep dataset DAG storage and speed, dataset squashing was introduced. A user can squash +a dataset, merging down all changes introduced in the DAG, creating a new flat version without parent datasets. + + +### Datasets UI: + +A dataset is represented as a special `Task` in the system.
+It is of type `data-processing` with a special tag `dataset`. + +- Full log (calls / CLI) of the dataset creation process can be found in the "Execution" section. +- Listing of the dataset differential snapshot, summary of files added / modified / removed and details of files +in the differential snapshot (location / size / hash), is available in the Artifacts section you can find a +- The full dataset listing (all files included) is available in the Configuration section under `Dataset Content`. +This allows you to quickly compare two dataset contents and visually see the difference. +- The dataset genealogy DAG and change-set summary table is visualized in Results / Plots + +
diff --git a/docs/logger.md b/docs/logger.md index 7572bc01..58842593 100644 --- a/docs/logger.md +++ b/docs/logger.md @@ -1,6 +1,6 @@ -# TRAINS Explicit Logging +# ClearML Explicit Logging -Using the **TRAINS** [Logger](https://github.com/allegroai/trains/blob/master/trains/logger.py) module and other **TRAINS** features, you can explicitly log any of the following: +Using the **ClearML** [Logger](https://github.com/allegroai/clearml/blob/master/clearml/logger.py) module and other **ClearML** features, you can explicitly log any of the following: * Report graphs and images * [Scalar metrics](#scalar-metrics) @@ -19,10 +19,10 @@ Using the **TRAINS** [Logger](https://github.com/allegroai/trains/blob/master/tr * Message logging * [Reporting text without formatting](#reporting-text-without-formatting) -Additionally, the **TRAINS** Logger module provides methods that allow you to do the following: +Additionally, the **ClearML** Logger module provides methods that allow you to do the following: * Get the [current logger]() - * Overrride the TRAINS configuration file with a [default upload destination]() for images and files + * Overrride the ClearML configuration file with a [default upload destination]() for images and files ## Graphs and Images @@ -30,7 +30,7 @@ Additionally, the **TRAINS** Logger module provides methods that allow you to do Use to report scalar metrics by iteration as a line plot. -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/scalar_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/scalar_reporting.py)) with the following method. **Method**: @@ -101,7 +101,7 @@ def report_scalar(self, title, series, value, iteration) Use to report any data by iteration as a histogram. -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/scatter_hist_confusion_mat_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/scatter_hist_confusion_mat_reporting.py)) with the following method. **Method**: @@ -199,7 +199,7 @@ def report_histogram(self, title, series, values, iteration, labels=None, xlabel Use to report any data by iteration as a single or multiple line plot. -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/scatter_hist_confusion_mat_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/scatter_hist_confusion_mat_reporting.py)) with the following method. **Method**: @@ -325,7 +325,7 @@ def report_line_plot(self, title, series, iteration, xaxis, yaxis, mode='lines', Use to report any vector data as a 2D scatter diagram. -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/scatter_hist_confusion_mat_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/scatter_hist_confusion_mat_reporting.py)) with the following method. **Method**: @@ -461,7 +461,7 @@ def report_scatter2d(self, title, series, scatter, iteration, xaxis=None, yaxis= Use to report any array data as a 3D scatter diagram. -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/3d_plots_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/3d_plots_reporting.py)) with the following method. **Method**: @@ -597,7 +597,7 @@ def report_scatter3d(self, title, series, scatter, iteration, labels=None, mode= Use to report a heat-map matrix as a confusion matrix. You can also plot a heat-map as a [surface diagram](#surface-diagrams). -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/scatter_hist_confusion_mat_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/scatter_hist_confusion_mat_reporting.py)) with the following method. **Method**: @@ -689,7 +689,7 @@ def report_confusion_matrix(self, title, series, matrix, iteration, xlabels=None Use to plot a heat-map matrix as a surface diagram. You can also plot a heat-map as a [confusion matrix](#confusion-matrices). -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/3d_plots_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/3d_plots_reporting.py)) with the following method. **Method**: @@ -818,10 +818,10 @@ def report_surface(self, title, series, matrix, iteration, xlabels=None, ylabels ### Images -Use to report an image and upload its contents to the bucket specified in the **TRAINS** configuration file, +Use to report an image and upload its contents to the bucket specified in the **ClearML** configuration file, or a [a default upload destination](#set-default-upload-destination), if you set a default. -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/manual_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/manual_reporting.py)) with the following method. **Method**: @@ -929,7 +929,7 @@ def report_image(self, title, series, iteration, local_path=None, matrix=None, m ### Logging Experiment Parameter Dictionaries -In order for **TRAINS** to log a dictionary of parameters, use the `Task.connect` method. +In order for **ClearML** to log a dictionary of parameters, use the `Task.connect` method. For example, to log the hyper-parameters learning_rate, batch_size, display_step, model_path, n_hidden_1, and n_hidden_2: @@ -938,27 +938,27 @@ For example, to log the hyper-parameters learning_rate, batch parameters_dict = { 'learning_rate': 0.001, 'batch_size': 100, 'display_step': 1, 'model_path': "/tmp/model.ckpt", 'n_hidden_1': 256, 'n_hidden_2': 256 } -# Connect the dictionary to your TRAINS Task +# Connect the dictionary to your ClearML Task parameters_dict = Task.current_task().connect(parameters_dict) ``` ### Specifying Environment Variables to Track -By setting the `TRAINS_LOG_ENVIRONMENT` environment variable, make **TRAINS** log either: +By setting the `CLEARML_LOG_ENVIRONMENT` environment variable, make **ClearML** log either: * All environment variables - export TRAINS_LOG_ENVIRONMENT="*" + export CLEARML_LOG_ENVIRONMENT="*" * Specific environment variables For example, log `PWD` and `PYTHONPATH` - export TRAINS_LOG_ENVIRONMENT="PWD,PYTHONPATH" + export CLEARML_LOG_ENVIRONMENT="PWD,PYTHONPATH" * No environment variables - export TRAINS_LOG_ENVIRONMENT= + export CLEARML_LOG_ENVIRONMENT= ## Logging Messages @@ -972,7 +972,7 @@ Use the methods in this section to log various types of messages. The method nam def debug(self, msg, *args, **kwargs) ``` -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/text_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/text_reporting.py)) with the following method. **Arguments**: @@ -1010,7 +1010,7 @@ First [get the current logger](#get-the-current-logger) and then use it (see an def info(self, msg, *args, **kwargs) ``` -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/text_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/text_reporting.py)) with the following method. **Arguments**: @@ -1048,7 +1048,7 @@ First [get the current logger](#get-the-current-logger) and then use it (see an def warn(self, msg, *args, **kwargs) ``` -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/text_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/text_reporting.py)) with the following method. **Arguments**: @@ -1087,7 +1087,7 @@ First [get the current logger](#get-the-current-logger) and then use it (see an def error(self, msg, *args, **kwargs) ``` -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/text_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/text_reporting.py)) with the following method. **Arguments**: @@ -1125,7 +1125,7 @@ First [get the current logger](#get-the-current-logger) and then use it (see an def critical(self, msg, *args, **kwargs) ``` -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/text_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/text_reporting.py)) with the following method. **Arguments**: @@ -1163,7 +1163,7 @@ First [get the current logger](#get-the-current-logger) and then use it (see an def fatal(self, msg, *args, **kwargs) ``` -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/text_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/text_reporting.py)) with the following method. **Arguments**: @@ -1201,7 +1201,7 @@ First [get the current logger](#get-the-current-logger) and then use it (see an def console(self, msg, level=logging.INFO, omit_console=False, *args, **kwargs) ``` -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/text_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/text_reporting.py)) with the following method. **Arguments**: @@ -1279,7 +1279,7 @@ First [get the current logger](#get-the-current-logger) and then use it (see an def report_text(self, msg, level=logging.INFO, print_console=False, *args, **_) ``` -First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/trains/blob/master/examples/reporting/text_reporting.py)) with the following method. +First [get the current logger](#get-the-current-logger) and then use it (see an [example script](https://github.com/allegroai/clearml/blob/master/examples/reporting/text_reporting.py)) with the following method. **Arguments**: @@ -1371,7 +1371,7 @@ None. Use to specify the default destination storage location used for uploading images. Images are uploaded and a link to the image is reported. -Credentials for the storage location are in the global configuration file (for example, on Linux, ~/trains.conf). +Credentials for the storage location are in the global configuration file (for example, on Linux, ~/clearml.conf). **Method**: diff --git a/docs/trains.conf b/docs/trains.conf index 9d5b2df3..552a4488 100644 --- a/docs/trains.conf +++ b/docs/trains.conf @@ -1,4 +1,4 @@ -# TRAINS SDK configuration file +# ClearML SDK configuration file - Please use ~/clearml.conf api { # web_server on port 8080 web_server: "http://localhost:8080" @@ -16,12 +16,12 @@ api { verify_certificate: True } sdk { - # TRAINS - default SDK configuration + # ClearML - default SDK configuration storage { cache { # Defaults to system temp folder / cache - default_base_dir: "~/.trains/cache" + default_base_dir: "~/.clearml/cache" } } @@ -103,7 +103,7 @@ sdk { google.storage { # # Default project and credentials file # # Will be used when no bucket configuration is found - # project: "trains" + # project: "clearml" # credentials_json: "/path/to/credentials.json" # # Specific credentials per bucket and sub directory @@ -111,7 +111,7 @@ sdk { # { # bucket: "my-bucket" # subdir: "path/in/bucket" # Not required - # project: "trains" + # project: "clearml" # credentials_json: "/path/to/credentials.json" # }, # ] @@ -119,7 +119,7 @@ sdk { azure.storage { # containers: [ # { - # account_name: "trains" + # account_name: "clearml" # account_key: "secret" # # container_name: # } @@ -161,8 +161,8 @@ sdk { # do not analyze the entire repository. force_analyze_entire_repo: false - # If set to true, *trains* update message will not be printed to the console - # this value can be overwritten with os environment variable TRAINS_SUPPRESS_UPDATE_MESSAGE=1 + # If set to true, *clearml* update message will not be printed to the console + # this value can be overwritten with os environment variable CLEARML_SUPPRESS_UPDATE_MESSAGE=1 suppress_update_message: false # If this flag is true (default is false), instead of analyzing the code with Pigar, analyze with `pip freeze` @@ -173,7 +173,7 @@ sdk { # of the Hyper-Parameters. # multiple selected variables are supported including the suffix '*'. # For example: "AWS_*" will log any OS environment variable starting with 'AWS_'. - # This value can be overwritten with os environment variable TRAINS_LOG_ENVIRONMENT="[AWS_*, CUDA_VERSION]" + # This value can be overwritten with os environment variable CLEARML_LOG_ENVIRONMENT="[AWS_*, CUDA_VERSION]" # Example: log_os_environments: ["AWS_*", "CUDA_VERSION"] log_os_environments: [] diff --git a/examples/automation/manual_random_param_search_example.py b/examples/automation/manual_random_param_search_example.py index f444edb9..2bd7ec96 100644 --- a/examples/automation/manual_random_param_search_example.py +++ b/examples/automation/manual_random_param_search_example.py @@ -1,8 +1,8 @@ from random import sample -from trains import Task +from clearml import Task -# Connecting TRAINS +# Connecting ClearML task = Task.init(project_name='examples', task_name='Random Hyper-Parameter Search Example', task_type=Task.TaskTypes.optimizer) # Create a hyper-parameter dictionary for the task diff --git a/examples/automation/requirements.txt b/examples/automation/requirements.txt index 3417fd38..6dac6a83 100644 --- a/examples/automation/requirements.txt +++ b/examples/automation/requirements.txt @@ -1 +1 @@ -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/automation/task_piping_example.py b/examples/automation/task_piping_example.py index 96acc86e..6be25679 100644 --- a/examples/automation/task_piping_example.py +++ b/examples/automation/task_piping_example.py @@ -1,4 +1,4 @@ -from trains import Task +from clearml import Task from time import sleep # Initialize the Task Pipe's first Task used to start the Task Pipe @@ -35,7 +35,7 @@ cloned_task_parameters = cloned_task.get_parameters() cloned_task_parameters[param['param_name']] = param['param_name_new_value'] cloned_task.set_parameters(cloned_task_parameters) -# Enqueue the Task for execution. The enqueued Task must already exist in the trains platform +# Enqueue the Task for execution. The enqueued Task must already exist in the clearml platform print('Enqueue next step in pipeline to queue: {}'.format(param['execution_queue_name'])) Task.enqueue(cloned_task.id, queue_name=param['execution_queue_name']) diff --git a/examples/automation/toy_base_task.py b/examples/automation/toy_base_task.py index 7e1521be..f0f53a3b 100644 --- a/examples/automation/toy_base_task.py +++ b/examples/automation/toy_base_task.py @@ -1,7 +1,7 @@ # This Task is the base task that we will be executing as a second step (see task_piping.py) # In order to make sure this experiment is registered in the platform, you must execute it once. -from trains import Task +from clearml import Task # Initialize the task pipe's first task used to start the task pipe task = Task.init('examples', 'Toy Base Task') diff --git a/examples/distributed/requirements.txt b/examples/distributed/requirements.txt index 27c16b3a..5107c4eb 100644 --- a/examples/distributed/requirements.txt +++ b/examples/distributed/requirements.txt @@ -1,3 +1,3 @@ torch>=1.1.0 torchvision>=0.3.0 -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/distributed/subprocess_example.py b/examples/distributed/subprocess_example.py index e0af0019..0726f5a2 100644 --- a/examples/distributed/subprocess_example.py +++ b/examples/distributed/subprocess_example.py @@ -1,4 +1,4 @@ -# TRAINS - example of multiple sub-processes interacting and reporting to a single master experiment +# ClearML - example of multiple sub-processes interacting and reporting to a single master experiment import multiprocessing import os @@ -7,7 +7,7 @@ import sys import time from argparse import ArgumentParser -from trains import Task +from clearml import Task # fake data for us to "process" data = ( @@ -51,7 +51,7 @@ if __name__ == '__main__': # We have to initialize the task in the master process, # it will make sure that any sub-process calling Task.init will get the master task object - # notice that we exclude the `counter` argument, so we can launch multiple sub-processes with trains-agent + # notice that we exclude the `counter` argument, so we can launch multiple sub-processes with clearml-agent # otherwise, the `counter` will always be set to the original value. task = Task.init('examples', 'Popen example', auto_connect_arg_parser={'counter': False}) diff --git a/examples/frameworks/autokeras/autokeras_imdb_example.py b/examples/frameworks/autokeras/autokeras_imdb_example.py index 4bef0a53..6d268891 100644 --- a/examples/frameworks/autokeras/autokeras_imdb_example.py +++ b/examples/frameworks/autokeras/autokeras_imdb_example.py @@ -3,7 +3,7 @@ import numpy as np import tensorflow as tf from tensorflow import keras -from trains import Task +from clearml import Task task = Task.init(project_name="autokeras", task_name="autokeras imdb example with scalars") diff --git a/examples/frameworks/autokeras/requirements.txt b/examples/frameworks/autokeras/requirements.txt index b50c4d62..6f74aa0d 100644 --- a/examples/frameworks/autokeras/requirements.txt +++ b/examples/frameworks/autokeras/requirements.txt @@ -1,5 +1,5 @@ # Plese read this https://github.com/keras-team/autokeras#installation before doing changes autokeras tensorflow>=2.3.0 -trains +clearml git+https://github.com/keras-team/keras-tuner.git@1.0.2rc2 diff --git a/examples/frameworks/fastai/fastai_with_tensorboard.py b/examples/frameworks/fastai/fastai_with_tensorboard.py index 63cdda9b..2fb2facd 100644 --- a/examples/frameworks/fastai/fastai_with_tensorboard.py +++ b/examples/frameworks/fastai/fastai_with_tensorboard.py @@ -1,10 +1,10 @@ -# TRAINS - Fastai with Tensorboard example code, automatic logging the model and Tensorboard outputs +# ClearML - Fastai with Tensorboard example code, automatic logging the model and Tensorboard outputs # from fastai.callbacks.tensorboard import LearnerTensorboardWriter from fastai.vision import * # Quick access to computer vision functionality -from trains import Task +from clearml import Task task = Task.init(project_name="example", task_name="fastai with tensorboard callback") diff --git a/examples/frameworks/fastai/requirements.txt b/examples/frameworks/fastai/requirements.txt index d36e6488..929405e1 100644 --- a/examples/frameworks/fastai/requirements.txt +++ b/examples/frameworks/fastai/requirements.txt @@ -1,4 +1,4 @@ fastai tensorboard tensorboardX -trains +clearml diff --git a/examples/frameworks/ignite/cifar_ignite.py b/examples/frameworks/ignite/cifar_ignite.py index de641cf9..0ebbfd89 100644 --- a/examples/frameworks/ignite/cifar_ignite.py +++ b/examples/frameworks/ignite/cifar_ignite.py @@ -15,12 +15,12 @@ from ignite.utils import setup_logger from torch.utils.tensorboard import SummaryWriter from tqdm import tqdm -from trains import Task, StorageManager +from clearml import Task, StorageManager -# Trains Initializations +# ClearML Initializations task = Task.init(project_name='Image Example', task_name='image classification CIFAR10') params = {'number_of_epochs': 20, 'batch_size': 64, 'dropout': 0.25, 'base_lr': 0.001, 'momentum': 0.9, 'loss_report': 100} -params = task.connect(params) # enabling configuration override by trains +params = task.connect(params) # enabling configuration override by clearml print(params) # printing actual configuration (after override in remote mode) manager = StorageManager() diff --git a/examples/frameworks/keras/keras_tensorboard.py b/examples/frameworks/keras/keras_tensorboard.py index cc17e05a..d24cf1ed 100644 --- a/examples/frameworks/keras/keras_tensorboard.py +++ b/examples/frameworks/keras/keras_tensorboard.py @@ -1,4 +1,4 @@ -# TRAINS - Keras with Tensorboard example code, automatic logging model and Tensorboard outputs +# ClearML - Keras with Tensorboard example code, automatic logging model and Tensorboard outputs # # Train a simple deep NN on the MNIST dataset. # Gets to 98.40% test accuracy after 20 epochs @@ -19,7 +19,7 @@ from tensorflow.keras.layers import Activation, Dense from tensorflow.keras.models import Sequential from tensorflow.keras.optimizers import RMSprop -from trains import Task +from clearml import Task class TensorBoardImage(TensorBoard): @@ -89,7 +89,7 @@ model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) -# Connecting TRAINS +# Connecting ClearML task = Task.init(project_name='examples', task_name='Keras with TensorBoard example') # To set your own configuration: diff --git a/examples/frameworks/keras/legacy/keras_tensorboard.py b/examples/frameworks/keras/legacy/keras_tensorboard.py index f36fc7bd..28f04d3d 100644 --- a/examples/frameworks/keras/legacy/keras_tensorboard.py +++ b/examples/frameworks/keras/legacy/keras_tensorboard.py @@ -1,4 +1,4 @@ -# TRAINS - Keras with Tensorboard example code, automatic logging model and Tensorboard outputs +# ClearML - Keras with Tensorboard example code, automatic logging model and Tensorboard outputs # # Train a simple deep NN on the MNIST dataset. # Gets to 98.40% test accuracy after 20 epochs @@ -18,7 +18,7 @@ from keras.layers.core import Dense, Activation from keras.optimizers import RMSprop from keras.utils import np_utils import tensorflow as tf -from trains import Task +from clearml import Task class TensorBoardImage(TensorBoard): @@ -88,7 +88,7 @@ model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) -# Connecting TRAINS +# Connecting ClearML task = Task.init(project_name='examples', task_name='Keras with TensorBoard example') task.connect_configuration({'test': 1337, 'nested': {'key': 'value', 'number': 1}}) diff --git a/examples/frameworks/keras/legacy/requirements.txt b/examples/frameworks/keras/legacy/requirements.txt index 7049a0a0..f37621b1 100644 --- a/examples/frameworks/keras/legacy/requirements.txt +++ b/examples/frameworks/keras/legacy/requirements.txt @@ -1,2 +1,2 @@ -trains +clearml Keras>=2.2.4 diff --git a/examples/frameworks/keras/manual_model_upload.py b/examples/frameworks/keras/manual_model_upload.py index 9aaec286..6b2a0b4f 100644 --- a/examples/frameworks/keras/manual_model_upload.py +++ b/examples/frameworks/keras/manual_model_upload.py @@ -1,11 +1,11 @@ -# TRAINS - Example of manual model configuration and uploading +# ClearML - Example of manual model configuration and uploading # import os from tempfile import gettempdir from keras import Input, layers, Model -from trains import Task +from clearml import Task task = Task.init(project_name='examples', task_name='Model configuration and upload') diff --git a/examples/frameworks/keras/requirements.txt b/examples/frameworks/keras/requirements.txt index cb700b34..4f7fcce4 100644 --- a/examples/frameworks/keras/requirements.txt +++ b/examples/frameworks/keras/requirements.txt @@ -1,3 +1,3 @@ Keras tensorflow>=2.0 -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/frameworks/kerastuner/keras_tuner_cifar.py b/examples/frameworks/kerastuner/keras_tuner_cifar.py index eb0dcf8a..a2b5e019 100644 --- a/examples/frameworks/kerastuner/keras_tuner_cifar.py +++ b/examples/frameworks/kerastuner/keras_tuner_cifar.py @@ -3,9 +3,9 @@ import kerastuner as kt import tensorflow as tf import tensorflow_datasets as tfds -from trains.external.kerastuner import TrainsTunerLogger +from clearml.external.kerastuner import TrainsTunerLogger -from trains import Task +from clearml import Task physical_devices = tf.config.list_physical_devices('GPU') if physical_devices: diff --git a/examples/frameworks/kerastuner/requirements.txt b/examples/frameworks/kerastuner/requirements.txt index cd066fc5..4677be30 100644 --- a/examples/frameworks/kerastuner/requirements.txt +++ b/examples/frameworks/kerastuner/requirements.txt @@ -1,4 +1,4 @@ keras-tuner tensorflow>=2.0 tensorflow-datasets -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/frameworks/lightgbm/requirements.txt b/examples/frameworks/lightgbm/requirements.txt index bc0c122d..ac7ee02e 100644 --- a/examples/frameworks/lightgbm/requirements.txt +++ b/examples/frameworks/lightgbm/requirements.txt @@ -1,4 +1,4 @@ lightgbm scikit-learn pandas -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/frameworks/lightgbm/train_with_lightbgm.py b/examples/frameworks/lightgbm/train_with_lightbgm.py index c4613968..b6fad561 100644 --- a/examples/frameworks/lightgbm/train_with_lightbgm.py +++ b/examples/frameworks/lightgbm/train_with_lightbgm.py @@ -1,10 +1,10 @@ -# TRAINS - Example of LightGBM integration +# ClearML - Example of LightGBM integration # import lightgbm as lgb import pandas as pd from sklearn.metrics import mean_squared_error -from trains import Task +from clearml import Task task = Task.init(project_name="examples", task_name="LIGHTgbm") diff --git a/examples/frameworks/matplotlib/matplotlib_example.py b/examples/frameworks/matplotlib/matplotlib_example.py index f00443f8..47575937 100644 --- a/examples/frameworks/matplotlib/matplotlib_example.py +++ b/examples/frameworks/matplotlib/matplotlib_example.py @@ -1,9 +1,9 @@ -# TRAINS - Example of Matplotlib and Seaborn integration and reporting +# ClearML - Example of Matplotlib and Seaborn integration and reporting # import numpy as np import matplotlib.pyplot as plt import seaborn as sns -from trains import Task +from clearml import Task task = Task.init(project_name='examples', task_name='Matplotlib example') diff --git a/examples/frameworks/matplotlib/requirements.txt b/examples/frameworks/matplotlib/requirements.txt index de3c8632..fdcc6684 100644 --- a/examples/frameworks/matplotlib/requirements.txt +++ b/examples/frameworks/matplotlib/requirements.txt @@ -1,4 +1,4 @@ matplotlib >= 3.1.1 ; python_version >= '3.6' matplotlib >= 2.2.4 ; python_version < '3.6' seaborn -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/frameworks/pytorch/manual_model_upload.py b/examples/frameworks/pytorch/manual_model_upload.py index dfd963e0..485d33fb 100644 --- a/examples/frameworks/pytorch/manual_model_upload.py +++ b/examples/frameworks/pytorch/manual_model_upload.py @@ -1,10 +1,10 @@ -# TRAINS - Example of manual model configuration and uploading +# ClearML - Example of manual model configuration and uploading # import os from tempfile import gettempdir import torch -from trains import Task +from clearml import Task task = Task.init(project_name='examples', task_name='Model configuration and upload') diff --git a/examples/frameworks/pytorch/pytorch_distributed_example.py b/examples/frameworks/pytorch/pytorch_distributed_example.py index 5a98e0c4..9130f3c4 100644 --- a/examples/frameworks/pytorch/pytorch_distributed_example.py +++ b/examples/frameworks/pytorch/pytorch_distributed_example.py @@ -1,4 +1,4 @@ -# TRAINS - example of TRAINS torch distributed support +# ClearML - example of ClearML torch distributed support # notice all nodes will be reporting to the master Task (experiment) import os @@ -15,7 +15,7 @@ import torch.nn.functional as F from torch import optim from torchvision import datasets, transforms -from trains import Task +from clearml import Task local_dataset_path = './MNIST_data' @@ -150,7 +150,7 @@ if __name__ == "__main__": # We have to initialize the task in the master process, # it will make sure that any sub-process calling Task.init will get the master task object - # notice that we exclude the `rank` argument, so we can launch multiple sub-processes with trains-agent + # notice that we exclude the `rank` argument, so we can launch multiple sub-processes with clearml-agent # otherwise, the `rank` will always be set to the original value. task = Task.init("examples", "test torch distributed", auto_connect_arg_parser={'rank': False}) diff --git a/examples/frameworks/pytorch/pytorch_matplotlib.py b/examples/frameworks/pytorch/pytorch_matplotlib.py index 933bb5cf..53a88b00 100644 --- a/examples/frameworks/pytorch/pytorch_matplotlib.py +++ b/examples/frameworks/pytorch/pytorch_matplotlib.py @@ -1,4 +1,4 @@ -# TRAINS - Example of Pytorch and matplotlib integration and reporting +# ClearML - Example of Pytorch and matplotlib integration and reporting # """ Neural Transfer Using PyTorch @@ -60,7 +60,7 @@ import torchvision.transforms as transforms import torchvision.models as models import copy -from trains import Task +from clearml import Task task = Task.init(project_name='examples', task_name='pytorch with matplotlib example', task_type=Task.TaskTypes.testing) diff --git a/examples/frameworks/pytorch/pytorch_mnist.py b/examples/frameworks/pytorch/pytorch_mnist.py index 0572336e..b1fac4e6 100644 --- a/examples/frameworks/pytorch/pytorch_mnist.py +++ b/examples/frameworks/pytorch/pytorch_mnist.py @@ -1,4 +1,4 @@ -# TRAINS - Example of Pytorch mnist training integration +# ClearML - Example of Pytorch mnist training integration # from __future__ import print_function import argparse @@ -11,7 +11,7 @@ import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, transforms -from trains import Task, Logger +from clearml import Task, Logger class Net(nn.Module): diff --git a/examples/frameworks/pytorch/pytorch_tensorboard.py b/examples/frameworks/pytorch/pytorch_tensorboard.py index ece50a7b..58005848 100644 --- a/examples/frameworks/pytorch/pytorch_tensorboard.py +++ b/examples/frameworks/pytorch/pytorch_tensorboard.py @@ -1,4 +1,4 @@ -# TRAINS - Example of pytorch with tensorboard>=v1.14 +# ClearML - Example of pytorch with tensorboard>=v1.14 # from __future__ import print_function @@ -14,7 +14,7 @@ from torchvision import datasets, transforms from torch.autograd import Variable from torch.utils.tensorboard import SummaryWriter -from trains import Task +from clearml import Task class Net(nn.Module): @@ -99,7 +99,7 @@ def main(): parser.add_argument('--log-interval', type=int, default=10, metavar='N', help='how many batches to wait before logging training status') args = parser.parse_args() - task = Task.init(project_name='examples', task_name='pytorch with tensorboard') # noqa: F841 + Task.init(project_name='examples', task_name='pytorch with tensorboard') writer = SummaryWriter('runs') writer.add_text('TEXT', 'This is some text', 0) args.cuda = not args.no_cuda and torch.cuda.is_available() diff --git a/examples/frameworks/pytorch/requirements.txt b/examples/frameworks/pytorch/requirements.txt index 169f0b09..d888329b 100644 --- a/examples/frameworks/pytorch/requirements.txt +++ b/examples/frameworks/pytorch/requirements.txt @@ -3,4 +3,4 @@ tensorboardX tensorboard>=1.14.0 torch>=1.1.0 torchvision>=0.3.0 -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/frameworks/pytorch/tensorboard_toy_pytorch.py b/examples/frameworks/pytorch/tensorboard_toy_pytorch.py index 71e1037d..8ff1dc75 100644 --- a/examples/frameworks/pytorch/tensorboard_toy_pytorch.py +++ b/examples/frameworks/pytorch/tensorboard_toy_pytorch.py @@ -5,7 +5,7 @@ import numpy as np from PIL import Image from torch.utils.tensorboard import SummaryWriter -from trains import Task +from clearml import Task task = Task.init(project_name='examples', task_name='pytorch tensorboard toy example') diff --git a/examples/frameworks/scikit-learn/requirements.txt b/examples/frameworks/scikit-learn/requirements.txt index dcb80536..07819fbf 100644 --- a/examples/frameworks/scikit-learn/requirements.txt +++ b/examples/frameworks/scikit-learn/requirements.txt @@ -2,4 +2,4 @@ joblib>=0.13.2 matplotlib >= 3.1.1 ; python_version >= '3.6' matplotlib >= 2.2.4 ; python_version < '3.6' scikit-learn -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/frameworks/scikit-learn/sklearn_joblib_example.py b/examples/frameworks/scikit-learn/sklearn_joblib_example.py index 9a04660f..b29a6bef 100644 --- a/examples/frameworks/scikit-learn/sklearn_joblib_example.py +++ b/examples/frameworks/scikit-learn/sklearn_joblib_example.py @@ -10,7 +10,7 @@ import numpy as np import matplotlib.pyplot as plt -from trains import Task +from clearml import Task task = Task.init(project_name="examples", task_name="scikit-learn joblib example") diff --git a/examples/frameworks/scikit-learn/sklearn_matplotlib_example.py b/examples/frameworks/scikit-learn/sklearn_matplotlib_example.py index f56d1c20..de5a3a63 100644 --- a/examples/frameworks/scikit-learn/sklearn_matplotlib_example.py +++ b/examples/frameworks/scikit-learn/sklearn_matplotlib_example.py @@ -6,7 +6,7 @@ from sklearn.model_selection import learning_curve from sklearn.naive_bayes import GaussianNB from sklearn.svm import SVC -from trains import Task +from clearml import Task def plot_learning_curve(estimator, title, X, y, axes=None, ylim=None, cv=None, n_jobs=None, diff --git a/examples/frameworks/tensorboardx/pytorch_tensorboardX.py b/examples/frameworks/tensorboardx/pytorch_tensorboardX.py index b0a1901f..498c09fa 100644 --- a/examples/frameworks/tensorboardx/pytorch_tensorboardX.py +++ b/examples/frameworks/tensorboardx/pytorch_tensorboardX.py @@ -1,4 +1,4 @@ -# TRAINS - Example of pytorch with tensorboardX +# ClearML - Example of pytorch with tensorboardX # from __future__ import print_function @@ -14,7 +14,7 @@ from tensorboardX import SummaryWriter from torch.autograd import Variable from torchvision import datasets, transforms -from trains import Task +from clearml import Task class Net(nn.Module): diff --git a/examples/frameworks/tensorboardx/requirements.txt b/examples/frameworks/tensorboardx/requirements.txt index 1c860d52..302ac560 100644 --- a/examples/frameworks/tensorboardx/requirements.txt +++ b/examples/frameworks/tensorboardx/requirements.txt @@ -1,4 +1,4 @@ tensorboardX>=1.8 torch>=1.1.0 torchvision>=0.3.0 -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/frameworks/tensorflow/legacy/tensorboard_pr_curve.py b/examples/frameworks/tensorflow/legacy/tensorboard_pr_curve.py index b490fdad..441aba41 100644 --- a/examples/frameworks/tensorflow/legacy/tensorboard_pr_curve.py +++ b/examples/frameworks/tensorflow/legacy/tensorboard_pr_curve.py @@ -1,4 +1,4 @@ -# TRAINS - Example of new tensorboard pr_curves model +# ClearML - Example of new tensorboard pr_curves model # # Copyright 2017 The TensorFlow Authors. All Rights Reserved. # @@ -37,7 +37,7 @@ from absl import flags from six.moves import xrange # pylint: disable=redefined-builtin import tensorflow as tf from tensorboard.plugins.pr_curve import summary -from trains import Task +from clearml import Task task = Task.init(project_name='examples', task_name='tensorboard pr_curve') diff --git a/examples/frameworks/tensorflow/legacy/tensorboard_toy.py b/examples/frameworks/tensorflow/legacy/tensorboard_toy.py index 5984eca9..f3b7832d 100644 --- a/examples/frameworks/tensorflow/legacy/tensorboard_toy.py +++ b/examples/frameworks/tensorflow/legacy/tensorboard_toy.py @@ -1,4 +1,4 @@ -# TRAINS - Example of tensorboard with tensorflow (without any actual training) +# ClearML - Example of tensorboard with tensorflow (without any actual training) # import os from tempfile import gettempdir @@ -7,7 +7,7 @@ import tensorflow as tf import numpy as np from PIL import Image -from trains import Task +from clearml import Task task = Task.init(project_name='examples', task_name='tensorboard toy example') diff --git a/examples/frameworks/tensorflow/legacy/tensorflow_eager.py b/examples/frameworks/tensorflow/legacy/tensorflow_eager.py index add5bc76..8f198991 100644 --- a/examples/frameworks/tensorflow/legacy/tensorflow_eager.py +++ b/examples/frameworks/tensorflow/legacy/tensorflow_eager.py @@ -1,4 +1,4 @@ -# TRAINS - Example of tensorflow eager mode, model logging and tensorboard +# ClearML - Example of tensorflow eager mode, model logging and tensorboard # # Copyright 2017 The TensorFlow Authors. All Rights Reserved. # @@ -30,7 +30,7 @@ from tempfile import gettempdir import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data -from trains import Task +from clearml import Task tf.compat.v1.enable_eager_execution() diff --git a/examples/frameworks/tensorflow/legacy/tensorflow_mnist_with_summaries.py b/examples/frameworks/tensorflow/legacy/tensorflow_mnist_with_summaries.py index 81b2b879..3e06fd80 100644 --- a/examples/frameworks/tensorflow/legacy/tensorflow_mnist_with_summaries.py +++ b/examples/frameworks/tensorflow/legacy/tensorflow_mnist_with_summaries.py @@ -31,7 +31,7 @@ import tempfile import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data -from trains import Task +from clearml import Task FLAGS = None task = Task.init(project_name='examples', task_name='Tensorflow mnist with summaries example') diff --git a/examples/frameworks/tensorflow/manual_model_upload.py b/examples/frameworks/tensorflow/manual_model_upload.py index ee0a6702..86f8dbe3 100644 --- a/examples/frameworks/tensorflow/manual_model_upload.py +++ b/examples/frameworks/tensorflow/manual_model_upload.py @@ -1,10 +1,10 @@ -# TRAINS - Example of manual model configuration and uploading +# ClearML - Example of manual model configuration and uploading # import os import tempfile import tensorflow as tf -from trains import Task +from clearml import Task task = Task.init(project_name='examples', task_name='Model configuration and upload') diff --git a/examples/frameworks/tensorflow/requirements.txt b/examples/frameworks/tensorflow/requirements.txt index 4c750c8d..a1f9ba5f 100644 --- a/examples/frameworks/tensorflow/requirements.txt +++ b/examples/frameworks/tensorflow/requirements.txt @@ -1,3 +1,3 @@ tensorboard>=2.0 tensorflow>=2.0 -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/frameworks/tensorflow/tensorboard_pr_curve.py b/examples/frameworks/tensorflow/tensorboard_pr_curve.py index 14245c7f..686a3a06 100644 --- a/examples/frameworks/tensorflow/tensorboard_pr_curve.py +++ b/examples/frameworks/tensorflow/tensorboard_pr_curve.py @@ -36,7 +36,7 @@ from six.moves import xrange # pylint: disable=redefined-builtin import tensorflow as tf from tensorboard.plugins.pr_curve import summary -from trains import Task +from clearml import Task task = Task.init(project_name='examples', task_name='tensorboard pr_curve') diff --git a/examples/frameworks/tensorflow/tensorboard_toy.py b/examples/frameworks/tensorflow/tensorboard_toy.py index 2ccd74e1..4c8d5708 100644 --- a/examples/frameworks/tensorflow/tensorboard_toy.py +++ b/examples/frameworks/tensorflow/tensorboard_toy.py @@ -1,4 +1,4 @@ -# TRAINS - Example of tensorboard with tensorflow (without any actual training) +# ClearML - Example of tensorboard with tensorflow (without any actual training) # import os import tensorflow as tf @@ -6,7 +6,7 @@ import numpy as np from tempfile import gettempdir from PIL import Image -from trains import Task +from clearml import Task def generate_summary(k, step): diff --git a/examples/frameworks/tensorflow/tensorflow_mnist.py b/examples/frameworks/tensorflow/tensorflow_mnist.py index d5cc3564..f663648e 100644 --- a/examples/frameworks/tensorflow/tensorflow_mnist.py +++ b/examples/frameworks/tensorflow/tensorflow_mnist.py @@ -8,7 +8,7 @@ import tensorflow as tf from tensorflow.keras.layers import Dense, Flatten, Conv2D from tensorflow.keras import Model -from trains import Task +from clearml import Task task = Task.init(project_name='examples', diff --git a/examples/frameworks/xgboost/requirements.txt b/examples/frameworks/xgboost/requirements.txt index aa52d2d7..a54eb3ba 100644 --- a/examples/frameworks/xgboost/requirements.txt +++ b/examples/frameworks/xgboost/requirements.txt @@ -1,7 +1,7 @@ matplotlib >= 3.1.1 ; python_version >= '3.6' matplotlib >= 2.2.4 ; python_version < '3.6' sklearn -trains +clearml xgboost>=0.90 ; python_version >= '3' xgboost>=0.82 ; python_version < '3' # sudo apt-get install graphviz diff --git a/examples/frameworks/xgboost/xgboost_sample.py b/examples/frameworks/xgboost/xgboost_sample.py index cc8c2a96..8157ed6e 100644 --- a/examples/frameworks/xgboost/xgboost_sample.py +++ b/examples/frameworks/xgboost/xgboost_sample.py @@ -5,7 +5,7 @@ from sklearn.metrics import accuracy_score from sklearn.model_selection import train_test_split from xgboost import plot_tree -from trains import Task +from clearml import Task task = Task.init(project_name='examples', task_name='XGBoost simple example') iris = datasets.load_iris() diff --git a/examples/optimization/hyper-parameter-optimization/base_template_keras_simple.py b/examples/optimization/hyper-parameter-optimization/base_template_keras_simple.py index c2782063..cf97f1ff 100644 --- a/examples/optimization/hyper-parameter-optimization/base_template_keras_simple.py +++ b/examples/optimization/hyper-parameter-optimization/base_template_keras_simple.py @@ -1,4 +1,4 @@ -# TRAINS - Keras with Tensorboard example code, automatic logging model and Tensorboard outputs +# ClearML - Keras with Tensorboard example code, automatic logging model and Tensorboard outputs # # Train a simple deep NN on the MNIST dataset. # Gets to 98.40% test accuracy after 20 epochs @@ -17,10 +17,10 @@ from tensorflow.keras.layers import Activation, Dense from tensorflow.keras.models import Sequential from tensorflow.keras.optimizers import RMSprop -from trains import Task, Logger +from clearml import Task, Logger -# Connecting TRAINS +# Connecting ClearML task = Task.init(project_name='examples', task_name='Keras HP optimization base') diff --git a/examples/optimization/hyper-parameter-optimization/hyper_parameter_optimizer.py b/examples/optimization/hyper-parameter-optimization/hyper_parameter_optimizer.py index 964b717a..45a1eafe 100644 --- a/examples/optimization/hyper-parameter-optimization/hyper_parameter_optimizer.py +++ b/examples/optimization/hyper-parameter-optimization/hyper_parameter_optimizer.py @@ -1,7 +1,7 @@ import logging -from trains import Task -from trains.automation import ( +from clearml import Task +from clearml.automation import ( DiscreteParameterRange, HyperParameterOptimizer, RandomSearch, UniformIntegerParameterRange) @@ -9,14 +9,14 @@ aSearchStrategy = None if not aSearchStrategy: try: - from trains.automation.optuna import OptimizerOptuna + from clearml.automation.optuna import OptimizerOptuna aSearchStrategy = OptimizerOptuna except ImportError as ex: pass if not aSearchStrategy: try: - from trains.automation.hpbandster import OptimizerBOHB + from clearml.automation.hpbandster import OptimizerBOHB aSearchStrategy = OptimizerBOHB except ImportError as ex: pass @@ -40,7 +40,7 @@ def job_complete_callback( print('WOOT WOOT we broke the record! Objective reached {}'.format(objective_value)) -# Connecting TRAINS +# Connecting ClearML task = Task.init(project_name='Hyper-Parameter Optimization', task_name='Automatic Hyper-Parameter Optimization', task_type=Task.TaskTypes.optimizer, @@ -73,10 +73,11 @@ an_optimizer = HyperParameterOptimizer( UniformIntegerParameterRange('General/layer_2', min_value=128, max_value=512, step_size=128), DiscreteParameterRange('General/batch_size', values=[96, 128, 160]), DiscreteParameterRange('General/epochs', values=[30]), + DiscreteParameterRange('General/optimizer', values=['adam', 'sgd']), ], # this is the objective metric we want to maximize/minimize - objective_metric_title='epoch_accuracy', - objective_metric_series='epoch_accuracy', + objective_metric_title='accuracy', + objective_metric_series='accuracy', # now we decide if we want to maximize it or minimize it (accuracy we maximize) objective_metric_sign='max', # let us limit the number of concurrent experiments, @@ -109,7 +110,7 @@ an_optimizer = HyperParameterOptimizer( # if we are running as a service, just enqueue ourselves into the services queue and let it run the optimization if args['run_as_service']: - # if this code is executed by `trains-agent` the function call does nothing. + # if this code is executed by `clearml-agent` the function call does nothing. # if executed locally, the local process will be terminated, and a remote copy will be executed instead task.execute_remotely(queue_name='services', exit_process=True) diff --git a/examples/optimization/hyper-parameter-optimization/requirements.txt b/examples/optimization/hyper-parameter-optimization/requirements.txt index e1a47da3..770f214c 100644 --- a/examples/optimization/hyper-parameter-optimization/requirements.txt +++ b/examples/optimization/hyper-parameter-optimization/requirements.txt @@ -1,3 +1,3 @@ keras tensorflow -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/pipeline/pipeline_controller.py b/examples/pipeline/pipeline_controller.py index ac00d024..3211c6c6 100644 --- a/examples/pipeline/pipeline_controller.py +++ b/examples/pipeline/pipeline_controller.py @@ -1,5 +1,5 @@ -from trains import Task -from trains.automation.controller import PipelineController +from clearml import Task +from clearml.automation.controller import PipelineController task = Task.init(project_name='examples', task_name='pipeline demo', diff --git a/examples/pipeline/requirements.txt b/examples/pipeline/requirements.txt index dcb80536..07819fbf 100644 --- a/examples/pipeline/requirements.txt +++ b/examples/pipeline/requirements.txt @@ -2,4 +2,4 @@ joblib>=0.13.2 matplotlib >= 3.1.1 ; python_version >= '3.6' matplotlib >= 2.2.4 ; python_version < '3.6' scikit-learn -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/pipeline/step1_dataset_artifact.py b/examples/pipeline/step1_dataset_artifact.py index f1e7a6a3..154ab554 100644 --- a/examples/pipeline/step1_dataset_artifact.py +++ b/examples/pipeline/step1_dataset_artifact.py @@ -1,4 +1,4 @@ -from trains import Task, StorageManager +from clearml import Task, StorageManager # create an dataset experiment task = Task.init(project_name="examples", task_name="pipeline step 1 dataset artifact") diff --git a/examples/pipeline/step2_data_processing.py b/examples/pipeline/step2_data_processing.py index ff74c89e..dca47520 100644 --- a/examples/pipeline/step2_data_processing.py +++ b/examples/pipeline/step2_data_processing.py @@ -1,9 +1,9 @@ import pickle -from trains import Task, StorageManager +from clearml import Task, StorageManager from sklearn.model_selection import train_test_split -# Connecting TRAINS +# Connecting ClearML task = Task.init(project_name="examples", task_name="pipeline step 2 process dataset") # program arguments diff --git a/examples/pipeline/step3_train_model.py b/examples/pipeline/step3_train_model.py index 332532b4..a705588c 100644 --- a/examples/pipeline/step3_train_model.py +++ b/examples/pipeline/step3_train_model.py @@ -3,9 +3,9 @@ import matplotlib.pyplot as plt import numpy as np from sklearn.linear_model import LogisticRegression -from trains import Task +from clearml import Task -# Connecting TRAINS +# Connecting ClearML task = Task.init(project_name="examples", task_name="pipeline step 3 train model") # Arguments diff --git a/examples/reporting/3d_plots_reporting.py b/examples/reporting/3d_plots_reporting.py index 0c9b7e0f..9a41f249 100644 --- a/examples/reporting/3d_plots_reporting.py +++ b/examples/reporting/3d_plots_reporting.py @@ -1,8 +1,8 @@ -# TRAINS - Example of manual graphs and statistics reporting +# ClearML - Example of manual graphs and statistics reporting # import numpy as np -from trains import Task, Logger +from clearml import Task, Logger def report_plots(logger, iteration=0): diff --git a/examples/reporting/artifacts.py b/examples/reporting/artifacts.py index 6ba0168c..25fe22c2 100644 --- a/examples/reporting/artifacts.py +++ b/examples/reporting/artifacts.py @@ -4,7 +4,7 @@ from time import sleep import pandas as pd import numpy as np from PIL import Image -from trains import Task +from clearml import Task task = Task.init('examples', 'artifacts example') diff --git a/examples/reporting/html_reporting.py b/examples/reporting/html_reporting.py index b630a656..b6abd0bc 100644 --- a/examples/reporting/html_reporting.py +++ b/examples/reporting/html_reporting.py @@ -1,4 +1,4 @@ -# TRAINS - Example of manual graphs and statistics reporting +# ClearML - Example of manual graphs and statistics reporting # import math @@ -10,7 +10,7 @@ from bokeh.sampledata.autompg import autompg_clean as bokeh_df from bokeh.sampledata.periodic_table import elements from bokeh.transform import dodge, factor_cmap -from trains import Task, Logger +from clearml import Task, Logger def report_html_url(logger, iteration=0): diff --git a/examples/reporting/hyper_parameters.py b/examples/reporting/hyper_parameters.py index 89a336e0..9e05452e 100644 --- a/examples/reporting/hyper_parameters.py +++ b/examples/reporting/hyper_parameters.py @@ -1,4 +1,4 @@ -# TRAINS - example code, ArgumentParser parameter logging, absl parameter logging, and dictionary parameter logging +# ClearML - example code, ArgumentParser parameter logging, absl parameter logging, and dictionary parameter logging # from __future__ import absolute_import from __future__ import division @@ -11,7 +11,7 @@ from absl import app from absl import flags from absl import logging -from trains import Task +from clearml import Task FLAGS = flags.FLAGS @@ -32,7 +32,8 @@ parameters = { 'float': 2.2, 'string': 'my string', } -parameters = task.connect_configuration(parameters, name='test') +from clearml import Task +parameters = Task.current_task().connect(parameters, name='more_stuff_deep_inside_code') # adding new parameter after connect (will be logged as well) parameters['new_param'] = 'this is new' @@ -41,6 +42,19 @@ parameters['new_param'] = 'this is new' parameters['float'] = '9.9' print(parameters) +complex_nested_dict_configuration = { + 'list_of_dicts': [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6}], + 'nested_dicts': {'nested': {'key': 'value', 'extra': 'value'}, 'number': 42}, + 'dict': {'simple': 'value', 'number': 2}, + 'list': [1, 2, 3], + 'int': 3, + 'float': 2.2, + 'string': 'additional string', +} +complex_nested_dict_configuration = task.connect_configuration( + complex_nested_dict_configuration, name='configuration dictionary') +print(complex_nested_dict_configuration) + def main(_): print('Running under Python {0[0]}.{0[1]}.{0[2]}'.format(sys.version_info), file=sys.stderr) diff --git a/examples/reporting/image_reporting.py b/examples/reporting/image_reporting.py index 7030401a..19cc6967 100644 --- a/examples/reporting/image_reporting.py +++ b/examples/reporting/image_reporting.py @@ -1,11 +1,11 @@ -# TRAINS - Example of manual graphs and statistics reporting +# ClearML - Example of manual graphs and statistics reporting # import os import numpy as np from PIL import Image -from trains import Task, Logger +from clearml import Task, Logger def report_debug_images(logger, iteration=0): diff --git a/examples/reporting/manual_matplotlib_reporting.py b/examples/reporting/manual_matplotlib_reporting.py deleted file mode 100644 index 19b932e3..00000000 --- a/examples/reporting/manual_matplotlib_reporting.py +++ /dev/null @@ -1,55 +0,0 @@ -# TRAINS - Example of Matplotlib and Seaborn integration and reporting -# -import numpy as np -import matplotlib.pyplot as plt -from trains import Task - -# Create a new task, disable automatic matplotlib connect -task = Task.init( - project_name='examples', - task_name='Manual Matplotlib example', - auto_connect_frameworks={'matplotlib': False} -) - -# Create plot and explicitly report as figure -N = 50 -x = np.random.rand(N) -y = np.random.rand(N) -colors = np.random.rand(N) -area = (30 * np.random.rand(N))**2 # 0 to 15 point radii -plt.scatter(x, y, s=area, c=colors, alpha=0.5) -task.logger.report_matplotlib_figure( - title="Manual Reporting", - series="Just a plot", - iteration=0, - figure=plt, -) - -# Show the plot -plt.show() - -# Create plot and explicitly report as an image -plt.scatter(x, y, s=area, c=colors, alpha=0.5) -task.logger.report_matplotlib_figure( - title="Manual Reporting", - series="Plot as an image", - iteration=0, - figure=plt, - report_image=True, -) - - -# Create an image plot and explicitly report (as an image) -m = np.eye(256, 256, dtype=np.uint8) -plt.imshow(m) -task.logger.report_matplotlib_figure( - title="Manual Reporting", - series="Image plot", - iteration=0, - figure=plt, - report_image=True, # Note this is required for image plots -) - -# Show the plot -plt.show() - diff --git a/examples/reporting/manual_matplotlib_reporting.py b/examples/reporting/manual_matplotlib_reporting.py new file mode 120000 index 00000000..294d4d39 --- /dev/null +++ b/examples/reporting/manual_matplotlib_reporting.py @@ -0,0 +1 @@ +matplotlib_manual_reporting.py \ No newline at end of file diff --git a/examples/reporting/matplotlib_automatic_reporting.py b/examples/reporting/matplotlib_automatic_reporting.py new file mode 120000 index 00000000..84a4cb08 --- /dev/null +++ b/examples/reporting/matplotlib_automatic_reporting.py @@ -0,0 +1 @@ +../frameworks/matplotlib/matplotlib_example.py \ No newline at end of file diff --git a/examples/reporting/matplotlib_manual_reporting.py b/examples/reporting/matplotlib_manual_reporting.py new file mode 100644 index 00000000..1d6b8e63 --- /dev/null +++ b/examples/reporting/matplotlib_manual_reporting.py @@ -0,0 +1,55 @@ +# ClearML - Example of Matplotlib and Seaborn integration and reporting +# +import numpy as np +import matplotlib.pyplot as plt +from clearml import Task + +# Create a new task, disable automatic matplotlib connect +task = Task.init( + project_name='examples', + task_name='Manual Matplotlib example', + auto_connect_frameworks={'matplotlib': False} +) + +# Create plot and explicitly report as figure +N = 50 +x = np.random.rand(N) +y = np.random.rand(N) +colors = np.random.rand(N) +area = (30 * np.random.rand(N))**2 # 0 to 15 point radii +plt.scatter(x, y, s=area, c=colors, alpha=0.5) +task.logger.report_matplotlib_figure( + title="Manual Reporting", + series="Just a plot", + iteration=0, + figure=plt, +) + +# Show the plot +plt.show() + +# Create plot and explicitly report as an image +plt.scatter(x, y, s=area, c=colors, alpha=0.5) +task.logger.report_matplotlib_figure( + title="Manual Reporting", + series="Plot as an image", + iteration=0, + figure=plt, + report_image=True, +) + + +# Create an image plot and explicitly report (as an image) +m = np.eye(256, 256, dtype=np.uint8) +plt.imshow(m) +task.logger.report_matplotlib_figure( + title="Manual Reporting", + series="Image plot", + iteration=0, + figure=plt, + report_image=True, # Note this is required for image plots +) + +# Show the plot +plt.show() + diff --git a/examples/reporting/media_reporting.py b/examples/reporting/media_reporting.py index 00f7ae70..7fb9007a 100644 --- a/examples/reporting/media_reporting.py +++ b/examples/reporting/media_reporting.py @@ -1,7 +1,7 @@ -# TRAINS - Example reporting video or audio links/file +# ClearML - Example reporting video or audio links/file # import os -from trains import Task, Logger +from clearml import Task, Logger task = Task.init(project_name="examples", task_name="audio and video reporting") diff --git a/examples/reporting/model_config.py b/examples/reporting/model_config.py index a0d401e6..bcfd3170 100644 --- a/examples/reporting/model_config.py +++ b/examples/reporting/model_config.py @@ -1,8 +1,8 @@ -# TRAINS - Example of manual model configuration +# ClearML - Example of manual model configuration # import os -from trains import Task, OutputModel +from clearml import Task, OutputModel task = Task.init(project_name='examples', task_name='Model configuration example') diff --git a/examples/reporting/pandas_reporting.py b/examples/reporting/pandas_reporting.py index 42ff8480..1792b254 100644 --- a/examples/reporting/pandas_reporting.py +++ b/examples/reporting/pandas_reporting.py @@ -1,9 +1,9 @@ -# TRAINS - Example of manual graphs and statistics reporting +# ClearML - Example of manual graphs and statistics reporting # import pandas as pd -from trains import Task, Logger +from clearml import Task, Logger def report_table(logger, iteration=0): diff --git a/examples/reporting/plotly_reporting.py b/examples/reporting/plotly_reporting.py index f70dea4e..dcbabc9b 100644 --- a/examples/reporting/plotly_reporting.py +++ b/examples/reporting/plotly_reporting.py @@ -1,6 +1,6 @@ -# TRAINS - Example of Plotly integration and reporting +# ClearML - Example of Plotly integration and reporting # -from trains import Task +from clearml import Task import plotly.express as px diff --git a/examples/reporting/requirements.txt b/examples/reporting/requirements.txt index 0b40bccf..a7621f15 100644 --- a/examples/reporting/requirements.txt +++ b/examples/reporting/requirements.txt @@ -6,4 +6,4 @@ numpy pandas pillow>=4.0 six -trains +clearml diff --git a/examples/reporting/scalar_reporting.py b/examples/reporting/scalar_reporting.py index 2be77854..adda0433 100644 --- a/examples/reporting/scalar_reporting.py +++ b/examples/reporting/scalar_reporting.py @@ -1,6 +1,6 @@ -# TRAINS - Example of manual graphs and statistics reporting +# ClearML - Example of manual graphs and statistics reporting # -from trains import Task, Logger +from clearml import Task, Logger def report_scalars(logger): diff --git a/examples/reporting/scatter_hist_confusion_mat_reporting.py b/examples/reporting/scatter_hist_confusion_mat_reporting.py index 184f5c8f..72b79318 100644 --- a/examples/reporting/scatter_hist_confusion_mat_reporting.py +++ b/examples/reporting/scatter_hist_confusion_mat_reporting.py @@ -1,8 +1,8 @@ -# TRAINS - Example of manual graphs and statistics reporting +# ClearML - Example of manual graphs and statistics reporting # import numpy as np -from trains import Task, Logger +from clearml import Task, Logger def report_plots(logger, iteration=0): @@ -117,6 +117,7 @@ def main(): # Get the task logger, # You can also call Task.current_task().get_logger() from anywhere in your code. logger = task.get_logger() + #logger.report_scatter2d() # report graphs report_plots(logger) diff --git a/examples/reporting/text_reporting.py b/examples/reporting/text_reporting.py index 2f91c4e6..99209ea9 100644 --- a/examples/reporting/text_reporting.py +++ b/examples/reporting/text_reporting.py @@ -1,4 +1,4 @@ -# TRAINS - Example of manual graphs and statistics reporting +# ClearML - Example of manual graphs and statistics reporting # from __future__ import print_function @@ -7,7 +7,7 @@ import sys import six -from trains import Logger, Task +from clearml import Logger, Task def report_logs(logger): diff --git a/examples/services/aws-autoscaler/aws_autoscaler.py b/examples/services/aws-autoscaler/aws_autoscaler.py index 4ff689e8..e9335bab 100644 --- a/examples/services/aws-autoscaler/aws_autoscaler.py +++ b/examples/services/aws-autoscaler/aws_autoscaler.py @@ -7,10 +7,10 @@ import yaml from pathlib2 import Path from six.moves import input -from trains import Task -from trains.automation.aws_auto_scaler import AwsAutoScaler -from trains.config import running_remotely -from trains.utilities.wizard.user_input import ( +from clearml import Task +from clearml.automation.aws_auto_scaler import AwsAutoScaler +from clearml.config import running_remotely +from clearml.utilities.wizard.user_input import ( get_input, input_int, input_bool, @@ -45,7 +45,7 @@ def main(): print("AWS Autoscaler setup wizard\n" "---------------------------\n" "Follow the wizard to configure your AWS auto-scaler service.\n" - "Once completed, you will be able to view and change the configuration in the trains-server web UI.\n" + "Once completed, you will be able to view and change the configuration in the clearml-server web UI.\n" "It means there is no need to worry about typos or mistakes :)\n") config_file = Path(CONF_FILE).absolute() @@ -85,7 +85,7 @@ def main(): if args.remote: # if we are running remotely enqueue this run, and leave the process - # the trains-agent services will pick it up and execute it for us. + # the clearml-agent services will pick it up and execute it for us. task.execute_remotely(queue_name='services') autoscaler = AwsAutoScaler(hyper_params, configurations) diff --git a/examples/services/aws-autoscaler/requirements.txt b/examples/services/aws-autoscaler/requirements.txt index 17225017..ae1e1883 100644 --- a/examples/services/aws-autoscaler/requirements.txt +++ b/examples/services/aws-autoscaler/requirements.txt @@ -1,5 +1,5 @@ boto3 pyYaml six -trains +clearml pathlib2 diff --git a/examples/services/cleanup/cleanup_service.py b/examples/services/cleanup/cleanup_service.py index c1cebad2..7939cebe 100644 --- a/examples/services/cleanup/cleanup_service.py +++ b/examples/services/cleanup/cleanup_service.py @@ -10,7 +10,7 @@ You can configure the run by changing the `args` dictionary: - force_delete (bool): Allows forcing the task deletion (for every task status). Default: False. Requirements: -- trains_agent installed -> pip install trains-agent +- clearml_agent installed -> pip install clearml-agent """ import logging @@ -20,11 +20,11 @@ from glob import glob from shutil import rmtree from time import sleep, time -from trains.backend_api.session.client import APIClient +from clearml.backend_api.session.client import APIClient -from trains import Task +from clearml import Task -# Connecting TRAINS +# Connecting ClearML task = Task.init( project_name="DevOps", task_name="Cleanup Service", @@ -54,7 +54,7 @@ if args["run_as_service"] and task.running_locally(): args["run_as_service"] = not verify or verify.startswith('y') if args["run_as_service"]: - # if this code is executed by `trains-agent` the function call does nothing. + # if this code is executed by `clearml-agent` the function call does nothing. # if executed locally, the local process will be terminated, and a remote copy will be executed instead task.execute_remotely(queue_name="services", exit_process=True) diff --git a/examples/services/cleanup/requirements.txt b/examples/services/cleanup/requirements.txt index 3417fd38..6dac6a83 100644 --- a/examples/services/cleanup/requirements.txt +++ b/examples/services/cleanup/requirements.txt @@ -1 +1 @@ -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/services/jupyter-service/execute_jupyter_notebook_server.py b/examples/services/jupyter-service/execute_jupyter_notebook_server.py index b53bc21d..0c30ad6b 100644 --- a/examples/services/jupyter-service/execute_jupyter_notebook_server.py +++ b/examples/services/jupyter-service/execute_jupyter_notebook_server.py @@ -9,29 +9,30 @@ import psutil # make sure we have jupyter in the auto requirements import jupyter # noqa -from trains import Task +from clearml import Task -# initialize TRAINS +# initialize ClearML task = Task.init( project_name="DevOps", task_name="Allocate Jupyter Notebook Instance", task_type=Task.TaskTypes.service) -# get rid of all the runtime TRAINS +# get rid of all the runtime ClearML preserve = ( - "TRAINS_API_HOST", - "TRAINS_WEB_HOST", - "TRAINS_FILES_HOST", - "TRAINS_CONFIG_FILE", - "TRAINS_API_ACCESS_KEY", - "TRAINS_API_SECRET_KEY", - "TRAINS_API_HOST_VERIFY_CERT", - "TRAINS_DOCKER_IMAGE", + "_API_HOST", + "_WEB_HOST", + "_FILES_HOST", + "_CONFIG_FILE", + "_API_ACCESS_KEY", + "_API_SECRET_KEY", + "_API_HOST_VERIFY_CERT", + "_DOCKER_IMAGE", ) # setup os environment env = deepcopy(os.environ) for key in os.environ: - if key.startswith("TRAINS") and key not in preserve: + if (key.startswith("TRAINS") and key[6:] not in preserve) or \ + (key.startswith("CLEARML") and key[7:] not in preserve): env.pop(key, None) # Add jupyter server base folder @@ -44,7 +45,7 @@ param = { task.connect(param) # set default docker image, with network configuration -os.environ["TRAINS_DOCKER_IMAGE"] = param['default_docker_for_jupyter'] +os.environ["CLEARML_DOCKER_IMAGE"] = param['default_docker_for_jupyter'] task.set_base_docker("{} --network host".format(param['default_docker_for_jupyter'])) @@ -79,11 +80,11 @@ if param.get("ssh_server"): "sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && " "sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd && " # noqa: W605 'echo "export VISIBLE=now" >> /etc/profile && ' - 'echo "export TRAINS_CONFIG_FILE={trains_config_file}" >> /etc/profile && ' + 'echo "export TRAINS_CONFIG_FILE={clearml_config_file}" >> /etc/profile && ' "/usr/sbin/sshd -p {port}".format( password=ssh_password, port=port, - trains_config_file=os.environ.get("TRAINS_CONFIG_FILE"), + clearml_config_file=os.environ.get("TRAINS_CONFIG_FILE"), ) ) diff --git a/examples/services/jupyter-service/requirements.txt b/examples/services/jupyter-service/requirements.txt index 340406f0..ad052a27 100644 --- a/examples/services/jupyter-service/requirements.txt +++ b/examples/services/jupyter-service/requirements.txt @@ -1,3 +1,3 @@ jupyter psutil -trains \ No newline at end of file +clearml \ No newline at end of file diff --git a/examples/services/monitoring/requirements.txt b/examples/services/monitoring/requirements.txt index 182dbbab..6972a82c 100644 --- a/examples/services/monitoring/requirements.txt +++ b/examples/services/monitoring/requirements.txt @@ -1,2 +1,2 @@ -trains +clearml slackclient > 2.0.0 diff --git a/examples/services/monitoring/slack_alerts.py b/examples/services/monitoring/slack_alerts.py index 59f12f4d..5ea5a89c 100644 --- a/examples/services/monitoring/slack_alerts.py +++ b/examples/services/monitoring/slack_alerts.py @@ -1,7 +1,7 @@ """ -Create a Trains Monitoring Service that posts alerts on Slack Channel groups based on some logic +Create a ClearML Monitoring Service that posts alerts on Slack Channel groups based on some logic -Creating a new Slack Bot (Allegro Trains Bot): +Creating a new Slack Bot (Allegro ClearML Bot): 1. Login to your Slack account 2. Go to https://api.slack.com/apps/new 3. Give the new App a name (For example "Allegro Train Bot") and select your workspace @@ -18,7 +18,7 @@ Creating a new Slack Bot (Allegro Trains Bot): 8. Now under "OAuth Tokens & Redirect URLs" press on "Install App to Workspace", then hit "Allow" on the confirmation dialog 9. Under "OAuth Tokens & Redirect URLs" copy the "Bot User OAuth Access Token" by clicking on "Copy" button -10. To use the copied API Token in the Allegro Trains Slack service, +10. To use the copied API Token in the Allegro ClearML Slack service, execute the script with --slack_api "" (notice the use of double quotes around the token) We are done! @@ -32,8 +32,8 @@ from typing import Optional from slack import WebClient from slack.errors import SlackApiError -from trains import Task -from trains.automation.monitor import Monitor +from clearml import Task +from clearml.automation.monitor import Monitor class SlackMonitor(Monitor): @@ -141,10 +141,10 @@ class SlackMonitor(Monitor): def main(): - print('TRAINS experiment monitor Slack service\n') + print('ClearML experiment monitor Slack service\n') # Slack Monitor arguments - parser = argparse.ArgumentParser(description='TRAINS monitor experiments and post Slack Alerts') + parser = argparse.ArgumentParser(description='ClearML monitor experiments and post Slack Alerts') parser.add_argument('--channel', type=str, help='Set the channel to post the Slack alerts') parser.add_argument('--slack_api', type=str, default=os.environ.get('SLACK_API_TOKEN', None), @@ -158,7 +158,7 @@ def main(): 'This will help eliminate unnecessary debug sessions that crashed right after starting ' '(default:0 alert on all)') parser.add_argument('--include_manual_experiments', action="store_true", default=False, - help='Include experiments running manually (i.e. not by trains-agent)') + help='Include experiments running manually (i.e. not by clearml-agent)') parser.add_argument('--include_completed_experiments', action="store_true", default=False, help='Include completed experiments (i.e. not just failed experiments)') parser.add_argument('--refresh_rate', type=float, default=10., @@ -202,7 +202,7 @@ def main(): # Let everyone know we are up and running start_message = \ - '{}Allegro Trains Slack monitoring service started\nMonitoring project \'{}\''.format( + '{}Allegro ClearML Slack monitoring service started\nMonitoring project \'{}\''.format( (args.message_prefix + ' ') if args.message_prefix else '', args.project or 'all') slack_monitor.post_message(start_message) diff --git a/requirements.txt b/requirements.txt index d3c3ba81..b840a10d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,7 +13,7 @@ Pillow>=4.1.1 psutil>=3.4.2 pyparsing>=2.0.3 python-dateutil>=2.6.1 -pyjwt>=1.6.4 +pyjwt>=1.6.4,<2.0.0 PyYAML>=3.12 requests-file>=1.4.2 requests>=2.20.0 diff --git a/setup.py b/setup.py index 7bbbfe6e..7e34c524 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ """ -TRAINS - Artificial Intelligence Version Control +ClearML - Artificial Intelligence Version Control https://github.com/allegroai/trains """ @@ -27,20 +27,20 @@ def read_version_string(version_file): raise RuntimeError("Unable to find version string.") -version = read_version_string("trains/version.py") +version = read_version_string("clearml/version.py") requirements = read_text(os.path.join(here, 'requirements.txt')).splitlines() setup( - name='trains', + name='clearml', version=version, - description='TRAINS - Auto-Magical Experiment Manager & Version Control for AI', + description='ClearML - Auto-Magical Experiment Manager, Version Control, and MLOps for AI', long_description=long_description, long_description_content_type='text/markdown', # The project's main homepage. url='https://github.com/allegroai/trains', author='Allegroai', - author_email='trains@allegro.ai', + author_email='clearml@allegro.ai', license='Apache License 2.0', classifiers=[ # How mature is this project. Common values are @@ -65,7 +65,7 @@ setup( 'Programming Language :: Python :: 3.8', 'License :: OSI Approved :: Apache Software License', ], - keywords='trains development machine deep learning version control machine-learning machinelearning ' + keywords='clearml trains development machine deep learning version control machine-learning machinelearning ' 'deeplearning deep-learning experiment-manager experimentmanager', packages=find_packages(exclude=['contrib', 'docs', 'data', 'examples', 'tests']), install_requires=requirements, @@ -81,7 +81,7 @@ setup( ], }, package_data={ - 'trains': ['config/default/*.conf', 'backend_api/config/default/*.conf'] + 'clearml': ['config/default/*.conf', 'backend_api/config/default/*.conf'] }, include_package_data=True, # To provide executable scripts, use entry points in preference to the @@ -89,7 +89,9 @@ setup( # pip to create the appropriate form of executable for the target platform. entry_points={ 'console_scripts': [ - 'trains-init = trains.config.default.__main__:main', + 'clearml-init = clearml.cli.config.__main__:main', + 'clearml-data = clearml.cli.data.__main__:main', + 'clearml-launch = clearml.cli.task.__main__:main', ], }, )