From e07c25b3657bf88201a6704d145574dd813c2738 Mon Sep 17 00:00:00 2001 From: jaredquincy Date: Tue, 8 Apr 2025 12:14:29 -0700 Subject: [PATCH 1/4] Ember commit --- ARCHITECTURE.md | 978 ++++ CONTRIBUTING.md | 388 ++ DEBUGGING.md | 47 + ENVIRONMENT_MANAGEMENT.md | 144 + INSTALLATION_GUIDE.md | 213 + LICENSE | 21 + LLM_SPECIFICATIONS.md | 592 +++ QUICKSTART.md | 217 + README.md | 408 ++ TESTING_INSTALLATION.md | 197 + conftest.py | 126 + docs/CONTEXT_SYSTEM.md | 285 + docs/assets/ember_icon_400.png | Bin 0 -> 11846 bytes docs/assets/ember_icon_400@2x.svg | 4 + docs/assets/ember_workmark.png | Bin 0 -> 16298 bytes docs/assets/ember_workmark.svg | 3 + docs/assets/logo_ember_icon@2x.png | Bin 0 -> 13173 bytes docs/assets/logos/anyscale-logo.png | Bin 0 -> 59697 bytes docs/assets/logos/berkeley-logo.png | Bin 0 -> 88640 bytes docs/assets/logos/databricks-logo.png | Bin 0 -> 2208 bytes docs/assets/logos/foundry-logo.avif | Bin 0 -> 4581 bytes docs/assets/logos/google-logo.png | Bin 0 -> 72065 bytes docs/assets/logos/ibm-logo.svg | 49 + docs/assets/logos/microsoft-logo.jpeg | Bin 0 -> 5892 bytes docs/assets/logos/nvidia-log.png | Bin 0 -> 58640 bytes docs/assets/logos/princeton-logo.png | Bin 0 -> 6330 bytes docs/assets/logos/stanford-logo.png | Bin 0 -> 11876 bytes docs/cli/CLI_STATUS.md | 32 + docs/cli/DEVELOPERS.md | 430 ++ docs/cli/ERROR_HANDLING.md | 160 + docs/cli/QUICKREF.md | 167 + docs/cli/README.md | 551 ++ docs/cli/SHELL_COMPLETION.md | 152 + docs/design/dataset_implementation_plan.md | 999 ++++ docs/design/enhanced_jit_design_doc.md | 157 + docs/exceptions_guide.md | 199 + docs/models/README.md | 164 + docs/quickstart/adding_datasets.md | 196 + docs/quickstart/configuration.md | 208 + docs/quickstart/data.md | 235 + docs/quickstart/model_registry.md | 260 + docs/quickstart/non.md | 278 + docs/quickstart/operators.md | 224 + docs/quickstart/prompt_signatures.md | 235 + docs/xcs/API_REFERENCE.md | 296 ++ docs/xcs/ARCHITECTURE.md | 141 + docs/xcs/EXECUTION_OPTIONS.md | 528 ++ docs/xcs/JIT_OVERVIEW.md | 163 + docs/xcs/PERFORMANCE_GUIDE.md | 171 + docs/xcs/QUICKSTART.md | 226 + docs/xcs/README.md | 124 + docs/xcs/SIMPLIFIED_IMPORTS.md | 49 + docs/xcs/TRANSFORMS.md | 594 +++ mypy.ini | 26 + pyproject.toml | 259 + pytest.ini | 33 + setup.py | 4 + src/ember/__init__.py | 219 + src/ember/api/__init__.py | 91 + src/ember/api/data.py | 742 +++ src/ember/api/eval.py | 369 ++ src/ember/api/models.py | 827 +++ src/ember/api/non.py | 78 + src/ember/api/operator.py | 51 + src/ember/api/operators.py | 91 + src/ember/api/types.py | 86 + src/ember/api/xcs.py | 86 + src/ember/core/__init__.py | 30 + src/ember/core/config/README.md | 145 + src/ember/core/config/__init__.py | 62 + src/ember/core/config/config.yaml.example | 98 + src/ember/core/config/exceptions.py | 21 + src/ember/core/config/loader.py | 321 ++ src/ember/core/config/manager.py | 151 + src/ember/core/config/schema.py | 225 + src/ember/core/context/README.md | 140 + src/ember/core/context/__init__.py | 66 + src/ember/core/context/_config_view.py | 196 + .../core/context/cache_aligned_registry.py | 331 ++ src/ember/core/context/compatibility.py | 97 + src/ember/core/context/component.py | 167 + src/ember/core/context/config.py | 167 + src/ember/core/context/config_integration.py | 278 + src/ember/core/context/context_metrics.py | 182 + src/ember/core/context/data.py | 251 + src/ember/core/context/ember_context.py | 477 ++ src/ember/core/context/management.py | 98 + src/ember/core/context/metrics.py | 261 + src/ember/core/context/model.py | 212 + src/ember/core/context/registry.py | 136 + src/ember/core/exceptions.py | 1301 +++++ src/ember/core/metrics/__init__.py | 31 + src/ember/core/metrics/api.py | 98 + src/ember/core/metrics/benchmarks.py | 112 + src/ember/core/metrics/exporters/__init__.py | 8 + .../core/metrics/exporters/prometheus.py | 100 + src/ember/core/metrics/integration.py | 160 + src/ember/core/metrics/metrics.py | 414 ++ src/ember/core/non.py | 516 ++ src/ember/core/non_compact.py | 346 ++ src/ember/core/registry/__init__.py | 16 + src/ember/core/registry/model/README.md | 310 ++ src/ember/core/registry/model/__init__.py | 138 + .../core/registry/model/base/__init__.py | 1 + .../registry/model/base/context/__init__.py | 210 + .../registry/model/base/registry/__init__.py | 1 + .../registry/model/base/registry/discovery.py | 530 ++ .../registry/model/base/registry/factory.py | 270 + .../model/base/registry/model_registry.py | 362 ++ .../registry/model/base/schemas/__init__.py | 28 + .../model/base/schemas/chat_schemas.py | 119 + .../core/registry/model/base/schemas/cost.py | 71 + .../registry/model/base/schemas/model_info.py | 157 + .../model/base/schemas/provider_info.py | 19 + .../core/registry/model/base/schemas/usage.py | 84 + .../registry/model/base/services/__init__.py | 9 + .../model/base/services/model_service.py | 224 + .../model/base/services/usage_service.py | 81 + .../registry/model/base/utils/__init__.py | 1 + .../base/utils/model_registry_exceptions.py | 34 + .../model/base/utils/usage_calculator.py | 104 + .../core/registry/model/config/__init__.py | 4 + .../registry/model/config/ember.yaml.example | 91 + .../core/registry/model/config/model_enum.py | 113 + .../core/registry/model/config/settings.py | 365 ++ .../core/registry/model/examples/__init__.py | 3 + .../registry/model/examples/api_example.py | 140 + .../core/registry/model/examples/example.py | 81 + .../examples/provider_extension_guide.py | 799 +++ .../registry/model/examples/simple_example.py | 30 + .../model/examples/usage_example.ipynb | 144 + .../registry/model/examples/usage_example.py | 88 + .../core/registry/model/initialization.py | 299 ++ .../registry/model/model_module/__init__.py | 1 + .../core/registry/model/model_module/lm.py | 161 + .../core/registry/model/providers/__init__.py | 1 + .../model/providers/anthropic/__init__.py | 1 + .../anthropic/anthropic_discovery.py | 249 + .../providers/anthropic/anthropic_provider.py | 572 ++ .../model/providers/base_discovery.py | 104 + .../registry/model/providers/base_provider.py | 195 + .../model/providers/deepmind/__init__.py | 1 + .../providers/deepmind/deepmind_discovery.py | 140 + .../providers/deepmind/deepmind_provider.py | 531 ++ .../model/providers/openai/__init__.py | 1 + .../providers/openai/openai_discovery.py | 168 + .../model/providers/openai/openai_provider.py | 440 ++ .../core/registry/model/providers/registry.py | 38 + src/ember/core/registry/operator/__init__.py | 12 + .../core/registry/operator/base/__init__.py | 10 + .../core/registry/operator/base/_module.py | 1028 ++++ .../registry/operator/base/operator_base.py | 288 + .../core/registry/operator/core/__init__.py | 40 + .../core/registry/operator/core/ensemble.py | 118 + .../registry/operator/core/most_common.py | 54 + .../registry/operator/core/selector_judge.py | 84 + .../registry/operator/core/synthesis_judge.py | 95 + .../core/registry/operator/core/verifier.py | 129 + .../core/registry/operator/exceptions.py | 35 + .../core/registry/specification/example.py | 52 + .../core/registry/specification/exceptions.py | 15 + .../registry/specification/specification.py | 261 + src/ember/core/types/README.md | 82 + src/ember/core/types/__init__.py | 74 + src/ember/core/types/config_types.py | 148 + src/ember/core/types/ember_model.py | 308 ++ src/ember/core/types/protocols.py | 132 + src/ember/core/types/type_check.py | 175 + src/ember/core/types/type_vars.py | 27 + src/ember/core/types/xcs_types.py | 394 ++ src/ember/core/utils/__init__.py | 3 + src/ember/core/utils/data/__init__.py | 202 + src/ember/core/utils/data/base/__init__.py | 1 + src/ember/core/utils/data/base/config.py | 22 + src/ember/core/utils/data/base/loaders.py | 147 + src/ember/core/utils/data/base/models.py | 74 + src/ember/core/utils/data/base/preppers.py | 54 + src/ember/core/utils/data/base/samplers.py | 70 + .../core/utils/data/base/transformers.py | 51 + src/ember/core/utils/data/base/validators.py | 199 + src/ember/core/utils/data/cache/__init__.py | 30 + .../core/utils/data/cache/cache_manager.py | 326 ++ src/ember/core/utils/data/compat/__init__.py | 11 + .../core/utils/data/compat/registry_proxy.py | 60 + src/ember/core/utils/data/context/__init__.py | 21 + .../core/utils/data/context/data_context.py | 545 ++ .../core/utils/data/context/fix/__init__.py | 85 + .../core/utils/data/context/registry_proxy.py | 159 + .../core/utils/data/context_integration.py | 142 + .../utils/data/datasets_registry/__init__.py | 1 + .../core/utils/data/datasets_registry/aime.py | 195 + .../data/datasets_registry/codeforces.py | 149 + .../data/datasets_registry/commonsense_qa.py | 74 + .../core/utils/data/datasets_registry/gpqa.py | 119 + .../utils/data/datasets_registry/halueval.py | 116 + .../core/utils/data/datasets_registry/mmlu.py | 100 + .../data/datasets_registry/short_answer.py | 48 + .../data/datasets_registry/truthful_qa.py | 59 + .../core/utils/data/examples/__init__.py | 1 + .../core/utils/data/examples/usage_example.py | 68 + src/ember/core/utils/data/initialization.py | 145 + src/ember/core/utils/data/loader_factory.py | 135 + .../core/utils/data/metadata_registry.py | 28 + src/ember/core/utils/data/registry.py | 306 ++ src/ember/core/utils/data/service.py | 328 ++ .../core/utils/data/streaming/__init__.py | 36 + .../core/utils/data/streaming/dataset.py | 465 ++ src/ember/core/utils/embedding_utils.py | 157 + src/ember/core/utils/eval/__init__.py | 22 + src/ember/core/utils/eval/base_evaluator.py | 99 + src/ember/core/utils/eval/code_execution.py | 829 +++ src/ember/core/utils/eval/evaluators.py | 291 + src/ember/core/utils/eval/extractors.py | 56 + src/ember/core/utils/eval/numeric_answer.py | 318 ++ src/ember/core/utils/eval/pipeline.py | 133 + src/ember/core/utils/eval/registry.py | 43 + .../core/utils/eval/stateful_evaluators.py | 62 + src/ember/core/utils/logging.py | 174 + src/ember/core/utils/retry_utils.py | 179 + src/ember/example_simplified_imports.py | 19 + src/ember/examples/README.md | 56 + src/ember/examples/__init__.py | 1 + src/ember/examples/advanced/README.md | 39 + src/ember/examples/advanced/__init__.py | 1 + .../examples/advanced/clean_jit_example.py | 281 + .../advanced/context_performance_example.py | 317 ++ .../advanced/custom_component_example.py | 280 + .../advanced/diagnose_model_discovery.py | 329 ++ .../examples/advanced/ensemble_judge_mmlu.py | 1729 ++++++ .../advanced/example_architectures.py | 248 + .../model_benchmark_specialized_datasets.py | 573 ++ .../examples/advanced/parallel_benchmark.py | 408 ++ .../advanced/parallel_pipeline_example.py | 169 + .../examples/advanced/reasoning_system.py | 357 ++ .../examples/advanced/test_auto_discovery.py | 126 + src/ember/examples/basic/README.md | 32 + src/ember/examples/basic/__init__.py | 1 + src/ember/examples/basic/check_env.py | 49 + .../basic/compact_notation_example.py | 176 + src/ember/examples/basic/context_example.py | 187 + src/ember/examples/basic/minimal_example.py | 185 + .../basic/minimal_operator_example.py | 41 + src/ember/examples/basic/simple_jit_demo.py | 783 +++ src/ember/examples/benchmarks/benchmark.py | 169 + src/ember/examples/benchmarks/benchmark_io.py | 183 + src/ember/examples/data/README.md | 89 + src/ember/examples/data/__init__.py | 1 + src/ember/examples/data/context_example.py | 190 + src/ember/examples/data/data_api_example.py | 206 + .../examples/data/enhanced_builder_example.py | 218 + src/ember/examples/data/explore_datasets.py | 297 ++ .../examples/data/mcq_experiment_example.py | 470 ++ .../examples/data/new_datasets_example.py | 217 + .../examples/data/transformation_example.py | 800 +++ src/ember/examples/integration/README.md | 37 + src/ember/examples/integration/__init__.py | 1 + .../integration/api_operators_example.py | 388 ++ src/ember/examples/models/README.md | 127 + src/ember/examples/models/__init__.py | 1 + .../examples/models/dependency_injection.py | 184 + .../examples/models/function_style_api.py | 202 + src/ember/examples/models/list_models.py | 341 ++ .../models/manual_model_registration.py | 287 + .../examples/models/model_api_example.py | 343 ++ .../examples/models/model_registry_direct.py | 109 + .../examples/models/model_registry_example.py | 352 ++ .../models/register_models_directly.py | 271 + src/ember/examples/operators/README.md | 42 + src/ember/examples/operators/__init__.py | 1 + .../examples/operators/composition_example.py | 408 ++ .../operators/container_operator_example.py | 168 + .../operators/container_simplified.py | 202 + .../custom_prompt_example_caravan.py | 425 ++ .../diverse_ensemble_operator_example.py | 188 + .../operators/simplified_ensemble_example.py | 253 + src/ember/examples/xcs/README.md | 91 + src/ember/examples/xcs/__init__.py | 1 + src/ember/examples/xcs/auto_graph_example.py | 299 ++ .../examples/xcs/auto_graph_simplified.py | 201 + .../examples/xcs/enhanced_jit_example.py | 178 + .../examples/xcs/example_simplified_xcs.py | 120 + src/ember/examples/xcs/jit_example.py | 404 ++ .../examples/xcs/simple_autograph_example.py | 226 + .../xcs/transforms_integration_example.py | 868 +++ src/ember/non.py | 230 + src/ember/plugin_system.py | 35 + src/ember/xcs/README.md | 144 + src/ember/xcs/__init__.py | 117 + src/ember/xcs/api/__init__.py | 33 + src/ember/xcs/api/core.py | 428 ++ src/ember/xcs/api/types.py | 148 + src/ember/xcs/common/__init__.py | 15 + src/ember/xcs/common/plans.py | 233 + src/ember/xcs/engine/__init__.py | 33 + src/ember/xcs/engine/execution_context.py | 166 + src/ember/xcs/engine/execution_options.py | 345 ++ .../xcs/engine/test_xcs_parallel_scheduler.py | 27 + src/ember/xcs/engine/unified_engine.py | 278 + src/ember/xcs/engine/xcs_engine.py | 554 ++ src/ember/xcs/engine/xcs_noop_scheduler.py | 55 + src/ember/xcs/exceptions.py | 221 + src/ember/xcs/graph/__init__.py | 26 + src/ember/xcs/graph/dependency_analyzer.py | 204 + src/ember/xcs/graph/graph_builder.py | 289 + src/ember/xcs/graph/xcs_graph.py | 376 ++ src/ember/xcs/jit/__init__.py | 31 + src/ember/xcs/jit/cache.py | 389 ++ src/ember/xcs/jit/core.py | 458 ++ src/ember/xcs/jit/execution_utils.py | 111 + src/ember/xcs/jit/modes.py | 16 + src/ember/xcs/jit/strategies/__init__.py | 21 + src/ember/xcs/jit/strategies/base_strategy.py | 163 + src/ember/xcs/jit/strategies/enhanced.py | 187 + src/ember/xcs/jit/strategies/structural.py | 210 + src/ember/xcs/jit/strategies/trace.py | 206 + src/ember/xcs/schedulers/__init__.py | 28 + src/ember/xcs/schedulers/base_scheduler.py | 218 + .../xcs/schedulers/base_scheduler_impl.py | 737 +++ src/ember/xcs/schedulers/factory.py | 78 + src/ember/xcs/schedulers/unified_scheduler.py | 101 + src/ember/xcs/tracer/__init__.py | 21 + src/ember/xcs/tracer/_context_types.py | 48 + src/ember/xcs/tracer/autograph.py | 1175 ++++ src/ember/xcs/tracer/structural_jit.py | 887 ++++ src/ember/xcs/tracer/tracer_decorator.py | 572 ++ src/ember/xcs/tracer/unified_jit.py | 104 + src/ember/xcs/tracer/xcs_tracing.py | 291 + src/ember/xcs/transforms/__init__.py | 35 + src/ember/xcs/transforms/mesh.py | 993 ++++ src/ember/xcs/transforms/pmap.py | 1075 ++++ src/ember/xcs/transforms/transform_base.py | 476 ++ src/ember/xcs/transforms/vmap.py | 574 ++ src/ember/xcs/utils/README.md | 91 + src/ember/xcs/utils/__init__.py | 31 + src/ember/xcs/utils/boundary.py | 217 + src/ember/xcs/utils/execution_analyzer.py | 342 ++ src/ember/xcs/utils/executor.py | 349 ++ src/ember/xcs/utils/model_conversion.py | 167 + src/ember/xcs/utils/structured_logging.py | 675 +++ .../xcs/utils/test_structured_logging.py | 326 ++ src/ember/xcs/utils/tree_util.py | 502 ++ tests/README.md | 106 + tests/__init__.py | 1 + tests/conftest.py | 189 + tests/fuzzing/__init__.py | 1 + tests/fuzzing/fuzz_config_parser.py | 105 + tests/fuzzing/run_fuzz_tests.py | 116 + tests/helpers/__init__.py | 1 + tests/helpers/conftest.py | 1 + tests/helpers/data_minimal_doubles.py | 293 + tests/helpers/dummy_lm.py | 18 + tests/helpers/ember_model.py | 155 + tests/helpers/model_minimal_doubles.py | 162 + tests/helpers/non_mocks.py | 435 ++ tests/helpers/operator_base.py | 248 + tests/helpers/operator_minimal_doubles.py | 107 + tests/helpers/simplified_imports.py | 156 + tests/helpers/simplified_xcs_imports.py | 135 + tests/helpers/stub_classes.py | 465 ++ tests/helpers/type_testing.py | 82 + tests/helpers/xcs_minimal_doubles.py | 195 + tests/helpers/xcs_mocks.py | 575 ++ tests/integration/__init__.py | 1 + tests/integration/core/context/__init__.py | 1 + .../core/context/integration/README.md | 19 + .../core/context/integration/__init__.py | 1 + .../context/integration/test_basic_context.py | 44 + .../context/integration/test_mock_models.py | 69 + .../integration/test_thread_isolation.py | 81 + .../core/registry/test_provider_discovery.py | 140 + .../integration/core/test_integration_core.py | 306 ++ tests/integration/core/test_minimal_config.py | 339 ++ .../core/test_non_compact_integration.py | 256 + .../core/test_operator_integration.py | 221 + tests/integration/core/utils/__init__.py | 1 + tests/integration/core/utils/data/__init__.py | 5 + .../core/utils/data/test_data_api_facade.py | 342 ++ .../utils/data/test_data_api_integration.py | 294 + .../data/test_data_context_integration.py | 119 + .../core/utils/data/test_data_end_to_end.py | 224 + .../core/utils/data/test_dataset_builder.py | 98 + .../data/test_new_datasets_integration.py | 173 + tests/integration/core/utils/eval/__init__.py | 1 + .../core/utils/eval/test_eval_integration.py | 409 ++ tests/integration/performance/README.md | 52 + .../performance/acceleration_strategies.md | 157 + .../performance/acceleration_strategies.png | Bin 0 -> 276287 bytes .../performance/scheduler_benchmark.py | 232 + .../integration/performance/test_benchmark.py | 468 ++ .../test_data_context_performance.py | 171 + .../performance/test_jit_comparison.py | 436 ++ .../test_nested_jit_performance.py | 905 ++++ .../test_nested_operators_performance.py | 974 ++++ .../test_non_compact_performance.py | 273 + .../test_parallel_execution_performance.py | 421 ++ .../performance/test_scheduler_performance.py | 306 ++ tests/integration/real_integration_test.py | 471 ++ tests/integration/test_api_integration.py | 184 + tests/integration/test_data_api_facade.py | 195 + tests/integration/test_end_to_end_workflow.py | 466 ++ tests/integration/test_eval_api.py | 143 + .../test_model_context_integration.py | 172 + .../test_model_registry_integration.py | 263 + tests/integration/tracer/test_enhanced_jit.py | 317 ++ .../tracer/test_tracing_integration.py | 136 + tests/integration/xcs/README.md | 50 + tests/integration/xcs/__init__.py | 1 + .../xcs/engine/test_unified_engine.py | 63 + .../xcs/graph/test_dependency_analyzer.py | 120 + tests/integration/xcs/jit/test_jit_core.py | 92 + .../xcs/test_engine_integration.py | 78 + .../xcs/test_jit_ensemble_schedulers.py | 350 ++ .../xcs/test_jit_strategies_integration.py | 332 ++ .../xcs/test_unified_architecture.py | 278 + tests/integration/xcs/test_xcs_integration.py | 173 + tests/integration/xcs/utils/__init__.py | 0 tests/integration/xcs/utils/test_executor.py | 103 + tests/simple_import_test.py | 28 + tests/test_aime_implementation.py | 73 + tests/test_import.py | 27 + tests/test_simplified_imports.py | 104 + tests/test_simplified_xcs_imports.py | 130 + tests/test_xcs_basic.py | 62 + tests/unit/__init__.py | 1 + tests/unit/core/__init__.py | 1 + tests/unit/core/config/test_loader.py | 306 ++ tests/unit/core/config/test_schema.py | 281 + tests/unit/core/context/__init__.py | 1 + tests/unit/core/context/test_ember_context.py | 298 ++ tests/unit/core/context/test_registry.py | 173 + .../core/metrics/test_metrics_concurrency.py | 103 + tests/unit/core/metrics/test_metrics_core.py | 266 + .../core/metrics/test_metrics_integration.py | 159 + .../core/metrics/test_metrics_performance.py | 110 + tests/unit/core/registry/__init__.py | 1 + .../unit/core/registry/model/base/__init__.py | 1 + .../model/base/context/test_model_context.py | 233 + .../model/base/registry/test_discovery.py | 754 +++ .../model/base/registry/test_factory.py | 370 ++ .../model/base/registry/test_model_enum.py | 46 + .../base/registry/test_model_registry.py | 518 ++ .../model/base/schemas/test_chat_schemas.py | 44 + .../registry/model/base/schemas/test_cost.py | 17 + .../model/base/schemas/test_model_info.py | 57 + .../model/base/schemas/test_provider_info.py | 27 + .../registry/model/base/schemas/test_usage.py | 37 + .../model/base/services/test_model_service.py | 324 ++ .../model/base/services/test_usage_service.py | 49 + .../utils/test_model_registry_exceptions.py | 22 + .../registry/model/config/test_settings.py | 164 + .../registry/model/examples/test_example.py | 1 + .../model/examples/test_usage_example.py | 71 + .../registry/model/model_modules/test_lm.py | 72 + .../anthropic/test_anthropic_discovery.py | 283 + .../anthropic/test_anthropic_provider.py | 108 + .../deepmind/test_deepmind_discovery.py | 94 + .../deepmind/test_deepmind_provider.py | 118 + .../providers/ibm/test_watsonx_provider.py | 1 + .../providers/openai/test_openai_discovery.py | 58 + .../providers/openai/test_openai_provider.py | 107 + .../core/registry/model/test_full_flow.py | 139 + tests/unit/core/registry/operator/__init__.py | 1 + .../core/registry/operator/base/__init__.py | 1 + .../operator/base/test_concurrency.py | 56 + .../operator/base/test_init_behavior.py | 93 + .../registry/operator/base/test_module.py | 504 ++ .../operator/base/test_operator_base.py | 243 + .../operator/base/test_performance.py | 259 + .../core/registry/operator/core/__init__.py | 1 + .../operator/core/test_ensemble_operator.py | 100 + .../core/test_judge_synthesis_operator.py | 68 + .../core/test_most_common_operator.py | 47 + .../operator/core/test_verifier_operator.py | 87 + .../registry/prompt_signature/__init__.py | 1 + .../prompt_signature/test_signatures.py | 170 + .../core/registry/specification/__init__.py | 1 + .../specification/test_specification.py | 192 + tests/unit/core/test_config_schema.py | 219 + tests/unit/core/test_ember_model.py | 128 + tests/unit/core/test_exceptions.py | 181 + tests/unit/core/test_non.py | 17 + tests/unit/core/test_non_compact.py | 570 ++ .../unit/core/test_non_compact_edge_cases.py | 393 ++ .../unit/core/test_non_compact_properties.py | 203 + tests/unit/core/types/__init__.py | 3 + tests/unit/core/types/test_ember_model.py | 111 + tests/unit/core/types/test_type_check.py | 128 + tests/unit/core/types/test_xcs_types.py | 385 ++ tests/unit/core/utils/__init__.py | 1 + tests/unit/core/utils/data/README.md | 0 tests/unit/core/utils/data/__init__.py | 1 + tests/unit/core/utils/data/base/__init__.py | 1 + .../unit/core/utils/data/base/test_config.py | 76 + .../unit/core/utils/data/base/test_loaders.py | 268 + .../unit/core/utils/data/base/test_models.py | 174 + .../core/utils/data/base/test_preppers.py | 193 + .../core/utils/data/base/test_samplers.py | 136 + .../core/utils/data/base/test_transformers.py | 152 + .../data/base/test_transformers_properties.py | 618 +++ .../core/utils/data/base/test_validators.py | 315 ++ .../unit/core/utils/data/context/__init__.py | 5 + .../utils/data/context/test_data_context.py | 188 + .../utils/data/context/test_integration.py | 136 + .../utils/data/datasets_registry/__init__.py | 1 + .../utils/data/datasets_registry/test_aime.py | 251 + .../data/datasets_registry/test_codeforces.py | 250 + .../datasets_registry/test_commonsense_qa.py | 123 + .../utils/data/datasets_registry/test_gpqa.py | 214 + .../data/datasets_registry/test_halueval.py | 149 + .../utils/data/datasets_registry/test_mmlu.py | 183 + .../datasets_registry/test_short_answer.py | 77 + .../datasets_registry/test_truthful_qa.py | 113 + .../unit/core/utils/data/test_data_module.py | 105 + .../core/utils/data/test_dataset_builder.py | 254 + .../core/utils/data/test_loader_factory.py | 171 + .../core/utils/data/test_metadata_registry.py | 286 + .../utils/data/test_registry_compatibility.py | 104 + tests/unit/core/utils/data/test_service.py | 384 ++ tests/unit/core/utils/data/test_streaming.py | 239 + tests/unit/core/utils/eval/__init__.py | 1 + tests/unit/core/utils/eval/conftest.py | 124 + .../core/utils/eval/test_base_evaluator.py | 198 + .../core/utils/eval/test_code_execution.py | 55 + tests/unit/core/utils/eval/test_evaluators.py | 455 ++ tests/unit/core/utils/eval/test_extractors.py | 192 + .../core/utils/eval/test_numeric_answer.py | 185 + tests/unit/core/utils/eval/test_pipeline.py | 357 ++ tests/unit/core/utils/eval/test_registry.py | 153 + .../utils/eval/test_stateful_evaluators.py | 188 + .../utils/observability/examine_metrics.py | 68 + tests/unit/core/utils/test_embedding_utils.py | 422 ++ tests/unit/core/utils/test_retry_utils.py | 350 ++ .../unit/plugin_system/test_plugin_system.py | 1 + tests/unit/xcs/__init__.py | 1 + tests/unit/xcs/engine/test_unified_engine.py | 123 + tests/unit/xcs/engine/test_xcs_engine.py | 196 + .../xcs/engine/test_xcs_noop_scheduler.py | 149 + .../xcs/engine/test_xcs_parallel_scheduler.py | 324 ++ .../xcs/examples/test_xcs_implementation.py | 150 + .../xcs/graph/test_dependency_analyzer.py | 156 + tests/unit/xcs/graph/test_xcs_graph.py | 327 ++ tests/unit/xcs/jit/__init__.py | 1 + .../xcs/jit/strategies/test_base_strategy.py | 137 + tests/unit/xcs/jit/test_enhanced_strategy.py | 236 + tests/unit/xcs/jit/test_jit_core.py | 60 + tests/unit/xcs/jit/test_strategy_base.py | 167 + tests/unit/xcs/jit/test_strategy_selection.py | 129 + .../unit/xcs/jit/test_structural_strategy.py | 222 + tests/unit/xcs/jit/test_trace_strategy.py | 216 + .../xcs/schedulers/test_unified_scheduler.py | 240 + tests/unit/xcs/test_xcs_graph.py | 68 + tests/unit/xcs/test_xcs_integration.py | 73 + tests/unit/xcs/test_xcs_minimal_doubles.py | 117 + .../unit/xcs/tracer/test_advanced_tracing.py | 498 ++ tests/unit/xcs/tracer/test_autograph.py | 306 ++ tests/unit/xcs/tracer/test_context_types.py | 26 + tests/unit/xcs/tracer/test_jit_metrics.py | 197 + tests/unit/xcs/tracer/test_structural_jit.py | 591 +++ .../tracer/test_structural_jit_advanced.py | 1074 ++++ .../unit/xcs/tracer/test_tracer_decorator.py | 166 + tests/unit/xcs/tracer/test_unified_jit.py | 121 + tests/unit/xcs/tracer/test_xcs_tracing.py | 75 + tests/unit/xcs/transforms/__init__.py | 6 + tests/unit/xcs/transforms/conftest.py | 24 + tests/unit/xcs/transforms/mock_operators.py | 313 ++ tests/unit/xcs/transforms/test_bare_vmap.py | 838 +++ tests/unit/xcs/transforms/test_mesh.py | 986 ++++ tests/unit/xcs/transforms/test_pmap.py | 917 ++++ .../xcs/transforms/test_transform_base.py | 255 + .../xcs/transforms/test_transform_imports.py | 21 + .../transforms/test_transform_integration.py | 481 ++ tests/unit/xcs/transforms/test_transforms.py | 943 ++++ tests/unit/xcs/transforms/test_utils.py | 92 + tests/unit/xcs/transforms/test_vmap.py | 782 +++ tests/unit/xcs/unit/test_tree_util.py | 61 + tests/unit/xcs/utils/__init__.py | 0 .../unit/xcs/utils/test_execution_analyzer.py | 154 + tests/unit/xcs/utils/test_executor.py | 307 ++ .../unit/xcs/utils/test_structured_logging.py | 340 ++ tox.ini | 46 + uv.lock | 4713 +++++++++++++++++ 581 files changed, 121021 insertions(+) create mode 100644 ARCHITECTURE.md create mode 100644 CONTRIBUTING.md create mode 100644 DEBUGGING.md create mode 100644 ENVIRONMENT_MANAGEMENT.md create mode 100644 INSTALLATION_GUIDE.md create mode 100644 LICENSE create mode 100644 LLM_SPECIFICATIONS.md create mode 100644 QUICKSTART.md create mode 100644 README.md create mode 100644 TESTING_INSTALLATION.md create mode 100644 conftest.py create mode 100644 docs/CONTEXT_SYSTEM.md create mode 100644 docs/assets/ember_icon_400.png create mode 100644 docs/assets/ember_icon_400@2x.svg create mode 100644 docs/assets/ember_workmark.png create mode 100644 docs/assets/ember_workmark.svg create mode 100644 docs/assets/logo_ember_icon@2x.png create mode 100644 docs/assets/logos/anyscale-logo.png create mode 100644 docs/assets/logos/berkeley-logo.png create mode 100644 docs/assets/logos/databricks-logo.png create mode 100644 docs/assets/logos/foundry-logo.avif create mode 100644 docs/assets/logos/google-logo.png create mode 100644 docs/assets/logos/ibm-logo.svg create mode 100644 docs/assets/logos/microsoft-logo.jpeg create mode 100644 docs/assets/logos/nvidia-log.png create mode 100644 docs/assets/logos/princeton-logo.png create mode 100644 docs/assets/logos/stanford-logo.png create mode 100644 docs/cli/CLI_STATUS.md create mode 100644 docs/cli/DEVELOPERS.md create mode 100644 docs/cli/ERROR_HANDLING.md create mode 100644 docs/cli/QUICKREF.md create mode 100644 docs/cli/README.md create mode 100644 docs/cli/SHELL_COMPLETION.md create mode 100644 docs/design/dataset_implementation_plan.md create mode 100644 docs/design/enhanced_jit_design_doc.md create mode 100644 docs/exceptions_guide.md create mode 100644 docs/models/README.md create mode 100644 docs/quickstart/adding_datasets.md create mode 100644 docs/quickstart/configuration.md create mode 100644 docs/quickstart/data.md create mode 100644 docs/quickstart/model_registry.md create mode 100644 docs/quickstart/non.md create mode 100644 docs/quickstart/operators.md create mode 100644 docs/quickstart/prompt_signatures.md create mode 100644 docs/xcs/API_REFERENCE.md create mode 100644 docs/xcs/ARCHITECTURE.md create mode 100644 docs/xcs/EXECUTION_OPTIONS.md create mode 100644 docs/xcs/JIT_OVERVIEW.md create mode 100644 docs/xcs/PERFORMANCE_GUIDE.md create mode 100644 docs/xcs/QUICKSTART.md create mode 100644 docs/xcs/README.md create mode 100644 docs/xcs/SIMPLIFIED_IMPORTS.md create mode 100644 docs/xcs/TRANSFORMS.md create mode 100644 mypy.ini create mode 100644 pyproject.toml create mode 100644 pytest.ini create mode 100644 setup.py create mode 100644 src/ember/__init__.py create mode 100644 src/ember/api/__init__.py create mode 100644 src/ember/api/data.py create mode 100644 src/ember/api/eval.py create mode 100644 src/ember/api/models.py create mode 100644 src/ember/api/non.py create mode 100644 src/ember/api/operator.py create mode 100644 src/ember/api/operators.py create mode 100644 src/ember/api/types.py create mode 100644 src/ember/api/xcs.py create mode 100644 src/ember/core/__init__.py create mode 100644 src/ember/core/config/README.md create mode 100644 src/ember/core/config/__init__.py create mode 100644 src/ember/core/config/config.yaml.example create mode 100644 src/ember/core/config/exceptions.py create mode 100644 src/ember/core/config/loader.py create mode 100644 src/ember/core/config/manager.py create mode 100644 src/ember/core/config/schema.py create mode 100644 src/ember/core/context/README.md create mode 100644 src/ember/core/context/__init__.py create mode 100644 src/ember/core/context/_config_view.py create mode 100644 src/ember/core/context/cache_aligned_registry.py create mode 100644 src/ember/core/context/compatibility.py create mode 100644 src/ember/core/context/component.py create mode 100644 src/ember/core/context/config.py create mode 100644 src/ember/core/context/config_integration.py create mode 100644 src/ember/core/context/context_metrics.py create mode 100644 src/ember/core/context/data.py create mode 100644 src/ember/core/context/ember_context.py create mode 100644 src/ember/core/context/management.py create mode 100644 src/ember/core/context/metrics.py create mode 100644 src/ember/core/context/model.py create mode 100644 src/ember/core/context/registry.py create mode 100644 src/ember/core/exceptions.py create mode 100644 src/ember/core/metrics/__init__.py create mode 100644 src/ember/core/metrics/api.py create mode 100644 src/ember/core/metrics/benchmarks.py create mode 100644 src/ember/core/metrics/exporters/__init__.py create mode 100644 src/ember/core/metrics/exporters/prometheus.py create mode 100644 src/ember/core/metrics/integration.py create mode 100644 src/ember/core/metrics/metrics.py create mode 100644 src/ember/core/non.py create mode 100644 src/ember/core/non_compact.py create mode 100644 src/ember/core/registry/__init__.py create mode 100644 src/ember/core/registry/model/README.md create mode 100644 src/ember/core/registry/model/__init__.py create mode 100644 src/ember/core/registry/model/base/__init__.py create mode 100644 src/ember/core/registry/model/base/context/__init__.py create mode 100644 src/ember/core/registry/model/base/registry/__init__.py create mode 100644 src/ember/core/registry/model/base/registry/discovery.py create mode 100644 src/ember/core/registry/model/base/registry/factory.py create mode 100644 src/ember/core/registry/model/base/registry/model_registry.py create mode 100644 src/ember/core/registry/model/base/schemas/__init__.py create mode 100644 src/ember/core/registry/model/base/schemas/chat_schemas.py create mode 100644 src/ember/core/registry/model/base/schemas/cost.py create mode 100644 src/ember/core/registry/model/base/schemas/model_info.py create mode 100644 src/ember/core/registry/model/base/schemas/provider_info.py create mode 100644 src/ember/core/registry/model/base/schemas/usage.py create mode 100644 src/ember/core/registry/model/base/services/__init__.py create mode 100644 src/ember/core/registry/model/base/services/model_service.py create mode 100644 src/ember/core/registry/model/base/services/usage_service.py create mode 100644 src/ember/core/registry/model/base/utils/__init__.py create mode 100644 src/ember/core/registry/model/base/utils/model_registry_exceptions.py create mode 100644 src/ember/core/registry/model/base/utils/usage_calculator.py create mode 100644 src/ember/core/registry/model/config/__init__.py create mode 100644 src/ember/core/registry/model/config/ember.yaml.example create mode 100644 src/ember/core/registry/model/config/model_enum.py create mode 100644 src/ember/core/registry/model/config/settings.py create mode 100644 src/ember/core/registry/model/examples/__init__.py create mode 100644 src/ember/core/registry/model/examples/api_example.py create mode 100644 src/ember/core/registry/model/examples/example.py create mode 100644 src/ember/core/registry/model/examples/provider_extension_guide.py create mode 100644 src/ember/core/registry/model/examples/simple_example.py create mode 100644 src/ember/core/registry/model/examples/usage_example.ipynb create mode 100644 src/ember/core/registry/model/examples/usage_example.py create mode 100644 src/ember/core/registry/model/initialization.py create mode 100644 src/ember/core/registry/model/model_module/__init__.py create mode 100644 src/ember/core/registry/model/model_module/lm.py create mode 100644 src/ember/core/registry/model/providers/__init__.py create mode 100644 src/ember/core/registry/model/providers/anthropic/__init__.py create mode 100644 src/ember/core/registry/model/providers/anthropic/anthropic_discovery.py create mode 100644 src/ember/core/registry/model/providers/anthropic/anthropic_provider.py create mode 100644 src/ember/core/registry/model/providers/base_discovery.py create mode 100644 src/ember/core/registry/model/providers/base_provider.py create mode 100644 src/ember/core/registry/model/providers/deepmind/__init__.py create mode 100644 src/ember/core/registry/model/providers/deepmind/deepmind_discovery.py create mode 100644 src/ember/core/registry/model/providers/deepmind/deepmind_provider.py create mode 100644 src/ember/core/registry/model/providers/openai/__init__.py create mode 100644 src/ember/core/registry/model/providers/openai/openai_discovery.py create mode 100644 src/ember/core/registry/model/providers/openai/openai_provider.py create mode 100644 src/ember/core/registry/model/providers/registry.py create mode 100644 src/ember/core/registry/operator/__init__.py create mode 100644 src/ember/core/registry/operator/base/__init__.py create mode 100644 src/ember/core/registry/operator/base/_module.py create mode 100644 src/ember/core/registry/operator/base/operator_base.py create mode 100644 src/ember/core/registry/operator/core/__init__.py create mode 100644 src/ember/core/registry/operator/core/ensemble.py create mode 100644 src/ember/core/registry/operator/core/most_common.py create mode 100644 src/ember/core/registry/operator/core/selector_judge.py create mode 100644 src/ember/core/registry/operator/core/synthesis_judge.py create mode 100644 src/ember/core/registry/operator/core/verifier.py create mode 100644 src/ember/core/registry/operator/exceptions.py create mode 100644 src/ember/core/registry/specification/example.py create mode 100644 src/ember/core/registry/specification/exceptions.py create mode 100644 src/ember/core/registry/specification/specification.py create mode 100644 src/ember/core/types/README.md create mode 100644 src/ember/core/types/__init__.py create mode 100644 src/ember/core/types/config_types.py create mode 100644 src/ember/core/types/ember_model.py create mode 100644 src/ember/core/types/protocols.py create mode 100644 src/ember/core/types/type_check.py create mode 100644 src/ember/core/types/type_vars.py create mode 100644 src/ember/core/types/xcs_types.py create mode 100644 src/ember/core/utils/__init__.py create mode 100644 src/ember/core/utils/data/__init__.py create mode 100644 src/ember/core/utils/data/base/__init__.py create mode 100644 src/ember/core/utils/data/base/config.py create mode 100644 src/ember/core/utils/data/base/loaders.py create mode 100644 src/ember/core/utils/data/base/models.py create mode 100644 src/ember/core/utils/data/base/preppers.py create mode 100644 src/ember/core/utils/data/base/samplers.py create mode 100644 src/ember/core/utils/data/base/transformers.py create mode 100644 src/ember/core/utils/data/base/validators.py create mode 100644 src/ember/core/utils/data/cache/__init__.py create mode 100644 src/ember/core/utils/data/cache/cache_manager.py create mode 100644 src/ember/core/utils/data/compat/__init__.py create mode 100644 src/ember/core/utils/data/compat/registry_proxy.py create mode 100644 src/ember/core/utils/data/context/__init__.py create mode 100644 src/ember/core/utils/data/context/data_context.py create mode 100644 src/ember/core/utils/data/context/fix/__init__.py create mode 100644 src/ember/core/utils/data/context/registry_proxy.py create mode 100644 src/ember/core/utils/data/context_integration.py create mode 100644 src/ember/core/utils/data/datasets_registry/__init__.py create mode 100644 src/ember/core/utils/data/datasets_registry/aime.py create mode 100644 src/ember/core/utils/data/datasets_registry/codeforces.py create mode 100644 src/ember/core/utils/data/datasets_registry/commonsense_qa.py create mode 100644 src/ember/core/utils/data/datasets_registry/gpqa.py create mode 100644 src/ember/core/utils/data/datasets_registry/halueval.py create mode 100644 src/ember/core/utils/data/datasets_registry/mmlu.py create mode 100644 src/ember/core/utils/data/datasets_registry/short_answer.py create mode 100644 src/ember/core/utils/data/datasets_registry/truthful_qa.py create mode 100644 src/ember/core/utils/data/examples/__init__.py create mode 100644 src/ember/core/utils/data/examples/usage_example.py create mode 100644 src/ember/core/utils/data/initialization.py create mode 100644 src/ember/core/utils/data/loader_factory.py create mode 100644 src/ember/core/utils/data/metadata_registry.py create mode 100644 src/ember/core/utils/data/registry.py create mode 100644 src/ember/core/utils/data/service.py create mode 100644 src/ember/core/utils/data/streaming/__init__.py create mode 100644 src/ember/core/utils/data/streaming/dataset.py create mode 100644 src/ember/core/utils/embedding_utils.py create mode 100644 src/ember/core/utils/eval/__init__.py create mode 100644 src/ember/core/utils/eval/base_evaluator.py create mode 100644 src/ember/core/utils/eval/code_execution.py create mode 100644 src/ember/core/utils/eval/evaluators.py create mode 100644 src/ember/core/utils/eval/extractors.py create mode 100644 src/ember/core/utils/eval/numeric_answer.py create mode 100644 src/ember/core/utils/eval/pipeline.py create mode 100644 src/ember/core/utils/eval/registry.py create mode 100644 src/ember/core/utils/eval/stateful_evaluators.py create mode 100644 src/ember/core/utils/logging.py create mode 100644 src/ember/core/utils/retry_utils.py create mode 100644 src/ember/example_simplified_imports.py create mode 100644 src/ember/examples/README.md create mode 100644 src/ember/examples/__init__.py create mode 100644 src/ember/examples/advanced/README.md create mode 100644 src/ember/examples/advanced/__init__.py create mode 100644 src/ember/examples/advanced/clean_jit_example.py create mode 100644 src/ember/examples/advanced/context_performance_example.py create mode 100644 src/ember/examples/advanced/custom_component_example.py create mode 100644 src/ember/examples/advanced/diagnose_model_discovery.py create mode 100644 src/ember/examples/advanced/ensemble_judge_mmlu.py create mode 100644 src/ember/examples/advanced/example_architectures.py create mode 100644 src/ember/examples/advanced/model_benchmark_specialized_datasets.py create mode 100644 src/ember/examples/advanced/parallel_benchmark.py create mode 100644 src/ember/examples/advanced/parallel_pipeline_example.py create mode 100644 src/ember/examples/advanced/reasoning_system.py create mode 100644 src/ember/examples/advanced/test_auto_discovery.py create mode 100644 src/ember/examples/basic/README.md create mode 100644 src/ember/examples/basic/__init__.py create mode 100644 src/ember/examples/basic/check_env.py create mode 100644 src/ember/examples/basic/compact_notation_example.py create mode 100644 src/ember/examples/basic/context_example.py create mode 100644 src/ember/examples/basic/minimal_example.py create mode 100644 src/ember/examples/basic/minimal_operator_example.py create mode 100644 src/ember/examples/basic/simple_jit_demo.py create mode 100644 src/ember/examples/benchmarks/benchmark.py create mode 100644 src/ember/examples/benchmarks/benchmark_io.py create mode 100644 src/ember/examples/data/README.md create mode 100644 src/ember/examples/data/__init__.py create mode 100644 src/ember/examples/data/context_example.py create mode 100644 src/ember/examples/data/data_api_example.py create mode 100644 src/ember/examples/data/enhanced_builder_example.py create mode 100644 src/ember/examples/data/explore_datasets.py create mode 100644 src/ember/examples/data/mcq_experiment_example.py create mode 100644 src/ember/examples/data/new_datasets_example.py create mode 100644 src/ember/examples/data/transformation_example.py create mode 100644 src/ember/examples/integration/README.md create mode 100644 src/ember/examples/integration/__init__.py create mode 100644 src/ember/examples/integration/api_operators_example.py create mode 100644 src/ember/examples/models/README.md create mode 100644 src/ember/examples/models/__init__.py create mode 100644 src/ember/examples/models/dependency_injection.py create mode 100644 src/ember/examples/models/function_style_api.py create mode 100644 src/ember/examples/models/list_models.py create mode 100644 src/ember/examples/models/manual_model_registration.py create mode 100644 src/ember/examples/models/model_api_example.py create mode 100644 src/ember/examples/models/model_registry_direct.py create mode 100644 src/ember/examples/models/model_registry_example.py create mode 100644 src/ember/examples/models/register_models_directly.py create mode 100644 src/ember/examples/operators/README.md create mode 100644 src/ember/examples/operators/__init__.py create mode 100644 src/ember/examples/operators/composition_example.py create mode 100644 src/ember/examples/operators/container_operator_example.py create mode 100644 src/ember/examples/operators/container_simplified.py create mode 100644 src/ember/examples/operators/custom_prompt_example_caravan.py create mode 100644 src/ember/examples/operators/diverse_ensemble_operator_example.py create mode 100644 src/ember/examples/operators/simplified_ensemble_example.py create mode 100644 src/ember/examples/xcs/README.md create mode 100644 src/ember/examples/xcs/__init__.py create mode 100644 src/ember/examples/xcs/auto_graph_example.py create mode 100644 src/ember/examples/xcs/auto_graph_simplified.py create mode 100644 src/ember/examples/xcs/enhanced_jit_example.py create mode 100644 src/ember/examples/xcs/example_simplified_xcs.py create mode 100644 src/ember/examples/xcs/jit_example.py create mode 100644 src/ember/examples/xcs/simple_autograph_example.py create mode 100644 src/ember/examples/xcs/transforms_integration_example.py create mode 100644 src/ember/non.py create mode 100644 src/ember/plugin_system.py create mode 100644 src/ember/xcs/README.md create mode 100644 src/ember/xcs/__init__.py create mode 100644 src/ember/xcs/api/__init__.py create mode 100644 src/ember/xcs/api/core.py create mode 100644 src/ember/xcs/api/types.py create mode 100644 src/ember/xcs/common/__init__.py create mode 100644 src/ember/xcs/common/plans.py create mode 100644 src/ember/xcs/engine/__init__.py create mode 100644 src/ember/xcs/engine/execution_context.py create mode 100644 src/ember/xcs/engine/execution_options.py create mode 100644 src/ember/xcs/engine/test_xcs_parallel_scheduler.py create mode 100644 src/ember/xcs/engine/unified_engine.py create mode 100644 src/ember/xcs/engine/xcs_engine.py create mode 100644 src/ember/xcs/engine/xcs_noop_scheduler.py create mode 100644 src/ember/xcs/exceptions.py create mode 100644 src/ember/xcs/graph/__init__.py create mode 100644 src/ember/xcs/graph/dependency_analyzer.py create mode 100644 src/ember/xcs/graph/graph_builder.py create mode 100644 src/ember/xcs/graph/xcs_graph.py create mode 100644 src/ember/xcs/jit/__init__.py create mode 100644 src/ember/xcs/jit/cache.py create mode 100644 src/ember/xcs/jit/core.py create mode 100644 src/ember/xcs/jit/execution_utils.py create mode 100644 src/ember/xcs/jit/modes.py create mode 100644 src/ember/xcs/jit/strategies/__init__.py create mode 100644 src/ember/xcs/jit/strategies/base_strategy.py create mode 100644 src/ember/xcs/jit/strategies/enhanced.py create mode 100644 src/ember/xcs/jit/strategies/structural.py create mode 100644 src/ember/xcs/jit/strategies/trace.py create mode 100644 src/ember/xcs/schedulers/__init__.py create mode 100644 src/ember/xcs/schedulers/base_scheduler.py create mode 100644 src/ember/xcs/schedulers/base_scheduler_impl.py create mode 100644 src/ember/xcs/schedulers/factory.py create mode 100644 src/ember/xcs/schedulers/unified_scheduler.py create mode 100644 src/ember/xcs/tracer/__init__.py create mode 100644 src/ember/xcs/tracer/_context_types.py create mode 100644 src/ember/xcs/tracer/autograph.py create mode 100644 src/ember/xcs/tracer/structural_jit.py create mode 100644 src/ember/xcs/tracer/tracer_decorator.py create mode 100644 src/ember/xcs/tracer/unified_jit.py create mode 100644 src/ember/xcs/tracer/xcs_tracing.py create mode 100644 src/ember/xcs/transforms/__init__.py create mode 100644 src/ember/xcs/transforms/mesh.py create mode 100644 src/ember/xcs/transforms/pmap.py create mode 100644 src/ember/xcs/transforms/transform_base.py create mode 100644 src/ember/xcs/transforms/vmap.py create mode 100644 src/ember/xcs/utils/README.md create mode 100644 src/ember/xcs/utils/__init__.py create mode 100644 src/ember/xcs/utils/boundary.py create mode 100644 src/ember/xcs/utils/execution_analyzer.py create mode 100644 src/ember/xcs/utils/executor.py create mode 100644 src/ember/xcs/utils/model_conversion.py create mode 100644 src/ember/xcs/utils/structured_logging.py create mode 100644 src/ember/xcs/utils/test_structured_logging.py create mode 100644 src/ember/xcs/utils/tree_util.py create mode 100644 tests/README.md create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/fuzzing/__init__.py create mode 100644 tests/fuzzing/fuzz_config_parser.py create mode 100644 tests/fuzzing/run_fuzz_tests.py create mode 100644 tests/helpers/__init__.py create mode 100644 tests/helpers/conftest.py create mode 100644 tests/helpers/data_minimal_doubles.py create mode 100644 tests/helpers/dummy_lm.py create mode 100644 tests/helpers/ember_model.py create mode 100644 tests/helpers/model_minimal_doubles.py create mode 100644 tests/helpers/non_mocks.py create mode 100644 tests/helpers/operator_base.py create mode 100644 tests/helpers/operator_minimal_doubles.py create mode 100644 tests/helpers/simplified_imports.py create mode 100644 tests/helpers/simplified_xcs_imports.py create mode 100644 tests/helpers/stub_classes.py create mode 100644 tests/helpers/type_testing.py create mode 100644 tests/helpers/xcs_minimal_doubles.py create mode 100644 tests/helpers/xcs_mocks.py create mode 100644 tests/integration/__init__.py create mode 100644 tests/integration/core/context/__init__.py create mode 100644 tests/integration/core/context/integration/README.md create mode 100644 tests/integration/core/context/integration/__init__.py create mode 100644 tests/integration/core/context/integration/test_basic_context.py create mode 100644 tests/integration/core/context/integration/test_mock_models.py create mode 100644 tests/integration/core/context/integration/test_thread_isolation.py create mode 100644 tests/integration/core/registry/test_provider_discovery.py create mode 100644 tests/integration/core/test_integration_core.py create mode 100644 tests/integration/core/test_minimal_config.py create mode 100644 tests/integration/core/test_non_compact_integration.py create mode 100644 tests/integration/core/test_operator_integration.py create mode 100644 tests/integration/core/utils/__init__.py create mode 100644 tests/integration/core/utils/data/__init__.py create mode 100644 tests/integration/core/utils/data/test_data_api_facade.py create mode 100644 tests/integration/core/utils/data/test_data_api_integration.py create mode 100644 tests/integration/core/utils/data/test_data_context_integration.py create mode 100644 tests/integration/core/utils/data/test_data_end_to_end.py create mode 100644 tests/integration/core/utils/data/test_dataset_builder.py create mode 100644 tests/integration/core/utils/data/test_new_datasets_integration.py create mode 100644 tests/integration/core/utils/eval/__init__.py create mode 100644 tests/integration/core/utils/eval/test_eval_integration.py create mode 100644 tests/integration/performance/README.md create mode 100644 tests/integration/performance/acceleration_strategies.md create mode 100644 tests/integration/performance/acceleration_strategies.png create mode 100644 tests/integration/performance/scheduler_benchmark.py create mode 100644 tests/integration/performance/test_benchmark.py create mode 100644 tests/integration/performance/test_data_context_performance.py create mode 100644 tests/integration/performance/test_jit_comparison.py create mode 100644 tests/integration/performance/test_nested_jit_performance.py create mode 100644 tests/integration/performance/test_nested_operators_performance.py create mode 100644 tests/integration/performance/test_non_compact_performance.py create mode 100644 tests/integration/performance/test_parallel_execution_performance.py create mode 100644 tests/integration/performance/test_scheduler_performance.py create mode 100644 tests/integration/real_integration_test.py create mode 100644 tests/integration/test_api_integration.py create mode 100644 tests/integration/test_data_api_facade.py create mode 100644 tests/integration/test_end_to_end_workflow.py create mode 100644 tests/integration/test_eval_api.py create mode 100644 tests/integration/test_model_context_integration.py create mode 100644 tests/integration/test_model_registry_integration.py create mode 100644 tests/integration/tracer/test_enhanced_jit.py create mode 100644 tests/integration/tracer/test_tracing_integration.py create mode 100644 tests/integration/xcs/README.md create mode 100644 tests/integration/xcs/__init__.py create mode 100644 tests/integration/xcs/engine/test_unified_engine.py create mode 100644 tests/integration/xcs/graph/test_dependency_analyzer.py create mode 100644 tests/integration/xcs/jit/test_jit_core.py create mode 100644 tests/integration/xcs/test_engine_integration.py create mode 100644 tests/integration/xcs/test_jit_ensemble_schedulers.py create mode 100644 tests/integration/xcs/test_jit_strategies_integration.py create mode 100644 tests/integration/xcs/test_unified_architecture.py create mode 100644 tests/integration/xcs/test_xcs_integration.py create mode 100644 tests/integration/xcs/utils/__init__.py create mode 100644 tests/integration/xcs/utils/test_executor.py create mode 100644 tests/simple_import_test.py create mode 100644 tests/test_aime_implementation.py create mode 100644 tests/test_import.py create mode 100644 tests/test_simplified_imports.py create mode 100644 tests/test_simplified_xcs_imports.py create mode 100644 tests/test_xcs_basic.py create mode 100644 tests/unit/__init__.py create mode 100644 tests/unit/core/__init__.py create mode 100644 tests/unit/core/config/test_loader.py create mode 100644 tests/unit/core/config/test_schema.py create mode 100644 tests/unit/core/context/__init__.py create mode 100644 tests/unit/core/context/test_ember_context.py create mode 100644 tests/unit/core/context/test_registry.py create mode 100644 tests/unit/core/metrics/test_metrics_concurrency.py create mode 100644 tests/unit/core/metrics/test_metrics_core.py create mode 100644 tests/unit/core/metrics/test_metrics_integration.py create mode 100644 tests/unit/core/metrics/test_metrics_performance.py create mode 100644 tests/unit/core/registry/__init__.py create mode 100644 tests/unit/core/registry/model/base/__init__.py create mode 100644 tests/unit/core/registry/model/base/context/test_model_context.py create mode 100644 tests/unit/core/registry/model/base/registry/test_discovery.py create mode 100644 tests/unit/core/registry/model/base/registry/test_factory.py create mode 100644 tests/unit/core/registry/model/base/registry/test_model_enum.py create mode 100644 tests/unit/core/registry/model/base/registry/test_model_registry.py create mode 100644 tests/unit/core/registry/model/base/schemas/test_chat_schemas.py create mode 100644 tests/unit/core/registry/model/base/schemas/test_cost.py create mode 100644 tests/unit/core/registry/model/base/schemas/test_model_info.py create mode 100644 tests/unit/core/registry/model/base/schemas/test_provider_info.py create mode 100644 tests/unit/core/registry/model/base/schemas/test_usage.py create mode 100644 tests/unit/core/registry/model/base/services/test_model_service.py create mode 100644 tests/unit/core/registry/model/base/services/test_usage_service.py create mode 100644 tests/unit/core/registry/model/base/utils/test_model_registry_exceptions.py create mode 100644 tests/unit/core/registry/model/config/test_settings.py create mode 100644 tests/unit/core/registry/model/examples/test_example.py create mode 100644 tests/unit/core/registry/model/examples/test_usage_example.py create mode 100644 tests/unit/core/registry/model/model_modules/test_lm.py create mode 100644 tests/unit/core/registry/model/providers/anthropic/test_anthropic_discovery.py create mode 100644 tests/unit/core/registry/model/providers/anthropic/test_anthropic_provider.py create mode 100644 tests/unit/core/registry/model/providers/deepmind/test_deepmind_discovery.py create mode 100644 tests/unit/core/registry/model/providers/deepmind/test_deepmind_provider.py create mode 100644 tests/unit/core/registry/model/providers/ibm/test_watsonx_provider.py create mode 100644 tests/unit/core/registry/model/providers/openai/test_openai_discovery.py create mode 100644 tests/unit/core/registry/model/providers/openai/test_openai_provider.py create mode 100644 tests/unit/core/registry/model/test_full_flow.py create mode 100644 tests/unit/core/registry/operator/__init__.py create mode 100644 tests/unit/core/registry/operator/base/__init__.py create mode 100644 tests/unit/core/registry/operator/base/test_concurrency.py create mode 100644 tests/unit/core/registry/operator/base/test_init_behavior.py create mode 100644 tests/unit/core/registry/operator/base/test_module.py create mode 100644 tests/unit/core/registry/operator/base/test_operator_base.py create mode 100644 tests/unit/core/registry/operator/base/test_performance.py create mode 100644 tests/unit/core/registry/operator/core/__init__.py create mode 100644 tests/unit/core/registry/operator/core/test_ensemble_operator.py create mode 100644 tests/unit/core/registry/operator/core/test_judge_synthesis_operator.py create mode 100644 tests/unit/core/registry/operator/core/test_most_common_operator.py create mode 100644 tests/unit/core/registry/operator/core/test_verifier_operator.py create mode 100644 tests/unit/core/registry/prompt_signature/__init__.py create mode 100644 tests/unit/core/registry/prompt_signature/test_signatures.py create mode 100644 tests/unit/core/registry/specification/__init__.py create mode 100644 tests/unit/core/registry/specification/test_specification.py create mode 100644 tests/unit/core/test_config_schema.py create mode 100644 tests/unit/core/test_ember_model.py create mode 100644 tests/unit/core/test_exceptions.py create mode 100644 tests/unit/core/test_non.py create mode 100644 tests/unit/core/test_non_compact.py create mode 100644 tests/unit/core/test_non_compact_edge_cases.py create mode 100644 tests/unit/core/test_non_compact_properties.py create mode 100644 tests/unit/core/types/__init__.py create mode 100644 tests/unit/core/types/test_ember_model.py create mode 100644 tests/unit/core/types/test_type_check.py create mode 100644 tests/unit/core/types/test_xcs_types.py create mode 100644 tests/unit/core/utils/__init__.py create mode 100644 tests/unit/core/utils/data/README.md create mode 100644 tests/unit/core/utils/data/__init__.py create mode 100644 tests/unit/core/utils/data/base/__init__.py create mode 100644 tests/unit/core/utils/data/base/test_config.py create mode 100644 tests/unit/core/utils/data/base/test_loaders.py create mode 100644 tests/unit/core/utils/data/base/test_models.py create mode 100644 tests/unit/core/utils/data/base/test_preppers.py create mode 100644 tests/unit/core/utils/data/base/test_samplers.py create mode 100644 tests/unit/core/utils/data/base/test_transformers.py create mode 100644 tests/unit/core/utils/data/base/test_transformers_properties.py create mode 100644 tests/unit/core/utils/data/base/test_validators.py create mode 100644 tests/unit/core/utils/data/context/__init__.py create mode 100644 tests/unit/core/utils/data/context/test_data_context.py create mode 100644 tests/unit/core/utils/data/context/test_integration.py create mode 100644 tests/unit/core/utils/data/datasets_registry/__init__.py create mode 100644 tests/unit/core/utils/data/datasets_registry/test_aime.py create mode 100644 tests/unit/core/utils/data/datasets_registry/test_codeforces.py create mode 100644 tests/unit/core/utils/data/datasets_registry/test_commonsense_qa.py create mode 100644 tests/unit/core/utils/data/datasets_registry/test_gpqa.py create mode 100644 tests/unit/core/utils/data/datasets_registry/test_halueval.py create mode 100644 tests/unit/core/utils/data/datasets_registry/test_mmlu.py create mode 100644 tests/unit/core/utils/data/datasets_registry/test_short_answer.py create mode 100644 tests/unit/core/utils/data/datasets_registry/test_truthful_qa.py create mode 100644 tests/unit/core/utils/data/test_data_module.py create mode 100644 tests/unit/core/utils/data/test_dataset_builder.py create mode 100644 tests/unit/core/utils/data/test_loader_factory.py create mode 100644 tests/unit/core/utils/data/test_metadata_registry.py create mode 100644 tests/unit/core/utils/data/test_registry_compatibility.py create mode 100644 tests/unit/core/utils/data/test_service.py create mode 100644 tests/unit/core/utils/data/test_streaming.py create mode 100644 tests/unit/core/utils/eval/__init__.py create mode 100644 tests/unit/core/utils/eval/conftest.py create mode 100644 tests/unit/core/utils/eval/test_base_evaluator.py create mode 100644 tests/unit/core/utils/eval/test_code_execution.py create mode 100644 tests/unit/core/utils/eval/test_evaluators.py create mode 100644 tests/unit/core/utils/eval/test_extractors.py create mode 100644 tests/unit/core/utils/eval/test_numeric_answer.py create mode 100644 tests/unit/core/utils/eval/test_pipeline.py create mode 100644 tests/unit/core/utils/eval/test_registry.py create mode 100644 tests/unit/core/utils/eval/test_stateful_evaluators.py create mode 100644 tests/unit/core/utils/observability/examine_metrics.py create mode 100644 tests/unit/core/utils/test_embedding_utils.py create mode 100644 tests/unit/core/utils/test_retry_utils.py create mode 100644 tests/unit/plugin_system/test_plugin_system.py create mode 100644 tests/unit/xcs/__init__.py create mode 100644 tests/unit/xcs/engine/test_unified_engine.py create mode 100644 tests/unit/xcs/engine/test_xcs_engine.py create mode 100644 tests/unit/xcs/engine/test_xcs_noop_scheduler.py create mode 100644 tests/unit/xcs/engine/test_xcs_parallel_scheduler.py create mode 100644 tests/unit/xcs/examples/test_xcs_implementation.py create mode 100644 tests/unit/xcs/graph/test_dependency_analyzer.py create mode 100644 tests/unit/xcs/graph/test_xcs_graph.py create mode 100644 tests/unit/xcs/jit/__init__.py create mode 100644 tests/unit/xcs/jit/strategies/test_base_strategy.py create mode 100644 tests/unit/xcs/jit/test_enhanced_strategy.py create mode 100644 tests/unit/xcs/jit/test_jit_core.py create mode 100644 tests/unit/xcs/jit/test_strategy_base.py create mode 100644 tests/unit/xcs/jit/test_strategy_selection.py create mode 100644 tests/unit/xcs/jit/test_structural_strategy.py create mode 100644 tests/unit/xcs/jit/test_trace_strategy.py create mode 100644 tests/unit/xcs/schedulers/test_unified_scheduler.py create mode 100644 tests/unit/xcs/test_xcs_graph.py create mode 100644 tests/unit/xcs/test_xcs_integration.py create mode 100644 tests/unit/xcs/test_xcs_minimal_doubles.py create mode 100644 tests/unit/xcs/tracer/test_advanced_tracing.py create mode 100644 tests/unit/xcs/tracer/test_autograph.py create mode 100644 tests/unit/xcs/tracer/test_context_types.py create mode 100644 tests/unit/xcs/tracer/test_jit_metrics.py create mode 100644 tests/unit/xcs/tracer/test_structural_jit.py create mode 100644 tests/unit/xcs/tracer/test_structural_jit_advanced.py create mode 100644 tests/unit/xcs/tracer/test_tracer_decorator.py create mode 100644 tests/unit/xcs/tracer/test_unified_jit.py create mode 100644 tests/unit/xcs/tracer/test_xcs_tracing.py create mode 100644 tests/unit/xcs/transforms/__init__.py create mode 100644 tests/unit/xcs/transforms/conftest.py create mode 100644 tests/unit/xcs/transforms/mock_operators.py create mode 100644 tests/unit/xcs/transforms/test_bare_vmap.py create mode 100644 tests/unit/xcs/transforms/test_mesh.py create mode 100644 tests/unit/xcs/transforms/test_pmap.py create mode 100644 tests/unit/xcs/transforms/test_transform_base.py create mode 100644 tests/unit/xcs/transforms/test_transform_imports.py create mode 100644 tests/unit/xcs/transforms/test_transform_integration.py create mode 100644 tests/unit/xcs/transforms/test_transforms.py create mode 100644 tests/unit/xcs/transforms/test_utils.py create mode 100644 tests/unit/xcs/transforms/test_vmap.py create mode 100644 tests/unit/xcs/unit/test_tree_util.py create mode 100644 tests/unit/xcs/utils/__init__.py create mode 100644 tests/unit/xcs/utils/test_execution_analyzer.py create mode 100644 tests/unit/xcs/utils/test_executor.py create mode 100644 tests/unit/xcs/utils/test_structured_logging.py create mode 100644 tox.ini create mode 100644 uv.lock diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000..4424dc13 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,978 @@ +# Ember Architecture + +This document describes Ember's architecture, core components, and design principles. It serves as both a high-level overview for users and a detailed guide for core contributors. + +## Design Philosophy + +Ember is built on these foundational principles: + +1. **Composability First**: The ability to combine, chain, and nest components (e.g. `Operator` components) is central to Ember's design +2. **Type Safety**: Comprehensive type annotations ensure robustness and IDE support +3. **Testability**: Components are designed with SOLID principles in mind, for easy isolation and testing +4. **Scalability**: support for Parallel execution is built-in at the framework's core. This is more Tensorflow/JAX, than classic Torch spiritually +5. **Extensibility**: Registry-based design makes it simple to add new components +6. **Skeurmophism**: APIs follow familiar patterns from PyTorch/JAX, to somewhat control the learning curve +7. **Simple-over-easy**: Minimal "magic" and a focus on explicitness + +## System Architecture + +Ember's architecture follows a layered design with clear separations of concern: +``` +┌───────────────────────────────────────────────────────────────────────────────────────────┐ +│ PUBLIC API LAYER │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ api.models │ │ api.operator │ │ api.xcs │ │ +│ │ │ │ │ │ │ │ +│ │ • LLM Interfaces │ │ • Operator Base │ │ • JIT Functions │ │ +│ │ • Model Service │ │ • Specification │ │ • Execution Options │ │ +│ │ • Model Registry │ │ • Input/Output Models │ │ • Graph Controls │ │ +│ │ • Usage Tracking │ │ • Operator Registry │ │ • Transform Functions │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ api.data │ │ api.non │ │ +│ │ │ │ │ │ +│ │ • Dataset Access │ │ • Ensemble Patterns │ │ +│ │ • Data Loaders │ │ • Verification │ │ +│ │ • Transformers │ │ • Synthesis │ │ +│ │ • Evaluators │ │ • Composition Helpers │ │ +│ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ APPLICATION LAYER │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ NON Patterns │ │ Auto Graph Builder │ │ Enhanced JIT │ │ +│ │ │ │ │ │ │ │ +│ │ • UniformEnsemble │ │ • Autograph │ │ • Function Tracing │ │ +│ │ • JudgeSynthesis │ │ • IR Graph Construct │ │ • Optimized Execution │ │ +│ │ • Verifier │ │ • Dependency Tracking │ │ • Parallel Dispatch │ │ +│ │ • VariedEnsemble │ │ • Visualization │ │ │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ CORE COMPONENT LAYER │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ Model Registry │ │ Operator System │ │ Prompt Specifications │ │ +│ │ │ │ │ │ │ │ +│ │ • ModelInfo │ │ • Base Operator │ │ • Template Rendering │ │ +│ │ • ModelService │ │ • Operator Registry │ │ • Input Validation │ │ +│ │ • UsageService │ │ • Core Operators │ │ • Output Validation │ │ +│ │ • Provider Adapters │ │ • Custom Operators │ │ • Schema Generation │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ Data Processing │ │ Evaluation Tools │ │ Application Context │ │ +│ │ │ │ │ │ │ │ +│ │ • Dataset Loaders │ │ • Evaluators │ │ • Config Manager │ │ +│ │ • Transformers │ │ • Metrics │ │ • Dependency Injection │ │ +│ │ • Samplers │ │ • Result Analysis │ │ • Service Registry │ │ +│ │ • Dataset Registry │ │ • Visualization │ │ • Logging Config │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ EXECUTION ENGINE (XCS) │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ │ +│ │ Graph Definition │ │ Tracer System │ │ Execution Engine │ │ +│ │ │ │ │ │ │ │ +│ │ • XCSGraph IR │ │ • Function Tracing │ │ • Schedulers │ │ +│ │ • XCSNode Primitive │ │ • Execution Recording │ │ • Execution Plan │ │ +│ │ │ │ • JIT Compilation │ │ • Parallel Dispatch │ │ +│ │ │ │ • Graph Optimization │ │ │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ │ +│ │ +└───────────────────────────────────────────────────────────────────────────────────────────┘ +``` + +## Layer Responsibilities + +### 1. Execution Engine (XCS) + +The foundational layer providing computation graph definition and execution: + +* **Graph Definition**: Defines the structure of computation +* **Tracer System**: Records execution and enables optimization +* **Execution Engine**: Manages the actual running of operations with parallelization + +### 2. Core Component Layer + +The building blocks of Ember's functionality: + +* **Model Registry**: Management of LLM providers and models +* **Operator System**: Core computational units and their registry +* **Prompt Specifications**: Type-safe template rendering and validation +* **Data Processing**: Dataset handling, transformation, and sampling +* **Evaluation Tools**: Benchmarking and performance analysis +* **Application Context**: Configuration and dependency management + +### 3. Application Layer + +High-level abstractions built on the core components: + +* **NON Patterns**: Ready-to-use Networks of Networks patterns +* **Auto Graph Builder**: Automatic graph construction from code +* **Enhanced JIT**: Just-in-time compilation for optimized execution + +## Component Details + +### Application Context + +The `EmberAppContext` serves as the central dependency injection container: + +```python +from ember.core.app_context import get_app_context + +# Access global context +context = get_app_context() + +# Access services +model_service = context.model_service +usage_service = context.usage_service + +# Access configuration via standardized manager +config_manager = context.config_manager +model_registry_config = config_manager.get_config("model_registry") +app_config = config_manager.get_config("app") + +# Configuration values are accessed via dot notation +api_key = model_registry_config.providers.openai.api_key +``` + +Key responsibilities: +- Initialization and configuration of system components +- Service registration and dependency injection +- Standardized configuration management with schema validation +- Environment variable resolution and config merging +- Logging setup + +### Model Registry System + +The Model Registry manages connections to LLM providers: + +```python +# Using the simplified API +from ember.api.models import ModelRegistry, ModelInfo, ModelService + +# Register a model +registry = ModelRegistry() +registry.register_model(ModelInfo(id="openai:gpt-4o", ...)) + +# Create a service for model access +service = ModelService(registry=registry) +response = service.invoke_model("openai:gpt-4o", "Hello world") + +# Even simpler with automatic initialization +from ember import initialize_ember + +# Initialize and get the service in one step +service = initialize_ember() +response = service("anthropic:claude-3-sonnet", "Hello Claude") +``` + +#### Model Registry Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Model Registry System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ ModelRegistry │◄────►│ ModelFactory │─────►│ Provider Models │ │ +│ └────────┬────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ │ +│ │ ┌─────────────────┐ ┌─────────────────┐ │ +│ └──────────────►│ ModelService │◄────►│ UsageService │ │ +│ └─────────────────┘ └─────────────────┘ │ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ OpenAI Provider │ │Anthropic Provid.│ │ Other Providers │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key components: +- `ModelRegistry`: Central repository for model metadata +- `ModelService`: High-level API for model invocation +- `UsageService`: Tracks token usage and cost +- Provider implementations: OpenAI, Anthropic, Google, IBM, etc. + +### Operator System + +Operators are the fundamental computational units in Ember: + +```python +from ember.api.operators import Operator, Specification, EmberModel + +class SummarizerInput(EmberModel): + text: str + max_words: int = 100 + +class SummarizerOutput(EmberModel): + summary: str + word_count: int + +class SummarizerSpec(Specification): + input_model = SummarizerInput + structured_output = SummarizerOutput + prompt_template = "Summarize the following text in {max_words} words or less:\n\n{text}" + +class SummarizerOperator(Operator[SummarizerInput, SummarizerOutput]): + specification = SummarizerSpec() + + def forward(self, *, inputs: SummarizerInput) -> SummarizerOutput: + # Implementation + ... +``` + +#### Operator System Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Operator System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │OperatorRegistry │◄────►│OperatorFactory │─────►│Operator Instance│ │ +│ └─────────────────┘ └─────────────────┘ └────────┬────────┘ │ +│ │ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌────────▼────────┐ │ +│ │ Base Operator │◄─────┤Prompt Spec. │◄───► │ forward() │ | +│ └────────┬────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Core Operators │ │ Custom Operators │ │ NON Operators │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key components: +- `Operator`: Base class for all operators +- `Specification`: Type definitions for operator I/O +- Core operators: Ensemble, Judge, Verifier, etc. +- Operator registry for discovery + +### Prompt Specification System + +Specifications define the contract between inputs and outputs: + +```python +from ember.api.operators import Specification, EmberModel + +class QuestionInput(EmberModel): + question: str + context: str + +class AnswerOutput(EmberModel): + answer: str + confidence: float + +class QASpecification(Specification): + input_model = QuestionInput + structured_output = AnswerOutput + prompt_template = """ + Answer the question based on the context. + + Context: {context} + Question: {question} + """ +``` + +#### Prompt Specification Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Prompt Specification System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Specification │──────┤ Input Model │ │ Output Model │ │ +│ └────────┬────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │Prompt Template │─────►│Template Renderer│─────►│ Input Val. │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │Schema Generation│◄─────┤Output Validation│◄─────┤ Error Handl. │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key features: +- Type validation for inputs and outputs +- Template rendering with validation +- Automatic placeholder checking +- Support for structured data extraction + +### Execution Engine (XCS) + +XCS handles graph-based execution: + +```python +from ember.xcs import XCSGraph, execute_graph, execution_options + +# Create execution graph +graph = XCSGraph() +graph.add_node(operator=ensemble, node_id="ensemble") +graph.add_node(operator=judge, node_id="judge") +graph.add_edge(from_id="ensemble", to_id="judge") + +# Execute with parallelization +with execution_options(scheduler="wave", max_workers=4): + result = execute_graph( + graph=graph, + inputs={"query": "What is quantum computing?"} + ) +``` + +#### XCS Engine Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Execution Engine (XCS) │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ XCSGraph │─────►│ XCSNode │◄─────┤ Edge │ │ +│ └────────┬────────┘ └────────┬────────┘ └─────────────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Graph Compiler │─────►│ Execution Plan │─────►│ Scheduler │ │ +│ └─────────────────┘ └────────┬────────┘ └────────┬────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Input Mapping │◄─────┤ Parallel Worker │◄─────┤Output Collection│ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key components: +- `XCSGraph`: Directed acyclic graph representation +- `ExecutionPlan`: Compiled execution plan +- `Scheduler`: Controls execution strategy +- `Tracer`: Records execution for debugging + +### Enhanced JIT System + +Ember provides three complementary approaches to Just-In-Time optimization: + +#### JIT Strategy Pattern + +The `jit` decorator now uses a pluggable strategy pattern with multiple implementations: + +```python +from ember.xcs import jit, JITMode +from ember.api.operators import Operator +from ember.api import non + +# With automatic strategy selection +@jit +class MyEnsemble(Operator): + def forward(self, *, inputs): + # Complex computation automatically traced and optimized + ensemble = non.UniformEnsemble(num_units=3, model_name="openai:gpt-4o") + responses = ensemble(inputs={"query": inputs.query}) + return responses + +# With explicit strategy selection +@jit(mode=JITMode.ENHANCED) +class Pipeline(Operator): + def __init__(self): + self.refiner = QuestionRefinement() + self.ensemble = Ensemble() + self.aggregator = MostCommon() + + def forward(self, *, inputs): + refined = self.refiner(inputs=inputs) + answers = self.ensemble(inputs=refined) + return self.aggregator(inputs=answers) +``` + +The JIT system now supports three strategies: + +1. **Trace Strategy** (`JITMode.TRACE`): Traditional execution tracing for dynamic flows +2. **Structural Strategy** (`JITMode.STRUCTURAL`): Analyzes operator structure without requiring execution +3. **Enhanced Strategy** (`JITMode.ENHANCED`): Combines static and dynamic analysis for optimal parallelization + +#### Autograph Context Manager + +For explicit graph construction: + +```python +from ember.xcs import autograph, execute_graph, execution_options + +with autograph() as graph: + intermediate = op1(inputs={"query": "Example"}) + result = op2(inputs=intermediate) + +# Execute the graph with optimized scheduling +results = execute_graph( + graph=graph, + options=execution_options(scheduler="wave", max_workers=4) +) +``` + +#### Unified JIT System Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Unified JIT System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ JIT Decorator │─────►│Strategy Selector│─────►│ JIT Cache │ │ +│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Trace Strategy │─────►│ Structural Strat│─────►│Enhanced Strategy│ │ +│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Autograph │─────►│Graph Dependency │─────►│ Unified Engine │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key features: +- Unified strategy pattern with pluggable implementations: + - `trace`: Optimized for dynamic execution patterns + - `structural`: Static analysis of operator composition + - `enhanced`: Combines static and dynamic analysis for optimal parallelism +- Automatic strategy selection based on operator characteristics +- Consistent caching mechanism across all strategies +- Advanced dependency analysis with wave-based scheduling +- Transformation composition for complex optimizations +- Comprehensive metrics and introspection tools + +For a comprehensive explanation of the JIT system, see [JIT Overview](docs/xcs/JIT_OVERVIEW.md). + +### Function Transformation System + +The transformation system provides high-level operations for data and computation transformations: + +```python +from ember.xcs import vmap, pmap, compose, DeviceMesh, PartitionSpec, mesh_sharded + +# Vectorized mapping for batch processing +batch_processor = vmap(process_item) +batch_results = batch_processor(inputs={"data": [item1, item2, item3]}) + +# Parallel execution across multiple workers +parallel_processor = pmap(process_item, num_workers=4) +parallel_results = parallel_processor(inputs=complex_data) + +# Combine transformations for complex pipelines +pipeline = compose( + vmap(batch_size=32), + pmap(num_workers=4) +)(process_item) + +# Device mesh sharding for multi-device execution +mesh = DeviceMesh(devices=["gpu:0", "gpu:1", "gpu:2", "gpu:3"], mesh_shape=(2, 2)) +partition = PartitionSpec("batch", "model") +sharded_op = mesh_sharded(pipeline, mesh=mesh, partition_spec=partition) +``` + +#### Transform System Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Transform System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │BaseTransformation│─────►│TransformProtocol│─────►│ BatchingOptions │ │ +│ └────────┬────────┘ └─────────────────┘ └────────┬────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ vmap │─────►│ pmap │─────►│ParallelOptions │ │ +│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ mesh_sharded │─────►│ compose │─────►│ Unified JIT │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key features: +- Common base class (`BaseTransformation`) with consistent interface +- Compositional design for combining transformations +- Integration with the JIT system for optimized execution +- Support for both data parallelism and model parallelism +- Extensible design for custom transformations + +### Data Processing System + +The data module provides tools for dataset management: + +```python +from ember.core.utils.data.service import DataService +from ember.core.utils.data.base.samplers import RandomSampler + +# Load a benchmark dataset +data_service = DataService() +mmlu_data = data_service.load_dataset( + dataset_name="mmlu", + subset="high_school_mathematics", + sampler=RandomSampler(n=100) +) +``` + +#### Data Processing Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Data Processing System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ DataService │─────►│ Dataset Reg. │─────►│ Dataset Loaders │ │ +│ └────────┬────────┘ └─────────────────┘ └────────┬────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Dataset Cache │◄─────┤ Dataset Item │◄─────┤ External API │ │ +│ └─────────────────┘ └────────┬────────┘ └─────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Data Transformer│◄─────┤ Data Sampler │─────►│ Data Validator │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key components: +- `DataService`: Central access point for datasets +- Dataset loaders for popular benchmarks +- Transformers for data preprocessing +- Samplers for dataset subsampling + +### Evaluation System + +The evaluation system measures model performance: + +```python +from ember.core.utils.eval.pipeline import EvaluationPipeline +from ember.core.utils.eval.evaluators import MultipleChoiceEvaluator + +# Create evaluation pipeline +eval_pipeline = EvaluationPipeline( + dataset=test_data, + evaluators=[MultipleChoiceEvaluator()], + model=model +) + +# Run evaluation +results = eval_pipeline.evaluate() +print(f"Accuracy: {results.metrics['accuracy']:.2f}") +``` + +#### Evaluation Component Architecture +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Evaluation System │ +├────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Eval Pipeline │─────►│ Eval Registry │─────►│ Evaluator │ │ +│ └────────┬────────┘ └─────────────────┘ └────────┬────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ Data Provider │─────►│ Model Runner │─────►│ Result Collector│ │ +│ └─────────────────┘ └─────────────────┘ └────────┬────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │Metric Calculator│◄─────┤ Result Analyzer │◄─────┤ Report Generator│ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +Key components: +- `EvaluationPipeline`: Orchestrates evaluation +- Task-specific evaluators +- Metrics collection +- Result reporting + +## Full System Dependency Flow + +The diagram below illustrates the complete dependency flow between major components: + +``` +┌───────────────────────────────────────────────────────────────────────────────────────────┐ +│ Configuration Layer │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Config Files │────►│ Config Manager │────►│ Environment │ │ +│ │ (.yaml, .env) │ │ │ │ Variables │ │ +│ └─────────────────────────┘ └───────────┬─────────────┘ └─────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────┐ │ +│ │ EmberAppContext │ │ +│ └───────────┬─────────────┘ │ +│ │ │ +└─────────────────────────────────────────────┼─────────────────────────────────────────────┘ + │ + ▼ +┌───────────────────────────────────────────────────────────────────────────────────────────┐ +│ Service Layer │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Model Registry │◄───►│ Model Service │◄───►│ Usage Service │ │ +│ └───────────┬─────────────┘ └───────────┬─────────────┘ └─────────────────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Provider Models │◄───►│ Operator Registry │◄───►│ Data Service │ │ +│ └─────────────────────────┘ └───────────┬─────────────┘ └───────────┬─────────┘ │ +│ │ │ │ +└────────────────────────────────-─────────────┼───────────────────────────────┼─────────────┘ + │ │ + ▼ ▼ +┌───────────────────────────────────────────────────────────────────────────────────────────┐ +│ Component Layer │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Base Operators │◄───►│ Prompt Specifications│◄───►│ Dataset Loaders │ │ +│ └───────────┬─────────────┘ └─────────────────────────┘ └─────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Core Operators │◄───►│ NON Patterns │◄───►│ Evaluators │ │ +│ └───────────┬─────────────┘ └───────────┬─────────────┘ └─────────────────────┘ │ +│ │ │ │ +└─────-────────┼───────────────────────────────┼────────────────────────────────────────────┘ + │ │ + ▼ ▼ +┌───────────────────────────────────────────────────────────────────────────────────────────┐ +│ Execution Engine Layer │ +├───────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ XCSGraph │◄───►│ Graph Compiler │◄───►│ JIT Compiler │ │ +│ └───────────┬─────────────┘ └───────────┬─────────────┘ └───────────┬─────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ Execution Plan │◄───►│ Scheduler │◄───►│ Parallel Executor │ │ +│ └─────────────────────────┘ └─────────────────────────┘ └─────────────────────┘ │ +│ │ +└───────────────────────────────────────────────────────────────────────────────────────────┘ +``` + +## Configuration System + +Ember's configuration system provides a standardized way to configure all aspects of the framework: + +```python +from ember.core.configs import ConfigManager, create_config_manager + +# Create configuration manager with standard discovery +config_manager = create_config_manager() + +# Access typed, validated configuration +model_registry_config = config_manager.get_config("model_registry") +openai_api_key = model_registry_config.providers.openai.api_key + +# Configuration sources (in order of precedence): +# 1. Runtime overrides +# 2. Environment variables +# 3. User config files (~/.ember/config.yaml) +# 4. Project config files (./ember.yaml) +# 5. Default config (package defaults) + +# Modify configuration at runtime +config_manager.update_config( + "model_registry", + {"providers": {"openai": {"api_key": "new-key"}}} +) +``` + +Key features: +- Centralized schema-based configuration with Pydantic +- Multiple configuration sources with priority ordering +- Environment variable expansion (${VAR_NAME} syntax) +- Deep config merging with proper override behavior +- Thread-safe configuration access +- Extensible provider system + +## Code Organization + +The code is organized into the following package structure: + +| Package | Purpose | +|---------|---------| +| `ember.api` | Simplified public API for clean imports | +| `ember.api.models` | Models API for LLMs and providers | +| `ember.api.operator` | Operator API for computational units | +| `ember.api.non` | NON patterns API | +| `ember.api.xcs` | Execution engine API | +| `ember.api.data` | Data processing API | +| `ember.core` | Core framework classes and utilities | +| `ember.core.app_context` | Application context and DI container | +| `ember.core.configs` | Standardized configuration system with typed schema validation | +| `ember.core.types` | Type system, protocols, and validation | +| `ember.core.registry.model` | Model registry and provider implementations | +| `ember.core.registry.operator` | Operator system | +| `ember.core.registry.specification` | Prompt specification system | +| `ember.core.utils` | Utility functions and helpers | +| `ember.core.utils.data` | Data processing and datasets | +| `ember.core.utils.eval` | Evaluation and metrics | +| `ember.core.non` | High-level NON patterns | +| `ember.xcs` | Execution engine | +| `ember.xcs.graph` | Graph definition and manipulation | +| `ember.xcs.engine` | Execution scheduling | +| `ember.xcs.tracer` | Tracing and JIT compilation | + +## Import System + +Ember organizes imports through the `ember.api` namespace: + +```python +from ember.api.operators import Operator, Specification, EmberModel +from ember.xcs import jit, execution_options +from ember.api import models, non +from ember.api.data import DataLoader +``` + +This approach: +- Separates public API from internal implementation details +- Maintains backward compatibility during internal refactoring +- Follows conventions from our favorite, established frameworks + +## Design Patterns + +Ember employs several design patterns that are consistent throughout the codebase: + +### 1. Registry Pattern + +```python +# Registry implementation +class ModelRegistry: + def __init__(self): + self._models = {} + + def register_model(self, model_info: ModelInfo) -> None: + self._models[model_info.id] = model_info + + def get_model_info(self, model_id: str) -> ModelInfo: + return self._models[model_id] + +# Usage +registry = ModelRegistry() +registry.register_model(ModelInfo(id="model1", ...)) +model = registry.get_model_info("model1") +``` + +### 2. Factory Pattern + +```python +class ModelFactory: + def create_model(self, model_info: ModelInfo) -> BaseProviderModel: + provider_name = model_info.provider["name"] + if provider_name == "OpenAI": + return OpenAIModel(model_info) + elif provider_name == "Anthropic": + return AnthropicModel(model_info) + # etc. +``` + +### 3. Dependency Injection + +```python +class ModelService: + def __init__(self, registry: ModelRegistry, usage_service: Optional[UsageService] = None): + self.registry = registry + self.usage_service = usage_service +``` + +### 4. Composition Pattern + +```python +class EnsembleOperator(Operator[EnsembleInput, EnsembleOutput]): + def __init__(self, lm_modules: List[LMModule]): + self.lm_modules = lm_modules + + def forward(self, *, inputs: EnsembleInput) -> EnsembleOutput: + # Use contained modules + responses = [lm(inputs.query) for lm in self.lm_modules] + return EnsembleOutput(responses=responses) +``` + +### 5. Strategy Pattern + +```python +class Scheduler(Protocol): + def run_plan(self, plan: ExecutionPlan, global_input: Dict, graph: XCSGraph) -> Any: + ... + +class SerialScheduler: + def run_plan(self, plan: ExecutionPlan, global_input: Dict, graph: XCSGraph) -> Any: + # Serial execution implementation + +class ParallelScheduler: + def run_plan(self, plan: ExecutionPlan, global_input: Dict, graph: XCSGraph) -> Any: + # Parallel execution implementation +``` + +## Performance Considerations + +Ember balances ease of use with high performance: + +### Parallelization Strategy + +1. **Graph-Based Parallelism**: + - The XCS engine automatically identifies independent operations + - Executes them concurrently using thread pools + - Configurable max_workers parameter + +2. **Operator-Level Concurrency**: + - Operators can implement their own internal parallelism + - Example: EnsembleOperator runs multiple models concurrently + +3. **Efficient Resource Usage**: + - Smart thread pooling to avoid over-subscription + - Rate limiting to respect API constraints + +### Memory Management + +1. **Lazy Instantiation**: + - Models are instantiated only when needed + - Heavy resources are loaded on demand + +2. **Caching Strategy**: + - Configuration is cached after initial load + - Discovery results are cached + - Model instances are reused + +### Optimization Techniques + +1. **JIT Compilation**: + - Traces function execution to build optimized graphs + - Identifies parallelizable operations + - Minimizes redundant computations + +2. **Efficient Data Transfer**: + - Minimizes copying of large data between operators + - Uses references when possible + +## Deployment Considerations + +When deploying Ember in production, consider these best practices: + +### 1. Configuration Management + +- Store API keys securely in environment variables +- Use separate configurations for development/production +- Override defaults with environment-specific settings + +``` +# Development configuration +config/ + base.yaml # Base configuration for all environments + development.yaml # Development-specific overrides + production.yaml # Production-specific overrides +``` + +### 2. Resource Planning + +- Set appropriate thread pool sizes (max_workers) +- Monitor token usage with UsageService +- Implement rate limiting strategies +- Set up cost budgets and alerts + +### 3. Error Handling + +- Implement proper error handling at the application level +- Set up exponential backoff for API rate limits +- Use the retry utilities for transient errors +- Log errors comprehensively + +### 4. Monitoring and Observability + +- Set up proper logging with appropriate log levels +- Monitor token and request metrics +- Track performance of individual operators +- Set alerts for abnormal behavior + +### 5. Scaling Strategies + +For high-throughput applications: +- Distribute workloads across multiple processes or machines +- Use horizontal scaling for independent operations +- Consider specialized execution engines for very large workloads +- Use caching for frequently used models or operations + +## Request Flow Diagram + +The following diagram illustrates the flow of a typical request through the Ember system: + +``` +┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ +│ │ │ │ │ │ │ │ +│ User API │─────►│ ModelService │─────►│ ModelRegistry│─────►│ ModelFactory │ +│ Request │ │ │ │ │ │ │ +└──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ + │ │ │ │ + │ │ │ ▼ + │ │ │ ┌──────────────┐ + │ │ │ │ │ + │ │ └─────────────►│ Provider │ + │ │ │ Impl. │ + │ │ └──────┬───────┘ + │ │ │ + │ │ ▼ + │ │ ┌──────────────┐ + │ │ │ │ + │ └───────────────────────────────────►│ UsageService │ + │ │ │ + │ └──────┬───────┘ + │ │ + ▼ ▼ +┌──────────────┐ ┌──────────────┐ +│ │ │ │ +│ User API │◄─────────────────────────────────────────────────┤ Response │ +│ Response │ │ │ +└──────────────┘ └──────────────┘ +``` + +## Architecture Evolution + +The Ember architecture continues to evolve along these paths: + +1. **Distributed Execution**: Support for distributed execution across multiple machines +2. **Enhanced Caching**: Improved caching for models and intermediate results +3. **Custom Hardware Support**: Optimizations for specialized hardware (GPUs, TPUs) +4. **Plugin System**: More comprehensive plugin interfaces for extensions +5. **Advanced Graph Optimizations**: Additional graph transformations and optimizations + +## Additional Resources + +For more detailed information, consult these resources: + +- [Model Registry Documentation](docs/quickstart/model_registry.md) +- [Operator System Documentation](docs/quickstart/operators.md) +- [XCS Execution Engine Documentation](docs/xcs/README.md) +- [Enhanced JIT Documentation](docs/xcs/JIT_OVERVIEW.md) +- [Example Applications](src/ember/examples) \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..495f38a1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,388 @@ +# Contributing to Ember + +Thank you for your interest in contributing to Ember! This document provides guidelines and instructions for contributing to the project. + +## Table of Contents + +- [Getting Started](#getting-started) + - [Development Environment](#development-environment) + - [Project Structure](#project-structure) + - [Running Tests](#running-tests) + - [Code Style and Quality](#code-style-and-quality) +- [Contribution Workflow](#contribution-workflow) + - [Finding Issues](#finding-issues) + - [Creating Issues](#creating-issues) + - [Making Changes](#making-changes) + - [Pull Requests](#pull-requests) + - [Code Review](#code-review) +- [Development Guidelines](#development-guidelines) + - [Documentation](#documentation) + - [Testing](#testing) + - [Performance Considerations](#performance-considerations) + - [Typed Code](#typed-code) +- [Release Process](#release-process) +- [Community](#community) +- [License](#license) + +## Getting Started + +### Development Environment + +1. **Fork and clone the repository**: + ```bash + git clone https://github.com/YOUR-USERNAME/ember.git + cd ember + ``` + +2. **Install uv (recommended)**: + We use uv for dependency management. [Install uv](https://github.com/astral-sh/uv) if you haven't already: + ```bash + # On macOS and Linux + curl -LsSf https://astral.sh/uv/install.sh | sh + + # On Windows + powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" + + # Or with pip + pip install uv + ``` + +3. **Install dependencies**: + ```bash + # Install with all development dependencies + uv pip install -e ".[dev]" + ``` + +4. **Working with the environment**: + ```bash + # Option 1: Run commands directly (recommended) + uv run pytest + uv run python src/ember/examples/basic/minimal_example.py + + # Option 2: Create and activate a virtual environment + uv venv + source .venv/bin/activate # On Windows: .venv\Scripts\activate + ``` + +5. **Set up pre-commit hooks** (recommended): + ```bash + uv run pre-commit install + # Or if you've activated a virtual environment: + pre-commit install + ``` + + +#### Note on Imports + +The project is set up with standard Python packaging, so you should import from `ember` directly, rather than from `src.` generally: + +```python +# Correct way to import +from ember.core import non +from ember.xcs.tracer import jit + +# No need to manipulate sys.path or use symlinks +``` + +### Project Structure + +The Ember codebase is organized into the following structure: + +``` +ember/ +├── core/ # Core framework modules (compatibility with src structure) +│ ├── registry/ # Model registry components +│ └── utils/ # Utility modules +├── docs/ # Documentation +│ ├── design/ # Design documents +│ ├── quickstart/ # Quick start guides +│ └── xcs/ # XCS documentation +├── src/ # Source code +│ └── ember/ # Main Python package +│ ├── api/ # Public API interfaces +│ ├── cli.py # Python CLI entrypoint +│ ├── core/ # Core framework +│ │ ├── config/ # Configuration management +│ │ ├── registry/ # Registry components +│ │ │ ├── model/ # Model registry +│ │ │ ├── operator/ # Operator registry +│ │ │ └── specification/ # Specifications +│ │ ├── types/ # Type definitions +│ │ └── utils/ # Utility functions +│ ├── examples/ # Example applications +│ │ ├── advanced/ # Advanced examples +│ │ ├── basic/ # Basic examples +│ │ ├── data/ # Data handling examples +│ │ ├── models/ # Model usage examples +│ │ └── operators/ # Operator examples +│ ├── xcs/ # Execution engine +│ │ ├── api/ # XCS API +│ │ ├── engine/ # Engine components +│ │ ├── graph/ # Graph representation +│ │ ├── tracer/ # Tracing functionality +│ │ ├── transforms/ # Transformation utilities +│ │ └── utils/ # XCS utilities +│ └── non.py # Non-deterministic operations +├── tests/ # Test suite +│ ├── helpers/ # Test helpers +│ ├── integration/ # Integration tests +│ │ ├── core/ # Core integration tests +│ │ ├── performance/ # Performance tests +│ │ ├── tracer/ # Tracer integration tests +│ │ └── xcs/ # XCS integration tests +│ ├── unit/ # Unit tests +│ │ ├── core/ # Core unit tests +│ │ ├── plugin_system/ # Plugin system tests +│ │ └── xcs/ # XCS unit tests +│ └── fuzzing/ # Fuzzing tests +├── pyproject.toml # Python project configuration +├── poetry.lock # Dependencies lock file (we're transitioning to uv) +├── pytest.ini # Pytest configuration +├── mypy.ini # Type checking configuration +└── README.md # Project overview +``` + +The `.gitignore` file is configured to exclude common development files, caches, and sensitive configuration files. + +### Running Tests + +We use pytest for testing. To run the test suite: + +```bash +# Run all tests +uv run pytest + +# Run specific tests +uv run pytest tests/unit/core + +# Run tests with code coverage +uv run pytest --cov=src/ember + +# Run a specific test file +uv run pytest tests/unit/core/test_app_context.py +``` + +### Code Style and Quality + +We enforce high code quality standards: + +1. **Code Formatting**: + - We use Black for code formatting + - Line length is set to 88 characters + - Run `uvx black src tests` before committing + +2. **Import Sorting**: + - We use isort for import sorting + - Run `uvx isort src tests` before committing + +3. **Linting**: + - We use ruff and pylint for linting + - Run `uvx ruff check src tests` before committing + - Run `uvx pylint src/ember` for more detailed linting + +4. **Type Checking**: + - We use mypy for static type checking + - Run `uvx mypy src` before committing + +All these checks are also performed automatically when you submit a pull request. + +## Contribution Workflow + +### Finding Issues + +- Check our [issue tracker](https://github.com/pyember/ember/issues) for open issues +- Look for issues tagged with [`good first issue`](https://github.com/pyember/ember/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) if you're new to the project +- Feel free to ask questions in the issue comments if you need clarification + +### Creating Issues + +When opening a new issue, please: + +- **Search existing issues** first to avoid duplicates +- **Use a clear and descriptive title** +- **Follow the issue template** if one is provided +- For bug reports, include: + - Steps to reproduce + - Expected behavior + - Actual behavior + - Environment details (OS, Python version, etc.) + - Code samples or error traces when relevant +- For feature requests, explain: + - The problem you're trying to solve + - Your proposed solution + - Alternatives you've considered + +### Making Changes + +1. **Create a feature branch**: + ```bash + git checkout -b feature/your-feature-name + ``` + +2. **Make your changes**: + - Write clean, well-commented code. We attempt to adhere to the `Google Python Style Guide`. + - Please add/update tests to cover your changes + - Remember to update documentation as needed + - Ensure your code passes all tests and style checks + +3. **Commit your changes**: + - Use clear, meaningful commit messages + - Reference issue numbers where applicable + ```bash + git commit -m "Add feature X, fixes #123" + ``` + +4. **Keep your branch updated**: + ```bash + git fetch origin + git rebase origin/main + ``` + +### Pull Requests + +When submitting a pull request: + +1. **Fill out the PR template** completely +2. **Link to related issues** +3. **Describe your changes** in detail +4. **Ensure all tests and checks pass** +5. **Include screenshots or examples** for UI or behavior changes +6. **Request reviews** from maintainers or contributors familiar with the area of code + +### Code Review + +During code review: + +- It is your responsibility to get your code reviewed. Feel free to `chase` reviewers as needed, respectfully of course. +- Be patient and respectful. User error is not the default assumption -- assume any question is designer error (either in the implementation or the documentation) +- Remember that the goal is to improve code quality for all of us. + +## Development Guidelines + +### Documentation + +Good documentation is essential: + +1. **Docstrings**: + - All public modules, classes, and functions must have docstrings + - We follow Google-style docstrings + - Include type hints in docstrings for complex parameters + - Example: + ```python + def process_data(data: List[Dict[str, Any]], options: Optional[Dict[str, Any]] = None) -> Result: + """Process input data with optional configuration. + + Args: + data: List of data dictionaries to process + options: Optional configuration parameters + + Returns: + A Result object containing processed output + + Raises: + ValueError: If data is empty or malformed + """ + ``` + +2. **README and Documentation Files**: + - Update relevant documentation for significant changes + - Keep examples up-to-date + - Add new documentation for new features + +3. **Code Comments**: + - Use comments for complex or non-obvious logic + - Avoid redundant comments that just restate the code + - Use TODO comments for future improvements (with issue references) + +### Testing + +We strive for high test coverage: + +1. **Test Coverage**: + - All new code should have corresponding tests + - We aim for 90%+ code coverage + - Critical paths should have 100% coverage + +2. **Test Types**: + - **Unit tests**: For testing individual functions and classes in isolation + - **Integration tests**: For testing interactions between components + - **Property-based tests**: Using Hypothesis for testing invariants + - **Fuzzing tests**: For finding edge cases and security issues + +3. **Test Naming and Organization**: + - Test files should be named `test_*.py` + - Test classes should be named `Test*` + - Test functions should be named `test_*` + - Group related tests in the same file or directory + +4. **Test Quality**: + - Tests should be deterministic and reliable + - Mock external dependencies appropriately, but not excessively + - Test edge cases and error conditions + - Include both positive and negative test cases + +### Performance Considerations + +Performance is important in Ember: + +1. **Measurement**: + - Use profiling tools to identify bottlenecks + - Include benchmarks for performance-critical code + - Compare before/after performance for optimizations + +2. **Optimizations**: + - Optimize for readability and maintainability first + - Focus optimizations on critical paths + - Document performance trade-offs in comments + - Use appropriate data structures and algorithms + +3. **Concurrency**: + - Ensure thread safety for shared resources + - Use appropriate locking mechanisms + - Consider asynchronous approaches where applicable + +### Typed Code + +We use Python type hints extensively: + +1. **Type Annotations**: + - Annotate all function parameters and return values + - Use appropriate generic types when needed + - Use Optional, Union, and other typing constructs as needed + +2. **Type Checking**: + - Run `mypy` to check for type errors + - Address all type warnings + - Use TypeVar and Generic for polymorphic code + +3. **Custom Types**: + - Define new type aliases for complex types + - Use Protocol for structural typing + - Document type parameters and constraints + +## Release Process + +Our release process follows these steps: + +1. Feature development in feature branches +2. Pull requests to the main branch after code review +3. Continuous integration tests on all PRs +4. Periodic releases with semantic versioning: + - MAJOR version for incompatible API changes + - MINOR version for backwards-compatible functionality + - PATCH version for backwards-compatible bug fixes +5. Release notes summarizing changes and upgrades + +## Community + +- **Discussions**: Join our [GitHub Discussions](https://github.com/pyember/ember/discussions) for questions and ideas +- **Issues**: Use [GitHub Issues](https://github.com/pyember/ember/issues) for bug reports and feature requests +- **Slack**: Join our [Slack](https://join.slack.com/t/ember-y0w7887/shared_invite/zt-31nm1aqdz-JtFcRWaatNg11OiUVEhhUw) for real-time discussion + +--- + +Thank you for contributing to Ember! Your time and effort help make this project better for everyone. + +## License + +By contributing to Ember, you agree that your contributions will be licensed under the project's [MIT License](LICENSE). \ No newline at end of file diff --git a/DEBUGGING.md b/DEBUGGING.md new file mode 100644 index 00000000..db30929f --- /dev/null +++ b/DEBUGGING.md @@ -0,0 +1,47 @@ +# Ember Examples Debugging + +This document tracks the troubleshooting process for fixing failing examples in the Ember framework. + +## 1. Operator Composition Example (`composition_example.py`) + +### Issue +The example fails with an error when attempting to invoke the "openai:gpt-4o" model. + +### Root Cause Analysis +1. **Incorrect Parameter Name**: The `LMModuleConfig` class expects an `id` field, but the code uses `model_name`: + ```python + self.lm_module = LMModule( + config=LMModuleConfig( + model_name=model_name, # INCORRECT: should be "id" not "model_name" + temperature=temperature, + ) + ) + ``` + +2. **No Error Handling**: The `QuestionRefinement` operator doesn't include any error handling for model invocation, making the example fragile. + +### Fix Plan +1. Update parameter name in `LMModuleConfig` from `model_name` to `id` +2. Add proper error handling to the `QuestionRefinement.forward` method +3. Update the model name in `main()` to ensure it's available (e.g., use "openai:gpt-3.5-turbo" as it's more likely to be available) + +## 2. Transformation Example (`transformation_example.py`) + +### Issue +The example fails with an error related to invalid input/output types in the `SimpleOperator` class within the `demonstrate_vmap` function. + +### Root Cause Analysis +1. **Type Mismatch in vmap**: The `vmap` transformation returns a dictionary of results, but the operator's specification expects a `SimpleOutput` model. + +2. **Missing Type Conversion**: The `_combine_outputs` function in `vmap.py` doesn't convert the combined dictionary results back to the expected model type. + +### Fix Plan +1. Modify the `_combine_outputs` function in `vmap.py` to check the operator's `specification.structured_output` and convert the combined result dictionary to the appropriate model type. +2. Alternatively, update the `SimpleOperator` class to correctly handle the dictionary output from vmap. + +## Architectural Considerations + +1. **Unified Error Handling**: Consider a standardized approach for error handling in operators that use LLMs. +2. **Type Compatibility**: Ensure transformations like `vmap` properly respect the type specifications of operators. +3. **Graceful Degradation**: Examples should have graceful error handling to make them more robust, especially for cases involving external APIs. +4. **Automated Testing**: Add tests to catch these issues before they appear in examples. \ No newline at end of file diff --git a/ENVIRONMENT_MANAGEMENT.md b/ENVIRONMENT_MANAGEMENT.md new file mode 100644 index 00000000..0727aff0 --- /dev/null +++ b/ENVIRONMENT_MANAGEMENT.md @@ -0,0 +1,144 @@ +# Ember Environment Management Guide + +This guide explains how to effectively manage Python environments when working with Ember using uv. + +## Python Environment Management with uv + +uv provides simplified Python environment management with these benefits: + +- **Dependency Isolation**: Prevents conflicts between project dependencies +- **Reproducible Environments**: Ensures consistent behavior across development setups +- **Simplified Workflow**: Reduces the need for explicit environment activation + +## Environment Management Approaches + +### 1. Using uv's Simplified Environment Management (Recommended) + +The simplest approach is to use uv's `run` command, which handles environments automatically: + +```bash +# Install Ember +cd ember +uv pip install -e "." + +# Run Python code without explicit environment activation +uv run python src/ember/examples/basic/minimal_example.py + +# Run tools without explicit environment activation +uv run pytest +``` + +### 2. Traditional Virtual Environment Workflow + +If you prefer a more traditional virtual environment workflow: + +```bash +# Create a virtual environment in the project directory +uv venv + +# Activate the environment (still required for interactive use) +source .venv/bin/activate # On Windows: .venv\Scripts\activate + +# Install Ember in the active environment +uv pip install -e "." + +# Run code in the activated environment +python src/ember/examples/basic/minimal_example.py +``` + +### 3. Using Other Virtual Environment Tools + +If you prefer using other environment managers: + +```bash +# Create environment with venv +python -m venv ember_env +source ember_env/bin/activate # On Windows: ember_env\Scripts\activate + +# Install with uv in this environment +uv pip install -e "." +``` + +## Environment Management Best Practices + +1. **Always use isolated environments** - Never install Ember in your global Python environment +2. **For simple usage, use `uv run`** - This handles environment management automatically +3. **For interactive shell work:** + - Create a virtual environment with `uv venv` + - Activate it with `source .venv/bin/activate` +4. **For running tools directly** - Use `uvx` which runs tools in isolated environments: + ```bash + uvx black src tests + uvx mypy src + ``` + +## Common Environment Commands + +```bash +# Create a virtual environment in the current directory +uv venv + +# Create a virtual environment with a specific Python version +uv venv --python=3.11 + +# Install packages +uv pip install -e "." +uv pip install -e ".[dev]" # With development extras + +# Run in an isolated environment +uv run python script.py +uv run pytest tests/ +``` + +## Python Version Management + +uv can also manage Python versions: + +```bash +# Install Python versions +uv python install 3.10 3.11 3.12 + +# Use a specific Python version +uv venv --python 3.11 +uv run --python 3.11 -- python script.py + +# Pin a Python version for a project +uv python pin 3.11 # Creates .python-version +``` + +## Troubleshooting + +### Python Version Issues + +```bash +# Check Python version +python --version + +# Specify a Python version for a virtual environment +uv venv --python 3.11 + +# Install a specific Python version with uv +uv python install 3.11 +``` + +### Path Issues + +If Python can't find Ember modules: + +```bash +# Ensure you're running from the project root +cd /path/to/ember +uv run python src/ember/examples/basic/minimal_example.py +``` + +### Dependency Resolution Issues + +If you encounter dependency conflicts: + +```bash +# Use cached resolution if available +uv pip install -e "." --cache-only + +# Force re-resolution +uv pip install -e "." --no-cache +``` \ No newline at end of file diff --git a/INSTALLATION_GUIDE.md b/INSTALLATION_GUIDE.md new file mode 100644 index 00000000..8af68373 --- /dev/null +++ b/INSTALLATION_GUIDE.md @@ -0,0 +1,213 @@ +# Ember Installation Guide + +This guide provides detailed instructions for installing Ember in different environments. + +## System Requirements + +- **Python**: 3.9 or newer (3.10, 3.11, and 3.12 supported) +- **Operating System**: macOS, Linux, or Windows + +## Installation Methods + +### Method 1: Basic Installation with uv (Recommended) + +[uv](https://astral.sh/uv) is the recommended package manager for Ember. It is extremely fast (10-100x faster than pip) and simplifies Python environment management. + +1. **Install uv** if you don't have it already: + ```bash + # On macOS and Linux + curl -LsSf https://astral.sh/uv/install.sh | sh + + # On Windows + powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" + + # Or with pip if you prefer + pip install uv + + # Verify the installation + uv --version + ``` + +2. **Install Ember from PyPI**: + ```bash + # Install Ember directly (creates a virtual environment automatically if needed) + uv pip install ember-ai + + # Run examples without activating an environment + ``` + +3. **Install from source**: + ```bash + # Clone the repository + git clone https://github.com/pyember/ember.git + cd ember + + # Install in development mode (editable installation) + uv pip install -e "." + + # Run examples directly without environment activation + uv run python src/ember/examples/basic/minimal_example.py + ``` + + By default, this installs Ember with OpenAI, Anthropic, and Google/Deepmind provider support. + +### Method 2: Development Installation with uv + +If you want to develop or contribute to Ember: + +1. **Clone the repository**: + ```bash + git clone https://github.com/pyember/ember.git + cd ember + ``` + +2. **Install with development dependencies**: + ```bash + # Install including development dependencies + uv pip install -e ".[dev]" + + # Run commands directly with uv + uv run pytest + ``` + +3. **Running tools**: + ```bash + # Run linters, formatters, and other tools without installation + uvx black src tests + uvx mypy src + uvx pytest + ``` + +### Method 3: Traditional pip Installation (Alternative) + +If you prefer using standard pip or don't want to install uv: + +```bash +# Create a virtual environment (recommended) +python -m venv ember_env +source ember_env/bin/activate # On Windows: ember_env\Scripts\activate + +# Install Ember with pip +pip install ember-ai + +# For development installation +pip install -e ".[dev]" +``` + +Note: This method is significantly slower for dependency resolution and doesn't provide the environment management benefits of uv. + +## OS-Specific Installation Notes + +### macOS + +On macOS, you might encounter issues with the default Python installation: + +```bash +# If you encounter Python-related errors: +# Install Python using Homebrew (recommended) +brew install python@3.11 + +# Use the Homebrew Python with uv +/opt/homebrew/bin/python3.11 -m pip install uv +/opt/homebrew/bin/python3.11 -m uv pip install -e "." +``` + +### Windows + +On Windows, ensure you have the latest Python installed from python.org: + +```powershell +# Add uv to your PATH if needed +$env:PATH += ";$env:USERPROFILE\.uv\bin" + +# Install and run directly +uv pip install -e "." +uv run python src/ember/examples/basic/minimal_example.py +``` + +## Troubleshooting + +### Python Version Issues + +If you encounter Python version errors: + +```bash +# Check your Python version +python --version + +# Specify a Python version for uv +uv venv --python=3.11 +source .venv/bin/activate + +# Or run with a specific Python version +uv run --python=3.11 -- python script.py +``` + +### uv Installation Issues + +If you have problems with uv: + +```bash +# Ensure uv is in your PATH +which uv + +# Update uv to the latest version +uv self update + +# Reinstall uv if needed +pip install --upgrade uv +``` + +### Virtual Environment Issues + +If you have problems with virtual environments: + +```bash +# Create a fresh virtual environment +uv venv --force + +# Activate the environment +source .venv/bin/activate # On Windows: .venv\Scripts\activate +``` + +See [ENVIRONMENT_MANAGEMENT.md](ENVIRONMENT_MANAGEMENT.md) for more details on managing environments. + +### Dependency Conflicts + +If you encounter dependency conflicts: + +```bash +# Try reinstalling without using cache +uv pip install -e "." --no-cache + +# Install with specific package versions if needed +uv pip install -e "." --no-deps +uv pip install "specific-package==version" +``` + +### Other Known Installation Issue Resolutions + +When using conda with or without uv, you may encounter known pyarrow installation issues. +``` +# Try installing pyarrow from conda-forge +conda install -c conda-forge pyarrow +``` + +## Testing Your Installation + +After installation, verify everything is working: + +```bash +# From the project root directory, using uv +uv run python src/ember/examples/basic/minimal_example.py + +# Or if you're in an activated virtual environment +python src/ember/examples/basic/minimal_example.py +``` + +## Getting Help + +If you encounter issues with installation: +- Check our [GitHub Issues](https://github.com/pyember/ember/issues) +- Review the [ENVIRONMENT_MANAGEMENT.md](ENVIRONMENT_MANAGEMENT.md) guide +- See the [TESTING_INSTALLATION.md](TESTING_INSTALLATION.md) for verification steps \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..cde7bab0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Foundry Technologies, Inc (mlfoundry.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/LLM_SPECIFICATIONS.md b/LLM_SPECIFICATIONS.md new file mode 100644 index 00000000..350696d9 --- /dev/null +++ b/LLM_SPECIFICATIONS.md @@ -0,0 +1,592 @@ +# Ember Framework: LLM Specifications + +This document provides precise specifications for building systems with the Ember framework. It defines essential patterns, APIs, and concepts with minimal overhead. + +## Table of Contents + +- [Core Concepts](#core-concepts) +- [Architecture Overview](#architecture-overview) +- [Model Registry](#model-registry) +- [Operators](#operators) +- [Execution Engine (XCS)](#execution-engine-xcs) +- [Network of Networks (NON)](#network-of-networks-non) +- [Data System](#data-system) +- [Context System](#context-system) +- [Code Style Guidelines](#code-style-guidelines) +- [Examples and Templates](#examples-and-templates) + +## Core Concepts + +### EmberModel +Base class for structured input/output with type validation: + +```python +from ember.core.types.ember_model import EmberModel, Field + +class QueryInput(EmberModel): + query: str = Field(..., description="Query to process") + temperature: float = Field(0.7, description="Sampling temperature") + +class AnswerOutput(EmberModel): + answer: str = Field(..., description="Generated response") + confidence: float = Field(..., description="Confidence score 0-1") +``` + +### Operator +Fundamental computational unit with typed I/O: + +```python +from typing import ClassVar +from ember.api.operators import Operator, Specification + +class MySpec(Specification): + input_model = QueryInput + structured_output = AnswerOutput + +class MyOperator(Operator[QueryInput, AnswerOutput]): + specification: ClassVar[Specification] = MySpec() + + def forward(self, *, inputs: QueryInput) -> AnswerOutput: + # Implementation here + return AnswerOutput(answer="...", confidence=0.9) +``` + +### JIT Compilation +Execute optimized computational graphs: + +```python +from ember.xcs import jit + +@jit # Auto-optimize execution path +class FastOperator(Operator[QueryInput, AnswerOutput]): + # Implementation with parallel execution where possible +``` + +## Architecture Overview + +Ember's layered architecture: + +1. **Execution Engine (XCS)** - Base layer providing computation graph definition and execution +2. **Core Component Layer** - Building blocks including model registry, operators, specifications +3. **Application Layer** - High-level abstractions like NON patterns and auto graph building +4. **Public API Layer** - Clean interfaces exposed through the `ember.api` namespace + +## Model Registry + +The model registry provides unified access to LLM providers: + +### Function-Style API (Recommended) + +```python +from ember.api import models + +# Direct invocation +response = models.model("gpt-4o")("What is quantum computing?") + +# Provider namespaces +response = models.openai.gpt4o("What is quantum computing?") + +# Reusable models +gpt4 = models.model("gpt-4o", temperature=0.7) +response1 = gpt4("Question 1") +response2 = gpt4("Question 2") + +# Configuration context +with models.configure(temperature=0.2, max_tokens=100): + response = models.model("gpt-4o")("Write a haiku") +``` + +### Type-Safe Enum References + +```python +from ember.api.models import ModelEnum +response = models.from_enum(ModelEnum.OPENAI_GPT4O)("Hello") +``` + +### Builder Pattern (Alternative) + +```python +from ember.api.models import ModelBuilder +model = (ModelBuilder() + .temperature(0.7) + .max_tokens(100) + .build("anthropic:claude-3-5-sonnet")) +response = model.generate("Explain quantum computing") +``` + +### Custom Contexts + +```python +from ember.api.models import ModelContext, ContextConfig +context = ModelContext(config=ContextConfig( + api_keys={"openai": "your-key"} +)) +response = models.model("gpt-4o", context=context)("Hello") +``` + +## Operators + +### Basic Operator Pattern + +```python +from typing import ClassVar +from ember.api.operators import Operator, Specification, EmberModel +from ember.api import models + +class InputType(EmberModel): + query: str + +class OutputType(EmberModel): + answer: str + +class MySpec(Specification): + input_model = InputType + structured_output = OutputType + +class MyOperator(Operator[InputType, OutputType]): + # Class-level specification + specification: ClassVar[Specification] = MySpec() + + # Declare instance attributes + model: object + + def __init__(self, model_name: str = "gpt-4o"): + self.model = models.model(model_name) + + def forward(self, *, inputs: InputType) -> OutputType: + response = self.model(inputs.query) + return OutputType(answer=str(response)) +``` + +### Composition Pattern + +```python +class Pipeline(Operator[InputType, OutputType]): + specification: ClassVar[Specification] = MySpec() + + # Declare component operators + refiner: QueryRefiner + answerer: AnswerGenerator + + def __init__(self): + self.refiner = QueryRefiner() + self.answerer = AnswerGenerator() + + def forward(self, *, inputs: InputType) -> OutputType: + refined = self.refiner(inputs=inputs) + return self.answerer(inputs=refined) +``` + +### Built-in Operators + +```python +from ember.api.operators import ( + EnsembleOperator, + MostCommonAnswerSelector, + VerifierOperator, + SelectorJudgeOperator, + JudgeSynthesisOperator +) + +# Ensemble of models +ensemble = EnsembleOperator( + operators=[ + MyOperator(model="gpt-4o"), + MyOperator(model="claude-3-5-sonnet"), + ] +) + +# Selector for aggregation +pipeline = MostCommonAnswerSelector( + operator=ensemble +) +``` + +## Execution Engine (XCS) + +### Basic JIT + +```python +from ember.xcs import jit + +@jit +class MyOperator(Operator): + def forward(self, *, inputs): + # Implementation + return result +``` + +### JIT with Strategy Selection + +```python +from ember.xcs import jit + +# Auto-select optimal strategy +@jit +class MyOperator(Operator): + # Implementation... + +# Explicit strategy +@jit(mode="enhanced") +class ComplexOperator(Operator): + # Implementation... +``` + +### Execution Options + +```python +from ember.xcs import execution_options + +# Configure execution parameters +with execution_options(scheduler="wave", max_workers=4): + result = pipeline(query="Complex question...") +``` + +### Transformations + +```python +from ember.xcs import vmap, pmap, compose + +# Vectorized mapping for batch processing +batch_processor = vmap(my_operator) +batch_results = batch_processor(inputs={"data": [item1, item2, item3]}) + +# Parallel execution across multiple workers +parallel_processor = pmap(my_operator, num_workers=4) +parallel_results = parallel_processor(inputs=complex_data) + +# Compose transformations +pipeline = compose(vmap(batch_size=32), pmap(num_workers=4))(my_operator) +``` + +## Network of Networks (NON) + +### Standard API + +```python +from ember.api import non + +# Create ensemble of identical models +ensemble = non.UniformEnsemble( + num_units=3, + model_name="openai:gpt-4o", + temperature=0.7 +) + +# Create judge to synthesize outputs +judge = non.JudgeSynthesis( + model_name="anthropic:claude-3-5-sonnet", + temperature=0.0 +) + +# Create sequential pipeline +pipeline = non.Sequential(operators=[ensemble, judge]) + +# Execute pipeline +result = pipeline(query="What causes tsunamis?") +``` + +### Compact Notation + +```python +from ember.api import non + +# Same pipeline with compact notation +pipeline = non.build_graph([ + "3:E:gpt-4o:0.7", # Ensemble with 3 instances + "1:J:claude-3-5-sonnet:0.0" # Judge synthesis +]) + +# Execute with identical interface +result = pipeline(query="What causes tsunamis?") +``` + +### Component Reuse + +```python +# Define reusable components +components = { + "sub": ["2:E:gpt-4o:0.0", "1:V:gpt-4o:0.0"] # Ensemble → Verifier +} + +# Create branch architecture +nested = non.build_graph([ + "$sub", # First branch + "$sub", # Second branch + "1:J:gpt-4o:0.0" # Final judge +], components=components) +``` + +### Custom Operator Types + +```python +# Create a registry with custom operator types +registry = non.OpRegistry.create_standard_registry() +registry.register( + "CE", # Custom ensemble type + lambda count, model, temp: non.Sequential(operators=[ + non.UniformEnsemble(num_units=count, model_name=model, temperature=temp), + non.MostCommon() # Auto-aggregation + ]) +) + +# Use custom operator type +pipeline = non.build_graph(["3:CE:gpt-4o:0.7"], type_registry=registry) +``` + +## Data System + +### DatasetBuilder Pattern + +```python +from ember.api.data import DatasetBuilder + +# Load and transform a dataset +dataset = (DatasetBuilder() + .from_registry("mmlu") # Use a registered dataset + .subset("physics") # Select a specific subset + .split("test") # Choose the test split + .sample(100) # Random sample of 100 items + .transform( # Apply transformations + lambda x: {"query": f"Question: {x['question']}"} + ) + .build()) +``` + +### Evaluation Pipeline + +```python +from ember.api.eval import EvaluationPipeline, Evaluator + +# Create an evaluation pipeline +eval_pipeline = EvaluationPipeline([ + # Standard metrics + Evaluator.from_registry("accuracy"), + Evaluator.from_registry("response_quality"), + + # Custom metrics + Evaluator.from_function( + lambda prediction, reference: { + "factual_accuracy": score_factual_content(prediction, reference) + } + ) +]) + +# Evaluate a model or operator +results = eval_pipeline.evaluate(my_model, dataset) +print(f"Accuracy: {results['accuracy']:.2f}") +``` + +## Context System + +### Basic Context Usage + +```python +from ember.core.context import current_context + +# Get the current thread's context +ctx = current_context() + +# Get a model +model = ctx.get_model("gpt4o") + +# Generate text +result = model.generate("Hello, world!") +``` + +### Temporary Components + +```python +from ember.core.context import current_context, temp_component + +# Use a temporary component +with temp_component("model", "temp-model", MyModel("temporary")) as model: + # Use the model within this scope + result = model.generate("Hello") +``` + +### Configuration Access + +```python +from ember.core.context import current_context +from ember.core.context.config_integration import config_override + +# Access configuration through context +temperature = ctx.config.model.temperature + +# Override configuration temporarily +with config_override({"model": {"temperature": 0.2}}): + # Config value changed in this scope + new_temp = ctx.config.model.temperature +``` + +## Code Style Guidelines + +1. **Package Structure**: + - Use the `ember.api` namespace for clean imports + - Follow the layered import pattern: + ```python + from ember.api.models import ModelBuilder + from ember.api.operators import Operator + from ember.api.xcs import jit + from ember.api import non + ``` + +2. **Naming Conventions**: + - Classes: `PascalCase` + - Functions: `snake_case` + - Constants: `UPPER_SNAKE_CASE` + - Private attributes: `_leading_underscore` + +3. **Typing**: + - Use explicit type annotations + - Leverage TypeVars for generic operators + - Include descriptions in Field definitions + +4. **Documentation**: + - Follow Google docstring format + - Document parameters, returns, and raises + - Include examples for non-trivial usage + +5. **Error Handling**: + - Use specific exception types + - Include helpful error messages + - Handle API errors gracefully + +## Examples and Templates + +### Basic Operator Template + +```python +from typing import ClassVar +from ember.api.operators import Operator, Specification, EmberModel, Field + +class MyInput(EmberModel): + query: str = Field(..., description="The input query") + +class MyOutput(EmberModel): + result: str = Field(..., description="The computed result") + +class MySpec(Specification): + input_model = MyInput + structured_output = MyOutput + +class MyOperator(Operator[MyInput, MyOutput]): + specification: ClassVar[Specification] = MySpec() + + def __init__(self, param1: str): + self.param1 = param1 + + def forward(self, *, inputs: MyInput) -> MyOutput: + # Implementation logic + return MyOutput(result=f"Processed: {inputs.query}") +``` + +### NON Pattern Template + +```python +from ember.api import non + +def create_ensemble_judge_pipeline( + ensemble_size: int = 3, + model_name: str = "openai:gpt-4o", + judge_model: str = "anthropic:claude-3-5-sonnet" +) -> non.Sequential: + """Create an ensemble-judge pipeline. + + Args: + ensemble_size: Number of ensemble units + model_name: Model to use for ensemble + judge_model: Model to use for judge + + Returns: + A configured pipeline + """ + return non.Sequential(operators=[ + non.UniformEnsemble( + num_units=ensemble_size, + model_name=model_name, + temperature=0.7 + ), + non.JudgeSynthesis( + model_name=judge_model, + temperature=0.0 + ) + ]) +``` + +### Complete Application Example + +```python +"""Minimal Ember application with JIT optimization.""" + +from typing import ClassVar +from ember.api import models, non +from ember.api.operators import Operator, Specification, EmberModel +from ember.xcs import jit + +# Define I/O types +class QuestionInput(EmberModel): + question: str + +class AnswerOutput(EmberModel): + answer: str + confidence: float + +# Define specification +class QuestionSpec(Specification): + input_model = QuestionInput + structured_output = AnswerOutput + +# Define JIT-optimized operator +@jit +class QuestionAnswerer(Operator[QuestionInput, AnswerOutput]): + specification: ClassVar[Specification] = QuestionSpec() + + # Declare instance attributes + ensemble: non.UniformEnsemble + judge: non.JudgeSynthesis + + def __init__(self, width: int = 3): + self.ensemble = non.UniformEnsemble( + num_units=width, + model_name="gpt-4o", + temperature=0.7 + ) + self.judge = non.JudgeSynthesis( + model_name="claude-3-5-sonnet" + ) + + def forward(self, *, inputs: QuestionInput) -> AnswerOutput: + # Get ensemble responses + ensemble_result = self.ensemble(query=inputs.question) + + # Synthesize with judge + synthesis = self.judge( + query=inputs.question, + responses=ensemble_result["responses"] + ) + + # Build response + return AnswerOutput( + answer=synthesis["synthesized_response"], + confidence=float(synthesis.get("confidence", 0.8)) + ) + +# Main entrypoint +def main(): + # Create operator + answerer = QuestionAnswerer(width=5) + + # Process question + result = answerer(inputs=QuestionInput( + question="What is relativity?" + )) + + # Use result + print(f"Answer: {result.answer}") + print(f"Confidence: {result.confidence:.2f}") + +if __name__ == "__main__": + main() +``` \ No newline at end of file diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 00000000..1f9ccbe5 --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,217 @@ +# Ember Quickstart Guide + +This guide will help you quickly get started with Ember, the compositional framework for building and orchestrating Compound AI Systems. + +## Installation + +```bash +# Install uv if you don't have it +curl -LsSf https://astral.sh/uv/install.sh | sh # macOS/Linux +# or +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows +# or +pip install uv # Any platform + +# Quick install with uv (recommended) +uv pip install ember-ai + +# Or from source +git clone https://github.com/pyember/ember.git +cd ember +uv pip install -e ".[dev]" # Install with development dependencies + +# Run examples directly with uv +uv run python src/ember/examples/basic/minimal_example.py + +# For CLI tools, you can run directly without installation +uvx ember-ai # If you have CLI commands +``` + +For detailed installation instructions including troubleshooting, please see: +- [INSTALLATION_GUIDE.md](INSTALLATION_GUIDE.md) - Complete installation instructions +- [ENVIRONMENT_MANAGEMENT.md](ENVIRONMENT_MANAGEMENT.md) - Guide to managing Python environments +- [TESTING_INSTALLATION.md](TESTING_INSTALLATION.md) - Steps to verify your installation + +## Setting Up API Keys and Configuration + +Ember supports multiple ways to configure API keys for LLM providers. + +### Option 1: Environment Variables + +Set your API keys as environment variables: + +```bash +# For bash/zsh +export OPENAI_API_KEY="your-openai-key" +export ANTHROPIC_API_KEY="your-anthropic-key" +export GOOGLE_API_KEY="your-google-key" + +# For making environment variables persistent (add to your shell profile) +echo 'export OPENAI_API_KEY="your-openai-key"' >> ~/.bashrc # or ~/.zshrc +``` + +### Option 2: Configuration File + +Create a configuration file at one of these locations (searched in order): + +1. Current directory: `./config.yaml` +2. User home config: `~/.ember/config.yaml` +3. System config: `/etc/ember/config.yaml` + +Example configuration file: + +```yaml +model_registry: + providers: + openai: + api_key: ${OPENAI_API_KEY} # Will use environment variable + organization_id: "your-org-id" # Optional organization ID + anthropic: + api_key: "your-anthropic-key" # Direct value (example) + google: + api_key: ${GOOGLE_API_KEY} # Will use environment variable +``` + +### Option 3: Programmatic Configuration + +Set configuration values directly in your code: + +```python +import ember +from ember.core.config.manager import ConfigManager + +# Initialize with custom configuration +config = ConfigManager() +config.set("model_registry.providers.openai.api_key", "your-openai-key") +config.set("model_registry.providers.anthropic.api_key", "your-anthropic-key") + +# Initialize Ember with this configuration +service = ember.init(config=config) +``` + +### Setting Provider-Specific Options + +You can configure provider-specific options in your configuration file: + +```yaml +model_registry: + providers: + openai: + api_key: ${OPENAI_API_KEY} + base_url: "https://api.openai.com/v1" # Custom API endpoint + timeout: 30 # Timeout in seconds + anthropic: + api_key: ${ANTHROPIC_API_KEY} + max_retries: 3 +``` + +See [Configuration Quickstart](docs/quickstart/configuration.md) for more options and detailed configuration examples. + +## Basic Usage + +Here's how to get started with Ember in just a few lines of code: + +```python +# Import the package +import ember + +# Initialize and get the 'default' model service +service = ember.init() + +# Make a simple model call +response = service("openai:gpt-4o", "What is the capital of France?") +print(response.data) +``` + +## Building Your First Compound AI System + +Let's create a simple example that uses multiple models with parallelization: + +```python +from typing import ClassVar +from ember.api.xcs import jit +from ember.api.operator import Operator, Specification +from ember.api.models import EmberModel +from ember.core import non + +# Define structured input/output models +class QueryInput(EmberModel): + query: str + +class QueryOutput(EmberModel): + answer: str + confidence: float + +# Define the specification +class QuerySpecification(Specification): + input_model = QueryInput + structured_output = QueryOutput + +# Create a compound system using the @jit decorator for optimization +@jit +class ParallelQuerySystem(Operator[QueryInput, QueryOutput]): + # Class-level specification declaration with ClassVar + specification: ClassVar[Specification] = QuerySpecification() + + # Class-level field declarations + ensemble: non.UniformEnsemble + aggregator: non.MostCommon + + def __init__(self, parallel_calls: int = 3, model: str = 'openai: gpt-4o-mini', temp: float = 0.4): + # Init ensemble + self.ensemble = non.UniformEnsemble( + num_units=parallel_calls, + model_name=model, + temperature=temp + ) + + # Aggregate ensemble responses with "Most Common", "voting-bsed" aggregation + self.aggregator = non.MostCommon() + + def forward(self, *, inputs: QueryInput) -> QueryOutput: + # Get responses from multiple models (automatically parallelized) + ensemble_result = self.ensemble(inputs={"query": inputs.query}) + + # Aggregate the results (input dict format for operator invocation, vs. kwargs format in README.md. Both are supported.) + aggregated = self.aggregator(inputs={ + "query": inputs.query, + "responses": ensemble_result["responses"] + }) + + # Return structured output + return QueryOutput( + answer=aggregated["final_answer"], + confidence=aggregated.get("confidence", 0.0) + ) + +# Create and use the system +system = ParallelQuerySystem() +result = system(inputs={"query": "What is the speed of light?"}) + +print(f"Answer: {result.answer}") +print(f"Confidence: {result.confidence:.2f}") +``` + +## Next Steps + +- Explore the [Model Registry](docs/quickstart/model_registry.md) for using different LLM providers +- Learn about [Operators](docs/quickstart/operators.md) for building reusable components +- Check out [Networks of Networks](docs/quickstart/non.md) for complex AI systems +- Set up [Data Processing](docs/quickstart/data.md) for dataset handling +- Configure your application with [Configuration](docs/quickstart/configuration.md) +- Use [Simplified Imports](SIMPLIFIED_IMPORTS.md) for cleaner code + +To see Ember in action, explore these key examples: +- [Minimal Example](src/ember/examples/minimal_example.py) - Get started with basic usage +- [Model API Example](src/ember/examples/model_api_example.py) - Learn the models API +- [Ensemble Operator Example](src/ember/examples/diverse_ensemble_operator_example.py) - Build parallel model ensembles +- [API Operators Example](src/ember/examples/api_operators_example.py) - Use streamlined imports +- [Enhanced JIT Example](src/ember/examples/enhanced_jit_example.py) - Optimize execution with JIT + +For a full walkthrough of Ember's capabilities, see the [Examples Directory](src/ember/examples). + +## Getting Help + +- GitHub Issues: [https://github.com/pyember/ember/issues](https://github.com/pyember/ember/issues) +- Documentation: See the documentation files in the `docs/` directory +- Examples: Explore the examples in `src/ember/examples/` \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..f1159376 --- /dev/null +++ b/README.md @@ -0,0 +1,408 @@ +

+ Ember Logo +

+

+ Ember +

+ +

+Contributors +

+ +

+This repository is in collaboration with the following early users, contributors, and reviewers: +

+ +

+Jared Quincy DavisF,S, Marquita EllisI, Diana ArroyoI, Pravein Govindan KannanI, Paul CastroI, Siddharth SharmaF,S, Lingjiao ChenMS, Omar KhattabD,MT, Alan ZhuB, Parth AsawaB, Connor ChowB, Jason LeeB, Jay Adityanag TipirneniB, Chad FergusonB, Kathleen GeB, Kunal AgrawalB, Rishab BhatiaB, Rohan PenmatchaB, Sai KolasaniB, Théo Jaffrelot InizanB, Deepak NarayananN, Long FeiF, Aparajit RaghavanF, Eyal CidonF, Jacob ScheinF, Prasanth SomasundarF, Boris HaninF,P, James ZouS, Joey GonzalezB, Peter BailisG,S, Ion StoicaA,B,D, Matei ZahariaD,B +

+ +

+F Foundry (MLFoundry), D Databricks, I IBM Research, S Stanford University, B UC Berkeley, MT MIT, N NVIDIA, MS Microsoft, A Anyscale, G Google, P Princeton +

+ +# Ember: A Compositional Framework for Compound AI Systems + +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) + +## Ember in a Nutshell + +Aspirationally, Ember is to Networks of Networks (NONs) Compound AI Systems development what PyTorch +and XLA are to Neural Networks (NN) development. It's a compositional framework with both eager +execution affordances and graph execution optimization capabilities. It enables users to compose +complex NONs, and supports automatic parallelization and optimization of these. + + +Ember's vision is to enable development of **compound AI systems composed of, one day, millions-billions of inference calls** and beyond. Simple constructs--like **best-of-N graphs**, **verifier-prover structures**, and **ensembles with “voting-based” aggregation**--work surprisingly well in many regimes. + +```python +# With Ember's "compact notation" it is one line to build a simple parallel system with 101 GPT-4o instances synthesized by Claude +system = non.build_graph(["101:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.0"]) # Automatically parallelized +result = system(query="What's the most effective climate change solution?") +``` + +This led us to believe that there is a rich architecture space for constructing and optimizing what we call “networks of networks” graphs, or **NONs**. This is analogous to how neural network architecture research uncovered many emergent properties of systems composed of simple artificial neurons. It would be frictionful to conduct NN research if we had to implement architectures from scratch via for-loops or implement bespoke libraries for vectorization and efficient execution. Similarly, it can be challenging at present to compose NON architectures of many calls, despite the **rapidly falling cost-per-token of intelligence**. + +Ember's goal is to help unlock research and practice along this new frontier. + +## Documentation & Examples + +- [Architecture Overview](ARCHITECTURE.md) +- [Quick Start Guide](QUICKSTART.md) +- [LLM Specifications](LLM_SPECIFICATIONS.md) +- [Model Registry Guide](docs/quickstart/model_registry.md) +- [Operators Guide](docs/quickstart/operators.md) +- [NON Patterns](docs/quickstart/non.md) +- [Data Processing](docs/quickstart/data.md) +- [Configuration](docs/quickstart/configuration.md) +- [Examples Directory](src/ember/examples) + +## Simple Example: Ensemble Reasoning with Automatic Parallelization + +```python +class QueryInput(EmberModel): + query: str + +class ConfidenceOutput(EmberModel): + answer: str + confidence: float + +class ReasonerSpec(Specification): + input_model = QueryInput + structured_output = ConfidenceOutput + +@jit # Autonomically optimize execution with JIT compilation (e.g. TopoSort with Parallel Dispatch) +class EnsembleReasoner(Operator[QueryInput, ConfidenceOutput]): + specification = ReasonerSpec() + + def __init__(self, width: int = 3): + self.ensemble = non.UniformEnsemble( + num_units=width, + model_name="openai:gpt-4o", + temperature=0.7 + ) + + self.judge = non.JudgeSynthesis( + model_name="anthropic:claude-3-5-sonnet", + ) + + def forward(self, *, inputs: QueryInput) -> ReasonedOutput: + # These operations are automatically parallelized by Ember's XCS system + ensemble_result = self.ensemble(query=inputs.query) + + synthesis = self.judge( + query=inputs.query, + responses=ensemble_result["responses"] + ) + + return ConfidenceOutput( + answer=synthesis["final_answer"], + confidence=float(synthesis.get("confidence", 0.0)) + ) + +# Use it like any Python function +compound_system = EnsembleReasoner() +result = compound_system(query="What causes the northern lights?") +print(f"Answer: {result.answer}") +print(f"Confidence: {result.confidence:.2f}") + +# Alternatively, build the same pipeline with compact notation +pipeline = non.build_graph(["3:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.2"]) +result = pipeline(query="What causes the northern lights?") +``` + +## Compact Notation + +Ember's compact notation allows expression of complex AI architectures in minimal code: + +```python +# Compact notation: "count:type:model:temperature" - each component precisely specified + +# BASIC: Single-line systems with automatic parallelization +basic = non.build_graph(["7:E:gpt-4o:0.7"]) # 7-model ensemble +voting = non.build_graph(["7:E:gpt-4o:0.7", "1:M"]) # With majority voting +judged = non.build_graph(["7:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.0"]) # With judge synthesis + +# STANDARD API: Equivalent to compact notation but with explicit objects +standard_system = non.Sequential(operators=[ + non.UniformEnsemble(num_units=7, model_name="gpt-4o", temperature=0.7), + non.JudgeSynthesis(model_name="claude-3-5-sonnet", temperature=0.0) +]) + +# ADVANCED: Reusable components for complex architectures +components = { + # Define building blocks once, reuse everywhere + "reasoning": ["3:E:gpt-4o:0.7", "1:V:gpt-4o:0.0"], # Verification pipeline + "research": ["3:E:claude-3-5-sonnet:0.5", "1:V:claude-3-5-sonnet:0.0"] # Different models +} + +# Build sophisticated multi-branch architecture in just 4 lines +advanced = non.build_graph([ + "$reasoning", # First branch: reasoning with verification + "$research", # Second branch: research with verification + "1:J:claude-3-5-opus:0.0" # Final synthesis of both branches +], components=components) # Automatically optimized for parallel execution + +# HORIZONTAL SCALING: Systematically explore scaling behavior +systems = { + # Scaling with MostCommon aggregation + "width_3_voting": non.build_graph(["3:E:gpt-4o:0.7", "1:M"]), + "width_7_voting": non.build_graph(["7:E:gpt-4o:0.7", "1:M"]), + "width_11_voting": non.build_graph(["11:E:gpt-4o:0.7", "1:M"]), + + # Scaling with judge synthesis + "width_3_judge": non.build_graph(["3:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.0"]), + "width_7_judge": non.build_graph(["7:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.0"]), + "width_11_judge": non.build_graph(["11:E:gpt-4o:0.7", "1:J:claude-3-5-sonnet:0.0"]), +} + +# Execute with full parallelism (XCS optimizes the execution graph automatically) +query = "What's the most effective climate change solution?" +results = {name: system(query=query) for name, system in systems.items()} +``` + +## Core Elements + +1. **Composable Operators with Rigorous Specification**: Build reliable compound AI systems from + type-safe, reusable components with validated inputs and outputs +2. **Automatic Parallelization**: Independent operations are automatically executed concurrently + across a full computational graph +3. **XCS Optimization Framework**: "Accelerated Compound Systems" Just-in-time tracing and execution optimization with multiple strategies (trace, structural, enhanced). XCS is inspired by XLA, but intended more for accelerating compound systems vs. linear algebra operations, tuned for models and dicts, vs for vectors and numerical computation. +4. **Multi-Provider Support**: Unified API across OpenAI, Anthropic, Claude, Gemini, and more + with standardized usage tracking +5. **Transformation System**: Function transformations for vectorization (vmap), parallelization (pmap), and device sharding (mesh), with a composable interface for building complex transformations + +## XCS Architecture + +The Accelerated Compound Systems (XCS) module provides a computational graph-based system for building, optimizing, and executing complex operator pipelines: + +1. **Unified JIT System**: Multiple compilation strategies under a consistent interface: + - `trace`: Traditional execution tracing + - `structural`: Structure-based analysis + - `enhanced`: Improved parallelism detection and code analysis + +2. **Scheduler Framework**: Pluggable scheduler implementations for different execution patterns: + - `sequential`: Serial execution for debugging and determinism + - `parallel`: Thread-based parallel execution + - `wave`: Execution wave scheduling for optimal parallelism + - `topological`: Dependency-based execution ordering + +3. **Transform System**: High-level operations for data and computation transformations: + - `vmap`: Vectorized mapping for batch processing + - `pmap`: Parallel mapping across multiple workers + - `mesh`: Device mesh-based sharding for multi-device execution + +4. **Dependency Analysis**: Automatic extraction of dependencies between operations: + - Transitive closure calculation for complete dependency mapping + - Topological sorting with cycle detection + - Execution wave computation for parallel scheduling + +## Installation + +Ember uses [uv](https://github.com/astral-sh/uv) as its recommended package manager for significantly faster installations and dependency resolution. + +```bash +# First, install uv if you don't have it +curl -LsSf https://astral.sh/uv/install.sh | sh # macOS/Linux +# or +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows +# or +pip install uv # Any platform + +# Quick install using uv (recommended) +uv pip install ember-ai + +# Run examples directly with uv (no activation needed) +uv run python -c "import ember; print(ember.__version__)" + +# Install from source for development +git clone https://github.com/pyember/ember.git +cd ember +uv pip install -e ".[dev]" + +# Traditional pip installation (alternative, slower) +pip install ember-ai +``` + +For detailed installation instructions, troubleshooting, and environment management, see our [Installation Guide](INSTALLATION_GUIDE.md). + +## Model Registry & Provider Integration + +Access models from any provider through a unified interface: + +```python +from ember import initialize_ember +from ember.api.models import ModelEnum + +# Initialize with multiple providers +service = initialize_ember(usage_tracking=True) + +# Access models from different providers with the same API +response = service(ModelEnum.gpt_4o, "What is quantum computing?") +print(response.data) + +# Track usage across providers +usage = service.usage_service.get_total_usage() +print(f"Total cost: ${usage.cost:.4f}") +``` + +## NON Patterns & Ensembling + +Build compound AI system architectures using the Network of Networks (NON) pattern with pre-built components: + +```python +from ember.api import non + +# Standard API: Create a verification pipeline of ensemble→judge→verifier +pipeline = non.Sequential(operators=[ + # 1. Ensemble of 5 model instances running in parallel + non.UniformEnsemble( + num_units=5, + model_name="openai:gpt-4o-mini", + temperature=0.7 + ), + + # 2. Judge to synthesize the ensemble responses + non.JudgeSynthesis( + model_name="anthropic:claude-3-5-sonnet", + temperature=0.2 + ), + + # 3. Verifier for quality control and fact-checking + non.Verifier( + model_name="anthropic:claude-3-5-haiku", + temperature=0.0 + ) +]) + +# Alternatively, create the same pipeline with compact notation +pipeline = non.build_graph([ + "5:E:gpt-4o-mini:0.7", # Ensemble with 5 instances + "1:J:claude-3-5-sonnet:0.2", # Judge synthesis + "1:V:claude-3-5-haiku:0.0" # Verification +]) + +# Build advanced architectures like NestedNetwork from example_architectures.py +# Define reusable SubNetwork component +components = { + "sub": ["2:E:gpt-4o:0.0", "1:V:gpt-4o:0.0"] # Ensemble → Verifier +} + +# Create a NestedNetwork with identical structure to the OOP implementation +nested = non.build_graph([ + "$sub", # First SubNetwork branch + "$sub", # Second SubNetwork branch + "1:J:gpt-4o:0.0" # Judge to synthesize results +], components=components) + +# Extend with custom operator types +custom_registry = non.OpRegistry.create_standard_registry() +custom_registry.register( + "CE", # Custom ensemble type + lambda count, model, temp: non.Sequential(operators=[ + non.UniformEnsemble(num_units=count, model_name=model, temperature=temp), + non.MostCommon() # Auto-aggregation + ]) +) + +# Use custom operators +advanced = non.build_graph(["3:CE:gpt-4o:0.7"], type_registry=custom_registry) + +# Execute with a single call +result = pipeline(query="What causes tsunamis?") +``` + +## Graph Optimization & Execution + +Ember's XCS system provides JAX/XLA-inspired tracing, transformation, and automatic parallelization: + +```python +from ember.xcs import jit, execution_options, vmap, pmap, compose, explain_jit_selection +from ember.api.operators import Operator + +# Basic JIT compilation with automatic strategy selection +@jit +class SimplePipeline(Operator): + # ... operator implementation ... + +# JIT with explicit mode selection +@jit(mode="enhanced") +class ComplexPipeline(Operator): + def __init__(self): + self.op1 = SubOperator1() + self.op2 = SubOperator2() + self.op3 = SubOperator3() + + def forward(self, *, inputs): + # These operations will be automatically parallelized + result1 = self.op1(inputs=inputs) + result2 = self.op2(inputs=inputs) + + # Combine the parallel results + combined = self.op3(inputs={"r1": result1, "r2": result2}) + return combined + +# Configure execution parameters +with execution_options(scheduler="wave", max_workers=4): + result = pipeline(query="Complex question...") + +# Get explanation for JIT strategy selection +explanation = explain_jit_selection(pipeline) +print(f"JIT strategy: {explanation['strategy']}") +print(f"Rationale: {explanation['rationale']}") + +# Vectorized mapping for batch processing +batch_processor = vmap(my_operator) +batch_results = batch_processor(inputs={"data": [item1, item2, item3]}) + +# Parallel execution across multiple workers +parallel_processor = pmap(my_operator, num_workers=4) +parallel_results = parallel_processor(inputs=complex_data) + +# Compose transformations (vectorization + parallelism) +pipeline = compose(vmap(batch_size=32), pmap(num_workers=4))(my_operator) +``` + +## Data Handling & Evaluation + +Ember provides a comprehensive data processing and evaluation framework with pre-built datasets and metrics: + +```python +from ember.api.data import DatasetBuilder +from ember.api.eval import EvaluationPipeline, Evaluator + +# Load a dataset with the builder pattern +dataset = (DatasetBuilder() + .from_registry("mmlu") # Use a registered dataset + .subset("physics") # Select a specific subset + .split("test") # Choose the test split + .sample(100) # Random sample of 100 items + .transform( # Apply transformations + lambda x: {"query": f"Question: {x['question']}"} + ) + .build()) + +# Create a comprehensive evaluation pipeline +eval_pipeline = EvaluationPipeline([ + # Standard metrics + Evaluator.from_registry("accuracy"), + Evaluator.from_registry("response_quality"), + + # Custom evaluation metrics + Evaluator.from_function( + lambda prediction, reference: { + "factual_accuracy": score_factual_content(prediction, reference) + } + ) +]) + +# Evaluate a model or operator +results = eval_pipeline.evaluate(my_model, dataset) +print(f"Accuracy: {results['accuracy']:.2f}") +print(f"Response Quality: {results['response_quality']:.2f}") +print(f"Factual Accuracy: {results['factual_accuracy']:.2f}") +``` + +## License + +Ember is released under the [MIT License](LICENSE). diff --git a/TESTING_INSTALLATION.md b/TESTING_INSTALLATION.md new file mode 100644 index 00000000..b58c2ceb --- /dev/null +++ b/TESTING_INSTALLATION.md @@ -0,0 +1,197 @@ +# Testing Ember Installation + +This document outlines a systematic process for testing the Ember installation process in a clean environment. This is useful for verifying that the package can be installed and used by new users without any issues. + +## Prerequisites + +Before testing the installation, ensure you have the following: + +- Python 3.9 or newer (3.10, 3.11, and 3.12 supported) +- uv installed (recommended) or any Python package manager +- Access to a terminal/command prompt +- Internet connection to download packages + +## Testing Process + +### 1. Creating a Clean Environment + +#### Using uv (recommended) + +```bash +# Create a new directory for testing +mkdir ember_test && cd ember_test + +# Install uv if needed +curl -LsSf https://astral.sh/uv/install.sh | sh # macOS/Linux +# or +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows + +# Create a virtual environment with uv +uv venv + +# Activate the environment (only needed for interactive use) +source .venv/bin/activate # On Windows: .venv\Scripts\activate +``` + +#### Using Python's venv + +```bash +# Create a new directory for testing +mkdir ember_test && cd ember_test + +# Create a virtual environment with Python 3.9+ +python3 -m venv test_env + +# Activate the environment +source test_env/bin/activate # On Windows: test_env\Scripts\activate + +# Install uv in the environment +pip install uv +``` + +#### Using pyenv for Python version management + +```bash +# Install pyenv if not already installed +# macOS: brew install pyenv +# Linux: curl https://pyenv.run | bash + +# Install Python using pyenv (3.9, 3.10, 3.11, or 3.12) +pyenv install 3.11.x + +# Create a directory for testing +mkdir ember_test && cd ember_test + +# Set local Python version +pyenv local 3.11.x + +# Use uv to create a virtual environment +uv venv +source .venv/bin/activate +``` + +#### Using Homebrew Python on macOS + +```bash +# Install Python via Homebrew +brew install python@3.11 + +# Verify the installation +/opt/homebrew/bin/python3.11 --version + +# Create a directory for testing +mkdir ember_test && cd ember_test + +# Use the Homebrew Python with uv +/opt/homebrew/bin/python3.11 -m pip install uv +/opt/homebrew/bin/python3.11 -m uv venv +source .venv/bin/activate +``` + +#### Using conda + +```bash +# Create a new conda environment with Python 3.11 +conda create -n ember_test python=3.11 + +# Activate the environment +conda activate ember_test + +# Install uv in the conda environment +pip install uv +``` + +### 2. Installing Ember + +#### Option A: Install from PyPI + +```bash +# Minimal installation (OpenAI only) +uv pip install "ember-ai[minimal]" + +# Full installation +# uv pip install "ember-ai[all]" +``` + +#### Option B: Install from local repository + +```bash +# Clone the repository if testing a local version +git clone https://github.com/pyember/ember.git +cd ember + +# Install dependencies with development extras +uv pip install -e ".[dev]" +``` + +### 3. Testing the Installation + +Run the minimal examples to verify the installation: + +```bash +# Check if the package imports correctly +uv run python -c "import ember; print(ember.__version__)" + +# For a local repository installation +uv run python src/ember/examples/basic/minimal_example.py +uv run python src/ember/examples/basic/minimal_operator_example.py + +# Or if you're in an activated environment +python -c "import ember; print(ember.__version__)" +python src/ember/examples/basic/minimal_example.py +``` + +### 4. Verification Checklist + +- [ ] Python 3.9+ requirement is enforced +- [ ] All dependencies are correctly resolved +- [ ] Core LLM providers (OpenAI, Anthropic, Google/Deepmind) are installed +- [ ] No errors during installation process +- [ ] Examples run without errors +- [ ] Import statements work correctly +- [ ] Basic functionality is operational + +## Common Issues and Resolutions + +### Python Version + +If you encounter errors related to Python version compatibility: + +``` +ERROR: Package 'ember-ai' requires a different Python: 3.9.6 not in '<3.13,>=3.9' +``` + +**Resolution**: Install Python 3.9 or newer and create a new virtual environment. + +### Dependency Conflicts + +If you encounter dependency resolution problems: + +**Resolution**: +```bash +# Try reinstalling with no cache to force re-resolution +uv pip install -e "." --no-cache + +# Or specify exact versions if needed +uv pip install -e "." --no-deps +uv pip install "dependency==specific.version" +``` + +### Installation Speed + +If you're experiencing slow installation (unlikely with uv): + +**Resolution**: +```bash +# Use the minimal installation if you only need basic functionality +uv pip install "ember-ai[minimal]" +``` + +## Reporting Issues + +If you encounter any issues during the installation testing process, please: + +1. Document the exact steps to reproduce the issue +2. Include your environment details (OS, Python version, uv version) +3. Copy the complete error message +4. Report the issue on the [GitHub repository](https://github.com/pyember/ember/issues) \ No newline at end of file diff --git a/conftest.py b/conftest.py new file mode 100644 index 00000000..a5bf79d9 --- /dev/null +++ b/conftest.py @@ -0,0 +1,126 @@ +""" +Root conftest.py for pytest configuration +""" + +import importlib +import logging +import os +import sys +import warnings +from pathlib import Path + +import pytest + + +# Configure logging to handle closed streams during Python interpreter shutdown +def _patch_logging_for_shutdown(): + """Patch logging handlers to gracefully handle closed streams at shutdown.""" + if not hasattr(logging.StreamHandler, "_ember_patched"): + # Save the original emit method + original_emit = logging.StreamHandler.emit + + # Create a safer version that handles closed file errors + def safe_emit(self, record): + try: + original_emit(self, record) + except (ValueError, IOError, OSError) as e: + if "closed" not in str(e).lower() and "closed file" not in str(e).lower(): + raise + + # Apply the patch + logging.StreamHandler.emit = safe_emit + logging.StreamHandler._ember_patched = True + + # Configure problematic loggers + for name in ["httpcore.connection", "httpcore.http11"]: + logging.getLogger(name).setLevel(logging.INFO) + + +# Apply logging patch +_patch_logging_for_shutdown() + +# Setup paths +PROJECT_ROOT = Path(__file__).parent.absolute() +SRC_PATH = PROJECT_ROOT / "src" + +print(f"Unit test Python path: {sys.path}") +print(f"Unit test current directory: {os.getcwd()}") + +# Add src directory to path +sys.path.insert(0, str(SRC_PATH)) +sys.path.insert(0, str(PROJECT_ROOT)) + +# Configure asyncio +pytest_plugins = ["pytest_asyncio"] + +# Silence common warnings +warnings.filterwarnings("ignore", message=".*XCS functionality partially unavailable.*") + +# Configure pytest-asyncio +def pytest_configure(config): + """Configure pytest-asyncio and register custom marks.""" + import pytest_asyncio + + # Use session-scoped event loops by default + pytest_asyncio.LOOP_SCOPE = "session" + + # Register custom marks + config.addinivalue_line("markers", "discovery: mark tests that interact with model discovery") + config.addinivalue_line("markers", "xcs: mark tests related to XCS functionality") + config.addinivalue_line("markers", "performance: mark tests that measure performance characteristics") + +@pytest.hookimpl(tryfirst=True) +def pytest_collection_modifyitems(config, items): + """Modify test items based on command line options.""" + run_all = config.getoption("--run-all-tests") + run_api = config.getoption("--run-api-tests") + run_perf = config.getoption("--run-perf-tests") + + for item in items: + skip_marks = [mark for mark in item.own_markers if mark.name == "skip"] + skipif_marks = [mark for mark in item.own_markers if mark.name == "skipif"] + + # Special handling for different test types + if any(mark.name == "performance" for mark in item.own_markers): + if run_all or run_perf: + for mark in skip_marks: + item.own_markers.remove(mark) + elif any("API_KEY" in str(mark.args) for mark in skipif_marks): + if run_api: + for mark in skip_marks: + item.own_markers.remove(mark) + elif run_all: + for mark in skip_marks: + item.own_markers.remove(mark) + +def pytest_addoption(parser): + """Add custom command line options to pytest.""" + parser.addoption( + "--run-perf-tests", + action="store_true", + default=False, + help="Run performance tests that are skipped by default", + ) + parser.addoption( + "--run-all-tests", + action="store_true", + default=False, + help="Run all tests including skipped tests (except those requiring API keys)", + ) + parser.addoption( + "--run-api-tests", + action="store_true", + default=False, + help="Run tests that require API keys and external services", + ) + +@pytest.fixture(scope="session", autouse=True) +def _add_config_helper(request): + """Add config attribute to pytest module for backward compatibility.""" + pytest.config = request.config + +@pytest.fixture(scope="session") +def event_loop_policy(): + """Return the event loop policy to use.""" + import asyncio + return asyncio.get_event_loop_policy() \ No newline at end of file diff --git a/docs/CONTEXT_SYSTEM.md b/docs/CONTEXT_SYSTEM.md new file mode 100644 index 00000000..812accb6 --- /dev/null +++ b/docs/CONTEXT_SYSTEM.md @@ -0,0 +1,285 @@ +# Ember Context System + +## Overview + +The Ember Context System provides a lightweight, zero-overhead approach to component discovery and dependency management. This redesigned system eliminates circular dependencies, improves thread safety, and enhances performance while significantly reducing complexity. + +## Key Concepts + +### Registry + +The `Registry` is the only global abstraction in the system. It provides a thread-local dictionary that components use to discover each other: + +```python +from ember.core.context import Registry + +# Get current thread's registry +registry = Registry.current() + +# Register a component +registry.register("my_component", component_instance) + +# Get a component +component = registry.get("my_component") +``` + +### Component + +The `Component` base class provides common functionality for all components: + +```python +from ember.core.context import Component + +class MyComponent(Component): + def _register(self): + """Register in registry.""" + self._registry.register("my_component", self) + + def _initialize(self): + """Initialize lazily.""" + # Initialization logic +``` + +### Core Components + +The system includes these core components: + +- **ConfigComponent**: Configuration management +- **ModelComponent**: Model discovery and creation +- **DataComponent**: Dataset management +- **MetricsComponent**: Performance metrics collection + +## Migration Guide + +### Old API vs New API + +Old API (EmberContext): + +```python +from ember.core.app_context import get_app_context + +# Get context +context = get_app_context() + +# Get model and dataset +model = context.get_model("my_model") +dataset = context.get_dataset("my_dataset") +``` + +New API (Component-based): + +```python +from ember.core.context.model import ModelComponent +from ember.core.context.data import DataComponent + +# Get components +model_component = ModelComponent() +data_component = DataComponent() + +# Get model and dataset +model = model_component.get_model("my_model") +dataset = data_component.get_dataset("my_dataset") +``` + +### Step 1: Update Imports + +Change your imports from: + +```python +from ember.core.app_context import get_app_context, EmberContext +``` + +To: + +```python +from ember.core.context.compatibility import current_context, EmberContext +``` + +This provides compatibility with the old API while using the new implementation. + +### Step 2: Migrate to Component-Based API + +For each usage of `get_app_context()`, consider migrating to the direct component API: + +Before: + +```python +context = get_app_context() +model = context.get_model("gpt-4") +``` + +After: + +```python +from ember.core.context.model import ModelComponent +model_component = ModelComponent() +model = model_component.get_model("gpt-4") +``` + +### Step 3: Update Mocks in Tests + +Update test mocks to mock the component directly rather than the context: + +Before: + +```python +# Mock EmberContext +context_mock = MagicMock() +context_mock.get_model.return_value = model_mock +monkeypatch.setattr("ember.core.app_context.get_app_context", lambda: context_mock) +``` + +After: + +```python +# Mock ModelComponent +model_component_mock = MagicMock() +model_component_mock.get_model.return_value = model_mock +monkeypatch.setattr("ember.core.context.model.ModelComponent.get", + lambda cls: model_component_mock) +``` + +Or use the scoped registry for cleaner tests: + +```python +from ember.core.context import scoped_registry +from ember.core.context.model import ModelComponent + +# Create isolated registry for test +with scoped_registry() as registry: + # Create component with explicit registry + model = ModelComponent(registry) + + # Register mock model + model.register_model("test_model", mock_model) + + # Test code that uses model + result = test_function() # Will use mock_model +``` + +## Best Practices + +1. **Direct Component Usage**: Access components directly instead of through EmberContext +2. **Explicit Dependencies**: Pass components as arguments instead of implicitly accessing them +3. **Scoped Testing**: Use `scoped_registry()` for isolated tests +4. **Lazy Loading**: Let components initialize themselves when first accessed +5. **Thread Safety**: Design components to be thread-safe using the double-checked locking pattern + +## Performance Considerations + +The new context system is designed for optimal performance: + +- Thread-local storage eliminates most contention +- Lazy initialization reduces startup costs +- Component caching accelerates repeated lookups +- Direct component interaction reduces indirection + +## Thread Safety + +Thread safety is achieved through: + +1. **Thread-Local Storage**: Each thread has its own isolated registry +2. **Double-Checked Locking**: Efficient lazy initialization pattern +3. **Fine-Grained Locking**: Component-specific locks for minimal contention + +With this approach, most operations require no locking, and only registration and initialization need synchronization. + +## Advanced Usage + +### Custom Components + +Creating custom components is straightforward: + +```python +from ember.core.context import Component, Registry + +class MyCustomComponent(Component): + def __init__(self, registry=None): + super().__init__(registry) + self._data = {} + + def _register(self): + self._registry.register("my_custom", self) + + def _initialize(self): + # Lazy initialization logic + config = self._registry.get("config") + if config: + self._data = config.get_config("my_custom") or {} + + def get_item(self, key): + self._ensure_initialized() + return self._data.get(key) +``` + +### Registry Scoping + +For isolated execution contexts: + +```python +from ember.core.context import scoped_registry +from ember.core.context.config import ConfigComponent + +def isolated_function(): + with scoped_registry() as registry: + # Create components with isolated registry + config = ConfigComponent(registry, config_data={"custom": {"key": "value"}}) + + # Function logic using isolated components + result = process_with_config(config) + + return result +``` + +This ensures that components created within the function don't affect the rest of the application. + +## Architecture + +The new architecture simplifies the design to a single abstraction with direct component interaction: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ User Code │ +│ │ +│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ +│ │ ModelComponent│ │ DataComponent │ │ConfigComponent│ │ +│ │ get_model() │ │ get_dataset() │ │ get_config() │ │ +│ └───────────────┘ └───────────────┘ └───────────────┘ │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Thread-Local Registry │ +│ │ +│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ +│ │ Thread 1 │ │ Thread 2 │ │ Thread 3 │ │ +│ │ Registry │ │ Registry │ │ Registry │ │ +│ └───────────────┘ └───────────────┘ └───────────────┘ │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Component Registration │ +│ │ +│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ +│ │ "model" → │ │ "data" → │ │ "config" → │ │ +│ │ ModelComponent│ │ DataComponent │ │ConfigComponent│ │ +│ └───────────────┘ └───────────────┘ └───────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +This design: +- Eliminates circular dependencies +- Reduces indirection +- Improves component discoverability +- Enhances thread safety +- Optimizes performance + +## Implementation Status + +- ✅ Core thread-local registry - Fully implemented with `Registry` class +- ✅ Component base class - Common functionality for all components +- ✅ Core components - Config, Model, Data, and Metrics implementations +- ✅ Management utilities - Scoped registry and temporary components +- ✅ Compatibility layer - Integration with existing code +- ✅ Documentation - Migration guide and best practices \ No newline at end of file diff --git a/docs/assets/ember_icon_400.png b/docs/assets/ember_icon_400.png new file mode 100644 index 0000000000000000000000000000000000000000..d5a8d655a5633bafec075da5aad7f1973b6b9e1a GIT binary patch literal 11846 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 + + + diff --git a/docs/assets/ember_workmark.png b/docs/assets/ember_workmark.png new file mode 100644 index 0000000000000000000000000000000000000000..f5fa3bb8b449a5a688d5848d7b85740b28047b6b GIT binary patch literal 16298 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 + + diff --git a/docs/assets/logo_ember_icon@2x.png b/docs/assets/logo_ember_icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..050d1821b4b00649a89a11a3a487308d4ffa9921 GIT binary patch literal 13173 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 GKJ!2Lm0+R( literal 0 HcmV?d00001 diff --git a/docs/assets/logos/berkeley-logo.png b/docs/assets/logos/berkeley-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..02a2987cb1a260a196b9423190a1b887d659be01 GIT binary patch literal 88640 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 z z5(t*fwdVKPW#8QwMi3e}A-T&DNY7S@bB^i98-MisZq%3|Z0R6Z_(uW~On!G`^elP? z>MeuK?GQWNOO)FE3yamZ_kDzczYTTk7--*Vv>V1Y4r#+bZ&2SWKQzB&0?_=SPz@t* zCLxsTTmA;VqRMZPuIekMU4fy`Nx*~yhU>wifL@*L9m}AhczrRSCj!6vu|elr+sk|% zw-PxX-h9y1AdhJS!cz2bZb>7x;YiCWAUb!^>nkgwjeVOXED|^~3$I9E(H?om$G+u6 zuKP+--3$is(==}|*Qb3~1~Ezo-5;&8dy~8ziYkg9|Gs&L-rTCdma~}E?64jK8BYc$ za7tSOs=WeuS)=1L0Gdv>+xeDncf;9S*Hez9W=EdBaAJE^->VWQRCG)Et=-OS6(3l| zM&QW6E5BjkkOo{SIWHjd@i&4Jji)qtg^?3$nBhO=I%*1sZ4!YlgHwI zWnw)NtJHy&_P(j8gX(rXQ}blpn#$K{0y6g>CToxNkK^JE@<8}Ys>AhR7+x%@TR^hn@H z5rZ+bi%*ViX~IB1k~EFCdDToY)i!{N>FqIAz&kjZ&QkPG9sy)2#i_F|OfL1mrMlRB zwA&U_Xp#5Y8AbG@1Qxzr+8-5l|EME$qlBO2#v|wUkL1M_2;BQjncAI1E3ZuMjBuw5 zDe;%r_+5*)FF40kiQrsMZ+^?m9Ki?y*bpF}(U14u8_~Dz$c{{OAvaXtN?I#Icr&v6 zUP)7t5xSTBJZM0G_|T!`cyYU12HzKN z@a0@C*-q6XJF!Jcs}@Zp##w$OAXgaQyO3EFm&u6d+(24V>5lVfKNwZ;)S{)S+bM0A zr`Vcg@-rKmAR(BwYror4W#+m65u11SW)7AZ41|TSbjbke5?~*anDR(Y2F#IdOCF+v zY+d`wU%q94Hl9nN5VIeFP({bY0-r(_U&Eg%5Xy@idAYLjMe&bpwg-MvDYE-aiKz_t z^fdo4UQ6$f$QDdH>>8|FSpY{oWz7+e>w%209sm z7%mcmD@k)VMe8e1I0E$0(}wZ_XDVh$T6=^YY$A2xD*f^{H+k#nCDFt?ecT+k05SVp zH&5Sw$VIUN^MtnwM$VQ^)m);&zv`8;9h7h8%xJ)eBML~Z-ldyG5)YRGrAz$T00$z+ zCMVc}WES=Js(Wz)i}i{JE9m>wY{DFKQtI@dtQGT8slQXNz4!A6j9$QX7xSrELqmF< z?em(`>By_Y{6C@#5`u((ha zP2ODddI~iK!>PDhNCzo+&fg;spLuOY!B3kYjyx9d!2<6?(q1xYq@{=aDfGx$fOyPv ziXncqAFZj;5(FLR^ndlV=!Jf1y~x9oul#3EV|v@WvJ5!Wms-t+pI3^oJ2qMG3|EQU!5)GuA{(f8n)DOnk0nQhSBU-=3XIShIEHmRC zU4xEmZ!?)AENg@VkFGtWmfzwHra^xNG@ zZ$)mC5sYCCM&dILYQ#`PMz@IX%;DuEM8h3^Q}M_lM&f(gSjiHO%TQ#FMf}v62(qWj zGzo8wAu8IBx}L9akP+0Bb%DwG!d~9M^UE?4q}@-EWwQ57AN$5*Y4-u59T{$aVZDST z)E?1!Mzwu1n*TDi)(c5wMEo4~{W;cdpiInYjpDH?Y#Mots7{$pe7r3AdUk2SKrn3c zHE1IX7Zwrfbn>>YdvGZ`AjVk(uSzsK-F#7VfeD~)a!+R5b)_noYzcld@E+38iqF~TJ z>uQ21w??;yef3bCs4l8}GD604LTfTuLk?M29D`0`(i`NKV6!f@Ww`Y(pu?8(?)23% zED>+2kO*`f_QS*?DkoHhCFEkc)R5Q9@Az;|VuYm;wWl8Xb@ZQMfaW09$7`|F-byLB z_eph}8C|y1RF}BIFO+(Fp#fcw!mkQoixH?Qy8igowocSN8`YbI+|EIf{FkN%O3@IO zE1RTpq+(@(!j%H4f;Rk1RG89lj{Y8441UmRdHg@O;Prz}@AwYN^;-vOHB-{kPclEi^A>1L@n*1^>zJA!BM=*kg+6H=82H zla#EmD~L__Q&o!D5_Vf#666YCTZ!iPr-Yhz`@?(F7kp6N@%2$|KY8vCu0rnS1F4ux_{$K< zh2OM$)|Ii*Yu_=S>`WhFiKPh6FkpllGDUQwrXG;Kbq4HdZa{($P!e<}W7ZaPSqN@j zM0tSF_xKymm2p&useTL)8P0pSw2LXiHG}Uhr)1 zb0t_Qvey)klvi=w?IyN#b3-gCn(2XkzX5I<$P}*KeY3X$s76!XHNjL9=${c34DI+c zrT0d#RY-YqLSP^iw?6guc7?Tz_N84T6l9~UePL1uo3oxb#xaA&&tlLrpLoW-LmKp3 z!Hcp6@35#qvbVL$}@8B2m{Fe4qPdwQsYp`^X+iaxLM zXr)8jczA>;=J~zdrR(^50{zz{=my}ZP-t;Ov_+8WRr{T~(NXM8kcuW2Xr_+?!%Sw6<^-Zbr!-jxK7gm>#WUeX_m7NOLSFLIHwy+7(~ z*^MXFd>xGO{z;1ps9xmVCx`n^Llb|*IkRcDQDHJ%QnNi{03bC>LVPa>7+^SAyknIV zF%agS3*TY!r`bAL)a(Kog_bfDhv+?DD#+$G=QYcZIQ>9o5sf9Q znv1OiKsRzs>BTtn3v}E-ATo-3lm}G;r1`aeolWY`t>7&b}4g%&if82n*KQ?QRAJ`F`{+fXZ}K&h@jArY&pqsg(MU=`BE5J{7(9uy5;eaRST^F@i;GSy+>Y~}Ka z=MW-40#x}6@`@-JHX*tno2Zi==6Q_Hi8yEB_tvj1x9G9L>^x<>KRH^yAVd&0vda7$xQR-22_>QDGCN-hKATu zYg2xNY34hRDtuLZpAj$Ro`HQcYsY3Z4EN&fecMoPxqUet?Xd(NeW+OlQ|(9Tp<*o2 zCEyx26o@9i|F@O}DdH%DqB=OpDgEezo=Q30t0RZ+q?#$@Q%@1xeH7Eo_n856#k=e3 zFGP_NeACM&&X3q^ir%_CdicpO>65l))qj?+!|5hW%aPgKwr#hES3xPbbvKr12(*!^ zg1S~Aey4yvwaPvI$m4y{pJBA1hW;rBClz__SIwE7>) z=ub&_@;mv#*|`3MN4mEwW6ep>8bK(_+nWbl=9%`02%u9NFm7|A!MOo#us=VMOvkIC z=g0{vyJh7}`HuuHyg>Y$yDv9hGm)N*5JXVtS$5(!VEnC)JFcMbbMz7pP!OsjzjJsE1Ck(+Z$!#5@(8Blv@Q#E>gQ*6pe+>|>$ zLK7yLGrx1qkHBr>(KdA6xEclJ_bIyZ)8;>#P;o(d34HR*b8z|ei=5S}%{mDe! z5dVM*GY1OUQ()Cc6L3?Z0g*s5r=JkRv(qxVq>nA%+n4>+y>hdkShYSh^U1~0CU z-1E|0S}of$v$C5jCovdyBt-S-Wub(yuCyk)e&e66`f49Det89Va3FVRMR2|-cw~D! zs~s6a0{J+^S)mk(z&^0e)BQ9Lnay=6UY%gk$w8qGia(%O{QycD(@c|7S$K(2D z(5u8%-)qqph$sqhZPW3`hg~4r2*8%NeM=}RN5ZNP56%a+u)Jmcma~5o>YGvNlAxE% z=+?N~ayh*WT)XgcOtnt+!s$DGTyUtLG0&y3^ZHQv_EbI(PG7H1@Ufdthh)3U@qlIf zuV8cY($_W;i!Il0i3Buy2M!A{969^8U%p8|l2cwMrSUZKYMse#`jUSB`&UeWuK~S4 z!(;dAcaONouQasL^3&lUqPhi&bQ^6b|7Xkf1_@(RNd@X^Ea7fg^N=6P}0$!TU{aXAhbdvt3 z`m3S?{f|#G$S|~tR8ZJ!5^=(uh>ZbP(I{ma#)eG|cYiqu`vZ@-V?t_m8WX#~kYmiwj-s z6n6CO`XJRYMB(cnKONa7ofP6Sl=Mwkx8zq}qRRyRFeA~PY(SVH(D6wS3#5}m?JzMJi3P;Ydh;shKPi@Zpg2XHaa#{aZh?Mk#PV?+?kK45+F5G$3N%)|PQ^Z*HC34pO`TrQd zw)wg%q-o3nl;r;y6hn#&LK)c?CU7R2zF~$%` zR*asjboJqMVDSOwn|CMA8Gw^Qpb(}jXMyTxRAm4H9pZ2>0pn*z-JJUIZq4V;$kX!~ zcu8_Jit2*4nPu~AdPPCX`g&Fi8UpbwbNRr^dFQJQmx0^Td=CTV=s2?<40>#RwUf`} zeU2?)alG?pQ2SP}PmlDX`wb{~^3&+F1I&0$SVM-b{G%+@LNuS7zTU6#dsJ)UR_xcCUZ909`V>2R1$d9e4i$DNrG6@=yFU-WL|WW} zs8(MI;3KG;C*n~B_Zi#e*XL6+Up|FUZ44K{NA3 zTLbhxC#;8LnVVvWo95}1uv(qKF@PJG)4_ca?;AcBgQvy8jc0hqiQANl*S{2CdaWt> zZ-sDrhK9O&`DsN3i;HXyrn|K)h|lDYpnPh;ERMdGKsW<7Q(e^7R^R;WB&lM-oH&0*Q!i#Be2B5VwX(^gf<#T!A#bbiZ!6J(_6iwl zy;YEBNSzQuZfTi8j9GgH=3IIwqtQ=42gYo(M`G$?ZcMD*&%Vfi>Wr9KJXIr#i`fso%gYh8=evNwW z-eR_ViSq{S+yA6Hd!*QNJ5PQhaktp*{xHBZD-;5`c-R5r9x!W6KgGcbwIGECs0Vqm zo0kM+nEr)z{@9N;%_@5p+zO{Nf8RRbE})Sf zD5eiD-m&L<<8qQ2W!C#lH8p=~hpQ~F5Y-6=6~3n}00y2YANZ~{3pV3$r*b_cjo+fn zpW`N&&?EIG6UcGZ_t3WPhOH7AVcUN6j?+i_BAqPRqea@9U@J$g2Bp=d%`k{OCYorGEHXEOzu%1Lw){?*6^g==Ja zUcC$VCoLH#Rg+a{9F$pss6e-O}3vqDK#nsycQ) z5Z=3L(RdWmeg36N$hIG4hmwEcTmr{q*b4K3f_ZUR)ZoUC9lf>xEPY6e$2=7yv8A~} zV>-)A6OoXoZ$rNSYI8lk@i*6TRctS3=e5kJe)^03mgl!ocuvQkVp0Y|B;>lnk(Ae~ z-%uu3f8lktAHB=%*Th%-AOmTCGG`m-LZyiUeS@XpJ{%}Nv9o>u@34zR`tiv8&t`b$8Cx)O-h2V{ZJQ{=$KqlUFhtL*XQD8# zX?U^ZqPATjmeZjWoMil6v#xATLjRUd*YKbCcp#@x@VO_XY0^AKb^ydOe3`{1J|^a) z)Y6zfd;+yX4Z<6aLNRvg74Z$TINp{F3BI8=GpE%fbGL=20lO%Cso4GOGfL;Gv4Z#k z;zx-Mb*{Pwya_{$@54SXgv>aqQhPP%aq!hbdYWDys1iW*2CI0gGJ?UCE%7{^x6}sNtoR(D?R40lS`?sb<#39^KrdvZ19@kGQ!6lfJ`d96wE5=)b zTlA?W4b09EK974X`ZP2#%HD)CZ~pPGrn%zy7zy{G+jm%g zeTdO}$BD;x{<=~d*EGWto#8M)v|(vyn6{Kh@aA;!KmkTTYq_34hAAu9nRHj!>eqRB(p2~53T;JAkKE$}r52>w8GG1Z!v1Sq27>!AFHSLqMJ*=k{^-#~jM ztE8rl^KP)~le<9i^qgHGW9^f#1sm_~OdD&E|BJ&ZSHq;?b`2VMVcw&`-E5j zMeNWgoP|4jUK!tCu#nBM4`t%7TkvY3g0CW~g22q-MnE3`F`$Um8ZhbFLVsG~sW#_uvF8vrSZTWUx{a}QOkat={f`zYl zCu@Le=;?_cU@t{so@sU}cP{?1+Cnhm+xSr%V}fu`w+X+5U-iIhxoO-`U+)gn*m_7Z1mHz`t$0IpYz_v9<9ssasn>ple-B)2>?zVY_A8IzpLwF-yK z0{3sMw->AtM>v~QUQb?#@N%&7H5Zr%_eWDO&l;+nqF3>te?zxWdHbgBxPDtwD1UJ=7lWcVhLgk{qZgDTrh3CR%XWZw?aQNBHC>C0Njzw zWQ67zuBjab%TZ?L{1o&Lcqf{P@F1q(@9@Hx$)hEqYWw5(8{I zY|pQ^h%pi!e0*hYnuP$cRu@u&5q3TZ$S2g%5Ybpw`0(51Ra+9g&8yw;Ij2DX#mo09 z#5x8jT3d?p_DOL^0sq~pzj|fb$GY-v?!)H-5z#&$YsjrFy}U3d2?nI>+B(&XGyk4F z@ZBKd`Vj&w$Kpn|2L9Z=F$Zu;S_5I<0o)bsH)DA6W;q(m)vRxcAtumTxhTh@owT_B z9KLv%4#Y`dJ#Im^9T(NmiLD|yMvUHdxP=A~_5?W7h*%w)X-td%PVyUjJM6}76;HNc zCC}0O-Zrd3P2H%k^=eAwSq*f_UdCgWH6nVF1xyyTvrBvGDnE4TdCRt%rFYK!O?&3A zx?Pz217^g1&3^xkYlH+Ekpx&0YV@?rw=-nCprB}lLBIKlfNTWiZ;5X{+G}hf3mf{H zDl3JJ7svzy9Sxswm)BL;k^Z2EVh#Z5R*{1Uo0?Mx8UhzXCNjVA%J;YxUVUi8XWqzBQW~Fnb%%p!M8_x|HF?@|rWlMONco!oE>xWxz|odQe$)pJC*WY!;Ud6Ec^oGFP3=2B97c_v2_Oepq%>Sa zs(sZijv7wC$YFk)pDIAf)Sq@^Kt^HE<^8e6RY;>JV(aPHliCEWp(o?!WD5=NoyftR zLyk@hk)Q1xke)T!efQTX|KgJvAdKMh8&GG40zL1aNmGM;bLH}2=RRkMjPE4Ioa&zM zGoY+)_*UrjtGKTUhoylUm#iPe1!jf-ZPb+!j=f2c?W!}2IV7YMGWkS9#h%8@f#N8q zEIy!XL5mMZtYWYG1;=ALZUHo>ZU3TsoiAJN@&gKu^^mLRxs)k7(xNROWR820)Ufzk zO+t5YV8PhxQ<55noFLD{+XbE z$(W#yOiO-oeLrgfJ=7b(rtSjcP3x_9j9wuX#g3}XhChDbBYktkXKO{% zWB}!Vu?K2r2A2+k8$Ng%WgIT=Hk^eqQERA-A2!r1(x`#waHhK!DE$4yOA??KdKjh( zM$C70S*e*J4|H|a3C!RIRt+b)Q<1|OWOft<6P7){be!EwxtDsanA-xy>_cUzckS9> zdkc~<&131+emTS}g82p59WKl|yct4m@-D0H?}j9}!SF|PE0%T%^Z_O#9pF$Y5*!hU z&Lsoy^D~nQO)Jq5WKqP$RK(EfBSO@euK(dvlFrwnFZZ#O$Z_=-;{KkRHm+%w(u23k z`R*Jsqa3le5>3~u>BM`jTr>~!TB#Ep8R?!Z3kX+!yu8{-Em0Kx?$MI81RXxipsQ;z z+P<}p6gRH#tMU8+$9E4z*mp$a0HD4u31wK-WNrwxl`xr+j@V)?qsC;CtawzfW zcA!%OtHxgR(^*Cj_etRmUiO`(L79b|JRySOmL@laO5F3E9*bs-;guNYlON?sHEp|* z7C5;o7+&cQMkIc%ZXt#wShcIMBEc2sqxjse0q&%yRSUBW{nEl;` zWmx7^16QL;P&?QItS|}wr{$Sh`n&x{?~g0)jgHLB--j6Y+orw0#>U?YVUx{>XrvQ; zGt|$jGb|U(R=+|8?${yx%4L%`2e>eR{}-ExqDjwb;NyJv!HVZG#i~^PIa8E_hA+)S zkfBDu>7Sk|p%fMO<^SoDdP#Bg=8QcJq1BH}lSVL2gA=fi45UIN@8i7CZ90q~<0n#? ztg2~J=^g%O{v)%b9|GPj-8gc4_@USH2U%TYhYLU{pA?;dfcy>f@q`W$5-|_-kI0aA z{zw-BKfwwSCIfFST+NYY&zI}E8hd0nMgb5LGO)z024y?_WtjpxVndIJr8J)^^I%6B zwC9_+BH#rV{wmd5JPjhoOTWG!9RgK^Xn7Ve#w#nI)X6(@uvY%PVwx{}WBYykH1+AG z`GqR6r8did5zI(Efcv}p(-rDJfVvo99NN4^nmaRp3Go5}IWQ{&Kc2kX#5UXRg`k-) zW)@dbuy22K)vbsl`ECtum#71KQcbFuk&_{pdK5PS{N?2P#&_ZO6x=hHoZE>*cB@*WaL_IHRo4IZ7dk0Y1))qNQKFF3bG2)-G zu%QT-C46BUEfkLVXMNJ;V45&=p_}KAF@!3fVq<*^fJI8VZgwA#<|@z=iOM-SH{%lT z`_E5M>sunI!2cJaMF#2C-hRVpiy~Grt%znoHAw$MxUha9r>3kiiYJ58U)9NuhL8t4 zoh@xe1dtxckI9%VUPTeAl97Hmm=HlXqO?KF^FqT$aSvT5?|5;iUTJjseU6ei% z+vrR4`5GW;tnWDiU1_Gml~S>@C9S*H8eh>#Fn-#kcOIgVC16)D! zDk72*lqx1w5Z^o$d!lh2vCp`Eu<-9Q_>KVhK&*4eI|aJs+E2}HUo{S1Y5biY!^EhU8V zBKYHhGW|)tv-#mC39Yrw*g_=4_Vt(hul`4#k&nd7Prr^%k6_;NO3w;;50J4^GRO(< zHL6?u(o1GZ{!r&juYo4@SgnWi$()cIlSY9e*f;3#FU|a%9Q?5`5VkgqCS2Jet^Rb` zrUai$NALcJf~N#?XFwrGz^Db(@kB~9vuAwGNfj5R;k?;Zbhi~VN!J~NSOYoYG ztd{@{vg!1ZQ~T?HwoM0Z1tB4K@hwE;B0#-zmu{W|>I%z|VvX6kzL%ecCHez}1j`xY zP2Vfdid(PPy;d#EeBRcO+UaxZiDDmwz>VamGb^vk5xOo2icBC`ee-e?SeNd7lfT(C znu2@kxjjW@dREuq4a9$R5_6gVcS>*`==3!43LzOmEU3DG+Kz`pCd#mW9|i;x1Ye{e z@Dp^3%xpimDJF|Q82L_;;O!}nL4t)P+1Q!nz6RX{z?xv&cX6a@Q|5=vT}e3|0NACp838yL(uIx1RNoP)ZndSL2dN)6{M&(p*|(JdY@ zA`v4{u=V5>LkrTcOrUHs^KEnf;Cv%#+e+oy+e)@^lG~msmL@!Ry4(~%t=oW~DlG(9 z{-TFffr`MU(J_pH#^a#+6W3*g>QxG_G5)QGng!s9E896JVuSPC{lZoQ4n0tEDo^~&+_@s?AGww(VwrPpRcJY00v%U2^ zcK!lj{w{k%HZJErK>5Ud=C)|Z|Bw2d1iYX3Pke+y;TD0W(`U(?Uk6#VNTz#eeB$EX z`%vXdBSdtX1RQTu8D-&e8IFB={<{{C0qSJ`#|Ei<_^e=%vaj=YBAGA6zwiz8H0kP< z77pc+i;RyWlMBuB$e@9{14nZTDBB6zsoQRd8{s`xMg%DX8o~jZSdNbvd8bgs--wDE8x%dzQ@%u3z&JT!%&y z^6kb{pd(-T0}C4Y7zY!{PxSqcU!Lg?(A#of>7f#!q{F|!)RYx+I7JepN0aSNGm+t}F!@P5OvZK4_vsw@*M9Xm5*`9ek z_ED3mrgd@_W0qsDNtbxz?CzSKnNN51!Vn_zb&}G~qtZbNeIys%#08s+Kg#|FkZGZ- zr|4e2Ml3H`(Rw$FW^wp!efVF#5pg2VOXM`=xDTlQ5E#Co^fS@-=pI1*{I6RP70|Ip z{F(Sl@8&3-A=}KMKqf-GRj;&|wR^ zHh=RZltuy^D+*sFyir2cV5Og}+$?>pd7U;{)+3MU3fn7IfePlBq4nM$Oh($>_OkC) zN5oA=$*&bJPR-1jtbYbQoGoKt$b*57cHY-Dg*|A1nCf%$H#;;0&oxgo7_$ODw;Yvz z;(lRUutaf0bpo{kmX1=jBVu`3<#w>(RM~_ zeSCTA%Pa@Cf#+U`+cXtQS!XHRp*Q)2b7`GfN5fEqK>w*?Ih_4P8PWz5=+Xet2DmTcRNkx!}NpC|cbj>E%vnB!Tum zNyTN}SwhI2(fVZtL6q9LxPb{t=kv^BaWlcXGI`Ob^ds|>1hY+~U(&9f0n)kT>YyGM z;+@H;K8ZDoI8Tk6PH%9S*C=>8T#Gnisx&oP-kl*O&_Vp*-+oPFRof{#Xf@`)zxKn4 z-7OEt(aKbh-^#oD#P!?@h$)fi|Er^g!%J_*-}@eQ`DK^r$k5Z`8;6DeO;O{LLWGYJ zCmxl)bskqD#J;O0*}SG%#pd20aTDQpTd1Aq$8%xR(Y%o9;-7w$F*2jq&HifBQ%zVt8oJ~5yZzH|ST zSl1jPSLvwL$=+=0iO%2?2I*u_(-d8u%IeGbWI~Eoi95x;GHX1Qu zsB=r+8dWjft5glj7L5BiV8#wQf9^MQ2W3sl#UQnZuxSg{> zi%UOMbC?7Ly0aD7tUyTJ0?w8HEfuRS`5r*1ZXIWuKFNcVIyiaX3y&;DE!NUVtLeLvP{F zba=y84X?Soo!b1!=$l+y~&-7nWw+}BWW9$G{pPM?re$8G25qHOS%0J%}EplVB zb6dzM_k@ZSqm+jKxS)wl>ea%}aUHOLVF=rSqdYK5*YN?=guyw}=8kNdBY3+cRvxL_ zycO$EKpYOcGdIdByq11gvp%$~EX@noHov&QuXiP&tTt;6urCd&&K(HPENXzs(_>%X zIinODQy6MJOcNNYK@g)fgPqF;i(B)<8`<^Mc=9$A<#eO}vdYOr^Qn~#AUITj zElu@JTSa~j8CBkgBQb!*!SpzP4(O==D=R(qi!_YR32mv^UL-MX#*qEZx@JF$18~iY zOSqssrg0tt@08A}lexFFex^M#O!;l!Bm~Sxk*Xr6MmYEGpcIdnspyEdr7TM7*e+Y; z)r)cx0a=tm?yGAgRxQ^O?s+f#r{d$%{BhATe_kTS76`lFP|!pH-+mfN9t{NCJos*; zxyxlbde!BFlK3bMI>z~T^wQzix3>y^e+k@OA>h;t}3!1@(sSWQ1HX&xrIw<3E@v z6=_@@r@cu$uBQTT>RjVve8+!B-=FH%KTc-Q9I`BhnyofP}Pk^WN|K{sYg> z?#}GYv$OLVq&0bTHvDEW+!@#+H&RX}Z)$WOihCpfY2r$j>eiA#{J5-$0~xOjOiM=ldQ&6aOMg$!hn_ii zVA-Ku^WZ0t$WmzepPhV%-;tB$kD^*gew;o&we!FN=roJ?QS7tgp&!a}ec3tZtx8I! z>gor|L=auldm$^noT_Z)gf^AddWz?%YJYyLZYCnCn56^iaktA!A!aoEylJ*=eKUlb z$-6%a29IKZCDNvO#(haOpuw*BVP0b;zCJK(lK?gUaGs zz`nedxUGTM_h1H#2>b{|bQxH{HA*=?gUwg-j{E?K=WFG8R5W3rk^vIaD)_3*x_pd1 z#8cqP7!dm4kI;`rb;A`B}8fz3N9-W=CT>JP!?OVL77k=1Z9!5>vPL_OK}t~-;G&(!IiE+w)ly2X6pt*(qN2a*f_SC|pDFm35m*)G?)q(bg$A?S$wPSR=0b&~>%CWW zLcF<$p?}`_*lxpYs%G#`yLX8i*NPpL{h)o2f46$B!31fF6)2InTx1xi(~OzMg|$4; zc=WRV;;}`pRQRCzi4Od14}Sq5agm)02@DLt!iHueT=WA=i}dO~z{$Vk6Tn^ZifD6+ z0${_dwWQeqEM&rywOG6dat|tTrI`_b1PkNwPD-n7hkZRY0+wdZF@sH`wYa3|hJQAR z?pGsNYNHt)(g$$^kGTQ>?D!#bB&`H;oFVA;~8A zz)xPE97ZEk#_GmT56NUlLHlskKPpVaU2r1*g0qUV^yu#gsPfrXhi~L5f67q0stG8l zs{;%MdJ>63HY@8Q)cjfMI%WLfYMAoc!JNt*0nvR?*m}cT?+NT{0FO&W+NP@}S8Fjh z&|!D$ep6nyxg{Aqjf#MqVHRdT`gpkM*{BQ($7oxV<-zpt>FC+t2RBkyn4}EK5tk>U zdSJUv$pvNTMMQK@LPJoQdVByqJURjnqIr+Y&EkP;5~y|$QLhT%LjevV0X}^j_)Fd7 z73|Zosr(zB1`!2`NkZLh+{T>eUps8uH1n8bux=~irivtcnV5t@U%Vqa=?hZY>&T$0 zn)n|CRzR`3Ne8AolCl-sq#=T>QyTr*gK}j{-g6W%t)J)OuPm>(UG5?b5xp~LKv^k; zC&>sRkRUQp01u#na(hck3t@tHLZ3@upjgPhN3`g|5|KUz9&LB~xQOjmRlaWCXQe{Y zHn*BgBj^Ma{4iYXHq^tRNZ(3Tq$B&~j=uS)w?qP zNqj(Se2xk~sIBt4TTT;je`K=ol{R<=wWbin0TSEd)7#0|f`}(%(Aj)(i)t{;))@FL zpYX$4ZMe%e`77hseA`y|mhM!P#U(f6lB9)9RLa5gYjaIDXwbP%OH(X9abe{l3}YqV zh?o(76x@eBbTld4v>Nr+x1N!G6TC$U_ihe7gg*(hHiC_*JN>)f89@Cm+KwZ^9 zz*xlMuFlJfo~a4M9JpY?9;+!8LdvY$9V+4#zKVu~Gz!sigIriiwzRTBx7#3WTN1%T zX8Hc0Xaj@K|IF?x_$!d|sf-n+V)R|Ukc)qKKEDYC!^1c{F(mh48h03RIwKW()HWK# zek$KI_8hn6AKk0X8fl7F!TM5mpmEf=x=JL`dDJm7p0lb!n}&OWi0=u*L)wZtJXDc2 zd6^JG(AM+1oprPfWI_4SgQpsC`gbtE9_GGFppDX-KZ#Msr&rv_=}m189vuAvJ2fju z?JwXhv?1s#Pu}jU^+P#CV0; zaWjZ#ni$qW2aFLkIIlUF9yZ^-H_`d=nhXvMMw?LSRYq0Cx5Fnnn3{iQB z!i{~eL5Y3Vj6r7r#=zX7gG#D@(az0+#88B5K%c8t#D;f<4!G5dS!HeMc}KdBhv(?E zlFC~-T7Y0~uNEh`9Gwx|jo>wAG)on<2C_JjHzj}x)1)Lfq@?BF>nF)i_BX#7>%;$@ zQ<2DZjPW0YnNij>=~h=btp0vOxY=$d_Gbm%JzGs)9m=MMguYj z*?0oQTOVO5E3-#=S=9$#$JbQJ@-17kyiIle_!k-<{zls^VZfAuH_HL(UTVfPrUkFQci!Y7_#66dkW2 zlCJQ)?7pCGj8b zg9)sQuuZS=+z8{p(U4<{B6h~V^<~E2{o(|Ib^3Dli)EXZFzY75fJrg9@6Tq>8v{p+q7;qD zfsVkq9ITjqmFLS<85XQ0yeBW}N^f@qOga_Ldl1!DLY`PHRn|q0B*F3ujo6E_*6?F9 zQ{0J60rU!0*oM?6KtVDe->Z_rIKi!{q#L9cMFk?ecxopeA9@Eb4D=OZ$#^x zrcd?T1>!##zRz2z>|(f=rO5f?1&F)h@WPrh8ptLUFZX2qLi&01q50dh1`?moM8K}M z0pXxpj0uT3t8R460%fve(9;ZAkqgN8NpeqETadnEun6=M4DE$3exDWv{i_C%t6zQO zH3v|}li|tT+D~|`Nm+wv>g0!1{&$AQEuRIyLzM#D(P51^P@LbGtkYEjJgda?B`Ow^ zkuqdEV8hNjHr?LmtKLB5vwzUn=Rf>W}vw0W7sgx(~o zC2S&r&?{etuk>9{6DMHae${)IpM-QXp24S60JlJRftEi6omUyRw$kMTHv0j3{)YaR+X(%^7xgp^SAV$_;@q=YP#(y%?G`z+sX8wn>)V- zLw|Z8368-lM4hM0<2hAP%Sx?Dj3x4sVHDdn)V!a_2e^ksXV~8xep^2Z2s*5K+n`-` zGqu=as+Y$z=}w8~!#flNw~oac`+c%tVoVqfTs830*O6h+j!%l_h+Us>$`*=#a|${j z(BB9^1odjy)$}Wq7m|zk_T)C0qbthiNK|Poxu;Y?j~Pt${&7in2_;|>Re9XSdR;<& zo=wdV+l9K+R3~7nA}o?=gH~8Z4~3{jeyGwoWAQWKc0%<&9!u)tfyg`l-3(3nlf%F* z4s0HuYfc3P-s{+xe=otasWTU5Dba!v;6xDvO_;hbGgIalNw4DkQ-uVp&az}^;;AZ+ z1}o-(HG;5+$%C+056Wt{c5MF%@?kU_cJw-`sOK7=@2mlr-w%(t*Y$9i;l z+vOfZ(}Jlf6nCk_%(b^PEHobmDCU2d87ga1cJ%2TPi?lSA~!+eS>bik9?GC1bh6=|zMSYms0C}{5H`h^_@c|j6h3&taO0J$aLDH=jIMt`A^616e%Gw{#f=k=j;=(8fZaQWA{HN> zt-gAvU*vmmW=|!0#r_&&7UI^8gR*Gl)e74jWAplavQ#uNFi$@iDms0xGG4dmWFM~?(NL>vTadW)_V;}s;OGjsQ30To)BPFbI0w(b=!E8EsJJ24`rIUjc78_# zI@`W>a5yUcr4cSTbCd=u>sE-;OAY!cCuyj448aWT?2;vHkZs;NrvwRh<}kzpOfhvn(a-F829Veb+jQ(_0@wKJDDVI2{{Yh<@dw)FjlEa?gdH!b87OP**adKn&c^dnS|!Ch#Y@w@k}=>&x^yhAt?lO z?~0Phv0=X@hzPOJH}+E)7$YE>GJvjW#py^cniqH#R*{BK%8g9@;sIU)(ILcygWO$z zr-X;i4(?YF8X?^N zfjYn)$$HGoQGfRie~z;4htk+(JNcgw4o1d}3-a!49arGZJ`*<1LD$it2j0Yq_>!iF z^08y3*2f_*E*roEzsp+KL~va=cDu_m(xBOFd|fH`1y3CtmXz~cIlg$gSY!LY)gix^ zhPA-CRju@3l#9Dok@G}fs@u+Gs*l<8TF`1zPpy#Exy2+|IL#4?f(+wQLUYpba^i6# zc~kb6H;6Nt75}#iVO2gF|D`;_B0!|E(hQX?w^I8UZ^1dq)}Mu-l_6VZvW{4q$H)+M zr(Amt=6IMScGf4o@eUTX8%}DKYy~fsl;Cu+ZgP-Ad)=vO1by_ZjWhI=6MlfI|F-=8gKM1 zqTbashv%7tclvePGfSo+YL=DARo{~Ke(25pE);I&53y~8^l}`5Zn6fvhX0VJ+@ehC z9reJ?sv8`5@t1JRaIs8s~C-LHUh#c$gGS`^s7e zp*2+rSsv#$(;m!Z_c>%%++T%OUirX?TFXioL_*1e^T+xD7p*f(tIR@pN-nuLdQxRf zX{@_rw;G*lRgk8uG%A8SG;yN)uIu*TJ=UtFEZX?EXS!#6!Gk!WI1fbO)AbuJ^G)W( ztaou9jh5chZ4YVBGN6*T9LrRiWOr*{h zLT)Da*^4ikjPTwUcJG>)((iI(9W7`w86Z5f%?z9?3ZqJxgQl;>@7OSh=4_D?bi;!f z!l>ru8I+HSXa$sP7&Ps1lXdxS*$@BJ>`hwar=HJqeDQ89WiKoPiLLK2WZm8qV%l?W zNRQSw#1ZR|{O~wWoG&ZMrLrv2i<7`yi@6r1+;G z6{}sPh8<%b(7}{Mbo)f@nYyxrpAgI~oWkqKRBNVOceJ>X*RJd%W3Lnv+fsSY@nJFV z`{slyJoYZ6&h^Js^UFCo*z_{yJ8koWX$Lqe4o8DhRRv}Nohp6-a^8V)06qcDj z2xLWDg=3@O1iKPt(e;lJ+Gaf=G`4GCKrA1T^7=A6V4?-VcO@5w)1TAz8r1p;QzWF( z&$F6vxGUK^tsWx^gYirL;Q;AO_5wm0V%1&==64pEp3igA0UytPOi*HGvI6W5u@n(_ zx{l!%sil4gLkG$G-E*ast$nH2t?%{GXwlv7XZiaxlaY`JLW@*88~tmo76Ov_cFg5Sl;;?Yus_L?zt!xwpb7n|5wpg z=T`xwSD>C#n%KM4?M*gAy6;CtzCUCWbt}~PDl(7m#x!OW=p@AF`Kqoo|0w7=!!An8 zLi)9*Q^1ie-pPZ4Po9ru;#Voo6iecvUsD$#S1pr-&~zeb#fJ?8q4hyK+|o`0AOhiK z4)djeEbGI7MY4|wn3EU>c13mHiBl}+Ay07oY(H6iI$Ye5hf^_>>hBM=!d3D9e9;)= zeP;UBJdBTNOl!p!nB8()(IY0{sG>hYR%xzZKyJoc$0Bi52A?HUGH3B6%(e+dNvf(H zFP^dC45N3iu8(7cAf1|N!wy4pA;j3@@VxUgLhZ2%*U^SRCvqMP3u<-4x(RKC5@ja?g_1^>( z%Dzc5NFX01!MIdEoau5B$#oqiaAIoAlXf|ZbAR5$t@bJD8)-}vL(O7*e)Vh>Qlh=` zhfdb!%?oiWC(hmmU(ytKM>i7Ts9Rmpm+#pW{*MYpA4rb ze&{?f6%kI`TBGnkIPNB0-~LukzlUaB!rub#wMnN&@mgfG!sTZ}L|_1Au`4Ez{tEM9ZiNn*If5_S7nInpHS3*KG@BdqdRoZH))FpGL9oo`L7}%-nRq1r z3`bjGf@)SPl!2d!FbG80*`fs<^;F{u*bBH%u5c)K+*T3XRo>vMH|b?x+l=7xz(Uf1 z?poYhQGn|`K-CtIU9UwYYP|?pgfhBYd~*JR-J?MVbk{v27Yt5ly?{*ENF_0mf&~!_ zyNsT_v&uVj7|DKxtk;F3&P&#+eiX9=2PM#{d3Z#%ZGIcPF*G?k)Pi;5z{EJmx@x`q z@wIC387?yUy)(#=!@c_hd%CQ)tMiRtSq>Urb$THRBm3hm+)&RfK6je|WY>6xu+J7g zMe+(7B=y4oC=q-|m-f-gNU&0D29BY*gTdQT}~cr3PiN7x9Dqm8i39&94_B1lCOCsL_hBfYTj zE@?jFdnD4Yy{N(usGt|!haa|U3x~00VJ*kJg?oa)@2-=vsU=Lzt1#mpc&&D|tjM#g zw8C1^Yv4D<-yeEq!@%$#Ru{IHqXXfBJHaIZ#Z<^Tqms(8@bitse3e;& z77=A#GpdUs=4i+BsP{kp%uj>I7Nph=iLZE^h13+~KN#@E|5c?F(}U!M5+;a z*|tWf3~;ee*F}-cw@^ZeW>j2rXh^Yp+Coa~S%KYZzZEYZtn{dh^?RY2ZPS}A79<0F zCGaB-n!o&5`kgyf4b1lu5}}!yK26EeX?r*Cm$_$BM(~Ug%Q=1^Io~plYh9UL^WrHD z72AK%WI-Vk_-DXYD1s4lMqi_%9pa5_AsW0#kX92K9+P(a$qneNznw_mFr?ti+J0Hb zh5WQAw3D}*P5g_O(wvnot|Zr`f91n@aLKn?u*vBVFx}U^{>ze~(p$g4MnRzfD!m$w zE3ctigsy<(B}AO$XxsV9fbC0>Z^rAe@xW5M;9w|`rxR+w?`7WXvp@7?ujx`wGEmX~ zU>Si1Zu7FsuS`wwFKJ?pmU|Ay`o8tNGn_cUf+~o`?x?|18minX!AoO`Nmz{c7#8nK zry@ZSPL($lK9UJuXnFzD;Nol&cNL8Gdwq%@xI&Y>Vn!IMBn_Det&Dc%8BmA1ZNFbhCz=}BZTBV-kj3vlT`PZKd((chMuPKf zQazw0bCk=`@x@9qZXUyt<1L%N=OY9JzUvv&$;ODzpGFAQVbB9(?`?AEoBBLsDcB96 z_Rz$Jw}p1t0hI#i;L>%VYy%(@VMc{jm$6?ynVe|*V=^D$-lpPW@TOu`ECITA+ zoTJ#DFFXZ5xI7<)^P)87-MnH=3|m{y$ZE0nQf%b>V{52Q9X2?zn(Y92b)JTKV^V^? z;lx{f8lzL=mFc3LKQ{QQB9(0KGRdY6`p^BeG_9eP5d6&ev95a(71Y1Z5X+4tu|2L5 z(#_M6c|8ttb;w^>kJ5B7MS}$L2BXy2F_YK2crJ`6a`bqP?69qOr#Sb8k_t#(1=A_ZY(H0t#Dc+{v_q>eYK2y~-` z4bsGY;zgULG;d>eF@!U-y7rh{eAW?)*$=ZK#NH#8%_Lq2TR?JA{rc(0(1*U2;No#s~BLn(wY1B zf0pgjr(PKVFX2L#7Ut$0CYrSwZo(I!EkKpWmL)ne8>Zn>R6 z!oL3WBPBjD)7A{ zG+v}lu}^ER;hG%=a@O7seWr{#r^kX+Q1uBmNPqkF`kf%cPrhGhD#?N5@{S8-z^*d+ zW9iqL0|a)MMha1_03v3R`8x97qO~~7r;n77m+oD92bo+IH|=VQYP0u519#~ykL&?E z$rT)g=Rp{LTL=xE@z?dW&+~;311QKeC8+Gv(p1LcNbNi@Y~q$5ltPQp%mJ}FzXwwV zoz-i;lvGPGtD)K(St}W!E=xLi*yM80dwZ%YXIK*5;PSHno_~N3H+(8+I z7SPWKwQb@YStFq^z^T@gJ$zJPq>?zl?fn**m)>h01QJ_B5COv`4=)^W4T=q7UUBhb zkSg>wv%@UB?WdgFK@x!u$z9wfUpncPGQX~*5;^8g@aD^y$_f)Ssfb}t9t8E{I!jHQ zMAn~gjncDwNeSL-_qeHWE5m-J#gl6OeM-ngTxm&o-aX#+(YGnjvJrc+4fzRnfJsEvM zS@R(^%?x*q`$SQlY|>ow2dSSKj0-JEQErdQvZ%hZ*dVtB8D#DeWBWLa$1S)lr}3t) zz2fFwtDG_3R8hYKfxEUk>0SFv{M$nwh+qTgF@h4xMd7$D@%!}qz3IwA$PkADS3#U2 zq+C@q?lW@KKmFj-R)!qHUL_y#5`Ig{!)WVNCo~h&9z{DM&>K2G(c=(3*@o9X%X5gQ z_}wah{qs;rc_M8Zcw?`tjXLSV@EAim)yy!YUDl;^Ika#)%@WcS(&lfZMJACFp|yOd znnbuAgA=I8DlIn;XW6Exw(=hW%pLlnZ=50D)dqwh#?h9&qDl9d_|v&XnvXI{(p0EG z0kvG!MX)XufkGDbgyf5=Y zV8^QHrm}D-&s%IKh~Y0yUb!t63{XW6^D&k3q*rejuYTd^q!|Mr#1T!l%fm5O6dka8@a|({?FtR7m-_5y?b>ne zk0QjSeuEx5+#%(UY7FiRB-1TU#06vM#rNyz^a=2*Ag}g=7~13K)EUMT^5}bW%V>gn zHSA`HXtC4TdDZhl#L9QeMgmK5>mS}C1HHoNn*QfBaxqo=lpJ%MZhe_}O-2Vww+#(O z%kA|SN$osHM+m-rs9D8^ia29^D=rZr_JC=FxXA^eT9jKi6=9CSOT|JnDfK2MaMpx0 zg8u#TFl6}w6r)=x@&-Ix>VP5nMrlkBkGnXIRG~Qf1FqH@b!IK()8~7b;nRV&sI}_| zf~o%d(TYpY+9~)c9>IT;IB)GG@sKF9h&O!Q!d20{yof2hRr9nKTajc&3sIQK6J~CZ zBDht_3w0R=n;oJjQ9c0cv%G9$(T!hJd8SmBaa%=LnP<$%q|yi{963cO`Kha>3i!)> z?CE{fx@*q` z0#i%e(WuZegEGri87ZR*W%)YHdp@_s>}9ez8lk}WW0hU#%vc{W^f;jS#BqPvD{Zj2 z0c}eW1zstE62WcoM_QdcsrfDXa~MAh)%I(sZa-cuAggv*T!!_xiiJT`&x5%t1=ZPG zV^2G7I+Rf8LrwcJAWVpkrP7OFFK_~by5V95EBE5&ZZ7>>^hQQFD$sT&A}UIKeX!jZ zU2`h?&aX$X&Kbn^8gOGjLw2ORuxrs4I%!9AdUw8svY^v>u>N*{{wRQ0mqX)XElnhM zoVZ=dIhK)Bh;HZN$I`1`==NVG=y=ufz-Kd12m?-IzMu*|Mx`1QjKC>RCi}PVn6x#x zXL!BTbXqxLrL&(PfF+`@XqrYm=;&7TgIw@JLv02|jQY3Xp+X6P{abN0^TSPqn;~xY zIs!+P7cADY%xBqP8vU%`MEXHxrO8Mj10h_!E!BGdbw~rn^*6i_HG)PR&Z@8v4s5P~ zg=Vms*kRfSNBra}Gy^MW8r!KDfYQHF7c5HlmYe<=+qCcFNCyG={U2nZCd>Eb7JqJ? zg+VAlMjT>1fTJ58*vGv6H$lG_Kbyq7qgnNzFgj~BgA>X-G-#R7DY0nd-txD*yi;^K zckf;pRwe#h+T@L31)}R9!Z$z3u`A4!AiYv5X&vw`+lA#!ngwc+(=15I1R9s01|W7ZFTA#ct>FpWe`9rU|&2ZQ5(k zGh~9%0S7vHqv75uzRHi7;|oai4&&xL9!W1kxJme*MG&E+(VtWLsrIK4`|rn(IIQG1 zZV_IN?X81fQ@4&c1n4LKoXRuwVcluHj?qKp0M#(32d(sAs($iIVgF6oN*dcW`(2#b zeMTVa%!u@1oa!B7&#mP3M9O!O#}$(PO;D>Pio^-g2?`7p zv~Y^%#Bs>6M1S-^MP_FiJRNHoah(sl>>4M*#2r;Ks98r8fB$soKy0%G^0h!06aMFj z#f+42|NM~{;zq1oGmU?#5=zwQ;L05u$(vXx;cXA~E5fwCj~VY_q5IPG)|k2#2Wbik z8|xniaj{?T6UZQWpI^8e9qYT}ZVNKjx6k-1?9w<;nd6Q453nc{7(pPHhBGh5TIFE; z>!39d3@Rpo+xW&}8VuFdKI>{5RZ{Ugc&p=99z+8Q8ZR)8+K%1*^u{9DGO8ng*Kx)? zRJ~DJI91gN<6Oqg>h-PZ3<}&>`T&drg&Sc5>yjRYl^#Y)NJ+^(uDV|!N$&4BX{k?GLjKMOFgD%Lczbs@K%Ldo)atpTD)S`e3@jQ}uK{o?-Mrmr3D7M-Ap#7)6YDNbT++R4vg!&$`Es^rinY&+O$&@U(}rgt2XG2= zgWXXm{aL5wK5Ff`9qkR2B;Be!x${1WI!Rd^8IieSr#%2-6Sl9zx=|itDtbZKOeCnc z8mQ0+v0)H;T_ERUS@8byR|_~+9B6P07^+rP}R9#;=d9wu8# zFYZY{0hB)fZq62W8r=N%2~cm=8$x$|FmPU!kQMI65KA8Hn!Ds%fAWM6cYVfQ4Gn(t z8(QT@?>--y3Wx$Nzw^AX?)6+-K#3E}u7I{a@Or-u2 z=e+U#Sb~M57gV`PoI~(!yU*G5`I!S z*biCWXQMt?5>Kx_6taCDtJ$@$v0Fl`&Avy5bIP2*uI92BcaEO$PXC#TGme2S8nM+% zcu{&8bJy$IEiRD+_J20t5uvO5%<9}W6Ma@g#(ysJP#6A%;^*W~M*7RUyRmo3Cw9F~ zWt|CN2orXhse0tk2+<1nt;Hza$TNDXqu1tdQKtCZcRie${U`IBx|gA52GnXDgY#1c zi+MeN>$$@O*yAm*vZS3;P5K9|!!miCqab|xQJ#N(*ePmP87hGaG^$_F^zGzj>NdQX zJedH!TQ4!Pe6Z_!Lbz3Iywu_sm)Si8YNosL_`hvVsrCmGafM$rc?({FQTe5REy@!w zpzQja^HF(f|ItPazI2}Nt^N9n89(;dmz=^ZLJs5-vZ~@$4A-j|L@V83bvxb5uSUr4 zb@T9=|DM3W&w$7-YfJ_%?YzxIX3rf+6pt|bQiNeE*fl2fQQJPg5=0Q^kEsZ)ZcAJn+l8cy>9+^({r1Pk9L4O&?;$I zJL}ArsD+CZaY}#e11A;X?=h5ocYi1B{P?aJI-(cb;z?g_zjA6%vPy3uBad_N9lTJsdM&e`Gvlw zNpIFRhT13jX;PV|AC7a0`r#ixdML6XFm{ThN1(a2J5Ogwj-TGK{)KbFCd*-UWyEE@ zX+sL)|4O3GhmLwl9ZE!pu_l5J?9qFP=@h=arzr0LFf9?Q+zVre`sFvmoU1m3cSlGY zSJ7iZv0D_A&yd&|C!mra6EuP`jFx9eu807$lU4x&u;e22bLHtDpU07N&x2&Cd{sXs zowyOZQ7A(@nWxqq{4paoqPa9QZWjNFNiH?CrYl?kf2Tle0<9rXr|&xpLfG8%$N&=w z?dJgZCA`;pWxHr95F4Pg92vVl3S9&za9Si$NO8yIRX#X}0ocoH!tli^qAZcX^o6_F zcUg{QOMb5!%nJ7!$ElGeDwAl%NSrYv%p-o6KM^cu(rWv%Y{1Gw6@>Tm9XKm9-%$_N z+Tjc&PcuG4B_GXIJ*=@i22h?lnucPLEI6e$bVzv-EKEbv-tqP#5L?K7=ONL?y2B~t zfgz){J6S5D*J|}OwYPvuv^EW2YkuHhoBHP^o)&D1_3-K6tXd@xIVFS(BlKxdSOXLL zDbtJ-c(HL)Ey|YEdztX(aY@@oH73`eByy31dp0D+F*Q4W8ZxeGnIHtimjs&@x%}-Fud^EvGY9 zelHwrg0!oB%~Y+F6!P<5D3Cf%vyU!@bUAoP_qyefl6oxXYYh~@PJc@S2TI&x4tI+` z@pJkx%9wNz-bn9F%`pHu%hAxziv?0O8WfpwhuZSb_}s0uMVp-Xd=_{{3~A#$>3%iz@r|E#-u3rh($|jBe3pD8vVMd~ zVl>n8q`sSO{`rpI3Rn;gcJmw4HWsU&$r$6?XAR!Q+vfUZVoT+@hR*IE$=0|5ZGVub z3LlALrTndOmXf%L`4*aR#mN@tYv=Ga4|MtzC@t%xAq2eq!ho1NjaAx(20GwSwantM z;QAAJSwb%{%>v;H^Z9OPaj%FWqVR*bCjJ6)L7EHmYY(exDK6$C&T``0_sxcMQo)Rz z<>Zmv71}VA_@3Gyox)%o8|u(J^}Rg#6MV`^4IGB&g>U?tJ%@aiW|$9^gJXeLESKp>7VfNgUjdJxoo*%ve#JEAt#KHXN3wHhG{0=7AoFBpmxyI;{ z?0ytZd{5LG@*`vB7XQJZ4qKX`3l+j~=5!hnE)_mo<;6mCoi*BE&>-zR9JY9Ia+U=% zqUiCXDp^-8Zq46zjAumhpHZ^I2N|!40W9P-^~)05R-?dNt;m6LM#&E6ve!IsuuQ-q z!BH?4jt!69DoqQgaZX__nZNv$w-~9KUq-`axMTCYCO|2bG}J{_87Fw~Zl2IW*$VEt zn>jJy_NngoKFc$;v@AFerzcVzc-VpO*wv6&iOW8z>^nv@WE=v@r~`ru31y?h~IGhGe?IjouOyQ<6Dd)M~6xEC_`*I`ssG5>2-A^TU)X(to|Gs ze^%1mrR#LFG+g!LwgzKs zZrW$_O=O`?Lr)xkhP`$oAb*W59yT^FbjB1I*qF97&QKoZzyJU#YOSPBbw_&~Z`q7* zOZHD!)L6Obthld>c@k3Iq>^urp7ta9_vXC{b_>+W&v^N%)cbAvfJQ3&Aq`e#6Q^t0 zwPl%EME{xxm|cD_Y6{{#CuP#lJun)Bpf36WZ*ilj+_SlF8u4AnV2l) zMBeyABivMjq{ULxuS>27$wWv*4`4pfdpn)mJQ!hWKyfRM<^N2f6MO1fr@3e<-1PEyvXJ zSaC%i%hJ=WYOE4rBA)3o-yZR{Q45y`H|t>FKJKE|sx z18>K};b%fIS6oT58yY`Qrf&p_W&{yGzSP9U>ga|QO0vb{bMs~y6YSZM6oq-{{zk@( z?MgZ^8@nfvDmOgjkpn^D3dWmi zC+Lm2r0S7u*Tt^E&`!!-G6Jov^_adTy|WB8}P`FJGOJ zN2TI`uOIHCU%rVC**Q|Vvm=U3Km0?xR3tzcGCj!V2}1a9GA)YG(}=A+dse7!55h># z+c7z|Wa5!c$zX4-tL8}=M0TV%g05|bG+R8r{F~kT!3z`$YGo(nj|y$o(eilQZeBuV zM&Wiepa}7<4y$mmSsLczSc>1je-hT`Z4RvuBEM<8TaY(yk5?7J$>?Q_htQ!&Cs<-_CKGb^ zrJBpMDL+!GPQyQaMuaAmCACK)cTQxl1T!U(V(HO|pVlB7@02};O6YkU1us2^$#Z>- zDY&KO7=r#xH`*y!UqVLqqv>meM|JRM)viBlo-3ye7sPUXE;8X|O$W{6vFjs5mF_uSNdF<#TXY$`sQEv$Yawr6KM zJ54Q*j!9AX^q9*Ov|XP2_Sy%GhzXa~Eg7P}tzz+hfVM#wmMd2ic^YHWRr0V&E+5iS zeR7~}j)pCiY%8m1?NQ@fmVEL~M7Q3kl`J1ds+8t@Wcu$bdXouhKi+%$o!?Iqa?pM@ zi>`rYw`Y(Z^ndGsZsX%eus?#oM3I;rt0gi9r9vP}GX-MaTTCf-8@BFANz>ySc@fZ9 z{2MNO$P^)BCqp-71rHgX(l6Ce>$na)!W4=v%QF7@FC(_QX-qY(bCrl0NY0kkGd>vt zCBnGe@IgA&z|Z=MxRReJZC56$ZG1hMYDcey*P|Qz#jUV3a;|k1p~3V~{l^X0H+Einp8PdcGoGUHsNAfVE#T`&Qc(mJ^H%}^Bc}%9{RH=QNX+9Kr z5D##Uy%nsDpfl_0rv;IV)aFcBi)Xcg<$VId;dJ!yA$*Z4Ig=p@oWYaI=aKeiv{jTn zD5C~-MzCB2j>~LAlf&iXUodoc`;TbdBEQ-ftn~|kUD#BD_OtvT#AIPN zp~U6q!j-2HBP5j6qUgpgmyzM@3|(jy^n%4^@!x#P?mBR5Kd}669o7VU-=tPhhtiG7 zjqU~0861Yuh9}ZLU1%VLK(b$Zs?nzq#o1L$=Uk>S@t8`SqY0FF9KDZU-Y(m@Mmro9 z;h2P>BGq1guPUKGGng}Y3&r_=n_DD=R$%y>o`#S4ztbc9mFLQy|IcTQYXCo_@p=c@1f}H69uq{YW#D9?ee671{8Zj$jkZqaAs~{3X0_UJBaZ86W0krRO(kj^ zW`p&Ud7eG+V=j8>R&&5`1$_fXm6 zM(Oa+YIRPHa|2&TWLp=6$3aIaz0)V}e|X8A-A*j?X-5gh)c>iW@VF@_NC7)Zf&+Cc z5{Z!&WD>WMq<2>{9sDOQ?-zG}Uy`s%o- zzUTdWcbA5xBm@Mcky^SNkw)oe1tcVulyV6P5mZn>T9EEW@**W&iZqKzrxGIh+xPeL zyZ`RK&bc%5oSC`j%$eu@RB8+@y4Hfr$ufs?T_K?S>k}e5zeo;6Z!G_J>L*ev|D}XK zXd$`+d;D6q-(@sj8ju#kM)4$gOkU5zUH)EGj_S+SVxRmY$=Mcs7g4kJpQNpY$l5>n zg~=(%z09n}3`&>Ve)SYN7HrjVIK`lubpLTl=zE`QnOBX4Z`{jgvhChMtBposNCG&k!o#yv2 zR3bw&u`JOuspuOMTMr+YHw@Y5&LrZ4)DbK)qKTVxtl+ufQ-7Eakxi=YrSO3Jh!4yuP-_+@N& zX81;V%Jo5zWhUwEWo8TLc;k5*XBhmmkSk$j+r``4L>c^MlB(2HI8j=CVF^Z5k6FZ4 zgk)|_Zp`_52f8bJQ?{7IrwgTBS^pSgq^e)Z zZlkxO;zTk-1$aW?Wq7Dj7T*2$)MtSpcxWD>`1mvx_@B$ZxtGg5R(-SX$@a+4KF>KN z*z?AhRivK2O!$k#AI?3(TQ%H9UZ=(w`&h&wKm8;wmF4`1nZ(7Wrq9(}f^%(BE38rm zUFfCq9Ynic!@q0;+NDu>6{=&3{J*sO|3AdxYPASpBmSFIN2D#U{3;hnGFb{LSdCtc z+i~=!H)X%wInSe1i3-!bb@1TMGM^#&Jhm+VT~xG2z2nApwZHhV`-+yA^*%Y`MR&gF zA;mU5KcAq@;Q;4$vxe}LIFahVvX}X_Y;!%?mxLHr&<;qvDyq-e%==NG@hD$?^yui< z$sMJ?oCu%O1E)8?CTC%0nZjwx8=m&^W6hB^v+f=V0%!y*EWi#HdI+OALsyI0yxfyb z(wnxDZk@Pm3rY*AHaX9C<{89`(xSzqDC|Jfg7@-5YAbl|3C-0Eg)dbrH zH!v*v?6Bb*irD((eI+PUVy7VNUim#?39*86K~zR9;tgUOA(d#Eygj=wsx;>0I*Z4Z zT+b4&{qEGIz_xD4lFsk3wQ8zU9N6t5%~q${Io~o7a+q~M+wo544NK(+)c5uH?P^{o z>l)MaX8Ar{4MGI$H#Z^LnPSt^Q$Lu4x5V@2&$eRhBk)*FRe^uirzRM^V~V~VnRMLR zL}^-Zd_G7xzzPcawN*4!Ng!RXR_u5pyIM^@)d#zR8H=#O_!xpSRsSeLLwPC`EKEsG z59k=$f51TGE&>xszENM;nSXEL@s~%~l(TQ2gr>1Y+UF~LdIzI&znNIrD3iW_6q5v zZV^v4Le^PkHOh`1U5lFfUoOU6OI*9GQ=vGDINwVe`}Ncl>4J;dEAj2~K1#Hq35`P~(@ z(k~EITVj&LX1;YHB;Ef zp2d1;npItnsO^%21~LhF=O53zU(6=7yTf-K>`MRX7e7+#qMQ(c z=~CFx1N*ebIvMKpe#VfXU4>DlVwr}rveK_BcZopdgqvh%<%_|ljv z>NLO1JKc^|R$q{omfs=pF?9?f!2=7zq3S4 zO%J{q1nlmzUu1E^N5|>MPU>V~O(jS3B!PZ4m6emcx6sGHTwKpA6X}Urm^u#1g|v`R zBaBQu3`cZN^pq!tT`E7RlU<`w+YDA4k|%S_v7__K9&6kWpDwkN9{oG`1oxFGS+lGNKJjLT}PS*@eECbOPtv z;;U1bkIa(|X27d&kG=A&Go4z<*I&-7=*#kBj)@Bn&QI|bHU9&g z6nK%?p%KPV_gk5daf*`>{YGeBKkAMWs3V&5poF99M*A$~g7e5YgB0bnrwx{#{&Q&Y zv)p-i;ObG}rn|U7o!FHKY!P12aCdg z8_JmS#JoaMRcB+ailOAst**a0_lFpkOCMFXGZfa!4wl{sdUhL8`ur|Ox;0VEvcZHW z@>}-yIcwcj-$!D{E3@P9c=F+0z*Gw+go$->CQ)TD{QWGXukCi}-)Y!?mgTRh++(rW<1D_uXS}BnhFzIVuzip|Yu{iYdHSO@rB41Kk#BjExMGW3u zfpCpg2&@%BDSf%h;vdf+KVykB@ssjR@fVM99Xor{@j^s?nPdBDOMkS4Y%cKMWIy;Z zA77BVGy7z{E<%Xz-4zW_9E&t$X01%L=t-Xq`&uIqEaj!($8WY&AvL%Ai_qZnLWS#} z^5-`KBBhTPmbOrxy8qH25bsLags0PmfK0qfrMgu4D}vE-V;azZmMI~UN+gh{Y7f~E z;J_Ta9faS%4@)W_nWMBHZhNfwAW-tkBvp;==?6T4$GUQl-dA&B8?G{Th?=l2Pq3Jp z>ouAjc9>aVaK#5>2LidV|6#vB?N92RF*J1mzVqNT2i386RWj&WXPauGs;F~f$%)s# zU(qAI{BB}A+1a~P{PzIk$l>%xWhLejf?k_EYL8E4Ie41|TI=bFg!xQxILM4!{r@#Z z2MJ~3oQw0|Mt5pVp;^<#A#Dz?e6Q-q^2ibrog0%C&N7ekmm49fmN zmzsBM`1>lsiq#4hVSG0>wg0o?4?XBUbDiZejnmu$SN0g5o+zu>=O#it^RbTiDcZ*E z*T0FRLXfbjwOtDbY9yt6cZV*vx2L`jS|9w4-0;x+snY$Y`+sgaiDvalJ*JbvXRUlu z!2VF9opRQe(Ff_|T}LG)ZRDl;@7WEnnxB7I`pOP{PguEjlw2J8e&*WV%QntqgiLx1 z-wWfn3b6c6iu|9;7s|qXlyh#0OiM`Uu_eMn63Uk*S3c3jBf2ajc6B)ae? zJ-vH@hj;(@#L_v_} zA6JrR6v~nPY>1mK!7gEal&TvM^LNnrt*nA}I5}hbh_RCQyc{)DpS+_oeX$(pQeY>Z zpcXA)mVoeB(8wTeNQ|Qr5!M9O$#0`Q{^ovs%gXK3g=LV@JLtTn;ZD?S4E^tw6yIU4 zVF91=-tu+PDMr(71wPt1=RKH{6(Th%Upf~y`**z$56)~WZJALBNMAo@mzGVL4|7uZIS=V* zE*l`CG1dRe1Gunxr(E)yU3pM0JNh@KK2m!y{4Q>nt_32H;TjZHhgLT_=3Hz29Mf|c zVDe*xpzWJ;kK-y=zLh+m7M^)plt~UHA>t=*(GCw0{lHIWQ#N1DjbLa%txats?PKUS z{z5o^h5bco+K7p8!`jL-!2;@oRcE|bZeHDDrrCO$eSV`G9zhVvK&c7BR$oL(R@^zM zOZXnS*nbF%02C5E4S3>KJPgR`oino<7=8ys;g7V&7HBwFestIx`y0BM8Gx^u)gDI{ za-bLeBk1ZThHzt2UdqutjQH>Vl4@1R+=pt@Dw{_tlg0)NJn9x{xg#{-%ghYxB|c)Y zQR|v}K16r0olAY8rgPD;PslgsMRxW#QW_0K_h^dNd5_VSu^8SNi=yTIkQm8H6i^4t zDn&W>r+HAG`YXL}kVosz|7uvj!@e>%#U?$M>Y(pTIdSiTV;Q{q+HtjbQR>P3%=ns* zi7dWV4h-hsXZjU!^(o?(F4a_3gTv*m6SWVO$?W`QpY8>jJWSPL!#-^#u~2vCUGpb2 z>v@Pr6fo7l_@Q+3Ut|Pq@WagrfF=ZRV+>!p*iGi*FOGzJ*pcDpL?47S8(VC!?%~syKPO>g_!MJ zEKN>%B~3G1lw!S0e$n8+u6EFrU^ayy*_5&7mkpE`Kc!^Kl z;gc{ayjFZZtXEP&x-M6tGEL!A6fceyCLAOq1`5|Pes*bHD070@*31n+^OYjkPXJB) zg^=FsMmMcc<9@87-iLy!(1FJ4!gm4tkAT$hk|n=3Z6rGFCbep0Lswy{2)O zaC^@{*9VO6sE`2ZB{kmcPg=#s=NxDmi+i^nYkhm>%v)021kD1NIlJ>OK$OK&K}r)m^~(*xCvz=?e_qPNQ|mfb zZ&F}{<6*lreWxMb&#v}q&KxZD9}E?d!OrA`21Hp&kAyavpoAd0lb4sU zRH^n+6sUv3&4%k19H5qNPvKe!i*`xmKv6^yJYt@@lxdJ1(-|kEULqOv(y zPd+@cf1UhTRNf-|+%x9mkvS1o7)bRYM!$3-JS0WKjE!tg<4COoNff&l3C{~R37`ax z7jl`>7s;$CiWD2w!tm6hm)=P-f#&&?oO;j965(wFB8JGiIUanYTV9D%wGqQW=*qcu z`8PX-Q(#YtHzTKp@RS&RE6rIJNQ#4-bqvF8Czv4;bh5bPK3jQGuq8NsocWa%eC2(g zert0Q|DfoWvoFJxwrKoUb+mM85z|M$e)Zz020&g2KT}3IMHsClXq0@*q>nrf`41IU z7uHF)Z2K}Q?K+jl3*p>Jc_p9=jzoOPo-S+ls>4Ga;-O#8s>;Js>(x?C0Ym-U=OD++e}0hOj5|wa!=bx;$4fz`#i$zUv|t1_7B(* zOk!G52}QxjICh}GaL@ZRa=TC+?ak;k>q0ni%bFmi_Ycimtt(%?|kzlK4v>`uykjvTXOyQ z>FAPgM$Rc_TB*4$gB`w|kQ;*s#zky=BidF6ypEJ{2l^CWOzxoXlMmDl5UhJp8d+Br z%tzITV_f(E)rlPQKEM%ktIQHl2c1wLg!fW+@$UZe(7(260DNVwGe7yEYk0>Q&{0RC z4H=Se$7{&0=7c6?8*rDsH%c`U%Wi%zun^K}K|>vM$QZ^WCFsN~tH=LFlw1H=tI;lR z)*oN_^3OU$zvc3;_r&z#k#9Qg-Y3HHVS)fuj*{;lq5B(3Wevw;f@3f?HfJv_pti#R)QCwA5dJ-JO7)&L{qADaLo1h& zn;>N$qxS05j~R;2#Q2J7T@Sd%C) z_fMsn0M(+HS}*%yK#ME^zNBPtT*;Vhx1$Oa+aX^V6J7 z8i)&+YzK5?;i!h>NF*cVfnZ|A%mBcvjx^dO-7OMaE#G|CBj|Mx?l3C7M2yW$v8+gK zPqktF%upeQO)Oj@@8u!-Kt%hyeH7`5H&kcO8gSk6wZ9_oi}tdWH{L}~>Zc7Vcqq$I z3E?ye=0E7904Nu^MG$j4)%QsbO`P(M+%Z1-J71V*ZxjLg!tQ6g`yuS$^kiZ>H7Z|= zeS#_8;M3BJSkh}+ABUM!={Mkz&LqhS&xnokz$C}>L-N;uqCH>qA%JyW2Uq4k7I^fH zvcQs+%j``Z!>U#wwE?WMUX}*wUHT0s@zr%Zo%I2(69ywwn87p)uJb|c8r$#NSe#n_ zkT`>A30@$H7chGt)syH=IU!FEF`Bn0>+P{*BwX-FgkJHxj#)ZpEK;aFQ=#?wqmmVp z{{dx2|CQ`=ICJD_iu0$Z!%{2N2aVM%*H+2`~e3LI$wgp6~! zY_JC93REAx>|O7T^};I~={hqT+~SN=BO5rc#+yXa0x5V}v(8nRB_8BZ1Zy{25nX@M z+SPTsn^IScW0u^;9Sn2LjPzIvL6t6@FFx8(TvS+Lf*ms_GlmcOBG88MQpya47>9BN z5Ldu{-Z-pOOaul{A?rBFNGRbZ@20B+vgP@wD>W0?uZmfI?HS?U3jWscA**wlYf#xe z__Z3bGTkKox9$YL^Ij$n9*j20wVdfQ>d}#~6Bv4y1XC<4AU4WH0q~6w-~^hZGT~4MK%Zz%0U(?UT^U`exIZb#6=> zkXj#xqnIzlHEW=1t zug!P1lvtKTTZ7tLG#%5!#Q|WB9lNU6AHC|XLQ%3P{52v z#9_uEg_scr{xqknjv?3TTG5wmf(D`hCdc7Tcej$b0a+7G#t#qYX=DkiM#ghiK-3d+ zo%vmxLcovcq0ffWYiei!cecNpIT6FG`UX2_CTg$MU&Xen<>#x2SH1GEKI45C;@Mr| zArRj1aVYcmfWMwkxt8Oy5;*{^$%p$8p@a5>dsqv#fpfN;P{|`WdfP*LhdOv8oRl0o z=y4-JZ>_ir1Au;SSc4H8%?pj~O4JYWS7_3>(6fN^ZMVv&pON%C&_5myBc#c8-dB-Q-G>Owt~-yu=(~L3p6qERyaOya z6bM7T$TqkKn6&D*P@sC`L!SZOl}rQ}Ivi;ME=dG2+`p7cIlbhmi}l#GsQAJj#u`1H zasNQwbA~u5O{K+i>Bh@M1mDTBS>iD9zamD{V=VE4;)5CpVrB4v79MgAHeBY}{G4u= zdy*PM6fDfUH8&-U`P|rS#2}VVg^7Q!VfA?b0ZAc|2&Dz1`l^>Hu2w1M9+1LfuFq-} z4!Y4n&r7u$B|7mnyRm>H-K;4Wh=vt6 zXzu&9EZA?|g>i>3TmDjt4v`rvES1f68xKBARz_5bBSgz)F!$+GUPL*vpy_f2vc-D^-$*Bp?b+ z<&~Spnt$};8rN@+2BHH{s`mKo%Ki7jA$(FaY3>|s`pWVt%q!cE`9m_iT(gVnp`k8U zofdYK^yl@{1ks=e(qnzsq5d7AGCo_%+3dCd2pup)Hc<(`0h8Jgd}N&@FzEpd3Bs^( z?{16tyd0borvzF;gw6?2H$^bTm5ST*w>DnLkZBhMkab#r+@+E-&EC(Si6nOG7*zB) z|K@Vrp!>B`4Lntu3*-Y@vt5Xj6#>zqQtWv~b_L}guvbZw|I@`D-z%;%_x$fuHlSf~ zh|27*$>Tq7Dv)&qL_^gQ{|aKR5(aC!lpp^dhOdpiA$)V% zhCaR=`;9b<+1m|t;mslGY?oyM*6%j%Ag^*f5DvH-lE9T5+Tu7 zX179;Lrq}0pp>A_jufAE>Rd_&3bYixwE#!77tY%#|GKS+PjQ!!L22tqMNtI*@evEGUjyf3hkQPl;_LO?ubhy~4JLk z;To}EH}4s3563?f8}peIOBHgbnmdEVhMvi@>~9idEy|~9p`TwlZ<0b^I1!~nk|Cg( z>#l1E3!J3>Gn;e&+)aE)ZQtQ>pfV!?O5)^m8U>U@P^AWIgn4=2GO;VPQsO-}!Iz-X z>orwr6?ny*?VXGt&5$PZglGuaw=}CH;p^LuM-b@B=Of75mqRjHH7iWID8e>o2zp5t zf5(Hiw1fQt@4mP*0@RdZelPfH_6QwM2{rLyzE|e2bqUG$A82Bw)pPKurv2|2j}hNB zqtbS+Ad~w3kzYNi)`@7&9}goxo5-QH=^@m49P*^cBt`BtgEL&8O0>*}wdxajY!MMQ zp7E*ZyX`&{zZ$Mk#cQEqfgbZ<3E(0IdI!F35K{Z@|JqF;rMY5|KG-6-v|gg?%n#0n;y!Myh};ej2m z{eQ-YV7$G)!p1i*$?vJSEqS9Qe;?x^gW-RKNTK0N!<_%h-&(vHOGo0L_9xd{am7S1orRY>)J7y6s1tx6hs3j*-%y)Vs=4I z`F`dU&sU%lV5Wk01wIS|sXVY$QhannVD1Ze)9*_iN(e?ElKVtJoH?|VTG|W|NJ~<( zU=;W(sy}0nTXKjaONFyeK#*&sfc4XqfsVfn3L;hM*mMyF5{l0U;;OAWOfKL4fI-D&h?=CGLE_Wy8wW(a#T_ccOxB9P z>rV~}XEb;_DOu6rwDx7CGqp%ODvs*M1mLs${?fmR7+njf;{#UNuiRt4q~W6O8Ri}3 zH*$>lv9qk>8)10UW~&}K^rcqdJI{S|CgPl~P0K}+I!1k6@fUJTOk10MH~ zG71Q30E~c_@0pYA!C{Lw0>-TnsW`B{cwJn!?-C2?tj9Fa4_hr18v+up%P z9%oMuV=mLDm3{@@s8JQ@K9mchckN)0;y?R`b!Rdq^QMG2TT?Cyg6zMG89 zQ1X_D9W7+iIK5zmbE_d2_6XF2%ZBAB?*c!8Vk^yQ4M*q=kTv?!f`l}k9BLNYDtJee zGu~W^2xJbiP}tSVn8trB4m?-~BuJbnE;H%sei2&pN1Rfp#4+*;xzyKO33bdMOU?iyeqi#tJnfVHI@?lH?f4nMjG0ZqIHWakF1CDIR?-})q z$eqcJ*SM8zQ=WCyT;^pi-D&_QISxRM$d1~JJr=J(Lq9%gr|R2L9K;FlHv$ujhHq~t zyEYQd+zC*kGnqjNvTi)KNCcQgG2>{!zzR+{<4AidqTB$|QuQFC9 z?}}42U}Yn&1E>E>iZvPRuL6426-Q_wcEIaU+HiI#ffjPO0@NoYnEqB~h-ZIy<6Y=8 z3>TAq@THPQCa$cIsomyf`aSv!aL+#IiTWIzn%A6 zm|h|dh_P>hR8j#SNBRMmAlDx`?R%DKWq?nfK>%oo8< z2Xal*UX-hQ_pH5U`NtdnATvw1CHdt{huot~9T66hVg8eRJ%pP%uHU|A%a8a!!y(xn z^*@UdoyXF_8kWirLb)m%&r6A$@Gvhz$5nvr zuymSHTa!MkJAP5}ots_uKRI96>OG1=$yS((0)mOqU9w~)K&TWkNP*Fw^ScG)HNsFH zZ3Wn6;MH(w1~t6ubVzS1Ms@i&@sGqWvEy>qZG_klE({+Liw8+zman*Oklg!y`jN5M zPzG?xeho(=$KE9}Mj4U1ctJ|&_Pk=B^RZ)!8cOH`BJ@sR9-j9tS}qJ3n7Y*9j{}~S zj4qs>FPn9I5|^M^Fk`k^Bo%>`M({vM6J3MriBSvTVV?WoACw0Gp8fkv>cQUvfSkH6oF z0Job2D3fQcU+Tq#fl>G2vJ@!Gu)*5s$(O|WP)ay`kqJY5!=@Bgo>13``1H-uwqyAh zKi^=3*MOh@{&R)Ns5}0Lu180$u32BIq(C=9=%QhP6ca0fss7Vez1Tb9=`DHnXDn%&=M;b>p`#@(g)+(a2y4y9+{1(MdCu5OMm<6u`_uq(ciwham*#r8dMqVf0j=E@Udi zybiTzJSZfN6E);#a5?eFnH0U;G*q4sI_Yh+!`tzvf;P=w%I&q6 zqL&Ys_1UKE0bH{}Vq5@UXwvGB2_EoOaw3dY3;QL$E98{B6WJ5L?V(}~Yq101eNM0U z*`At_&Mxa#m<3KR#|F{TJ)C*?cVd0?{R*8CT0kF2hoKtXC1GeWLQL%9&l=b?55|&Y z;Wt2ka}@LkQCq?7Cg8j>jLz4r<*$&?=(C7@?W13hsitZEq^QU1yEO}uV`Tws(1`q5 zyT+ONQ1G7$Za~p!hdbSMFqs?E2S;=K`PDU>L)m$&ekm)j7)-4Ty`q5%z*l@|gCNSy z`fm)7Do0of0{s>-!k26%=_5MB*lwkK^K&3Q^*LIZy-Yyy!5bWJ$n(#Yl+BxYyYuf? z3<67b@Rj!#@0beJLMa9|2q%m8||B+cy2si#%sHvlFl za~AAlZ5r4wl3OpAC`2~;r7%m?Sdp0seA|jIGs_p;^7v>1^>P>AWOo~IeHH7k+(eAc z0!bTpEdbi)2}bn0PZM>Qun1G&FNj_h73KvjcV9`}kf_}S=bw|N@e@NZA}jaVen+^g zABQ+V|H)ljfx!|VeI>*UuZLeLW%BHY90G#)?1$0&Stg)dD3GK8y1A5*I}-!y>>z3? za9Rg^WdWN`W5tZ;vW>A3?If9Yl7@Gv<^ct3qkolV@C(zJs{AW}Q|i=iFBZ=gsl%^S zde&QZ;l|`x#WrIgod9L^s2NNp1<<#QhRC6Uym!`MnH9ezDXx^K?s_$h=ZLqkdQQ}WXePGTYe;`B1HkL)51{{#@ z<=}7t$8>TQ6=EL9W1a{BQ!eIrk4pzMz*o4>cM#2ajr>LhX*?D11yOs?ZkZEfa9>+% zZAo3v_nMpRh{|)??1S%mEuz(URPAL_DH@nV5LctcOe632$P_=_rXs=$>Y42o&_adc z@Oe>8EC}TN2B*`AFq)pgR4`H`5NMS7u-opgwqn7+f*Jo}0ND`@nUax&R}Dzs#t>C! z29V$NG;q7s_xr`*Mj(`$$QQe~Ck>FC$G7Qq(QhT#7=_hK(K$~7>b<}#0-!3vOqCC_ zgxlDh0MxsH)Yh9AI&MslIa*Id;YP;!$Ms0ghTNk{Zb=q`op*i6(C8PV{tt5FJtrCy z86DrI&;EPyea_SRRn=o)=OxnR11vxdXu!v-qUGzwZ9i}T9<_V9<^a8`$KROV`fqqp z8wI5R1(aOmxn7Ti!k96PQNmWX#To^Pan3tJcMq@La0ZzdC!5MSJa@)=rbwWt2rfQw zCUy|2U5bc8*G~JSflNK`r4l+o+Q5m7ygol$N(KyX81hU&rI5WEv9LXw9PR8 zu4W+$17dgY*h7&e<9iP$CNUA0haDwWt5i@Y3h?XXQ7zb1g{9h8s{jqBZ1kiMi2Gp( zkPG}eV^1_c(6vQ^b-IN~e|(xptW!X4cYxZvFf-1u zbiIu%O|w#CsxTm;6W$QANdPx$yIjvQxfD=O~Dgyz;4%kQmJE z>2U%v+K(JsJ^+vcv<$GS`bpZ`*%t&T0$A#8a3~7yC52_H;UKTGfJx3b)W8l(ABk@) zJp=^3(oDHuN|dwT)l3@NC8odl#$|SGSw7&U@kHt!!|Bh6tJ=`h@~uE^8VGy#hT`!k zG1O@fn|`IF2lT?HYlx;u;rvsB7(yk<|BZ-2Y7i4*d4IcbEe_pNY>E_7a%vE&*&M~B8*-% zwP}~RF;%+_*vX1rNx3}e33%*0aQ|P9tLaG!unOfT89M@ zb}d;|>&b$*oVQGPBph`Qlwt++kyzX|r6nnj?@XQ4kuY=)m$0T2LUA;Z7Ey-!HebR> zK1z$B=V!_Sa_+-{^sudUVQ!5__p#3mOH7*yO_li|@V3fTv2sQ7p_5?PD@y zIuX5@7N-_vEi-`I^OI= zK)vFGln4t^V*c>}y+WGaKouB9%J|BM96N&NHnH0atNM;^22rZ;>CN$H+{leSf~pCk z1u0Vge51^lFI3!v_G&3I35UiFrV={dW?r?eh4{;&db2q&yCA9gcV-qS*akoz2R=dr zuI(~S9)|?bL1%ZH`@EgtCdkBQv-lA200xkHsr*2kt^CZm9Av9%Uhp`Sv#k`mz3}jM z@Rthv4Di4Qv3B0x_uqC?>cDd2GXx# zY?^>5agu15RKN{@Q7%D)UI&3rV0-Belu8QUhCvM;&$)pH2A%o2UIB?(W-wLg7KEcO z_!_y_z!e;C+Qy&EjbFHTlZo@iiSC5Y<@c4f8^otch$-F=@oV6 z6$keP?NPmH$1c4W2{aJM*8c^sN^mriky=fqD^d-X8s>Cx0Ic123hM*bQb*_EX1n!d zoz256Km-Bx--dX6?CqK=dTxM^(<`wqBF7U62LJp#q<^Q0AUtp6hw(*;efxX)Mtpzp zBI6C5VK>6@H4?4rc;`OZKYT0(PF0Q%uR5Xn%L)>BNr4z~LHMdk7Y*hn5(~L=H#zInB_Mz`pOP|g+w@mNGyhB zL&TH?goZSP=IwO}u@tAVEyo|8KtWx%D-+k+=}&EL!RTdhxQ@3R;uOHB9!iQP0ybJN zLLM=j$WqT%!vuE+sXDpaf)ZPvliVCMi!tU8T!`im)s01))BJSS*j##Fn4$^r$-4{@ zLuKR`_yMUO9POxKhNmgJ4-6SOqh~+ff1Sl??d1KMXj|rg%H!yb9Nz`wFeMrYy$_m`aTy)7voN^4VX69wWG$ z?t8tqZ!fV77_h0){*m`IZ+!X@kE>D=(4M(=+o66+_rwNp3;~nV_bkgCZ0H!qi2Xd_&VBTx{GSazP_EC$7N&JkcXK9YWfwNumW3w6O z7xIul3eP_;z^p9v-t};g3eZdbV2TND6%xwyn67*lu5zP6p`@y9$Niqv+!x- zpT<3m&nC!^H1})jeb+cZx)F(}TF?ok2N(_9lqj=VTCZ#V3T}9@g9F-Q6Rjd!xNdGee!znp?M*zoNO*l z*2XWZm1n?(MDCpb#NbokYc(pUYL&kmOdY0%mf6ASHB5mlz%It_Q13{a&XEH2BDo&7 z6n4P+s{!sZ~P7eJY ztQvcVD}B`%+q{7Vn2tac<4tHt#b(*JX9Ga;PpL=qabFCES$RJO>@_~1V}<-l*Kk1FbBU=lfP#j?moV6 zNINrM@=yDw8N|t@h9hj`#;8tLMh9rf16~*!$U{FC=I_JWw|N9OR*ZOm1c#~sx(+BS5gC z@QWFTPyg`HQPvEZIHzvn$btE%2K4@y4dUE6l_B}p1E812;x?`)9O-;NBW}}OHT@kO zZ17yuEDbZ9gdil-f2KxmweuDR2UNm zzbRwO6Vs6iMnB4-sC@t!mDjKhp6be_`SjsiEq)=@w4=l1S+NGiwy_k?8dehQ^&xj_~-S?NJ?t|FF&cknkw zJ^PdNvz$_Hsd|<&OI8~Fx84I7E_QZy#-t80owP2%vz6vgvJbzREZsW&4wXl^ky_NP$uhQ`j z4ov^ouV3%?YMg~f-_cbr9xJrJ_vo9^p7C&`<0s5R0m9gh|K3p$)S0Ez!8+<{JurS+ zrp?(Rf8!_C!`{?&Dkmpr&4P~5X75SCQ;J-tfBQnU6B=k|9= zVDPU=r{KT3(VEv>m~2JgE2saNn4Pf)ciG?T+a@yDZf-4c;b_m)ysWv`JF_h0bFE>n zpQyR)l}#*$xTSTBCw^ZaB+IPUlEhb5dh4aA!L2z$dc_Mhwy zdFGL~4Wu5eeYPVHZQ^p7t(A3yikd&)s6Aty8Ek$>ng-r88> z59TRJyT*kreQV=UJc9`-9fvbM5}E{j*xw{P;u!E$-IRdC%Sdr(j0{`CHbNWMGj3vN zLN0C`y|S4A*nID3xvnBc1MR|LN%BOkuG57`?2)6Nq%{++o%&WuBU9{SI={;S{6CUU z05YhbFbRGJFY{DrO%fG>3`JX0|;a-@oDe+w;7Cy07d(-Pe7+-j>0!>vQMxU($%13{(Vza{7`AxH9{D??y4b+kHmVRz69KE_|Lm z8{&4M!Bv}%G(0foNBCGQHyl@3jl6>I0Lr7oh`+}*zgvAIo@epv`P9@QREsP>Y=^{& zI@pCo)tza`VDPR~;)MUf zT@oi+_iYp`^=5aFo6Jb`PVqJj@I{e}zSrI(FU&>BMj}i}AAf1FZJMw54KU96s#<^# z-JB;_3P$?UK4pDU_*Mb4K;2;ty6cYWY6lC@Q74OtS8JZOL=~|{uM_53<%0(cd{)ge z7ctOoU0?8s&eAs{_~i@A=zhfh#T%AEw9`)UzPI|H%*_lID_rImM!k%)l+cl_Ot|)N z#?#kvSa%E+eW!6C%6uEeb)@RiRqEtBV})R79%t|8pr3KY^-0ZC9feR?E{Z!Ej1b5NYSfvRPK%Y8V2-&Aq(yZ-#?eJDX(gybXLpCJ- zibRHioi}zp_ZAKtRbSlo_2KVZebYJBnUS*AvN%3{vMwt}mQ`}bEgA4-U+PdVtfCza zXw)xz%M-2}WeoE72(S3>+;%Iu^4Nt^LEZ$F}v6HJi!T{^-pgCo0i}Ya1_k@AG>M(x%ey{>rJ%X0f7Q7Y7 zQ50$)rmHAtuHGz*Cc-u=thmcJ7PGOwa6&#sLB(?pA5r}fOE2y(*@7Yb`LnV#A(=>- zco=6&nn@=-tt-!eVVkuAa;8_Kdix_zZ~VAC>aD!A!-9mp;}?LUl^0Dz)c##xeukIB zN-HU&69U}qrBTd^0szf{YpW*gUg*A0Gk9yDG$1-Fb#gkliSb@YoXo0V{g|9i5ZNWe z47ZO22$%EISr@HV=(d6an%_+koe-X58?+2K+@-vW#|HXHYnYJ*3s`r({7u%Sdb?Ew zFYUDV66ZLX?|_n6So<5CPV;{7>*SXH)IT=;%(PHWCB6%>x_+GX=UU;zrnq_07>Q2| zp6H#TZN9+*O0Y1qHw`AKG4`X6Qq9r*&4sl@Y8qF^`a*91&|s{se{(gdlM&)`RuOD7 zrOzbpnwDN0wE?24LE z29CrWcXWuE2vn!czZ@1@ye^+i<(Wy zH3`8lMs1VQjYIF*V}iI}9d2ulVdtM7$Tq$XrJz47U%T!UDpI}}s8xcWj&P~fqdDN+ zIc0l=jPs-3UVb&jZ;-3f5JrMfsPuK4kUc$*1*x#swQ|)SOXBJ}&S4%=+tp?mMin)D z^L|}c=XEOT6XYxm%xE>%!xWE&6QXkY3#9Tc+oXBu>-x*4VBZ?^Z@Mfm#DxbCgwbZW zuN1CcYfIO2fFRZIo}HkG};k+2qq3!KRewm zYgOsNwqf;=Ygtf_v`_Mf>CLR&TA$|VnC+>!+0t4T>3mMmAQNlTty#W+((Y;jTLbfq9r*y!_1ugv)nD^=Y26 zg2)y|1Kpqd9;k)z@*w(2yM_i)h>IL5#06|d;2u5urrD|J2wdP3><&?zJBJQ5=+BtD zP>RM)Y!w}Ild?^SNXakW^BM$eqj;Q7QOk!GqyeYminaXMK%IIvS~89)WC8oY2V)vJ6;{ewfhaPHNv z+sRa8Yde(uJMYuH4R9Hp853_Hd0S=Y==SiyZ>!Wulmno@L<8`=1b*}Zk3uy_#i=hm z21-S}Qg*q1D;cu!!`1CVxtJ#nh^OnXRsrR&6Q z==rMk5RmYmV5V@k8nW)BK`kqG4mAl(p|T zAa=yG7Fa5ld8z*20xBk3$^SdFKyk+OkBWcgpNzm$RaJ^@e{e~&FVmLtE+2NR1^#byKvzG004V4 z{3Ro$?H9oJf&P8r$_m1zu&_{7RrTuCs{{gJHU2MC6O*l)s%2Y)6;HeM?3=Tu2v_i%}L89imKn3e1JSiL&4L5C`n(cJfV%FIYC4r%keR!CBm?t42685WJHIk}7$ zjE6(D@A7~2|2I0&ei$^dGw~%mo$$3$bZMw%ZyCGiyJNhJ@ZA%=A6v_V8AYzFSFqL0 zO+KZJjGr^=qgmhiT$9StZ|{xBbsFI}ihiG%F9}BJW7$1Q6=vPF-1KZfP%OHLWENqz zzs-ToqrKc{4f6e*4e$M%ru~yl{w0elPP|jq5!y8?w zDTXM0E9bEoELI+aX~t%>)8f}RIFvQ6E%2SR#sFB>tge!9N zW1oe!w>n0V1i=0SENoXnCOYQD^D$LFeG1tCLvZ_uq3MWKVoOVadAkeEYIe@gUcpLz z@A|ssm>|*=YvNm{ExxGSGNOL?jHPW`ALw5%fUF=9zx=1Adxx8}*q|ofM5v<&_G?JK z_DNdz(M7=zd#FQ@78vR;M8l5iTLMdYVnG#b6V5+)CEmtKk-plW<-wyXnQVdgSw-PV{EV zJ`=JK7ROg<1bg8S{Q)=PuJ!UNA9|Lf-JcYH(voU5rLZ!JM1E)AvlAyG{*LDQ+RQo? z*Pe1780Dlusj`xMbG`fuMnLY9GPt7S6uxJp%|G`Z>Dz1KBnzqXzQ~ISk!^BXTL)^C z=W_{w194C9sl-!*_JaB4Cy;pQPzm+!$azZfz0?Q0Zy~z?#U)o#6`J@)IkY@*`uM9k3xLFkoOr7Z;>XUQw(Ebds zi7yM3r2iF3?pk-(+xw$^*9R9#hZk%u}YCt&bE=7^O(ysnDgHrL^ZF5)*~Mtxd! z0xu0r$1~-Y&3?Pg^762B#3Ksb47Ct4$;w=4VD1KA0r<%Ktptst5+GpJ`?GBgk$OzX z2SRmBoFy7FcATq^kqwz0!T)RK60rJ$@V5nULBJ2EM2Sm+pW4^^xh@vQ8Pf zZe^QrSaS~w3aMPgadT?A1XdatSB@7?at`a_QSduZj_+QvL}6OyZ@yJ=)ywK%F0(9E zX&53CiI4L-X@S|tKO%V34UrNDsgc|PDDoB~N~D3|BNR;QUrQ~~jebtFob*EZGf%Ob z<=^<>lB@XRgNY=cqe?alTLu^(3S?o+wFFZCU%_x-W2=VCVN{wMsq29iw|0s)=MgO_ zm=rZ2p2jAQBsZVd8g_Ee=h6aYxVU0K5z?Q$P5VD2+J?*x;tc|e!b*Uy=~6(KaZG01qLj)_>BfLB<)Lv^;U~2q#*bZ|)*zYiSy69A)+VY%OQsvBw4xAOoig4I&6I=w)5J zIU+5BRv%IU4#xnHkAw}M=6ABR5G6?_))eVAZ%2W`dpYTy^0s?QsXEJc>v!EG_ED#` zsxS8R_;ouh=zXj__40O&hfB834d`cL8B9Vq*dh27?{HjIxSmz`ns-u>^^|aHlk{bL zDZr{NF5Uai@%GAF`Th!7?9oFPmB2mf80a4~3KO0zw6;HC3= zPn(a#c|q~H3NM|=QDXce_<`{W3`M}RuG4i59gf3nug1H zm*U1^gJR;B$NqFBBa%vPNGBBT19y+*pncKgf8*#di zXe>|7m>vs=PZ+-5_wtSL_PE>3gR*%n8=xx)JG#DVX}vM5}HI>fJhO6(2G<-2vt!!(xplN=s{Wl zsS47IbP%LI{NB8`cV^G-IXk=e*WQ^6006ihFurJ{7s>%}ZGX`PVk{LOxoK49PH`EM?8pOfhed zm>r=w#`1$`f!%=QsL9loLt({T+UON=A}7b73Y=@0l)BMheQ0Qo+p^iOAb!J4VbY!y}G)J z{45rUpUoAIZc)IV#T}LhLkpdVd!8MaYbOt{lQN?GH+pgSIDAK9ZdJo%rt6A|Iwzj# zpCZKk>m$cag`1ILgxB*0g1g1)e6J`Dio0&Ap>b8B8^!;(pqHBLhYd@%M}0lUc?!9N z`3$!-ArF5shqUy(n}q$I)K16rvs_J>fDN+o{b6$^KG`v;tzYw9`Gen*FshZ$Bd_;G z_+xFFbx1q`Rmq%*19_~pjONMO97=LUSAWcy@M_xbCY*kTrW(JFwJggVdrqo*V4o?=NmqzT1O7<}Im5!(vt0!O#bw(WSmsH+cWT4YALo)~q)567M79*)nL2Ezgn|M*@!k7qFo2`y4$(7@<`x**?T$Vazn^gR@ zcI?pY)e0gx7Jbnf`2pNy1~t_9NPwReTyfOC23E?<;FskXTBiG2Uqb8unC}e?X6iO4 z)9!UnNB;ZSuvb&YE6JitEF(9()DYuUr6^VY2_hRdSysVVX(uqJIHmuA{=vikLN-Z? z2hAwEQw>P8p5nlk$ig3Ivd(s^=f8%-V4iMr-(e;^EVHeWx6h{nEBkXA9eB_C^J4jF zH2K3%yGmX%e}_K{(BM+#PW2h^jZzM*5I=JU$tsuzNW4+f$V+s4ywB6Qw2?KwvXon# zl}kc|D@}+t+COnMO;3O_0*OXvOMi*tjE+n6t@7gaWVu>b6Dd0w8D~NuzPWp!l{%_lQF>pvmcdKIBcB0Pxg-1M{Ea;B=(p0xRdVF1}AzObqs9PA? z0y96BLzXp*Uo^7#c?45azKd~ndd=H+mDO zFN230uIgod1TKOZzs_Q9w1bM5Dqm35t?T0Mbe(xbYL1Vs zsQ`5zH-2GRtTww0TMEh4y1lsG%U#<^f28#$@OpQiyC9nEX^esNR*ohJP}$>(t;hW^?0fm2N`&>@F*>Wk3Tt7MmP4JF~8*OK;X^aGN#dlMx=3_&Q&fUr9VAvF= zm|y4!*Ds_Lq#1Jb?aa)8>+LzL_g26*dyu-n>+UrCWBRQ)o-ftoL5{YL`EG-C8e1eo zrz54*@;iKZIU7;kUm{1EXT+2dH=@q zR(!DZqn)T#SCb;2tJe?Fi&puj5BKWiCr-w7-#zA?xzwh5O`f&B)5dgp9-?;Pq6|q` zj}&_or{J@;=FU14YZ6T4bB~f&Gv%Ds9rsVk10bw4OH4!7i{se+Tke-ZcGU<6lL{G| zitG-C3FSJwYSpeuth0(Pf`1>mMGcIo0_#~PG~GC zc*b{9ti6>ikUBKDi-qh*R}PAuhC#t8ZZ}9tTHu+zd+&5L96)l|9s!llz!V2|jn!H{)f(zU+=s)@^UY$Dib9^oGh?x`BocYP zLat8`ty_6=q>rRY*{}{X3+72Dsk3a_-4n_2AJkrDYcBk1H3Zm;-N~osGkpH1zdQrjMH@W#0KD_Yu1*P$?Zk4zsIS-vWq6 zKm+6f|GuxvTs z1o~~1%%JbPJhJnvhveFg!=!Pe=5-#k=b>5sZ4EYs&9P@Z1wLyhK0bl^AhLe!m*f;X zVw|}g6Y-|Z+AQ?=7W=ufcs+e%)J|u|m#JB1msBb3ln+6>Jo;hfAK2444GKSV^O9g# zC>K!u>8qixG!;_dT9McHzQ!kD-qkxi#YFYV98b4Yh=7(?u#*&RNKtOM?fxZ+%W8?3oMee~lVcDSlynh)IplXj^aeko zPyD#BqdWiPt_j+l1mP^jq6RlYv#T*4XO6czRu>GO){=nHE)O2_wa7#d-YpJgifowe z>DmAygB2!TbC@{~o)g$l{gL<^Htd-17YYkQ;Hp!aoloRnxUWhPJ8$Y1Wu?s8$1)`i z9@TO`?qy!@c4D5q8|+<2q~G$*d)+-W3skv7IJj_0kG-M0Ft@#6RK>M7$ThU{c3{qe zv}(QJGL#jWY&Wk?sd+e#9}kAdEBos>)h^x6c(JQ>!&=FaUcH^HfT1{q$igUFok`>Gi{iYvA5nd^?LTO6vS{eoS zb5EqV{AT~~qh)_XHO9dD3l)&C!P)`w?_NX?C2H1+Y~X%K2S+Jp2520a>~f)5Vv#W*R5|p0Bsgg>}8D$x&<8 z*4E`Ul6QUtO~;UJl}sNRaD@cx6)(PfQhw4n)lI0Gio|^li{G1NA55ej!Z*1Ozi0OG zE1hZvJ>K8ED&}7!S{g3{2pQIyuSb8&8><#zcI5;fbqZ%IR7Vo`_ia2EyBW>CrJf(+ z=;g*g5$clGW6f)_LSI`y#%?NJafK9U%BU_js%cJ3?^<7(^cwiJFH-s`hV>Vv0}U@m z&tf@4D~1%ZX&BQ1Q3$-;kr^3-q$Gj`@hL4l`S@RSJZ|!ocMLyHE`($oHT!Jv7 z(&*jKR{-k$^=Hu0uk6a@BIUMFnY+qbxizYTGLdwmpd;f0hTFc|$E}E%^T#|m!{7Xy zU`H@zWY9y!JErp=ez$FqW1J^7S6xcbs{1U`^GZuMwf(nQ_8X#1hG|i^KET7bO_@Ro zGl2%#J9Muu?p&sRO!*~yYa{3R%G79N^78}MS5gsQJQ^GeHEtXe-{kT^{XV|ctPbpQ z?=fQ!u*yyM-B*N2S;tG_dtz34iOGR8AzS6~4SAs)niSFEN(JBTn?yycX`M<9i1SC4 zLdcudmls!L2A2TaA`3LS8a}~YzaUHn$3DP{$VGK1mNW>e%Q>OHW6-CHA{C=Ndou;dO zZqMqeEcQvI+XxAHOA+-iMM|y=Bfi0vpMXm*MAYd0o0$i{85ZM3kJZk7v?;QVx^Y3;PK0VJyF~5?$lQN`_zh4a5eQ69f5i3+YCLl^dORX@w!8|w{ z!gcF~Q;h_p9eU0h$m>{|wBWpmCA4;4wJf!EsVm0f2*&tMp}bDUj62@DDu1o<0&b8Z&2qIn5p&%g$2!n)_NK4LuQX)u6sB||-2~vZCq)G`$ z4&9vt!!YL=-2Tq~Ugw+?jPc_;BQ8q&f0+g;JfOm$m5m#U|Pb%W5ZKZyshVHx|&Q>^Hj?9){AuiHphHrLp-B3Q0+(k-Mv&zy? zc8Rz>^)=p3;%kEnk>l2{lteAP$n1m%8uSnLy3=71Ki14hl27*bh;Rq+KdI<>Uvy3u zWk{TsdcE?>N<<7R&x1pGUGED9bOaAv-bk%=CB*4a|I7(c!_FU&%!sBYrv&1j{;lk_ z$|J#h?_{^pgqVcxlJ~OUNJ5sOJ%5gL?~DKK6PKk@X(HUg&5q~6!71RI_MA6_G2xKD z!Aw_pV|ZduBDG7~!d)pNdHlXc7wH$rhY!9`!f6Q>WzQAEIZ%zX4)FIUd%dT>()<-S z&jVV^#1-?V*^2%*n*pgoco&j_XwR}8edQK7{o~QF{5f#<={Iy_HmG;RX=!(B9y~`M zcEg%3X>t0=B%NMFkrXs&X@YWq!HfLGj^5%=`-6`_$pYTTWq*7J!eGb(8;17H3+BDB+to&(qHkS}O`yOC0+O_UT)fUm^)u}Y$J^P|@Wa*J%g2+VVR%RHwx$@F zHv^DQ2m%HKYKatI%Pu6jP7f_1CD$r-k4KFx!wtIQcIRn_8<%|w91EE!Fj&`aY0-zC zQ$Z_lU6P`g8@!SGYoo>OLtgzdD0aU$%^_QLId6Ie*!dm=!XLvEMR_uzJpysQH?SiM z$hdO?^-dv8Uh(Jle63z~dG#V(!gyXA%#f;*grxJ& za>Xi)*O=;|3rKV{2fp$@E8A?7J#of3R^_wccPvfTe$Ksr6_e5#s$m$K0kbcBCiHeH zf&2MpS6GB-vfnJ_p*?W4%v7!mgZ`Q(5k1|TiP?rBCD1EOQAvwv;cTA?uZ1Al<0;DC zxBKz60hNpUOFpxKs_DY6jnYU%t(%1x^))Xstr@Qbc}t{aLnn!3!|Hz~NAbR$TpjKq~t-a2wJL4!=XPHeSD8eCm(2f)0Y)g|*+Ur@1(*q}dNmD)whHMh&oy z%SbM!DBD71qcfjSUj-U%{nQv`N2<#%QzArchf(6&)gQg%jVFl^7l&_ybL-Ap8r`Vw z)4H!uvSTcvw!7o9vasl{+Enc@`f>e+u&8jgyGK8Xt+%T~cQwX0dabarxRF5{`$Jr< za7{AXtbnWP=K$qM^=%rs!+8|h*(P?_m?a_F)@{5ArmdFFMCffHrF)kd%_V9#5&utyLGazK*fBSZ~ynXpP z{o$0qnC00sYyKX+jVwq;5n1V0d@_VDLHK_~S~*!`n@4FGP~UAKLO9NiSmcQ$WgMrq zuTZhxMSbp;$HSPX-!i1bc`5GNDYkTQEeE)iBA7T0!a}XbDg`c6#e;PH4rUcpO)?*P zIQ(xYV_ra}={c{`6G@TT{JzL6{6Z3S@7VI@&hMb`q4Zj1@KO^vj z4DZtOGJ@&<^O2=FJng8F3WIyJ#RQN z@8Gi8d%_-pMLJ}jKkM=13v!5XAKyD;fuVn|S*OJCz1F<{27a8|%0;2m7m z`%K62k;u+r>(qu!+dB*Nj{W*_mUoOfkM1gZZ*YtncrEsG1el1iRlt$gdedQymRV+# z38j{kxa2Y!h42k-hssFKcDI2fl1S5&9N*FZt#hm2*fpwE#P3d#e=J_Uhg%gv`L(se z(#}{r-3})8k%bi+@FCUxx9qt-ev$#HUmXvVq;BUejr-fQbC`NKX?(`v#K5cNfXibe z5S{XC1+W3qJ9B3Y_@vFNfV*UT`yqYsaHo-Br22~0G#=uZnh4?htUWc7`80g)FzzJ! zxtXzgGCX_CT2xZfnmoOCK|wvsEN(X*7ty5Dm8h0CWYDV>7ParHdK#-Djk`~kCCGGUbLtiXN! z0`EmxzOwIoAl~ZX?(14mw40u4Ex|UZEVAOU<_})e9{xj@IF*gpbQSa)`0r?(3pvV7 zHQk$&_UHPu{C0-#-=_E{#8DjXlm)OJ>yVg1hu5Do)?z{+F%m*KKMQjoikViN*mS(! zkAuWiklt7^wn;5bI8A}OVW%1T)K#DSan+Y?6y55d%j<27#*1qSbg+X-u89lIYvy>y z-ElcEM#4pCDlM>I0L=VojWG27-&hY}FHX9w4bI$)2G$c0CCfx*Oyp6en5Q4>G-8ul zESp#b9`GTE91mUWyFre10GQ4pa30HqgH%01@W*Fbele1naeh#CM|~DZkfS5LQGLBX zB@-s|elq~dh(8}GA`k49I1TDs-hT$%UL`fwbegyK^KYQlu=rpgMx$xBv{V-4fOGh} zssH&@9?}e=3Ysb5p9t0Ou(d<^F;xp75B$e7y+2|g%6k1PDODg7qT|TF z=IXYtM12hxIZfnm_ao-K1GlCuNKPRj_8NeIr}#^ur(29Ip2guO^FOikVp`;tQ^W`_ z`!`~Aio(H~DHbYL#M>Fe@-#fyZxGX33UHaspSXkvaGCwvqjxk^Dy%oO7hBoB=&zt`NXOxhU-)O1{PnZA)t;pb;u2fBpE=`OtVg8WmMT@g9Aro?EUv8W; zG!KHx;O}b4NJ^jHX)?|D52XJU_%!`iHvfer%2RmWL};BJ^xPl5)d6S&0L$=?J@T?1 z^ZrFeMS&nVoWYnB#Oej7?7PEy?_)6H)u_Hk<`owr+0n&*!WYNGZwKs~1%Bh@5#k#N zK}1zYdr@j8)TN_Xdgu%y^x`#!g-f&I*(Xm7CN?=n40symk=aQcuzp;Gl@x2U&4g`s zF_aG6Y)=g_eQ6QDmDo-72f9V#?c*N}-;}TYDWJ6PuSZ_Q*li-tCe9|kX0O~^_p(WE zY zLqF@{EOt*whnbZ6>wR<42_cNyFYaJEHVWy_Asz5kIe9Yno=+8g5U%qk-e;H(6;7fM zY6RaLy=F2Z4;`%B-EYks4`jB9pMALVPN%c##fK+rx}9I2)~(I242PwZ{2F*Sw|l!m zu+ov!KqU7KFjc)zkB)O<-kSm_TycuJbgj-}V$=)#Fj52fTem#cmiU>YWJZU^Ty>z# zooa`+A7T3H233@~4qC)(qxV|w5@{AqiTYKt`N=pC$fCY;`oooFeUw2;RB&_^A>4nS zY&EnkI_2-lv0<_rX;b3A3*xeP9uD5#+2NV;Uqt74E#_y)qbC!1`6`y#{bXJM-yZ!{ z0OvP+bfTI-H!nJ0?PjYMIhosd;c!L&}~Tno>hx)>Ww%ppQ+tTNS{!Juk#VQGAr zngeM(l=9dYbrrm45KR0W0=M=3VU9}J&jPQTezgfusJ>6SQ+)r6Tpq%cf!udwfhwvs zbGI~->yLT;Cl`xm1zzy@UJr$55XY>TYNHGYZ!RQhSeK5tu&A4G7!2=}6JqCLMtl7J zpcjgNsLYL4;>7;}n0$H>`j0QLoUQyrd29#=^8mXvBsODx0DQ`SA2v0g+m;7)l4Cj_ z_`vrs9z zkEuJ_SR1WIU(S*XjM;aP`}S@Uc$!WC{ozhDVA25WbuU^2u!j`dF&=h~zLlJLya4+} zUq4jxHeVylvmt2z5Em(E3F3ZO92@01{0xG!R4?=3KDhtk_tUp=dlW#MeRKWrC#aK`646z7k+TVeVR z^OUSA|JW?hME=WWegD@l_R0$G$S*S^LwY_(bSHYolC-E?IAsk8;3%#Hr;Y;nKR^RO ziooT#T6imdhnZLwQ(bs>;-MIj+D&7bQzG+-;9uVO*8e|pC%9_#==3do z!~54&H_~1=0po81?}7+O3quMyO1P{6EUC_|N}W`Sk%l01y8uk$jN@rZIcw4;M=ZKI^+JA4m?rLU8q8 zG^g_4&?yMg_YP8CUVi?g!zk^pN4|~@gZGGmNlfMj@9>odElADD$q_r$Y12&M=dt4U_ z$#AUQ{BkZ6|Lsg=uMBD~d}x_rwp&40i3dzsDg*a!>lr}n=B`A0C;|O z@by9oQxsEF%Koj)MH9sj1s?M^GGUKk1H}JtO~pfEe^c?_RQz8M;BPAan~MLY;=if* zZz}%3pB4X2#eZ4xzu5TyS5t9Kaj(*!UVyWI8S-C-{FfpBTY>(|kpD8|zhX5gwf|9- z{)*Lq#p=Ie^zI0 zpJT;cX=VjzdH6vcG6;G+O?R747_$}WM`oQ0d-kOGWK@SAz7-b2XS(%jD@KW#F5h+4 zW7sOeDPO~c7uRWCd|>wgJ|wi6IAl6vy>yr3fkl#>?|FGb(6R`6E`Cp(ShM$hJr0JL zFFija$>t(*vKb;9c#gk@?RZf|mK1TaSK6GPn{tUcVy9bHHpzX^aBCqBvfTwe5n{_fGKRbTFxdJk-lB2Prd7L`RwN2?tv4L)_=pGMNv{rZ}b8KZm8 z|DTqdYlO9L<*p$R#r$jboWi(?2GFjv6B0y=|B-(e*J*kdP2VJRRJFaCEdb;3-S9!4 z<4*B3M-7z1Y2e#$QWaGcG+#0i6}z<`E@rgzL}#XF#8F|Y^;Ku{#wO2-5{uRifB!P! zv%y^Qtg0|5*<(W7D=v!?&cagJtq@6^7>OG#;_L}}Zf1{9p_2@LvzGT{^&W1J;izU7 zFB-B{k&3xyGcY~o+D)FD3ilS93BUPeLFVAo=3c3v^a-|viHzt4$|f#{D`fVmN1gF6 z`_hICg$$aQF4O(;DXo)Pt(=mW*xB4?H}KKFhs|(fYSg!t{&d#RzW{wnWxF<+PeUmN z8(*_xQEgN9P_z+hnhrs)DLxnLH2=<8nR^zCL0}hb#?4vcZn}hOJmipI9jc$d)!c|) zXWai~5&5>(eU1+*{_tcw0qXdG1in|QcpH5Lx}|^5#ZCExM(Aze!G^?Sw`FJiA9zchN-_j-P}BsEc85$igr9I*1Oq<)We#r1EUPH%j}Bf>RiU56;5g)1|hw>!8)D19d( z&H^F(&Nh)D`!3<>?F^r0xda$W;CqE3u>E0fCYN^hsb|%7CU<&ywck$qUOa8J3p>&9 z64*|Vw|&NZ+TXTipML8O1c@8;T9-#m`iptzIpB3IMFpf^EPSIW!NUaG?RBo25k(xn zo~eGCtWxR}#22^%#U4#LNBTUhS#xk?)UAwd%oZ+5>ideat?}B8AtPLV3w+F%EJwxUM9@X;k2w~AV zyg4`DSx#1x+~j9QsC5rSU1hF;xJ<(vmAF^g7b@31+a!Y#hlz;LHnizcUxMa|$<-!H zJzc)jhCwklS|c&GMY=lB-T3R>cW(mF{J;7FwEbzMUS-a!{Z@M9v4@mc%IB5%zO2A{ zbk7sB0%eWt9x!3H7#^Lvu+otm7o6=@1fdXPlRDXojMP-?v{U_or?!SXk5onDJ{jT) ze(T0r>ejYFMpol-{71(TKF1}iHSOdaLa6w=u7&# zHs$1IC(XW;+I&t)cF?c^Yra+D{MwUbx=5!ZNm0UsRSh$4@|t8Mf&22VBXBQuv*;oG54?WtZTUn4eyn=8h({yB|(8)KwCWzmU$o39M9B8-rOjE8iMn?X)v&TTBLL4iU7L8y!V(bnNMba}z3GQwDTBBp4 z3gDN*9`7^@wlQ76;^ORWI#Qh@E;bcKI(in*$>&qOk#M*Ao)5hA#Ep%h=U9i>j4kWl zdlMq~rUsWk1axONu5%_10bQ-=(Inr^8~XDSwn@;Gx4O5Ny9KrXsN?2U8ZT=m&SI`yRVGNLbHhCf!Kz zexp;)@A|GQ(0FW`c1lglTj!S_7Bl0p%+*PMMeL#*iJGAgh&I2wv~QdRO{wP5FAv?p zSBp0REu8QAxEE4!LrKUl*sJ3E|ZhOc+FmvnULL%Z4GG5n>!kPG3l->UVzZ zs1ax#Xv+EAW&vqaMP>H=P<;*`mpvKvNB)a<_B2t4Ev&dee08o#5Ptoq_0V-ec-x=* zj)Im?I_g0sS?*L{7tgIQD3c8Ku-mor={vy>QPqnRQMkA<^{(6Z@tyDQJ-nvs&&I!% zt7U28!nbHb+5GNXro%O&T7d68{f2rTIX5rrO{Ca$TlTO+>kBRvh4>xi`jH|}_N%-0 z=pBvd@x_@%>!-+@FQlScYHpjL6^pFME-;af@X}PQ%=n{zPx)Hlrc7u<-$Lmy(-y;L z5WSLYBO6=w3(^Ahd&Q1cnV+;|61JDdpN(FZnqlaE$!&E@fd7g8Cip5$Q6fC5ST8zK z2~2hMP!?=0e170`_(%O4E4byf7@Io**KDah+N_eIou<_D>*n|dTvTemERsAo$wj@# zgf+HUZIajEle!f93U#EX;;)Ym#@i|skMOwt?#L^V6%nes7J$ZGFp2!H2ahfxUvw#E zT;O??=_cpaQnJ45d9strDzg=;6&uSwQI$nlDUOMb^tBvIg1@$Z$hnA`_$U-iLUCsN z%9$nEHheYfTg9hSH2+u;vA)~`{7)~N$~CX}p_*C0sBtG>oItgT2J31`yK69)6=vF0 zrTOILaS^aA*D+hi|V%c2cY0P$Ud zA9g{51^f=Xw%l%D80@r3|m&Dc=h3^;2Bv(Znc`t|AH4uQdR>}~j4dp!6b z=jMk(Ashh)!KUi(HF#M{1v9T=!HnhS&7Zk4x1Nfy>QJjFZMZjA>)$AWt=X&O&NM+N z!;{?ck+?}Sh$&n?fd|6AjpGYXyqd*GRRP22Qp087(PkC6eWj6>K{6~mm2fGzq<=!GkE?e$* zgVBjAOjHbYpMoth!zCGl;%oiPtQ)WmpJp6hv$;W;-kx5wn=Qax;+njoNMwP89gq*z zP3(PH10SjFwfnGr4VfB!0;e^1v5xaJ({&8GRc3g}W0Haf3&|~v@$vGb++7vZK z=||5T^N?Y=!0{Ql%VyGo6t}6)uZM?=iK%;xw#dha0jaO$T#rXmCW!5Jv!OO%F#yJX zW}v9y+i~!u|FxU4d$-n%C$_XL&txr69=%dApm<4>ow2_GNI-L;>0ZGmX2Z{KiEL*6 zpk1tSWT1rhse7SuP#r)Vk2V?(A}HG9N`2?@>6UM0Hf3|(*t;KR2;*&4w|xU~X=Shu zq=YRhOjY)4o|BmNWat~4^_4pK)J=}dV>9YH4c8zDFQL0=5wc09WE^N*2!D)G4~{}e z#cX!XbF>Nz!#)@uErQ<0K7N!)%oeGQD3W9=EG%5fC+}w> zJ!ejmB_feV2VW#(IrERKB@8PXMgZ^BY|$0dPS6iCJ?u14UQpnElueHwIEXX7Z8tNt|0rx7 zIwG1Zmo2b_6d`#It$I;}=oJw0V#qvU>?0*U>b}x_e@(EPl@FXuk}zW(=H*(r*9c~z zmM`0*-8%bKWVWL>(}<*PY!7_fKmD>wFq!6U!vH688XcVwS)8svx*W&d$6g|}Xu{Pg z93XXHxpC{YW8ei%G4_&IixV^sz8hWC^{Z9_j47B^>yQwsS$186$oVouT6o2XDq3X! z#caD67==_3$BD* z_E2l=P{5ju6X|@xr@-8t9JUzXDTSc0>;GhJI#z5_(yVSc#H2W!J`cjM*~yG zJKYDu&ixf5qM3~AbH2i&NydI^Bt#|W-~%2#GWL;AODJVgRn%t3A5V$TA&T7nOv}MQ zV!)3S4|YEm?{Slrd)IlN@DR-caBxn`yYJ2P{DKwFEBzIH7YBZ99Rgj4+Ay?b2)kpf zF?GKdW>E8m=1Zh;gDMs{a$L2maz$V^!L~ut66|IR&<%N=H{!x3IrUym;zDK2i4|x+~)K{d?A)I zWQt6BAkK73<`O$kmR@SntHC(53|xtB(wQEP3G?P0j>ZE zf$_v=_p!e(2eOBJ?a=eROo$jop6_ncw(xL+ofVb7msy zDBrANB&U+kL@3`!MqNNR^3e;0laVYL%z{Z|%>9hfmQZ8s@8I+-$lf2wNT&Ot!}Y?2AYeR;FqYGJ=hzN$?jPq zP#ZUe4;os3Uo|ihLX{^pT$4KLjr<{_^n@k#`~~8(aB-4VjT0B+J7|{<>h#^{0Hpq0 z2t+5tnt_$;>N7zE`3S!D`yU$6qrT1U1ca2SQ*|DP$_#*+kHf#n0^sz$5${771%F3Y z_x=)U7JJ-{4fpYOdr~TrHx$-4QaN=DU{p(O=8!eorKYd(p9MR#1cX$lL&c6;U^dAY zCWq(r>5zO7Kl*tAj8)5b`a*yv!bq?8@eTked{UStElTjP4FT(i?bqoayqRqTQ75>W zQdY{;90d{|hkj2=`yVvb= zbbbYRXVDGlC8eQsWbs!`+?+z6-QRd%iLU(okg*>u-=OUubDC^*CM7#-_KCW_eJgRB zrcxlNZ&hM*)cf@1bRL(1qc8ZkPkAm#A{kPSe&z<_w3@laOA~tI8(ToF5gVJmA}T1Q z7MQ2mbm{hh3>9-lp+$tVoReHVq?^~z0YM4*@S5tVI}k z09QGX+Z?~{CiZJeIwgFbyVfR?Tn-t*&Ef%#3>YMCQ_iXA z@+7@VpN^>I$CJSeVE+NmG3NXiQ;3L=`1QC~78OeL-?)dGWF$59ACBEmNr!jiHlS2ej*s#yt?|@n$Z5XA-6;c?o<-E79p)nm$+dn4clR zOutDufBFG?s_;!p+}XpmWhuYl_gcA0?5T@dteC!(3Dc~Xz@-HXmYugaEK>t1-U?fM8Wn7q2xqNPI5S*a}Hf2u4RzGvr*A4Q-XYc{Asgz^sU8v+4u?k z!~JRmGX=@Ag$=~?Jn>*vB`Vt%vwG>tvU zXxVcZFqVjm>Ov7nb_q7x`JH7UIP7vrlVd(JmDdXuCTB&@!HN_bIC>O$oC~g`Oux5rE|FCA<+-R2=j^W;byJmU3Jpwn3!ogPO znS%txu@y9uK6Nk}(G6R7ZO&xb%k$iMR&hfvTuyM4^SM>hmf53q;Ir_dIdw{N`T4a-Wq6emczREHh?h z=J&1|mr1a5V!2`kJR6h7CSxY#3u>=pJPHNwwEf!Amvan=xg-*2GP+%oR~~XRx&PFj z()6g+T~XdVPnvU%5~fPIsa6x44}Xh?Yg{Fk+fPaGpj(<_qc1fCe`1c;mL$q%rHfeYJt`Wln*lg5Hv`T7tt5vS1$r+ZTL z;qv)Q$2(@w>!OHk5CO56jSxV#N~ZXrhw9=k*Bxtt(!y#Auw#(q#8$*@w46>C{Y5s2 z*!@c*E04^oZoW5w;7<2D;shb5LAXF2;i0X7p(I1Lb3_|>*0GB#)1PGz-^h|s`uuAC z0y5R~U<2#-5+IKUGU9%?2@Jk+$VZ%RlA!JW??EdcU>bn^r=k=nNH#zO?$oyT>c?@a zO#swyts<}|^T^N_BAlbUc&7mnVxArZdGSBF4HfxEW8~2w4pj=M6wloqL2tE+HVUqm zck%zeLo@ysJ6O3&}dU*88%Q@b*yhG@4sKr=M{j}rz}-&W!NYZt401W-c-Q*I2j6R_LOif~ebKYL zJ0Yc%@yVML12MF zlBA-?7G7vp^>(%MsJtU9^_CFUi0<*B0{j z1Tb%6Kj1gbfD|R7HgG%9uI61f?D<-5o#OQv1q4*#9rIzFAxwD>)tT0OCVxtGT8RiV zSv9|n-f`n8I=TL-2Pq*0GfnsFI&dtY)rN*4TI<}NQ^XtsC_z0pjidNtV0TcaY2NCK zg3^LA7?63SY)l(*Wes=#BjeAX)rs<$Emn}};%xDUnOc}@!?Aad3ZWR@&dk2!?83{1 z63%-#Wn?TMlHX^zE7;z2=lxW$X#JzuHV{3ww+xqx?NZ8r)%7>R!godkAsjEyXC&$P z4W7RnCx-(vB;D}+ip+bv+D~2HB(@|DdH|7O5NbeP02Y-nQ91YHQCBdr=fF1YX{N<# zu5BOS)Tbnm39sI~V_?5D$(t2FB=}B%L5-8OTidiG@=()FV%E*n>GPQ_EC!&`Zz&o-5eD_s zG&5NO+_T*$tKAv+?C*X#RF7x8$v|+O+jTrViPKblhn%&^OQjJzo)<+hSjm;AX#~>v zM$NFp(!5|34W>fNZVVqf=lDH7uhDRD2hR~p}4 z@H<%$^v}Uo1BTsVre>U$b%KtMhCg^6S?pHPAYLHK#RU{Vk!Iab(5Ib`fvByi&;7cdWq-yyc^$WUORZ)mu_^SdY(qre-Y812fC=Wea&$ZM4rKV5x)o>Kh0&?-(B3oZpB+SG2pR%ESQ zaLVp;x7$20HU-Uy_5o1s`~Z~iU`8aWbqXgAu6odPHJDUn*}p>rAxWp72DMbsUM9KS z&e;rhV7=Mniw{lJA8*90IjX!n24WqJ`8_YfIR zYsc4~(k0u7UvaQ{hx+dNq3(m$5HnS_rXEF$a7YHZIc9;NK#ilyCW?n<`DW_jon_7v z?^gxPpggy=Xc9)S!to`YGT+kxx5H-njq#o@s59(;YH^6d6bk5%d_#j$z$Q>?FDr*z zTJjcLK2$dx-qcR?HF9~taQPCS(N|xf$FeY=FAlFPW)Xr9xs~5XT#Z}KWX0Hsfl_GZ zXTy%?9IwKzxrkkK_^BRB))zn_aTS;5LnB`9N*r|$O766Vz;kT2z*^Enr|D4cU|mgd zF5iPXru52dGbCcl9Cbm9)mTQ2kIj=KXwPeQ$rxijf-$PY7A z!wa>WyMC@EHsrFg5kqw5aZiYh@M_hNsW$gO|I4-lsHLoyyPSFx_?Pfv)uk;UjeMY+ z(k9#^(ejkPbEqSnU3@BVg}B6Ly+=6ecj{$Nj>ht=jXDXxC%p$24?(|Jz2q~>YX7J& zc>?khpK?@f(&k9(!ynyMWc&*=AFCT2YJk17KK1TTY^@}JeNbE0f-=dJyo<2ej@QoF zGvvT>8GstbhZV43qZjgze_ z5H_iIZ-u{0jnAtpodMeA%hnu`XkM*n?MfC^Bb7xKA8DBHvplUb2;34Ju6zG8PBSwu z0`Tvd+qSIg6(gkC65r&!cKy)Reu;4wIi;q_m{h2Vq4u5q;qXRi_$cZWo3q zpGkL_r{J2(4iF6-YXFp@bKP9XmL>m;&#+9Ys_tjF#wXrVD{^}$ZvJ|9Fn^c&!{r10 zoi|Cd3KZg(j|ZTb0q>(t`ZYvQslRF-3uaLz1dEEqs;(&*NUvdgHu_p-uLIeMDffES zc%?wx&s}fhxYRyg%LiA5a_>_*{Ordvz86XzsuPkDZl#&>1==DL(EaL)Q_FRwtM8*d z^!?382y^rHanKA`!~J?8EO^~t^G>hQH2J*28v{R!p!FyBd#0Uv~^;wqZw;ZmeM; zo5D|$&L=%5AGoEL)TRJpTKE=M$}YyHV1lp4VC>+|iz$MIxCEzSj~Cj!GzxbVV!MtG z^dnyC%U|?2xK!4csu9or&GDRvT&yEMSMS_;iw0e*aGNt(im%i{DN3rZw?R_4KU8*$ zCRJaO&6eyO_UuobxY*|J@;IcVUDx{o_qgqnaeji%?)?;${t8lrHV&?xYOiB(aqEnL z=k27QRir|}8F4o{PRah;_g0?*pYbhQcf8QK5%=r>ryS*&^Bc3kN**pdy$GO`5o3Dx z>yaRH#ivU`ghYybY!a_(G|=sDUJPVoGT5HK;J{VaPpL-B46@oN`VOz^6>CGEH*q=l z3&7E)tR(Bfg@h_YA6Tqm zPmox~Otoy$hewTBskzx>aVhDtxI~?)ty50+$TtsJ)waOA;i+=R`YQEHo{kTt9%{6e zh9PM?{tqx}(6cfD$gHPtP+p5T15d8>^TxnIj6YhapJZ)6D~^94Q%vw=8?FEZg*+|@2A z8R7huJlABG!8SWrk`!3ILV23-wdDBh869__??vU`Fohzym0G=4Cf{=W1DUj$MQ#KO z-^s4M+K0sf^l_5U_=fyMiu-Bnj5_y>U=?wv4|JrOA27np23s309DB_AV9)*)ysX}J zisGf_P|x*`of;dNizRr;786nzWDh(j(*s-)4kNB6#B6I_+&45%vfACBA^OOxdVPy* zMR+W$E){%#ZFDkdO08wsx|Oc`+D&h+A4q|zR;st7o>B`CHCOgD6u*9FlU*KrSi=%R=gzj5-wtXN{lu(QKu)gC7q??{ZX`AT8 z#ud9;irkjAPiv0`N}tx=sIyz4TI~-i@o(SiVHkqVr8EM5N_i>-qjT>X<`R!lNr=r! z>a4_?>0?bmLxya_gfOuF(;8-_GIJp>BvvTV{{^)~tuEuwD(2~|h-)zQ(Qxd}mA5R?M-|P2nFH}6e;Riar7!2f&RK1?&j{A`p2QIRa zTA8+Y)C1m(wB@Wn@PFb?r1&Fbou$u|Qk+eKDWF_g&b6O;-6>=<5(LjFKs&c`y3Xm+ zlYeeB%7bLwEim759Z$t4pk)FCc@i;p$Tn>oea56G!N>d@j4`=#R6T*M-x5T|WwU6+vrQf1>O#~b1Ud@%hhUw$Dd!{O zQ#?xV?i^5jh8u!Ik~b;k?hjRGX*M1{1mEJR?{_`-lZC^W^^nccywq* zUpAS~*JI?_D^nJ8MH_W@u!)26`WIYf{u*~y*GZLcLK3C8&Iq=d^li|XvWZgL0n!gk zUs(~k~4zX(Pwm2Lb~%-cPf7 z6l;)aTg z5v65FvZRBktgdNjl^0F#ni;^bN?fXp%t(xK?<&-!zsK|F8d-XPM)~#6WJFmHBUMi- zpA;V(&OO7fTBm*vO8CSiP0Kwlv&NG~d zeYQP1CAvRdgC}(>+?tS?)s&fgyc*u&;J5QBNP_}d;Z>(j?orn|@Wzeq% zrRN1BL$%Evlns8r+}yoJ{!B?wVzQ_W&W@e<`EdGUw>O$@ys^t<-33>TTl;1lr_ug! zufgcHo?TGHk}fH2wiLcnQsvf0%}hkt(gTNVORN!@p2_9hNU{Dn+Kfy0UCkn+!3g?l(fpxI|)hh?3^iRW6n9A@&&b3wza zCt?R(iBHIxCwE)8Wt<;3RaC-xtPpxo#66-}K*JS#CZ#s&ca9r+x6iuAbDT&Rl?kz_ z<1+P(zZ<{l3PO%<7<1r<_2>zD+^}eODIH=2RHbF8??c!sOls4AQ;l{rN>#;|r*h>bNkEm4LW3Skn zNCZO8n=jMwv025+?Od<*diX{YaBfXX?H1z%@@ZeU{*e9&?;yU1Ky_E2ONx{D74#xy zFUaVOuA+9=CR5dDD$}B<8m;izY=zvr$N9xPR&4EudPZSM+9pD(hAadY9&*AeJhyf~ zbprwX@YVg1@^Y_+6%&E8oK*r@pCq8_2)*mLgS~}hNSaFlr2)fx7>*GYB4zc}jqswyKRL2KR#kCev z{orH5#@HY0-fahuUwiD8KJ7?}e>Jy;)WdK*d-Y7iFJ9)-po-0Yf9L(i?YL4VG!&UH z^%!HaHrj`j_+)!^iNOeSk9E=a#EVNs*7!(nW*JCaE_c2@n3tBLAu2x47gzRPA^Sq? zeBMc^+xvaetI2n)7SFEyVvYhOz|ERA>8G|@^?gk41BIryCeT?kL)i&gg~E+o38d=} zf&L_@t0Gh+-31zbhcbQnnMQgQd=B_(3IJ(6%EecI86KfARNK7m{u4VT> z;;ALpp|ei`EvDM6SCg$(=WbJa-;;vftoHp=d&(su&6ACg+HTLQkj@rI*xp%*x>(%D z-~6k1o>!c{Pffy1aY@5x{gZWl3j4r(41bI-FIAqbg#H7ct;?xlPH%5*bn<(CxsXD| z@1Czw?D2>Mqmw`si4n4gGX_C2C}JQSj|u~yykn+{Jf9~EdMjU99{C9O@-oY}dQ{AI zCh3#yY8DsiMStF8Z%P}WTkaHB_>imf#gF_1*PO2M zi%NHre|}B-p>;Nl>|Sw%ZOjleH*Urv;Hj4BS@C;5dk*R=aa&-zL1ag6=Mr(>Ib1Qo zoHUrJN{MbOsyY3_jGJ2(XpUobk%;~H_NGk1Iht%rx0c-w?o=jCS^JPhFRJeZI zqXTi4ImIQJ52K)KrR31VG|{znqy8YY|0)yJ+-f6$r4$~(_rt{4?g#cuK93c;m$+eT z&&tO(p8s3>!!?QByIiA)EfDAivkPy{*#mrgqc8KgUN_+5J;3QOy-iVDhTTDqZxDJ% z1IsTpJNuX0amtt`=kxrvzLso^JuXd(!aR7+NJpmf>&8LK$-1xuq(gwAL%+tAHXKYy zUYh2q-qo~_4okh_#gOEp?0z&F%AG=w>yB#CYgD2uF6qMWu{)_uYp&dnyTsZ@R2zGT zhdqp6;!um)N_^o6y=;K+4sRVKm)bzxdmqnKjDx^iETOo5@Y_5xUDHvTD*Hf-(&_B7D)FZfkDS%Y-+RAM* z3pY7orZXca8<3it2?cwmbyoVA=j2BIoIr03a{d2d_R%+ zZ#12CSQOv;_df_oNJ@${(j8LL-OUoxogxc}fJ-ag-AH#M-O{k+N`o{kCEf7Met*~V zKU^0xbLKGT9j`l5N|+4I3g=er+Mh|>`1btFU$F-h39aBm5;dAkoX~bp%4e?k!|)rs z!hE(oyY``}W`xa8cVf7q8ui)p=YK?}iM&Ng{}tM>vtTP4H597^M8S0`v|fT>6CS?l zvyDG50ReW8_BZvD8l)bSfcUunidD&Qqhp|8-|#&L^dc#_@Bti!fAn2{7M@FLryd>s zCX4^r7UFY!6MJ6iW7=?5S2Ft2`Y#jE5g3$2qex5)wAo)H^uia9dR16Ff;3yZHJY6K zo*zwSpaq0PSTJ3x2O-&KTJT9PZcwUhn2hH)ee_uzsJ=+xFwuD_y{{Z^>k7*r-HZ_z ztCC8_(edE+m9Krl)1bOn_>$d6LMcwgFNU9)_3mfGyJ}=w%a5b;&rc`Moi$;)m=D0f zfzJ&!WTFg4^tlABEdE3#j;8$xcyU0E4^HL^FW)5?GHL#>xrc7-Q{B5s05RuV#jTy?j=xOk!%0Q+K(bxRCztgE#_$~zD zC~S5T2=$L^E49UUd2JfAQY$_C0f+mg2qOm~nN6*LwCSD}4!}4sfD&uNw^gXmeT_*d zM2@b3K_`0`$?~ue;TG9qr?2FA%((39l-_$kJ7m@2N4oFy-iBN6?UiT(<4LBsZ%X)? z9qDD74&ViuvNGLCU(ONEW%l6=>;~4voL-#yEK8aR_o=)p!AAVGn`fO$DUXhE?`27n zvWs;;Rf=(pU`#QqFJ{CFgTOcTCovpU+P}M8kkui1(hP)=u``v4$vV6FloB-;NA0bu zzODY6(XH-*SY5JvK{h^vJO1B*EFmVsxbmbRl>|&frWu-w;}#Hopkq zTbm|MHHBgqEfz2$OZ%u>eb!IX&v@95%j%Su5E|eSZk(;WcfRAF+%93>1?_9L4A$~{ z&E5{<>$XO9s z$WI(GOx#RLV#PO#xs8^`OktL|2lBV=IBgwS`p%HX5il{To*S**nT_Fu?uZ>JPg}Pa z=AWFu)M-TeC=6b$J%J3Zu`$XN>x~F$;gufb>Eap3-vL2#(QGBXGWQ-Ab3nPvJ3@Tt za%P|_f1uV4;g~@YQ5{m~VR?Tsy_SFen*v z)-PX}yTRjpLlHhXim~6eH*au+I&~UNA92H6R-X7`o8a0wQMpo41v=Q!feit^lG_@k zs2OD*e-aLKM&Q^2qU=pfDRb)hFa2BllaM>#*JiuL61dMSql3(|~mKm)`!j34HQ2IMhL&%{%Z^8&=j zNmY+bw|SK{FP+^-Zewd%t*fw$R;PDwG*FDLWkmqfGrHL7(%xO6i%C}%zxmGfH~o$M zrF69J+Wx!rZmUC>2&;|D71NZ&mRl_$+~{(R;8%1z>3jWDs^RGwHkgBJ4? zi$D#E$|y?wSrq+ZFu+}JZ4)*@lbQPFT$Fe^XFC!#@I8}~d2nZ^!^jX4gZpM5kxUEv zlt1@ltCK)IB4_%s=^n5mK9#NRf#-muOh=N0i z3XAr&)G7nvota+!z3OU7YLp3)mj>=FC2CzW0)?w?JmnC`xC`tgg&^-kn!9qtcMru* zOIHbZrckZOg8Dlquo$2=eUPy=^`X>KS_58ERbe#~w~7JRIeQ1;S`DNMt#WE0&H$WE zqJo5HOo~Alng!@47kMO=>Lv7M$sh;B1x|y=ohC?p zhy~KOqUd`5wL1yf_D_@@Hl=?xElxIysG_JuO^bqzNl*z31pr0(W9#20E;O0IvO?oG z7!bl0+uVmXmZlDrv003Fm-k8y%(9Yhm>`Fk`Gfs;c-uXzcYm7rKTz{zdhF-&Yh39T zjNytu{QFwfr6$B;KrAHIfMoD8F|()hO5N^x5b;s}8E|P=qBKkCcr5OfsN&;VfLf~T zuC%=Xpiez!EQ*cuE^1#!+KSK}m%{rbw3hfz51uHGa{dWY!#b!Iweupb?wEu>OGL|$ zu%s4>0xNl(KWyE;IE#1&)1%ca$GZFj^>iip@HYs}#@)EVusTVCBGO!R-5&ppaX}kT zrTnxw+uH%F`QY7$@k_{c@$Prt!wxli}xrd{?y1qr9iN|<)ZQ^VLAor zA0nQAt(TrN15b*)vEQ96?o_d-3tv3o3hJa?U98Uau_e@1VK3aCT?8I?#bWVLzM8Sl zqV!ybcsalQdqu`!`{#f`B+X|;3on|L8d4Ak{M-5`!y5W0LVoEkzx>JhzT>V%5D__z zVx@sp1v>-6F%R>C&SWKSkYV|S@VeSy-$&)OGf$w_F_;^|F$yCuARucz$*-mkz0nDv zFVt%~Qgqw|dSQTU*D7=sfcwpC$&=)^B{?w$XdYe8roQG1;Xx7r1~?MpmzHu)u>^jS zS_7gusyLyEO=|dYJSWnUirn@=^=J9zQ3Lb?zj=hHH~yE+k#oBrYJxR6TIk4VuvWFm zW;4}tA6-2XDRVT)5|$QP9ml@~mJJ)Zrs zD5AFcDdx$$z%umW!f_Qbb{&hw9Sj?8L2sAM@*Kez$~ljY_BqGFH%ncQOSyD^?^%>u zCNZ>hYoSzzM7qiTJLzI00cez@Q6kO-RPYD>m>Hn$wP1%_Am~T`)dg4pBJYb@SO0Q~ z7GlGMHE6Gy_A+njWV`HiH-S=wuDeLI_|pyPg)q=;^G1Z6)tbBG`>IQ)MywQYVzIF5?EplU(c?qG*$NDrc%|wl0nds*Xiy~}tF3Bc?!O&! z2Fk}HHRI)UA%>;Cs%Taw&v09BIn5KXNVUczAjS1n<-C+oE9Wdln!gD$Egw#K@WZ5% zP2VHEv2u~H6vKd-O>5q{PzVa#HJP6Y%6CkyP8y|B;MAgR^obd1=~+LXDvyaMaLqka zx?2OTefm^lulmcBE5$Dmt73fx6GYLZ!jwOCx>M&z%Vtx<12Y-Bm!2?)N~Ng|Ij?g{ zU#rY+j?IIwnMc20(f1?$?LdYTUz_-j$?ufJ58o}I^7eQp(Ts$Z+VFi{ zCVVoo4E6@<2;2_OY5q~9DVI!GSNIr0(AnGGaT8io!k#MC)7rU2hnSwFD2q2i7EwyH zwG%&7Y<9JA2(%2VZdj#xpD7r3G4c2SnJw0ArWyGucu3wC*lM#ug1Q^MZOPpU;MgcG z|6U|9E!@~gU)e#zWqu&k{qs-~@&29(ER{r`d&^x2`NO{*y%v97y;}G*`Mr>bvW?^8 z0@9RXk#JtiLBgFCfjyB%biT)?SBIbSa89Pa^E@*Hj+RK)!RlFN8C~%) z2jB)oyBCY{vZ6YgJdZGG1)CI`dUV98$LXtvgTKN@Yat`1WW(c)?ME{V5^vnXH9U;@ zqCHT`k3qFB2@}EjI_;g%89jHCa&zZWi}Ald;JBL4!wYlkj66103hu`4nWrCD&yrL9 zjFb2ujbQgDz=1C}u|y2yh-m1MW@`UO-v}Z8vU>Va>#1R+LU#bscgT`IMl6S!Z5-jf z+^@49DYE;$n5joV{L=Fv`+@NZ zS^k=8pZ1zixnI}6@0=)w4hla#jS2fF3pFp>FO&xEW!v1)jhkRv(r`IV%=7PB=*rjDuP(=^uyT3wY)zbq!+ zjP&y%mp>W7&)U^+Cb`qXUtDV@URPP(RFvY6|1waUR=VY=Wo9WoO$cPzjt`Au)bw=LQsY_b_cdI>MRSE)dPK zF~ieD!dvbC6!s^Tw5Ne48`X3_1cg~-jsL*FSd`|m3L@OpwsI6W-Iw$_JzjU_n=PjJ zD6j-m02iSdSJV^L>JO)?heX5c)6_u`hMhl`nzKks_pPwXPu5Q!x`Z`K(uRcf2H3?A z@tlR?aNh%w$0}@`H#bVf>7b%0j4bbh1Q~ZJ**RIpu)R-V1|+WwqZfXTs@H}bUGo$vd>9JLYuBy9Ygpp-OVi$XbF?(&ysfiS-sxH)wZOIh)m~|ht;7Qv1j9+~5lfB6Bro(~OD&xcI1#(r6Brsv`76@-0S@Fqdr43-vo)ddvD90U^@X*Bizs-g?U+rHQPSU)&*eDY94E2M&>T$1VNr zpYR1T9d(t}jFPgm@3K1wPQuCY9_zG5E1k1e9=NiC3oVxu4;JM^9N!q-F0_i+zNs#{ zMprmrkiE2r3tYfDSvE?)!8m3z-K9dJyi-=FmbNhD2B&W$UtRZ=n zkj%noK3o=2HAXED3W#oa?iGb<1lM(8j@zxz5+j|qruh*Dyv#`#O=fU_HLLN!KifTV zx=$(b?t!6An{@*r)%PLV0bhC2I|~n_&6K{$pHoaTgSq&UiMpppsu9cHH4ugQm z5B#$%W}{;D!3^Q-8#o)ga~BZTcFhsq*7a9i-^&Y1G5+t~E{DNAtI+RaO5T&~_D}pS zqH~-EeqZV5VICK4tjl7NA`87*0yeVGKsw!a7AN%X@5$5g$wu&u$JD-7t0z<8km4WJ zl|gbh6(tWn3ZWt4c>RQ=Vl3lldtDtLkJipyEw||C?pdXvD}5d7RZ1cXv&q5jG{Y>- zEziZWy~+C~)nC>=b|+cWrfn=AVMv;A!@28yyJb7*pJrywg8L-bT(catTH)KR1WU{X zfNY|%arw$CKB^Az$~7wM5_a1fn(Gs!ihJ>lo^L446#OvzmX85f0x;O!A?X`Vt`^U9QB#W&$K1K9&_Bn^Z#c7_(xS8bNJI(tjiA+ zimzz*QdOBt46L!vic5+II`cY>tD7AxG@gqp8b;7TRaLZLW0LK}QKZwN_gLnE8G~B* z>f=ajK-jxYj#6)#=%RJZnqvm;zZb|WRIP*$7p728v2iGr#hT zMe|o4GOcmptAFWLgZj#+n>3cp3_-2~(=* z)(q`63fQ+Vh=t^YDK%N`jEPm@!jJNrrlU_W_RfX_PnAvel@KyFM1e~ryX}B>2Yd&Y zr;w#`$ig9C+Y`})c63W~BAU)H*IDLlOPM%9vl z96gXJ`~@a-1RNOp+O{7l3OOuXGqRqWLsn6Sq~b50tZZ2QP_CS2KD8P;4ihbYe%?lK zfvM-F2*b+rCG5Oiull(1qiv3H@uw9ZzeZ5?+)6ckReKHaMLQ-|ZFA;*(icNs13pX3 zbeMSv!T5klM8L#j!Ty%cRzt|IxDyl6Z#An>gQGS5Tl8z78J5F(Ft?ey(>^pz4=cA< z*SKt3$mlhpR-)N$|NMhXSjh4BM~u&u7gRpH=~(|b?$`a1ahSBJ%g54h;>ZG#<3EZ4 zKb}Vw*XrfYWqF5-e2K`ZfZn)JQsA+ei2_UzHi3}c_E=@w-eib_%!m0U$;)O0{J>g? zbvJt($~DvK| z-&ek1Mq}TN2Je3L+i}c{M5qwkt2ngoiDv`&VXh(!`y}c7k^IH9SPADGhcnjwUYr@XVm#Jh#WOjkXY|;P`Hj4n@a97T%4v&u_ zd*V3WbY!cIhjZ)eH*pgtE1ta0Xu-O=)7t68^gBQOmV#3u{}KA#Gy$PwwtM8=DI{~G z5OfMl#@+sGLE=jW<3tUHMoimKJ6>nnaFGaDMQVm(+`y>?4FN^R(x|gt(N~+E zTsY_hG;&DvQ+KWUNfsWnL|GKo zoES?*?O9IS7`xZ+Oj}-iOP3BvMd!*ojwh4!pb%#!Ex$>9-aE7cChb!uH>EP=V~hw{ zB8KT-5kc@0XwuT&7MGG1VLDE}ljCkXdpFmWzOxn4`(0Ve4{A1zc@xdIK~IdbK=m|w zbRqMso>^YJ^zfW^%tep_(I76x1;8QnN;_OPLOGj2_epa0u~b0QI-qq2;V)z+YI;@RvN-wqERHf+3U2lv z7kc-${5^I9q9BN0fbT*&Vs~qvjj0x;@qhXl)ACY^t7P@eRLm1VT!5CSPF9go9oOTx0+Ht*7lr zi$!^uEEdI8|5j(T&`xUI!>I=F$Ah(Cout0RHqtQ8Oxpk~4gB&0WgG=zO=xqsm?e!X zaXv-6(5qz`eX7e6`J@FLojO`fo~m@1#-RLO5BbsCOyph`6rq_DuL+;JqH&!N)W9c1 z9Bxct>!fxr575b8kd6xPbi)6WG>`iuwI~gJCEL662~?diV!(fTFpAUyP;zvI6`UDO zcQv?->rUz*Tb%^<#(ZeOWsXA*By+$Pi23?6^${THucF3>lX zzC}~*%0a!Qd(qny8L{L4`FJYLHal&xaoeqava9wk4ISN<43ReW(YypW2=G zD<{di%q8JTZs(tM|C>jVNv$|)*z?NpXYca@y;KnV7E3g^jP@~paJU6CvBBxXyAo(j z!U8wC+iv4k2bvWzA$9SD_PyWKmA{625b~*rkA%%nKT8Tc;+A>j-hqeZIiNv2GQIF7 z5V`l8JWBBE-co~$Njki7YyuIDa$0Yua!BjD| zlUXMWg|uX8LZAO$xIiW1eVIovKV$}Hw`rhmX5^tI9#94%OZg~BiU2KIZ%>II1*WM~ zp*Y&X4D#=#fPwP1zxE;grFVN;`8gw6h(t0evgvI2^M@d7Nka)`}I0|m`?gKeHfP9Y&-CBEEkoJcda3{ zk_|zsTRN||n$ZVv)j|fLg^v;Z&!EdSt$m0N^yohuc!3e*Pn-A)*+?zw*VDVQgeds| zL|PyWMq?93R&>+QFDN#W)O{1P*QUR(%#AGmahGoCPnBJvnu7?h5!t5qUo<@$t5>@O zm4iPC8SwA+UxWXQH-`%(EDBVgk?>QxaT%3WMI3Qnebj(eAJLLY(?pWnQ^QVd3XcJR zCp(w$PNQGn{lK0$Io@4JxR($oR#F5aDI_sx*9cQ9z%3E={9D-?d5Lq0kr68UzMnB!Zzi`#qk#++b`R@3NGUF;yUn~PS|-V8RqR^y+Re)E zbTE3>qP?EUd2*jUFBLGpU!3C@5_eH%HzK^vmq40=RgFxk!AZ_W!{Xl?n~%}TAIc6H ze+?>OcP`5w5-oi^uQFxQ3ZTi(_+a@Dq5QP!jJuwrwTF$>-X!}xliAK9YMmx~w^5>I z1p_~++!Cb+kuXA(issQ$OuX&WHWHSQXkPe)d|0M&2yX$(^Wph1Vy!pRDV>BK&uptQ zrnOxOqUq$M3WVW0Hfo%>DTiHG+0Gf_AUbNA$Kpr2rIXxqi>NxqoPlr@Sj`=}yxx+e z%nO$kt?tX^r&zN7M`N$!gLMxaZBCTgK7hyj_@#IOOy*A+nsR*e61?evz#|fwe{3aO>r_9@TzJ#Z`aD7&s z!kS}?T#L0`>wi$@OPn4Ov=FNDiuCWMKr4tr%_N8L?DNL44=_Q6+)yH>beb$WP2KNV zA|Qt9J@B%=4rcwI6im*bPhEgon7d}8og2>u%=`F48jW}$FqCyI>S`(D3; zHr~H?BCFN^zgl6bJ49jgExo$xqw-#kdqgG}lcw`|KrE}`nX@8B^u+AVTFcT)Se zq%Cd0lT(0tc1XL*afiE|U|VtrqT}g)174M-m#@@T5mjp*cJ9G#4~e^Qe|@c*dA6u; z8|@Q)-zx`uv8>$;P&SM>2T-1=s$?msVAt1&UY|Dfy3w&X+iGUI+HchpM&tf zx4SY9|HzV41vqouo2@Xo{})05r(rJ{=PDCsh1s@+`~Q0+G5RdoVzD4UB4eC7d~Pd_ zu9=GW!!bib>m|wrN-_JuX~bTw+;SQ%!uU$h1Z%8xU+oo^&c4t3#;G~3IZC~GuZU-x%*!`kQLmy zD>InmWNVFkkv4i$(QEw#fH6&UYe)*5pUj@gaL~_9jt>wR(>L4I696c$;@SnP4Z!VG ztMrUE4q5;Q^FspSwRxkQd-B3mv4-WKj*&pTj1fesG}&hz!8T0F7%9h(Nu4kXKGocg z?Gqyn^G9JU7(XrX#H0AQ(!8pR5`5BQN3HsO+^B{1Eo|*oF&ygI=_d4dp5!$P=(N-L zl^M*w{6~ewOXbsS(_xloaaynW-o1l*GCvs{`StN{QYk7q4X1 z1d-p#U*Z&7F@TlIrgu(f~x-lri(O z)Gzc4;0SoZ>V^Shs2#W2?j1JEf7}F;JkzJtg`s7|e;nfmvKQa1vDt+6c68wWoRTrihk3!)1}_>YwXpJ%clg=2^k_oLuGWgbN)nN&e~(DAL)OLwsYx9W-K=nc;NS-(=Ey=JVhm2wW_USm@S>YT znD*NMEvbL)ODU{5)~e<_ca##o**V#@`t-0FvyOpF&hjkMzzT)k&iMq15fV(V<@YCN zAydN+jOC*(*dIWN%$3R)d{-NMpQdZTrldVizqTsK`A3RP>P3)TR@+-tAcu67DWL?+ zE{L$r+|N%NA(?doSiA4_95n3EcN4gZz7a4g{c9;2d)xD zyw8N8iuj)s^MLOyk-VOvXLWyNXkv@JIJZAoJr`01V?5#gr{0^nUKr=Z z10axsi6Uk(l^Vy}0;_mQ;{!%UUO}0XO294*RbcAZ10(P1fD1d#KO*ht1PCH^yE7JM zu>(Uz*Rt*s^Hjl`^YWiW6V?XBu4;K!n6G;03l2T!ysek7^ShX?m7d(-Fpm%Svz$8V zwDc^Vr61?(?vzH9AQR*7dCeBkz-AMbApxXA@oIR?<;9+Mt{Ww7JG>C#Wg~|uVoA$Y%n)^=E09YP%Ug+E;gHy!x4M8 zsI`Lic2Vqq53B4N!L3a_2Cwvuuw*=yW>NakywXv&P}e?=7)~eT1`L$B3Snx&N5Kaf zdhp4!KReH0YB{H&%0@^e*cZzh>}D!Bj7WlycG$s0CF>WvxZ9bGq|zW)U0dxtFktu9 z)LGx=^z%~trkOL|{%!Q*Y8|;P8{UR{O;djQ@etbh{R1fEJs`I1kmE7nYN06v?dNYy zHRDToqrRj|QneVZ8Hjv`9s5N|kUa6(l3x5e4FmRviL5)3I0mJ7bBC#0<@@ zC$dk%aqa_Ijq~A21V8Y0Pio9`1wt84`?z~0t*S;Lniko}ehYp&D~TVbO_R0r<}yM!K-dcWsp$7*K_1z;NLN(CtpRBl@2>xU z>EV)0mk0!4$1A@*yWlJxVrX_rNR=hw-)0{^35EnqUA*0(p}`p6i+r6i#fdoa@O8DX z0+$YOQ*!2MNr2{vYgJtieJMiwm2~jZje5u6N$fmrB5~LBV!Z)8Po9yX=v?|X%egK{ zbIc?_EYG|l%Hh+HiPHNDgVew9_Jw6xy5rvL$tL5GyNa7lsr0A-H+OhnC?}rohDw zBbDM0Ei8Op{<>CSQJePJkc7qqJR(Hoo&&k!e*5QsqcHWM8(mTic2^50EtQN>neMzzt)Hc!CU;zr!o7k^hAmpKB?%LS8d0MdN8WWo zB-o5q4L$C|Xp*oWA7rpSI;QA)yvK!sj`}~^$8aL7$X}fkFH67R-G(^vY>|gQUM)>* z2XF0}jsEA{=4p7;$FwQ(9g$|~*gBaL(vUu`cI1u@5nJd4@h~UQ4zV3WsBF!~1jtg=F)Wn@_2gjU7)tPkhvLmZ= zz9~gazYEvURgn+WpJkik#WLFr->%7C1oa|q=7n+B38LI)%tC?9r3|^(L0N^g9Ov_L z>B={pRfmz?_a2kYSNKxJzs?b#*N3I72`C|=NWnGSd*~QNf6}U`R!QAxy&tpxx%kGf zEm}vP^DWAk5hb9u+(Rl%=I(`L#1(GK$qu+Nt9>Wl`3h17*E82m4)%w$;e2aUIpn*W zJF8+o3Sup9B@G~TZ{g&>t``rRO-npge#@LRb`F8f%X`wi+N9+_FECXgqH+F(D^Dn7 zX=0YZTS~iL2j4}UrLD6eRA`;+@76E;~JOO`FAgVt^m4=@AiMSTYl%!x;ETd zOAIKbYTM1e2W=3+w@$?UsdV3e#$bG1_DL|j29o}@0RHCF`s-bO-ysgxdL5$uX?rIJ zzRl2ZnhK^`{mDO_MH6Z7if59=Bfau$Drld#7{y&LO%MBY2zvu^+nvW=j0ySz03rb; zy3%Sswmj;+Nkp-T4mR~;xr_Kwo{Vz;?V;P=LGMq?`t#;+w+0%UZyG;H49r|Ks7PK; z0K|12sQJgHPf_vfsb8=qySR#Lu7mchsO}wzdyvdc#CB3G!<)JQZDQVZk7Z{VNaXf5 zOnv~?2%lQn5uI>E_Qs^y75geMSin?It@%!fw>ro3VQNwGjRhC4{rQX|O5xX%1mTiW zh&!>|%ggqA9v+6q1nhk#7cHZ!MMusAf%H?@d1O`vMfQ6s3iI;me<4R42cm=p)rZ28)Zfu2Nu`zZFNDu`TkVaLo=K zk|1mxv^9CY0D`ZU)pzftyqTwT$k#ft3eCPgT>|_@h5A8Nu=L)V{v(?7bgJO3h$k$6 zlHo#dO@3>(57&U2;smH0X>&45%Q#O;vOUB~?KL8o^;%JM)jq!Eg?`25p`Y}C$P$zE zAYtHtEGxO>cHyp?ZyS=L!0{cURX=?A5PTa246f;YHQE=pP&|-o{xcThSl}O{oN&39 zl3JUPu%>_s3gyx#<5$z1?K5W1(StBl5Jx#uz3<=#-SUn3TIvpl=xDLcjrI_^BbCBu>R3OWvu28N_Kk5AoW+ZW5dVt1|QXHzK;?F>VqF_ zSb1WRPj`J;@t9NV{DOWKau|Xg4=FG~iXM)enP7H3Z22o6hYjkw6J+8PR9879^fu${ zE^tJDe7hvJI70gp^MBcV|wOLIyGdLwQSzqwg0TozaL{iU&fA0WT7dTK#CjH3eaP+WN$5Dso{DR z64z<1gP26o$OKlQw8dxn&!x^2Ec!Vlb@E$<-u@eG2PDK*On6d>?bU?FcjU-nuLlcE zy>7Xi)>ZOJ+NO7%d1P5=3d0Rj6~ad5#Kl3+syrn(#v=~{Vq8#cy28Q}NN~ho|6G@a z;;_}d2+lYBghezKZ|QR0qzHWc|5<>U#I9ep#9QelLY6ok+{ck04u|`2K2*53*Qocd z;#K>GIh*3#yW5W@vwz?c)Vg+>r3m7v*t!)b9bI5zjU zrcChkfHSn3XY+)3lm46EUmew)0~Tx!+xuA25fzKC2^k-PJ48Oy6-1t=8fxUSkP!Pu zW)zDa*;{+Wb#f5CP0G;kx1gF~8>Nb7^WjRxTW~sriPu89(^$4r+{j$?9u(eq9a>T? zmGk-n_S`6z;_yHX^-!UgoiVhC2U1) z3EUJjF~RMd!VerYf-vfZ7xd{!)}P>R#)Z!)--%|#A`NJ%bq3)11D+XX-`Dz5E|LK* zq8O_6n^F-ST<7y_8MfBe)+(9ge8|@aov`&Wl*|DRI{s2}SHbyn$?bR0(NKe)=-VoN z->q^>Cp-+e+humc|D?ce%*e*hyXNbhNu=kInu3ougUS1oaziEOiXo4ebP`l1rHO# ztcgcU%CBnk^-HKZj}Qayx5(QWZ!jOi544C0EWDsL({zql1^CwPCoATb`O z2qE$VWZl6m?nv`#+u#3vVk@gz3r5#kF}se$jkL82&^}mC34w{rCqx#Qu4MA-u#RX0fQ(!HCvHPmb4FQ0`7qUQ6_0D$0P4uLdPkGR;2U9wnqA6)v6EU(#u2y4cW|%a&|5A{bh^PKDMS0|3WhxR!oDML)#U{SdC&WG^BIxiMh?-eN*7K3_8+uf}+o`eV(BqO-w?}iNp;_rb( zPo4bb{TFBiEQev~wdq>#|Fg`F=@{hkU+9t`!%FhG>(sC#6|VTTkyuDZ4jH0qsjp~X zuZa5s+x;!yWtOU)lHCdS-p2JM)fN;;+#XLuTYYDF=uATtfzf#!do|TnTNjhvbNepk z5eQY=y1@G2cbR966>bN9F(B7IYBzy+y`W;7cacdthOvgfE zHV3nD`46u%z1O#dHj9g_^NWOf*^-hK0lb$CMQh8p|_;GXo zCYLQEdPVQFe3I8n;dX&Qsc5O!>-*F3S7JqzzFh9R$@+*EOj5A(K@I)3c_y{pQusv= zjZ+suDo9~1-CEXKOCMf62rW?goUrKhrkfO{BDCg(2hbczVQpqA?9{ukyz`H0B8^oc zhDrAojpIs(WB8Fl$<)vb3l>7vF$bFOHl3Z^&gq1^Urz8&h}0)m+HZZW&xx>OEp%kx z%#SkGn0zP@CTA9PQaV}c*|^6z0)(_{jzRPUqh>H5BhnrBDAKL`NMy}Jo|)#>Vedl< zXJ5+djfu)7j1UCQUB&Uglu&|)UX-d1ecv8=FDCU?q3ehEx#%mCnMt&WV}CQ-THDYd zjD29q61xaB;G%^_?OzJ9Ha+yWv+nN}fVz%7s#y`FeCtdKpLNt zSyLX&^)=kGAtZv$GdzN>AcG!nU=*AI2eCfjnOXlGyx)l239V~rq$Qz;8RrA9hxekOa%+oU|-FtV;IvH&KFy(34XC z!ApPiz5D_?Sde~QPn*TlV?d4v5={N4C~E#9cVnn9#l)~ms@KbKK;n>E+CVcc@~o7c z9MlCqkFaN?aV~4UG+3=!<+ys$9rgt;i|&z@fxX<(cZgIeHi?dw3gW_F4enXbZQwsb zFHCo1+WVIk$q3342c|AuiIwWDW$4Ob64m%&Teg)4!Ed7VeM#TTpaTEPPLiY1R6a}H z^M5IWzWKo*hb#QyN{NEXsiIgy!n8O)#)oPr2bh4Do2hr=Ui^Vb(99YCe*UTPpQUTW zo^bi`-bkn3%F<%19S*t(X~vK{7(AT&|b) zdJqbZ(e~gf8*#=$pALDP}Mvdm$+COR+WPGZ@{oVPJ!XNrXZNS)@qS8%5SDXxM+bQUS5F)l4g;s zURl88Y;qz}r1^Iq+d@b>)GbyL+LHSu7|qSfnm`^`b%Tlu-7x{R8HlDA^(a2)O@=9H zyk|FJe*B>L>EJ=oHC4C6zT%tS(i^oMdMRa}`L8Ro`#Yq*7at6xYhLwWHynXqooZP2vFE1GLdtJ>it@FEOd0teODg{lRnawx4Yv%WGVs&YK^0zYp45qGm$;M5W; z*G&)?)xeCLt5)68MWO5{AvhO?Pb1%?`PLr!w~38?(Jyrhy%IVkWLTg>fl8 z9nO;*37pRo2L8F)Nx~aUzdFG(8JfEmqT$vw~;(X)#{e9Ih*Mv~PMYzZmP4k?0-ejjOeg+7sNF zOqqqk4}@Nlvc^AHoypIKhX4JBN4$%v`Pz5luVueD)=SzqrjKwvzzQVe=)XlrL*|(} zN3*pm@e#7{>ciX(3fB{)f>its`BjKxmMCP;5UiywPM55H2qC2q?5Xfg$nGByxI)+I zYiE8*3|73=0Ywaz%6n}-ynakeeo@V1zR^3hF)67<+s0Qjz`S?&%pF&Y8+4ID^Dh@7 zNUL&2IBiyq$GTC`U?BbEu`n=%Q@$)CBB+8R3cF_6DBzY1M^36{E7e;+*BX#-WZ!el z%mLIpU-&D6hKSk#^1q2%u(%}KX;Ud2@3P~(uCxfI#&IPcd@gsHD)Kvh3R1T<;HK8} zfXsSQlnQ2!%QX%|z8hrXM~hQ?N3{+>99&d^gP3~9G32j-sw#A z%o$El^-`1F#{b9OdxvBBzyIS|5i&BfM^|etq`mbNqgPzK#w@$Kl{|U)S|~p3lemI3MTvFi!61ZjqHl#}U=i zFi`tq6fYUBE>mZ5gy|rzS7tt(PI|c1BUy-WT*2&HoW9`n4vqiLH4H9FI(EUmU^SLd zeqYMW(s$ED!D32`s7NV-0WKd4(d^Qq#{siX7VveX^=4l0Gp=``CC?+=CJ=Tc4|eyp z)ESRjE~2bdpYFPjblzXt$SR%!b|O050dJTF)*T*{EN8!^m&Wq=(A730N#3=%cp^WO zq(kSC($R9rdYNnYgKjy7)UlpqwiMOzdeB>;0Cl;$WD#Q5+be>Jn@Qqn!B>T6@K{;Ujj0OCa22NOEkdlyp_^UV zR3aQ*7GuIQXR)f^m}Ta=avvc%w-hQUzq!e;cOQs=8OTa(yb)q0_(1gJpvIK)oRU4Q$-4=CVPMc zEs2=D?19E2lp(|*BgZTGYFgnDvk1Co>ize`6VvN5!tzy*uFwz5JY1*N(Fpa98IJXI z$uc$x@QaFd>t;#Be{t0;P=ZpLOKoty3p0w^3|E-(CK|T?=(kLgq#O@~etHVUSG24% zA<`G5rm5XoHSCjv>~UIY%U}FRViJu`{X|%=d^v`x7uWgv6gR$B zJRMup3k)%>yu==hE@VY9^7<9?*p%xME<*_Ii*fi`tm4`4`-OrW$WNr-&E9 z!eH55X+fK*cl_ia?vvQd#!-h^&GXx*Kiy)_Mnr2 zTsgOjL-9`3I|nbxm2WinXsC@s17eItdP{DcgzVbF@Hnr^(ZifyMfZgTu}oEQVr2D_ zVb1RYhb&Ir_*gH=|%E#FcFScY>=(a|k7t{vhzWHhkMW}3*E)Kc>$ltF!A*CTm zRV!X3Uf6zMv_hfrG6o4vLh)B@-`aQ;Y_Z^5y2GT7Vas)jFOcU%H-Do6Bm5f8ox6ER zZox0xwZh+P0^KB~f@AF!)4oHAt2tc;>&^sS6uwA=Y_Wq0Z*KghwPDF6rwdiH%0~># zdh@>0!_|I+34T<9t&Ko_ zaRd48)st7Phw+&SHBuLU0t3TDvU1Y__oYgo8(VVMRv~9s55bN>!n0Iu4@SAv%Ox_D ztZ6R9+i>AsJTG?np^_|^!;eFz3?7eer5;#>(~J5fXj&@>1-2;VR2=`&2CQG}0r5!KcrdhO+l=N&L-^0%GXlOTKR-3FqUi-DFmT zZb~O+Tu5N$sBC4d)=GIRGiZho>qO~@FyP#`zOkL(5l4RIj$;j4(vxF7{l{davMNO% zv~nueXm^jD(M#1d1~wtNgoiwh$1%HbNo;gO(Bi?wSP~9_w9u!DBQbIhYis(V=ksGt zs0ALL+hO|RH`9*1#Y0z#4ow1oLPN^q33|UG$cGb+;U2Z<9ab~NQRa-dJ$Z&SQ={Wl z#cLzH=cy1)I()781!+#5K6B1ld${qsY|E8SgrIy zh_B7SX3D2Nm!TxbwbriIS5FX0Ou0qzBN;hIVAy|p5(+KXpE+2VHs)6!1Sl_EpHa^CBH^mdl!M+g=eM*;8_mlrr;|eDtC19`6crK0#IzgfD5_eu6>v<{szu7IVx1(n}>H>Wzp~E)v)3XtPe~ zk$O{xd0YC!Z>6ln6~{oscJ1&M4s8@yNdh#@Ih^|I(!C(I@u&UZ^&K7q!xF9h%Z+oi z>oFvztI9ntIl9mwK^OHw#@+Szx>Vy$Z+wHe)D~jnQYcQCOb42{-5t|42JnQX=%49# z*jthW?^m3$*I;Zxw#3teBFF@O@g!qm-xpeL^CWCCx-@75hwi|g$Uvl!E2%I0q>>8l z(#+@gx*6US82yGExu=(HvM(lZA0 z3aG31&u!qOD_Qr1oNVW>-9CXj|MlynMre#GeKO9iuQ^@L?^7+dXqpY-7RmLkEdPbK4 zd7?LBZH#j{NEFqdayxOE8=B;CHz|e2Fp#i*C2cdqf9@`~Aay_e-kabAY`maeYL}8d z`=rr&XV2rO^u!{=4(z$UPP%WOYUMjT(7$9}#ho%BR$#FI6;Z)_Id})cKH;P>$p!q4 zbKMnFU_#*@JMBI+JCynM}ER#HRrP3hKn8+RXq#vk&6e8ZKS#Xp?$R*!+1DF{CfPDcK~Vhql~%y6qInVxFT zsjZYjSJ$NYq7ZRRe9W8>8m;2-il`o=g@#;_W+g@5>yQvxvCgmIovLAE_hx5;=^s)> z?v9Anht!Q7*OXKiH!Of6=;SnHzqsYl55%eRUWupdPj|4)aW5G`zJfPyr+AfH?Ud*B zQy6R0;}ZjDDgip}7L(8fgn~%;VPYV^GZ}~fCv7dwG41%Ru*+?Sbbb2u zKkI&cl6_I!F9xDXo$?ZnZFK zZXJzX^pEoP-gBn`gUrm|$G-6xAxr&6*(sdwVnkrlWKXpQOa-*!U`ngT2F`ONuUh=_ zOmW)rR;c$)=S_7M2v59^mJ1T8RTM_zqOSL7%k=1Gn-vp}Il@FEH*I1&KkW^z%dA1e zglC~XYB@Y|`5|Q!le%Kh7HmoOWI6l!Mgk_p@QM5Or4@9O0&;{S;M>dwA%krV)zZt5BQQa z{q-|mhg;p9_zAoFChRjGG{#myByfJ^8aOvZu3jS2I2MyzjWu^Pesp#2XNJzPJG~&E zMsh*|OBjb*!B7lUE;c}w0 z#O+Y4WPC{|ANI=usk4jvAwxc?GW{)AkEO&>Gla;6?$KO*jpQ_Gk*nKdU9~hZPibRb zcVesH1Y1|$Jt?gkxGuD9J;a?&N7~A;;t1xEWa1OOHL7}yh=`xD^Q!$cwHV^t26yX& z8NDsqJ!(!AiD%ix?Mmb|ROlqz_AR>reMCPAU^bz9iiX&84sY~N zAOH*8PE+~Gf_At_QKEzlcp9RfthgGC>=^EVsI2Mht`VZ!wq3O^T19+@eNW0HB2_BCgH4E=#&=A@1 zX#I>{Goc|K7E@b+jJOno14usl06RP6*9&3Ip?7@~k-~JK4XxY}ak9q=CTO_nvSia> zT>B0)UB9YvtoEhrT2vPpr9GrkK|=e=MGkX9DzvJWw7{P~#g>aeJ=)s1J!%TvgQMNk z7ZUi&8nmDXS2aO}gTr(C4K4vjc5%EB%jMv>^dVtBD|~Wz#g;n4K4hyibq6>iRy)hL z!aMXszuYW%V-eGopDP${uxkp;9bz!}4GD0{WO*LR#i~Sj4@f&EsF7lc$r`W|bUm$K z6I6FKa~>etRf3%+U|boAyS$(4%qu+3?h#MVqOtki2lz_%ty;%n(UbUWZ0Nr-m3;wP z?9x(iskgy9WAIV>d?pSug)iGzh9R@wN{uVTvHFH5GVgc=*Pmq^lR|>2UP~%AJyl$z zf`}=FN}(TH!P^QV1CS6rf7$WdP^n0+jGF$JX$J+?oix`;4vxsI$*HPufD$7O#z>Q_ zE`@Yp_s1VQnii^9CF!!O_Jj_u?wUlaeohDNQ&o$;m{;$S4^7EzgiZ%lHdc`n-&J{4 z8H@aDt)=NwE! zv(;GwyeAxoq8#~?{WGM~B1A>{_p*FKLSo!tr-zG)3%tRpUbMqNV<`$I@Ars3K3+#4 zII|7bV?e`e@e!7PRLk{JLCw37Ftb$(CUcwQ4!Vo?{6AU zrdOfpgz?$34Ab%UHOiu@WGJJHV(atQFN>r_4yWUzt%wl=oiyqipB}EScO_|sHS~Ct>88iu+q^J3N=;>)m@2jmqV+NGw;_6mW zGo=hPFRXeP`DGq*Z3SwEZ#G|ic53&vaD3sQZ0kpHaPXk`Q8Is-jP;Om>8;A>NCltd zi|i3YEKAg^4myqNz;f>8g0n&`GnF7FJnr$Mmy;CPW-_uN@fr$ikg3{o(q0kal5R2D zSI{)iqxr)@&{5Rk-Xs&G8$0vtvMI+gZQX?E%-i~H zkGMQu(_Adh6MG}Y9jpGGTcbKg-B~+>-@yJRe=l4{qwiJKr@0;zeK{~`x(g;fvf7bIN6Vvg?)Iq)T{jv~U>x=v@yqG{#yzlp$x5eU zXuxqjOggePd0PbZ(e&cnqtGS5coXg#h@@0JPKwiGZ@t&@)D#U1*6!VYwjhp&_ez$c zLM^C)sf6pp>@73;nWe~-s-Tu~1y-lGsstfsn0t>tWcIy6@nOE2-~7&pslF$~5kLI+ z!w~sJgRT*Crj6YGX`z6-Exx8ifz8qbOq{IuaUqA>+R3iWSvDWja`A)qcjjMU)>EF> zn-3UheM#a&!%PAI{YuZFE2X}d)so`Ueo4P1oiX6q-K6A^9>*tqy#6RgvyWpcyY_C{ zbuk#j6%JBEce^gg3KXWdJ--wu;aMCWUU;2_Lth}bl9=-wmow3&Ik&jScjv~(G5Amp z;)nh;yk~FpI{X^CFc*aa4mn+U)E(FU?W|#SiL@0g<_Cwg6y`!U77-x!CRAAfW14}(W7Eb`$5-x8O< zdXMl8QF9BX6EBCsT?x}t;@A&rk9UO{kne>H!Vf8eU-ctuxhIuZm^e(09!RfDIj-Lf zUu%6Lr7|Sfr_Z(ekv7S3EBH0jSSpU3kfO<#RP*J1{rT}Hb2ZD0V{wE2eErxukurFa z>6c4>QkEJSX`7F@9kX7YC{h^`;`UZe(2sCLE*8Q#Z?z+DPqwL|l6N#luFVbkJepzk zemAeWHC}+)G=j-U7P1FRuQlEh_r`3u&qTSR99d2Ho8wyjrVHH65kDM;Z+*T!(6w%g zmCt=eCQ@T-Vyubm#q6Rc|12B4;$G&CaYL!R1fiw`Vz0XV2CxH4Ya?y)Jv5ke=u_ENG&Ymp#4e=Jc>o&v`Kb4SUk)2_Cnw@BN_42ZHcpy2Wj>XymHUH z8?V7z=f~e)5);HKJT+jv9PXSwilhuKe!5x!cU3$tp3*+KW3JE`o4xVcn?S`-40r6M zS?9L(6fVZ5k}m&j;sAHV-ELzMY4CNYJ0p$u_?qyY0Oi?Q?t!uCZOuxm6}#bsjolXq zm*b{}U*0fuouNw@m|Lv7e@*!#quNR}eE> zhLa5*+fi@A5p`7dd~j)O-N=*I!*S2=cCXCFOpd$c@qCL5QPfQYrq3MkSqsKYVEHWI zS$+_j5$LNcp~N|b)A#s z0V?Y)PpN4jj9uC+fA4V5HYDS~WAv@=qQdDlpBIQH=tfb|aVjE3?qH0@=LrviIfD}j zA>Q9!S$P59j3q_PY#O$pW$7E`kp$}QxVqAg5q-YhCa7Io1ZzTLgFf3E91+!{b|&Ju z^#u54#r=iOX6H^?w+EYHx((T)YBxLE85_?lOik*#i96xZxd)e{0c4cR$i4nSJo_Ff zz|kIe%8en!gTQJdN9PAN^Y_-Px6Ibr3M8LNGGLeVw`3br5NtqX$1K!QMtEuGr@Gxr z#aFkf#)DN0i94G_$~N|f$2Du)c^RK^tkAL)8G=#WXpUW(7vEr{XFnBp2Uos_F3d_~ zM#B2-_1>Xn$5!j631Wt#X(MnJc)OZ9wh_yb0{(x$MTnu{W|2DN4gveXCJKWfx%+ti zH*FNKnDwxjBL0l1FlIkyc{zG;+=fJgaPOamIf$lu@hxFGcsa4Y_>|0VCfBwB;ojc*xfmm#Kg6Lf>S%r}I2q)xFTym~kaNRb``&%z+gAns@Bo}4W% zqo*Re*)|K!%d(i_Biyp^-63d(LM=-0&=PVBx8XMb(PHh~3$GOujdfn1v$p&*25!K9y-Hok^ zYD3CrTANhVCRcHD*UrC~g@}y-i8It}80TwB8)xH1k#UZ6U~fmE3alM^P8epAybpL=c@7rcZUHgn~L3MA;^H`A}$==MG;G%(sKrU8cT$r=?K^FgKjss-V-{zl(Nw04o}u{R(e?B+>Mz#8M z;_@N}uftF1p^|Cu6-52oJHrCwn_7o>JVkqlbza1W(BkZC;8+p_niI*%Bt19}oZKL1 zA4EcZoW3eJYqp<%bN&`|&@OaX7aLUcWO#ykUE`d(KM8?5IJ&fF`oT=*31r=P2p2Ag z8f4ocAK>9jS10eb8+;f>&y?GH)`xJCq!Hs+#TB_IO@J10`0bO|Xp^4C+&YQGW))G) zY1JTAsJ}`P4yyh|cEiY~bP^CM;xJ~HNH{35MeQngo5A0?d1VmO7E`AlmW*-` z1uAuVQphYZEE=|Iw(#AFU=(kx)Z6~u-mM}%+hI5;=y{wuizav-@!ws9g8& zH#7889Xqa0TsOv2vlX@A=@%&XP!?uTS&oG*U9k(~~(`#RfeThF#6` zGM=Mn^6{hVtRiTtcj4N;ptI$gQu*TQOS6q~baC@pY1pzwZ#x5I0@D zIWmY8vIH&-DPa_dgZ6f9U8Avy`iSF93Gl3M^sb8oMF@9^v6c6ML--VG8@gGu^R4Ln zdn=CcUbvyGb=)yxis*z!E<+CS?Z6F$OFnMh{HYns8R(W=TFKv;Cp@0>hwbxxDZJR> zK?5j;nudORSh^U!OhL={XA{_EU98_2;M*X+$V<`Zd}Uq?oQ|pp2Y;UKp~!^2|G?a&HPavMz+q+YZ=sO0U9h zucFb&6o+iOO<*s}EIOh(2A7_Bx4kWZt48g0qbV$1x*UUP$-i-@*Y71t;Zy@>K1otz za%d-Fa{NAt|IrP552a1uowWa2QTO9%-LkU1!B1>qP<#EVB5!;W4sX~QRtl$RT#_}{ zp9L)^^gtM9*sHmamjP>Qw|6`+ca$VzkZL!2E#iDNYWp3}{)L%s4*#Sc)irQSWaRjm z-Nv|$)ynTcsE)(QU0KXHS+y`1Ax52tM4cZ&yW`;y7nz048O1nAilq zwrzUzXd7%1e)KBPi<dLfsSJQllZ`@pi~*+-Y0*o!_dzz#WA> zrDOIr8}GL@k5RP3pKG){=@YJauq%WQYNb4Yz3UBWSNl937^iJ?1E)_aI5?x|dCp#$ z5OYx?01_#ymZ=nk?U04@yO|-w zGoY82xIy^X8wi+n)5C|y+fhzX$b;q$hZ}yGCI8W+vmN|BT2T0b`w0b246hzKkS^x#H9LDlQ9uat&_P|fLouH?gW)st zZh|SA`3I1Gx58ul`#jd@r~SfjogVbIqdpxs)73>DQ_%|+m9dKG&dD$H z(S_Rb+02PPW;`M?Al2-1Bglg>VucI3RksiqKe7Gt-Z2fm3iRPCtQp>9YA=U9#=6&) zIbWWp8|TLjcXib+xQCiOglxyTkSRi77Tz6+5Z-*UTuS20wV**)|DH4fAl9~~8y$63 zPPQWLy>q@iK7}g#2cRWb69t6Mkyh}6{V$;Ll?&2zI%PzBH=f|pnduQ0f6^jeR$!u! zCipc245Bqy!?Utt><1$BG~5gg*crbE$gF*cil2uY=>0}eUo2}Wcn!-PTh5jMM1wZvKQXsW|%ST zb{n|ehe3_x?Z9WX6S$4gd9A9ig25hG9ERzKk&z2B-c6uvN&x{5M?mUOKu!X^J5`Xl z$42Uly3d&xbs@gn*@E$@`6e{yx4jXFI6G9wQ8O4kAPU=GL%$M%66`cf#eVSh zeL5#Pf509VM$Qj34VTGcMuif}Vi;$M`lAJ9)GUtt>8y~zR~Gmzg>)*m*rlOw`R3`W(F$mMJpC{S{L(_Y(F z2Ya-NXi2I-3!%DYktN}|&a~0`sS(K1dq#Q=^~-wZataDMi5Wbfff{!XSG`wN%2!*a zT-g`|D|QjyGO+}GyZ$sAcH2;A)nIefIJJk?#h20f=g4a(Jn*Bb2t$KFo+YG=B!`Ap zzRJ(#q({>zhw!S?S?BxyJp;+5sK%X)=mo9~=y;sdUoz?Z(Tz4ynWyBPCiC@Hv&%RO zSOqUS3+%-B*+XDQ=fLqv zM@1){VFM6}a)TD)se^}}%^6QJum`Y@ZJvUOc8Lj%raTka6}j`ik|sJk;pMvH=})}7 z&>RQjpF4htLtFEQQmbokLP%1HhuS_{1kxu|2)$i5K3y>G@!ty4YI)atx-?f+==$>yHyM(esUP#SQKJR zT@qiWk~%Aft<@QB8{Wwg6z(z2_<1mQMLg~jb*Tfx!LrfBy2uxa{=G;|ez3)4BDqq& zJpTY_mTPTDVB`#7K^oCA!d?IBbNDIf%2fwUeg=CEBghQ=RPNJ{z~cFuKv%ZrwD)TL zdee}Xc+eoiuEPvQe0R?69WZ3uTR-odYjZSNHmuxyRBZ=}dg~MBQM6H0 zV7B#a`&+8ZzHyU@L7FEi9c4d>lun0*6iHGK~&=>}_6$|Z-YKB9Hg!tgI zom&H)RRB3{#oV<&df!p5%G(B@m%vl0Xl1nG99%2C02>VnGn&&nzPO_aj)rF{+?`$V3{S#tG#i(867*Ka| z?|WR{DQ=A!ZvPKtN)8I0q}skH^?o~2T=ANZ>yt4y@T@0s@RcPfv z-=$=v0m>>NJGandjux#H0>jY5!7z1C^LCYf#4>;3X37A!3@?So>7Onm)>R{6hOB2n zgH3P3$o8`Evy`<@t*6Kn$%!O3w{c>AkuW1M2r%BVW}!LIBHiPO<5o8tMf}gSaT`EK zaHnqsu#rM(WH=ax*YTtHffee=(+JfDXjsSX&sPX=2wf6XNU5gDI*!8eD`3*Lnh7bB zi<&s+Hx!-;`ir@)@Ev~3TBg{0?tR#6%)KA1#u47556PYCy=FMPuiPUfj)s^NcThw& z$TzH5G<#630J47UP$(IV=g zPdGH1<$TO2WWjYE4DVPcg<6zFmppyQJN=7a2+_rVYy^MO_zQ@vH$FLkbH1T?7POyu zGE1VgxeX;!ChTa=A2dh%e~}837he+Vt?kLqb!K@(J;7nm280WoWw;wQT4q64u!ltg zJ*<)M)GC|y9HT%z{tFqOzkC;L2h;SmAIwpWTb|U({s17YjEQga;@|$npU}#H(Tii- z3`POm-U~hj**qt0G#DvgDk>4Mq7S_eY!WiYH0y#i*Xy_Arxv)~I0%I2V`jm;bfw&ieNrlO~!Cr7V5gBUAq+?UZAd;K99p}wp_B(GyrK>EOi`Ite^GV(Uj%2~K{ zix8?uw@D)vkSux3Ei*y356)WYPt{Jd>U5&Q-(Jt=&sBGPh)vxS>iVW;4jRr?v6$|a zOhX{dFuwjaB{u^mL=l_8#6a+B2y@Z5fXtg-6ksD}KiSmjh!ECq-0&ZpZ>-Wzm~yR* zyf@piuxTDT56LcgP(ettHdHL$qMa|a(cxBz<@Do#Mw(O=70W(1^PG6Z2?_j| zp^(%qCag7#bB>4syG=@oAY><8^&tpZT$sOq1!Fdzg2R$t5(2Sk!VKgFPLjFC-djx2 zgN1&j#EB zI_Xl^Xx8_bmQK?m;S3Om%K;Wyu3DVmLJs(S3+Bwj{*Ds(KG!DDIbJaN{LXHHqtM96 zC}^Z{t@mrQx46Kd=3x>z7BZrY3%rZy9fs=(8Tqmg= ze8H#$0vy^(tC9S-Is&5A4Gjl;wLb%VNpyB8jD)>g^(XagFIHxOx6VNcaQoy6t>Uohj*fBBk!>Pzc-Fge zJhqaRNbD!gnU^F++Va^!F5W2e?{eUS>d1=xDJ5{xn(nBb-VeJ#V%K6qK-+=qUAn2` z!)no%y}qZN=36K2D|flTp?%Am>Xs0LPJ#5AA$Z&3=FITf@wZ1*se#2&ai=yneLm_K zx7#mF>-XEQ@iQNr1p4kM)tC0wozy^@wxT`VrwD%qYtW;Y{8-Oc8cu7T;q$cAywJS zfi!3P*QBLZz;`(>@YYSZ>oTcF&OPf4d-^!AtmJAeQJza>GPt6^vk=~nWcGU@K`0h! zOyAhP0A`j^dQ*K#gDs?A&uFV@`7~oX8himhqLy_7yGMB*13C!*-ydW zE+Pr-u)kiLuy}raLNB4FTYh9c&sd{-VGIe9ukn4|He2~}5zZ_Tt=G~=P~Jrw^E>Z~ z`%m+(JV!j$^8>*W4$+3XC=}`*6GL-X`MsN_O|0>h`0CLQh+`Pv@=#KO$yow+Wyu;u ztq9NP$(k#}_?#uP6mpVV6rDxO++a~to-Z{%Ck=$$5li6Yc;vGIqIx#1jYIGhgY0`lAun&!sn>o@&h>h z!~Wk%M{rIer6l+K0zWP_&fY#dXA1Q&+WyYgTQc(sGl-jjhem*2Sx&R@qz$M-ezAHD zSFbWO-F|TP7GIKH`Fsa2Tj1R&lT<<+%*#SozHq_?_He0dIja!1D7eb6Dg!@J#D}-f z*D=6mTx4K4?m@G^w~7JL%O5W|en^Q$oAr{Gm2Bey=vYbQPWrE?=l}Fiafb;+3A3ML zn2WyxOXj5kDW!|g{{)uYj2mxrGe9(+m*upbwP0evvTG4=sydHL_?8egejWy)9|OZ+ zpF!X~+#w_rYwqvp-R&>*z6hvE9m0kxUYoiaxVu?jXwNy>v#pTz3%`f&gxhO@dXWH0 z3|xP8v%>R=CvUzZ9l+)08v!GO9#2N{m0!xSeKQo;JAOKKjg4W9gKEF>ye|1KZ2kqT z!ep#b=hDBl0H8+M62CL0Q8IYGG;tN$E)OG#V_3g1!7&zU{L?wYo_9ZP4Z7S8f=q9Q z4{Cj0$Bi~B<;ih}GSfL6H?eOVZ6Y(BwMa<4+S5uFL@eR9)N^@+; zu_m&Pndp>OBfp{Ofp##Xd6M&3(_oafr-8236YVD`F>kquZQ`Utn36eF*1s<_S}ZRL zUbQ-E+)+B;@%HagFQL%@82*W4^()p5?FW}>9|-K#E2`pNTp0WxDvLW+=UW9T!%ggL zZ*4i%5{e0+5AR$7D7M+3R_eIry3QxIn*oB_hb1sWE;H--hhSqwU+{2A2gPQ#LmSr2 z%`EVb&v?%45_W*@%Jnq%=}nammp*CRDWcC>3;BBIh<}D)Db?W*kzQjNrIr69cb=96h`c>?^%% zxvu4;5g6(CmVd`r^S)hZ%l98Yraw>%`%m+0C&`Ep)-_-)>f>~Yzd4Uff9D5$_kQyO zXm*&a*lpPN!Cl;y+)Kdt7V!xi;x(mdg|w4PX=M z<77e~Fk}ph4!+>V|GMGl#7R0Eun%CH(O^C{7M|`8fdOza)Jera;C_=|(%ZfeC*&Xx zY+(h9&baeibsD?@5GxrJMb$9dq-^>clc&9Z0jOKe`j*|2F@L}gSQ0OHs%VHZ8Y}~q zQTH)(GnL=pdrE#DfYI#!ge~aDXox@%^oYe^g0rG)46;6Ol6>t0qkl6w@+0G%5 z1Asuj;DuNc%C}HXRG7(CynTC14_jtUX=${F8GJSl%(`SrfN6HdAfR|*cIQxt z5?vd_+iO93YjnyEmj)kCQ)mo|*Pa6-h7+1!R3WI101Puq{@D+JpUe+Xbla#ZDd}~{ zuYuK)-O4~bY7Ke}KZhyxyngbh8cSp)1c2T8cj(8D=YNlWhCh}WDi!2_4huFFP|1kj zWCfV&-ChI;p!jIZU~^Im7fmsrypU2p@*rOw$s0aq|EROB_JTa8<~r4R*8_ev%t%OI z+g_9x50?#fpB8RC6?QYx6P&iy-BBI(M+eW#z{NgO+JHS?weu`xRUU!=0D*~p4gdS# zqtcB|D*Igvr+ZvSPmRYe72d&=;hH9Wt@lvb{~~tVigO{%253VHY@ryeW9(n0Hs(0& zWA_~y=1-PnbvlUp$j#U928Cf{3jATDZ@>;c@ z;Jv$PG1n3KBUQZQrW6EwSXkg|(!9JcP}NmbZovnK5$NC@_jZk-@(=r&c!qf}#(8#0 zxs(=F>Tc`eetbJgF+41ld{v^}IjljQxf)p$tpGMbj^Qo1*p3bpR(h&=r19pqeC9k- zT6Jz*&ff75FxnUCJDdfcH=nfw>AF}S@1+f48Oa6?g)A}fxzglx%@^HO_0B;Q&k6*d zMPfm@w*;vBqjVLHjcZcI(NmQRk~v)o!gKihBl zfRqv>XHa$UHOjvXOijgM7Y(mW0 zp&(rSrgm33@yaHgr=d#fzr#n8%)GLa-v3Q(d4Fnk)mJ?E{2>h^$qlM%pRagHFI#LX zu`!&y7>Ht<`4gi5L@a{T|1n~b3I4tScj=o$@w;=nsNqZC-Byhp>{g_ZL3Hp57j#R1 zu1QS9%v&~n>0GE}3hzXLuNL&C2o}dr&go}yms7eub+!~M` z>w1Tu?m#7iw4Hq0y|vWl1$d>YwUl|xToKv1hcDNQ_`@B=4`{0G1M?3KgHpiujeBTq zko4lz(3*@23JN-mq3`b=38N1O7`8!ztihYI>b$RPKfTHN)CBW7+>Sm=`?B)7^<>0$ z>b=4>Fq6KJc(p8XvPSAYs`N$GFO0$_bHwvdCpRN6V=gZbNI@+i^$#5)mb8@Uk-U|) z_Rz->VGZ%}qx*Vx)Zpaya($H(GFJmQ4tKr;WC=_>0=zRFbSi|7>5p{)sKZ%67*(=H z!Op*3yYp<0b>|al=23XSEw15Eh&4>DtH}7n8iGk{E^=Wl^;@+5CNunK_t$xg0`8o_@<^+AWKyoBLjTt|$u1P>2S;_;v+GlMeE z5Dot$utKUjldjOxOkp>=BrcGpYQ>p8m>;U?y2C7(T?i z;WR{@l(GMzm=Mc!iwr$^%6k|j!$7(f0^u!LDeHa3W{^Jp1yl5Z5++2RAcQ7nK;|B> z>&-jpmpGTmKsn667&PoQoKn~N^W0+<<2?7UKZT?%I~5m0{)M2>t`6Qaar!?65d*)M ze*usS&<70ETYISNK;RCp^81DvDE+Lkrv5t|73LdaEP}S2=_(!M% z{TSedFaQ+>?1+EmVl3G6N8|fwC1N)Yw`YDOcNi9c=5hxwWY70nL@ezcS5hSW=F+0m9E+YIf}In5^T?YT1I9SqRHb^}n^;>gRNZQ{oiGd2Md+ig?5B!e%0 zFOZar>f;zLJ_)Ih;L|Vf2bO=U3p6!m$Hg%*n7fVdlsLMDWFXlAkzW-d+HVg4!WPpB zzr%@!YICLY&s?u(c_zvwFvc4M>G0~(XJXC*EvfT zs~ASiQ824m8{_AF_W~b@3$rCVyrUeDF^#i{9XCWl{TgUa5Btw|%=R`l7@p3Ipz04f zOja}Hl@W82l>{XX6BFkfzS;%li$sU+kAya!h{9PCO;W)0rI#Yl3;=Qo*>-RlnyEy3akX=}bcK{1muMgp!TxMSmoq zKEU&}e-92jf#tmXK#pZZo=#RQbYhde2%*l+07vV4S=7ZIdu%aHQmnY{pv%-@YoBWp zCC(0}y32n4s=KDhILSzcP&I$^EP`>iwIQzy|H3FPQn_cd=CVinN5T&clGo$md+Lxt znOdP4mpCXsUx&<2ERA_#yBHZT_70rf5YZF%effw{Gjr(sJRQsv3|^4 z<6Gj;zsbiY#A_6?l9RcnE$fMpKxnIe&P<2CEMs)}#J1YLd+Y{8rlAcVRG$kOAQ2T{ zTqdBRF1dl&@**u4QmaJ(^$gPJ(4XC@Yp3k}Tw`x6(52Z}o6mzk6x8&YLZ`gAL~mx@ zNLJFM)8gV2zSy)63TvE-uSgI}St3q3KwCbi0Qe?WP_U<>ZyI6*(mXn`WbI>T0rX0s z-5>V*a9AjEr6P?U%r?6Um7`a4)c2LEU~@F+r_q8gj)BNdvZBp0u=s!%u*S0u>`z3{qS#@ws-i>06ikC;MYdGUvm=#Zwi-QlU#FJx>OCS)E&XH(gmh21!i^`1 zUZQ?W@dVDxV0)1S=jF+&*T#z2xk_dtnLV{fKgs0NYu?$X%1wb1mJUkPOL0_uDxC(@ zFQOlA{;Yignme!g^ke>74d3mdwi9`mL<0FR&C!p})#Z_c^Hb+a7Cj1qNpZui@q6-f zHHwm3i*Xd^B@iHk13I%mb=~ntxSt#DeVtrVJe|bpmQ3(liG$iywZNM#n%4nc!H1Aa z=a(EsgZH;e&R|C1?}cg`6mIQ0$w!H@%^x|h{LiNY$p5_{^`8lVUee^!9LW-dNM982 zrQLY^7kvwwRwI;SFf;&t-TGVEGwcJ^Y`&lOHL+>@y>RAqpP_@b3)FCiUv*iY?q>a} z$MN}ep;hcif;M}Tze$G9#|Qit0^RyGwn87Y$VvdMucsuK1MqPvN5fY<^_+(WKij)s z^R;BJnm8Hdb^g@)>B$W$jh&W2t%%_2=mpmg5OaGzGe9!xQrjm?SxHhzV)P%bOiYA* zql{sm@`I6U$mHU0VGzckl+t$axhl}!{an{5Ljp=}KnC=yK6VR@`ri};v7h~y1wqhV z)c!|Sl@R#RR>a{iLDJtuRhh&|O#c_1WZA@nySt59J5_&#M^HQ1xyT><|Esx)0eb-F zKIehB$r+-tURi|}JDc~uo)r5YLNcr#lb?kW>(H&%}kES~MJPtCa2D~lK8hwl&~l7;lGrBTA3!5Hv^vP&@;-N*qP zMud>(yoG9c##G}4g=Uy|##eEID8vKqtiYWIY^RkzMN9Is&71BGJp98x1wP+#pFK4V zm3sMPx#95U_<-D5y2ybn^SUDq{2&smi)TJ@)4yhkoe?3k(1lE=fv>OZyOfI)1WUsu zgj9t*vKkY-dt^OoO`g`?*-$y*#EW|T66U0SrE%z)tWNIxEFa_@Ut`#L zGrA;q<}J3KDW^t!jxp}y5pb-kM`@5Vm~W~-t9a&rje=1OH^%LUaW9WczRmIJX;a)& zGFbI~(CL_Be@!bP!T_zqzHHR{4r)Uas|#8D>5UltU<`Ms2Z^}DF#cnAUpuF3pJVr7Ek}UzDg=Mi5uLjm&V=k&tM3SL6t_12MW*2ha z!UD{3rfKZNF#3q?*qRQH(|u!&@ZxPs-TWyNO&hcGs{E(%VVM45o%YfGOI4!bYT3S} zshd|e!`ZIRBCEiM6Gq#*c{o9THTotm!sEq3W5!hOh0VGpmXvBFJh=Vzy-!(_rG)OI zckc;zkeY3T2r6(hk;6{ZsEu%(m<(oXq}fJm`MpdVIGxX>##Oa`8%ZTQrm=hj--coz zrHqkc_MUo?q4AGPQ*&pOLB`4=uii19nm#>bM{O9AFi6B@q!CNO9e2|0``?I%2=7Hm zxJsJt&%?D!(6718kjbVv)@I!>sV>a**+p+NZXA1{1Rf%|@34<=Z@>>Y(B~~=Z6;j_ z;n3pz)_Pfx+un(tB%~me9v*h#P0-b~svc9{1+3gqss(n1*dX$XKl9xl&$=`pnCJt@Zh*9;^MmS!K@vQ6Nr4+Y|9XxPH@N&LHZT^^8Yqzhy z;4#K?RFaiW-B-S1yl#9gp8tE4CIRjKT9Jmq3w1t42SRVkzaE}Shy&7`Ta>vHPEeGc)Z zsTsOw2ik;V3eu=q*JXLI93(ZlK4m(h0tsfb9 zSG;rC`TsR`uHjIoe;l8KNfSckY)rIF2dCPK9A@mAD3;W2a;OpdE5cfvvuB3Lh}}`y zSi2!=t;7_TwW-lMhjj?qh?;Q>G0ZUZ%*@_1CIa{=0)iJ7g>@@R(dk#;lZt8H*%tT^} z$mYxWlPB5=gVQ4YQ;BR>hBezX@D#3Dz*ptghdR+#N@wAv%QfEbDQL^QPOqh&PA|xA z#`Hs$T&}nG*z%KRxr5k%UJKdF``XB-W2@Sbn*)k=K4kFk=u4%tNO!5T$R*M{T_&iwtC!edZ=OKmJ+906)&oddM1$v z{NTbDgNDQ{O7$6tPv_GqI=}OZo$Twz&l7?#N%E28&@hsLZCJ^#ieYZrx*ix~ML>A+Uo{@A!paE@3@SgYy%p&*XK0;4++&b`A7^sjG>7Kk-v!^ znOtA!fr!cZsDXG}JAPRPEa@V=4Rmp1D-cN5Qkx{au{X*8?gD|(|z+1<+l0j zw;XImaLY1`E(sbzK8HPqlRB)>9ChG*oI@c%7c)z22jq$9JSqfjrBEnW`i)hb4~tn; z@z(0W;04PAXYNu3eGRQAwAr2ARysfeUq~bnab)vKW48e@Hbw})$2e|zzqm596!tYd z_6^qf?!;kkme7gpuzSn*&7An_*F{#s{qEV}Do(29pE^x+~$$ zteCl(c4P9p+&$&`jS9lpVI=&n@VX$@`b)a#8Q`3O9U$R?*#1LTfzcMH{`7h*s~oW_ zjggafTYG2C<|#K?t(VvnD&Bu)aCv$8_O~UIB~K3Vn5P1t>Pis73<|n8J_s^uHwik` zcon!3^Hjb&BzldkIm=`*wa8CXGANqQnR{-#6uk;62?W3J{3-TEuE>O6+?eNm`UmE- zU9NLeBb)=4uy41-3K!f2Z>tSSkRj2^APHtq+TbS3ZRy%eyq{_lzxwd{3U@3$(kNzz zcDFO`viP}s`}3EjJ*?`u#Eddy-y`DO>vW2Bs}eOAJY0tq+e9r4Tvf)-VL+A_HvazcD2G&#P++ZgU-|-ERi|wq4E);zXoVIzvpM5==`8)J;*~ z5BWe}iDSh2#c{%JqfFl14mzd7(K7_JEgUrpg8$GyAQ}%EyimirqN`-E-`gbX^VI|V zQc@hx@(#nbuidkjv!#wFD zA=M+8Xx_zlJ+kAv8Scxb>ZtQ}8R92>YC+{r6Yc*y#bG0mZNjH7KELFp^%CEf~8B*$=N$=V2!a`ecW55MqOAr zi7Wsw$f}qc>5NyVuaWg&6s$}&cL3;c1U47<+i#sl_sbp#E9WcSYlaU-VS;MY?nL}C zbbImmGrdv{J%<3?Ueqt1Zn`V@V_WFaWGDa)(< z;_^<`AAN<0qo=8_Sv_}OB3xd2_z~5ud2@FX^KN+Jg1u@DoWOI$j4D&zDi$o7m_>9w z$P3jT8az?W1bimeYFUXJF3*C77vy}Yf3v*jN7=hsb2eum9&0WbEWf z#Xy~@T5SK4{`#$yijrIu%vN5b1P$KX_em20rztsqeDo)aQZ|YHg2IcZ5*g5 zNfbTO3L@W#X$I*&Y1VIBana?d6OB-*LoygCNw>UuM=h z+-WIYlSC&g38YOZ;~NUdN!k3!O@`oniAo>&{mfx$YN~~YtVB2D6}Tdu;b?A8JwsQC zlbeA6JYe=O9w_OU%3IUSv^qHrRpuZOr*8)G(wj%LrTO`KSJg@L1p1kL#4ed^V(sJ_ z-xLA9S(3T}7TdL<;x0dw@?#S6Gi1+R|7@zwF)0YP>#5?O>uUUV9-;mJ@C88oe%|qI z`ORz4fwf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/logos/microsoft-logo.jpeg b/docs/assets/logos/microsoft-logo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..60dbab3b9dc703c0751cc2f44f11b9c392982d74 GIT binary patch literal 5892 zcmYjV2UrtJ*WQF;=mZELJ@jJe51q-E%R0u>>&c>D<%-AP@k6fERG_8Hfa^ zC@(QFGX1#`tOzCqf{~GljS;LE84*mZtO&5MbBpq^a|m%G5J(xMkeGy|lq4IkoR*v- zS`;NI0imX*rl+IlU}R*KK=KNs(Xw)A^c5MjjI<&e6eQ6SXtc}~6iQMOg$BE$&}az> z6bh|?LP>xHC5yUf0pKto4&qG);Rm2_2pJr5(E)G*02E3FF7p2h83amBd5HovYBK^5 zGBOA`#U%I*l(B$>|HWq|{oV=#7sb6?% zTI=Z8cSol@*7iShfJ4DK{{JN86i~`b5Hipx2M2uwg;G#mqWJF;AmAJna3-X23JXG3 z-o)p1t^V{<2e3>s50CyN{T zW^SVcg}kC)ixnm|y*|mv;&}?;iD+=_E#AHUOF~#CEG!;VSul}jsMi~h35&*5u21CI z>4jL6ldHL201w|_H+T?hVD;zm2nb?LKmAndNG*pN(C#J?F>P^gzu*{8`^miguQm}&% z!{JthO1kNuHd>wnef6qJib=1wx;%wKfi+QMAuk_OYFGlro6Nm5A;!feAjE!QOuj6= zH2NbjZGplz-Y8F8UN6FwoP&tXi`~Bows;;`x%s(PdPm4dMTZnM4gh?~te2HEgj}i} zfYGR!mDFfN=ExOBT6P-vhLC=5!>*M9J9iH<0^+3Wd;4eFLX{Ic4Auqh$}%pzo?6Av z4&z5bwHnj)i?K2Gd`NaGW_Kf*UTn0+`A>|dbedWb-WU(GLFt%?f86nJYx}C!Nok7= zDU3L3oNsDszfyUJfMuaji_1`sy2?>Z-0)|{4ub9wzshO?`T#qK;7T|3HNg&TQa^Sr zUX6Qhy^z5&w-ZKOFC=0>pNSpMLktJ4^D%k(8ZIm+xpARp+w$6&mR(cgr&b8I#6>4g zWSqMseM1e#PiJy(lzB6QvIut7kf4RlGgZ!w39vFZePRFBCU>yHGHAct%B*%fVu3=d zmi__Rn?Q;_i^bV@Q$pux@vQ;Zq@NN!Jv#$#pOV;|=x7)}j5VnL$Lf@Fcu@K)_Q`Xi zlFp1tuJ|64zV&#p?slCSmmmcxS;Twvz9bV zrY15nmR?U#N$dwLIl1PNpkaxSlGyj>AZ$1BrUsrS4s0-(cAM#uD1kx&;*(AeT^0{P z$lf ztF{ixMgF*Xgypz-^ftg0I4t(NbTQ?v+lV=Wi}KT^&vb^1u(In#&aFYH8Vp}p^7}YM76o85 zz0I*O(-)Rkyai?>5~t2(v33^#{HEdC-_AK7{^3uri9PPm9UTpeL zMLu9<9Vt&_QohO2f82znZLX;qFHjKj{dO=b{3vxavrSp}#17YV>T_D8Y{xS}On#=| zI=7Oq_1rHZYM+AhR-+;$B#G8L3*Gw_a1Vv}e(O_5MIW9Q_XjQ-Mx$(v*x%Z5X6sYY zk?6_zvTbb$ZW=pZ|9*|Qu1E?FrtG$fnAYgI^i> zeEh2(^B)#ShH&vaIYstRbluj1u85~CEi*5Hdl=%Ay#@j5``#WYY8@%IRbQsul90t zY+e8g!t#)d{R9`;l}nJj{DsGk_>6XyJSzbw0|psW8qGj5{>8S zN0-Ot7l6~pL3uB_l#>r@+V7 zLipO|=F65@H)fo}1_?heT>yWr7Qg3G)teRs3b-;;Rv_y>8Q8y!;mPM)pweJ?u#*5a(}W+4tsJpH^( z5him+dzv*`6~8&e=o~HmgJXe%JCYo)A&QK8w}wgwx0E$@g~D zW-=?QUe@1qdc}G7`%<{!S-jjsg|GgGAIfcaWu-msW<$xwYKDaqk!dFbM|zWouNo#1 z#*M2pU83E;t@X7(3=YRJXc9v`1Qpyou8}!;%zGc&W;~+Xee3z$V~&e!J^Yi-6rPDv z5o1%^KK(X7q0E)bnLgtJ$lmZ9=2N2B(%0r1tbWT-Np5Q!PS<+rHZD0Bw_Gdq=9v=z zGRZ&tQf$-p=&0@!)Z?tjE{r`J&n_!QIC^L}VJap4!jw3q^!pwoBcFUe;A*-r@)?oA zq;}JqYdXTSJ+on_xm+oXGAB7g%0DQxFt02{@B6xj6Q_*^|V{t^2o*YX4qm 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 CW!b&} literal 0 HcmV?d00001 diff --git a/docs/assets/logos/nvidia-log.png b/docs/assets/logos/nvidia-log.png new file mode 100644 index 0000000000000000000000000000000000000000..40fd014bc5951682a5664a9f8dcb5918d11a1dad GIT binary patch literal 58640 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 W^4++yNj*U%Tx)%OIR?G(Cy@uoSwX-^N0jMhg( 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
    i?(BPU1 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 literal 0 HcmV?d00001 diff --git a/docs/assets/logos/princeton-logo.png b/docs/assets/logos/princeton-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c902cab835547833689d00243a91e93b8a92a648 GIT binary patch literal 6330 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 R{_DSE>1i9^th|9G{V$pNc!2-_ literal 0 HcmV?d00001 diff --git a/docs/cli/CLI_STATUS.md b/docs/cli/CLI_STATUS.md new file mode 100644 index 00000000..0fce38fc --- /dev/null +++ b/docs/cli/CLI_STATUS.md @@ -0,0 +1,32 @@ +# Ember CLI Status + +## Current Status + +The Ember CLI is currently being developed separately from the core Python framework. It has been excluded from the main development workflow and git tracking to allow for independent development and prevent integration issues. + +## Structure + +The CLI is built with: +- TypeScript/Node.js +- Commander.js for command-line parsing +- Python-bridge for communication with the Python framework + +## Key Components + +1. **Command Modules** + - model.ts - Manage LLM models + - provider.ts - Manage providers + - invoke.ts - Invoke models + - config.ts - Manage configuration + - project.ts - Project scaffolding + - version.ts - Version information + +2. **Services** + - config-manager.ts - Manage CLI configuration + - python-bridge.ts - Interface with the Python framework + +3. **UI Components** + - Spinners, progress bars, banners + - Interactive prompts + +The CLI is currently excluded from the standard installation. When development resumes, it will be available as a separate package or optional component. \ No newline at end of file diff --git a/docs/cli/DEVELOPERS.md b/docs/cli/DEVELOPERS.md new file mode 100644 index 00000000..f2e4bf05 --- /dev/null +++ b/docs/cli/DEVELOPERS.md @@ -0,0 +1,430 @@ +# Ember CLI Developer Guide + +This guide is intended for developers who want to contribute to the Ember CLI or extend it with plugins and custom functionality. + +## Architecture Overview + +The Ember CLI uses a hybrid architecture: + +1. **Frontend**: Node.js/TypeScript CLI interface built with Commander.js +2. **Backend**: Python Ember core framework accessed via python-bridge +3. **Configuration**: Local storage using the conf package with encryption + +``` +┌─────────────────────────────────────────┐ +│ Node.js Frontend │ +├─────────────┬───────────────┬───────────┤ +│ UI/UX │ Command │ Config │ +│ Components │ Handlers │ Manager │ +├─────────────┴───────┬───────┴───────────┤ +│ Python Bridge │ +├─────────────────────┼───────────────────┤ +│ Python Backend (Ember Core) │ +└─────────────────────────────────────────┘ +``` + +### Key Components + +- **CLI Entry Point** (`src/cli/index.ts`): Main entry point that sets up commands +- **Command Modules** (`src/cli/commands/`): Individual command implementations +- **Python Bridge** (`src/cli/bridge/`): Interface between TypeScript and Python +- **UI Components** (`src/cli/ui/`): User interface elements +- **Services** (`src/cli/services/`): Shared functionality +- **Utilities** (`src/cli/utils/`): Helper functions + +## Development Setup + +### Prerequisites + +- Node.js 16+ +- Python 3.11+ +- TypeScript 4.9+ +- Ember AI package + +### Installation + +```bash +# Clone the repository +git clone https://github.com/pyember/ember.git +cd ember + +# Install dependencies +npm install + +# Build the CLI +npm run build + +# Create a link for local development +npm link +``` + +### Development Workflow + +```bash +# Run in development mode with watch +npm run watch + +# Test your changes +ember --debug + +# Lint code +npm run lint + +# Run tests +npm test +``` + +## Adding a New Command + +To add a new command to the CLI, follow these steps: + +1. Create a new file in `src/cli/commands/` for your command +2. Implement the command with the Commander.js pattern +3. Register your command in `src/cli/index.ts` + +Here's an example of a new command: + +```typescript +// src/cli/commands/example.ts +import { Command } from 'commander'; +import chalk from 'chalk'; +import ora from 'ora'; + +import { getPythonBridge } from '../bridge/python-bridge'; +import { isJsonOutput } from '../utils/options'; +import { displaySection, displaySuccess } from '../ui/intro'; + +/** + * Register example command with the CLI program + * + * @param program The commander program instance + */ +export function registerExampleCommand(program: Command): void { + program + .command('example') + .description('Example command to demonstrate development') + .option('-n, --name ', 'Name parameter') + .action(async (options) => { + await runExample(options); + }); +} + +/** + * Run the example command + * + * @param options Command options + */ +async function runExample(options: any): Promise { + const spinner = ora('Running example...').start(); + + try { + // Get name from options or use default + const name = options.name || 'world'; + + // Get Python bridge + const bridge = getPythonBridge(); + await bridge.initialize(); + + // Call Python backend (example) + const version = await bridge.getVersion(); + + // Stop spinner + spinner.stop(); + + // Format and display result + if (isJsonOutput()) { + // JSON output + console.log(JSON.stringify({ + message: `Hello, ${name}!`, + version + }, null, 2)); + } else { + // Human-readable output + displaySection('Example Command'); + console.log(`Hello, ${chalk.cyan(name)}!`); + console.log(`Ember version: ${version}`); + displaySuccess('Command completed successfully'); + } + } catch (error: any) { + // Handle errors + spinner.fail('Command failed'); + console.error(chalk.red('Error:'), error.message); + } +} +``` + +Then register your command in `src/cli/index.ts`: + +```typescript +// src/cli/index.ts +import { registerExampleCommand } from './commands/example'; + +// Register commands +registerVersionCommand(program); +registerProviderCommands(program); +registerModelCommands(program); +registerProjectCommands(program); +registerInvokeCommand(program); +registerConfigCommands(program); +registerExampleCommand(program); // Add your new command here +``` + +## Extending the Python Bridge + +If you need to add new functionality to the Python bridge: + +1. Add a method to the `EmberPythonBridge` interface in `src/cli/bridge/python-bridge.ts` +2. Implement the method in the `PythonBridgeImpl` class +3. Add corresponding Python code that will be executed by the bridge + +Example: + +```typescript +// Add to the EmberPythonBridge interface +/** + * Run a custom function in the Python backend + */ +runCustomFunction(name: string, args: Record): Promise; + +// Implement in the PythonBridgeImpl class +async runCustomFunction(name: string, args: Record): Promise { + await this.ensureInitialized(); + + const argsJson = JSON.stringify(args); + + return await this.bridge.eval` +import json +try: + # Call the function dynamically + result = getattr(service, ${name})(**json.loads(${argsJson})) + json.dumps(result) +except Exception as e: + json.dumps({"error": str(e)}) +`; +} +``` + +## UI Components + +The CLI uses several UI components to create a beautiful user experience: + +- **Banner**: Displays the Ember CLI logo +- **Spinners**: Shows progress for async operations +- **Tables**: Formats tabular data +- **Colors**: Highlights important information +- **Emoji**: Adds visual cues + +When creating new UI components, follow these guidelines: + +1. Use the `chalk` library for colors +2. Use `ora` for spinners +3. Use `table` for tabular data +4. Use `emoji` for visual cues +5. Always respect the `--quiet` and `--no-color` flags + +## Configuration Management + +The CLI uses the `conf` library to store configuration. Key features: + +- **Encryption**: Sensitive data is encrypted +- **Schema Validation**: Configuration follows a defined schema +- **Persistence**: Configuration is stored between runs + +When accessing configuration, always use the `ConfigManager` class: + +```typescript +// Get config manager singleton +const configManager = ConfigManager.getInstance(); + +// Get a setting +const value = configManager.getSetting('my.setting', defaultValue); + +// Set a setting +configManager.setSetting('my.setting', newValue); +``` + +## Error Handling + +Follow these guidelines for error handling: + +1. Always catch exceptions in async functions +2. Use `try/catch` blocks around Python bridge calls +3. Show user-friendly error messages +4. Include technical details in debug mode +5. Use spinners to indicate progress/failure + +Example: + +```typescript +try { + // Code that might throw + const result = await riskyOperation(); + // Handle success +} catch (error: any) { + // Handle error + console.error(chalk.red('Error:'), error.message); + if (isDebugMode()) { + console.error(error.stack); + } +} +``` + +## Testing + +The CLI includes a comprehensive test suite: + +- **Unit Tests**: Test individual components +- **Integration Tests**: Test command flows +- **Mock Tests**: Test with mocked Python bridge + +To write tests: + +1. Create test files in the `__tests__` directory +2. Use Jest for testing +3. Mock external dependencies +4. Test both success and failure cases + +Example test: + +```typescript +// __tests__/commands/version.test.ts +import { registerVersionCommand } from '../../src/cli/commands/version'; +import { getPythonBridge } from '../../src/cli/bridge/python-bridge'; + +// Mock the Python bridge +jest.mock('../../src/cli/bridge/python-bridge'); + +describe('Version Command', () => { + beforeEach(() => { + // Setup mocks + (getPythonBridge as jest.Mock).mockImplementation(() => ({ + initialize: jest.fn().mockResolvedValue(undefined), + getVersion: jest.fn().mockResolvedValue('0.1.0') + })); + }); + + it('should display version information', async () => { + // Create a mock Commander instance + const program = { + command: jest.fn().mockReturnThis(), + description: jest.fn().mockReturnThis(), + option: jest.fn().mockReturnThis(), + action: jest.fn().mockReturnThis() + }; + + // Register command + registerVersionCommand(program as any); + + // Verify command was registered + expect(program.command).toHaveBeenCalledWith('version'); + + // Get the action callback + const actionCallback = program.action.mock.calls[0][0]; + + // Create a mock console.log + const originalLog = console.log; + console.log = jest.fn(); + + // Run the action + await actionCallback({}); + + // Verify output + expect(console.log).toHaveBeenCalled(); + expect(getPythonBridge().getVersion).toHaveBeenCalled(); + + // Restore console.log + console.log = originalLog; + }); +}); +``` + +## Building and Publishing + +To build and publish the CLI: + +```bash +# Build the CLI +npm run build + +# Test the build +node dist/index.js version + +# Publish to npm +npm publish +``` + +## Style Guide + +Follow these coding style guidelines: + +1. Use TypeScript for all JavaScript code +2. Use async/await for asynchronous operations +3. Document all public functions and classes with JSDoc +4. Use SOLID principles for code organization +5. Use semantic versioning for releases + +## Best Practices + +1. **Security**: + - Never log API keys or sensitive information + - Always encrypt stored credentials + - Validate user input + +2. **Performance**: + - Minimize Python bridge calls + - Batch operations when possible + - Use streaming for large responses + +3. **User Experience**: + - Always show progress for long operations + - Provide clear error messages + - Include helpful tips and examples + +4. **Code Quality**: + - Write unit and integration tests + - Use TypeScript types strictly + - Document complex code + - Follow the SOLID principles + +## Troubleshooting Development Issues + +### Python Bridge Issues + +If you encounter problems with the Python bridge: + +1. Check that Python 3.11+ is installed and accessible +2. Verify Ember AI is installed in the Python environment +3. Use debug mode to see Python errors +4. Check that Python bridge is being initialized correctly + +### TypeScript Compilation Issues + +For TypeScript errors: + +1. Run `npm run lint` to find code issues +2. Check import paths (case-sensitive) +3. Ensure type definitions are correct +4. Run `tsc --noEmit` to type-check without building + +## Getting Help + +For development questions: + +1. Check the existing code for examples +2. Review the documentation in code comments +3. Open an issue on GitHub for unanswered questions + +## Contributing + +We welcome contributions to the Ember CLI! Follow these steps: + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Write tests for your changes +5. Run the test suite +6. Submit a pull request + +## License + +The Ember CLI is licensed under the MIT License. \ No newline at end of file diff --git a/docs/cli/ERROR_HANDLING.md b/docs/cli/ERROR_HANDLING.md new file mode 100644 index 00000000..450f8486 --- /dev/null +++ b/docs/cli/ERROR_HANDLING.md @@ -0,0 +1,160 @@ +# Error Handling in Ember CLI + +Ember CLI includes a robust error handling system that provides structured errors, detailed information, and helpful suggestions to users. This document describes how error handling works and how to use it when developing new commands or features. + +## Key Features + +- **Structured Errors**: All errors extend a base `EmberCliError` class +- **Error Categorization**: Errors are categorized by type with specific error codes +- **Rich Error Information**: Errors can include suggestions, documentation links, and context +- **Python Error Mapping**: Python exceptions are properly mapped to TypeScript errors +- **Consistent Display**: Errors are displayed consistently across the CLI + +## Error Class Hierarchy + +The Ember CLI error classes follow this hierarchy: + +``` +EmberCliError (base class) +├── PythonBridgeError - For Python bridge communication issues +├── ModelError - For model and provider errors +├── ProjectError - For project-related errors +├── ValidationError - For user input validation errors +├── ConfigurationError - For configuration errors +├── AuthorizationError - For authentication and authorization errors +└── NetworkError - For network-related errors +``` + +## Error Codes + +Errors are assigned unique error codes for identification and documentation: + +- **1000-1999**: General CLI errors +- **2000-2999**: Python bridge errors +- **3000-3999**: Model and provider errors +- **4000-4999**: Project errors + +## Using Error Handling in Commands + +### Creating and Throwing Errors + +When you need to create an error in your command: + +```typescript +import { createModelError, ModelErrorCodes } from '../errors'; + +// Create and throw an error +throw createModelError( + 'Model not found: gpt-4', + ModelErrorCodes.MODEL_NOT_FOUND, + { + suggestions: [ + 'Run `ember models` to list available models', + 'Check that your OpenAI API key is set correctly' + ] + } +); +``` + +### Using the Try-Catch Helper + +You can use the `tryCatch` helper to handle errors consistently: + +```typescript +import { tryCatch } from '../errors'; + +await tryCatch( + async () => { + // Your code here + const result = await someAsyncFunction(); + return result; + }, + {}, // Error format options + true // Exit process on error +); +``` + +### Handling Errors in Command Actions + +For command actions, wrap your function in a try-catch block: + +```typescript +.action(async (options) => { + try { + await commandFunction(options); + } catch (error) { + handleError(error, {}, true); + } +}); +``` + +## Error Format Options + +When displaying errors with `handleError`, you can customize the output: + +```typescript +handleError(error, { + includeCode: true, // Include error code in output + includeSuggestions: true, // Include suggestions + includeDocsLinks: true, // Include documentation links + includeStack: false, // Include stack trace + useColor: true, // Use colored output + asJson: false // Format as JSON +}); +``` + +## Python Error Translation + +The Python bridge translates Python exceptions to TypeScript errors: + +``` +Python Exception → TypeScript Error +----------------- --------------- +ModelNotFoundError → ModelError (MODEL_NOT_FOUND) +ProviderAPIError → ModelError (PROVIDER_API_ERROR) +ValidationError → ValidationError (INVALID_ARGUMENT) +FileNotFoundError → ValidationError (FILE_NOT_FOUND) +``` + +## Best Practices + +1. **Use Specific Error Types**: Use the most specific error type for the situation +2. **Include Helpful Suggestions**: Always include suggestions to help users resolve the issue +3. **Add Context**: Include relevant context information for debugging +4. **Clean Up Resources**: Always clean up resources in error handlers (like spinners) +5. **Validate Early**: Validate user input early to avoid deeper errors +6. **Handle All Errors**: Never let errors go unhandled or display as generic errors +7. **Add Documentation Links**: For complex issues, include links to documentation + +## Example: Command Error Handling + +Here's a complete example of error handling in a command: + +```typescript +async function myCommand(options: any): Promise { + const spinner = ora('Loading...').start(); + + try { + // Validate input + if (!options.required) { + throw createValidationError( + 'Missing required option', + GeneralErrorCodes.MISSING_REQUIRED_ARGUMENT + ); + } + + // Do something that might fail + const result = await someAsyncOperation(); + + // Handle success + spinner.succeed('Operation completed'); + console.log(result); + } catch (error) { + // Stop spinner + spinner.stop(); + + // Rethrow (will be handled by command wrapper) + throw error; + } +} +``` \ No newline at end of file diff --git a/docs/cli/QUICKREF.md b/docs/cli/QUICKREF.md new file mode 100644 index 00000000..3791fe96 --- /dev/null +++ b/docs/cli/QUICKREF.md @@ -0,0 +1,167 @@ +# Ember CLI Quick Reference + +This quick reference guide covers the most common Ember CLI commands and usage patterns. + +## Getting Started + +```bash +# Install the CLI +npm install -g ember-cli + +# Check version +ember version + +# Get help +ember help +``` + +## Provider Management + +```bash +# List providers +ember provider list + +# Configure a provider +ember provider configure openai + +# Set default provider +ember provider use openai +``` + +## Model Management + +```bash +# List models +ember model list + +# List models for a specific provider +ember model list --provider openai + +# Get model information +ember model info openai:gpt-4o + +# Set default model +ember model use openai:gpt-4o +``` + +## Invoking Models + +```bash +# Basic invocation (uses default model if set) +ember invoke --prompt "Hello, world!" + +# Invoke specific model +ember invoke --model openai:gpt-4o --prompt "Hello, world!" + +# Read prompt from file +ember invoke --model openai:gpt-4o --file myprompt.txt + +# Add system prompt +ember invoke --model openai:gpt-4o --prompt "List 5 capitals" --system "You are a geography expert" + +# Save output to file +ember invoke --model openai:gpt-4o --prompt "Write a poem" --output poem.txt + +# Show token usage +ember invoke --model openai:gpt-4o --prompt "Explain quantum computing" --show-usage + +# Stream response +ember invoke --model openai:gpt-4o --prompt "Write a story" --stream +``` + +## Project Management + +```bash +# Create new project +ember project new myproject + +# Create project with specific template +ember project new myproject --template api + +# List available templates +ember project templates + +# Analyze project +ember project analyze ./myproject +``` + +## Configuration Management + +```bash +# List configuration +ember config list + +# Set configuration +ember config set defaultModel openai:gpt-4o + +# Get specific configuration +ember config get defaultProvider + +# Export/import configuration +ember config export config.json +ember config import config.json + +# Reset configuration +ember config reset +``` + +## JSON Output (for scripting) + +```bash +# Get providers as JSON +ember provider list --json + +# Get models as JSON +ember model list --json + +# Run model and get JSON result +ember invoke --model openai:gpt-4o --prompt "Hello" --json > result.json +``` + +## Environment Variables + +```bash +# Set API keys +export OPENAI_API_KEY="your-api-key" +export ANTHROPIC_API_KEY="your-api-key" + +# Set defaults +export EMBER_DEFAULT_PROVIDER="openai" +export EMBER_DEFAULT_MODEL="openai:gpt-4o" + +# Other options +export EMBER_DEBUG=1 +export EMBER_NO_COLOR=1 +``` + +## Common Options + +```bash +# Debug mode +ember --debug + +# Disable colors +ember --no-color + +# Quiet mode (minimal output) +ember --quiet + +# JSON output +ember --json +``` + +## Shell Completion + +```bash +# Install shell completion +ember completion install + +# Generate completion for a specific shell +ember completion bash +ember completion zsh +ember completion fish +ember completion powershell + +# Output to a file +ember completion bash ~/.bash_completion.d/ember +``` \ No newline at end of file diff --git a/docs/cli/README.md b/docs/cli/README.md new file mode 100644 index 00000000..dc8dfe6c --- /dev/null +++ b/docs/cli/README.md @@ -0,0 +1,551 @@ +# Ember CLI Documentation + +The Ember CLI is a powerful command-line interface for interacting with the Ember AI framework. It provides a beautiful, intuitive interface for managing models, providers, configurations, and projects. + +## Installation + +### Prerequisites + +- Node.js 16.0 or higher +- Python 3.11 or higher +- Ember AI package installed (`uv pip install ember-ai`) + +### Installing the CLI + +```bash +# Global installation +npm install -g ember-cli + +# Local installation +npm install ember-cli +``` + +## Getting Started + +### Quick Start + +```bash +# Display the version +ember version + +# List available providers +ember provider list + +# Configure a provider with your API key +ember provider configure openai + +# List available models +ember model list + +# Invoke a model +ember invoke --model openai:gpt-4o-mini --prompt "Hello, world!" +``` + +### Basic Concepts + +Ember CLI organizes functionality around these core concepts: + +1. **Providers**: AI service providers like OpenAI, Anthropic, etc. +2. **Models**: Specific LLM models offered by providers, referenced as `provider:model` +3. **Projects**: Ember applications that utilize the framework +4. **Configuration**: Settings for CLI, providers, and models + +## Command Reference + +### Global Options + +These options work with all commands: + +| Option | Description | +|--------|-------------| +| `--debug` | Enable debug mode with detailed logs | +| `--json` | Output results as JSON | +| `--quiet` | Suppress non-essential output | +| `--no-color` | Disable colored output | + +### Shell Completion + +Ember CLI supports shell completion for Bash, Zsh, Fish, and PowerShell. This provides tab completion for commands, options, and even dynamic values like model IDs and provider names. + +```bash +# To install shell completion for your current shell +ember completion install + +# Generate completion script for a specific shell +ember completion bash > ~/.bash_completion.d/ember +ember completion zsh > ~/.zsh/completion/_ember +ember completion fish > ~/.config/fish/completions/ember.fish +``` + +For detailed instructions, see [Shell Completion Documentation](SHELL_COMPLETION.md). + +### Core Commands + +#### Version + +Display version information about the CLI and backend. + +```bash +ember version [options] + +Options: + --check Check for updates +``` + +#### Providers + +Manage LLM providers in Ember. + +```bash +# List available providers +ember provider list + +# Configure a provider with API key +ember provider configure [options] +Options: + -k, --key API key (omit to be prompted securely) + -f, --force Overwrite existing configuration + +# Display provider information +ember provider info + +# Set a provider as default +ember provider use +``` + +#### Models + +Manage LLM models in Ember. + +```bash +# List available models +ember model list [options] +Options: + -p, --provider Filter models by provider + +# Display model information +ember model info + +# Set a model as default +ember model use + +# Benchmark a model's performance +ember model benchmark [options] +Options: + -t, --tests Number of tests to run (default: 5) + -c, --concurrency Concurrency level (default: 1) +``` + +#### Invoke + +Invoke a model with a prompt directly from the CLI. + +```bash +ember invoke [options] + +Options: + -m, --model Model ID to use + -p, --prompt Prompt text to send to the model + -f, --file Read prompt from file + -s, --system System prompt (for chat models) + -t, --temperature Temperature setting (0.0-2.0) (default: 1.0) + -u, --show-usage Show token usage statistics + -o, --output Save output to file + -r, --raw Display raw output without formatting + --stream Stream the response token by token +``` + +#### Projects + +Create and manage Ember projects. + +```bash +# Create a new project +ember project new [options] +Options: + -t, --template